static void compute_file_name(char **strp, const char *user, const char *suffix, const char *what) { char *str = NULL; str = *strp; if (!str) { /* We'll put our various artifacts in a user specific dir * within the state dir location */ char *state_dir = NULL; const char *state_parent = test_state_dir ? test_state_dir : #ifdef WATCHMAN_STATE_DIR WATCHMAN_STATE_DIR #else watchman_tmp_dir #endif ; ignore_result(asprintf(&state_dir, "%s%c%s-state", state_parent, WATCHMAN_DIR_SEP, user)); if (!state_dir) { w_log(W_LOG_ERR, "out of memory computing %s\n", what); exit(1); } if (mkdir(state_dir, 0700) == 0 || errno == EEXIST) { #ifndef _WIN32 // verify ownership struct stat st; DIR *dirp; int dir_fd; int ret = 0; uid_t euid = geteuid(); // TODO: also allow a gid to be specified here const char *sock_group_name = cfg_get_string(NULL, "sock_group", NULL); // S_ISGID is set so that files inside this directory inherit the group // name mode_t dir_perms = cfg_get_perms(NULL, "sock_access", false /* write bits */, true /* execute bits */) | S_ISGID; dirp = opendir(state_dir); if (!dirp) { w_log(W_LOG_ERR, "opendir(%s): %s\n", state_dir, strerror(errno)); exit(1); } dir_fd = dirfd(dirp); if (dir_fd == -1) { w_log(W_LOG_ERR, "dirfd(%s): %s\n", state_dir, strerror(errno)); goto bail; } if (fstat(dir_fd, &st) != 0) { w_log(W_LOG_ERR, "fstat(%s): %s\n", state_dir, strerror(errno)); ret = 1; goto bail; } if (euid != st.st_uid) { w_log(W_LOG_ERR, "the owner of %s is uid %d and doesn't match your euid %d\n", state_dir, st.st_uid, euid); ret = 1; goto bail; } if (st.st_mode & 0022) { w_log(W_LOG_ERR, "the permissions on %s allow others to write to it. " "Verify that you own the contents and then fix its " "permissions by running `chmod 0700 %s`\n", state_dir, state_dir); ret = 1; goto bail; } if (sock_group_name) { struct group *sock_group; // This explicit errno statement is necessary to distinguish between the // group not existing and an error. errno = 0; sock_group = getgrnam(sock_group_name); if (!sock_group) { if (errno == 0) { w_log(W_LOG_ERR, "group '%s' does not exist", sock_group_name); } else { w_log(W_LOG_ERR, "getting gid for '%s' failed: %s", sock_group_name, strerror(errno)); } ret = 1; goto bail; } if (fchown(dir_fd, -1, sock_group->gr_gid) == -1) { w_log(W_LOG_ERR, "setting up group '%s' failed: %s", sock_group_name, strerror(errno)); ret = 1; goto bail; } } // Depending on group and world accessibility, change permissions on the // directory. We can't leave the directory open and set permissions on the // socket because not all POSIX systems respect permissions on UNIX domain // sockets, but all POSIX systems respect permissions on the containing // directory. w_log(W_LOG_DBG, "Setting permissions on state dir to 0%o", dir_perms); if (fchmod(dir_fd, dir_perms) == -1) { w_log(W_LOG_ERR, "fchmod(%s, %#o): %s\n", state_dir, dir_perms, strerror(errno)); ret = 1; goto bail; } bail: closedir(dirp); if (ret) { exit(ret); } #endif } else { w_log(W_LOG_ERR, "while computing %s: failed to create %s: %s\n", what, state_dir, strerror(errno)); exit(1); } ignore_result(asprintf(&str, "%s%c%s", state_dir, WATCHMAN_DIR_SEP, suffix)); if (!str) { w_log(W_LOG_ERR, "out of memory computing %s", what); abort(); } free(state_dir); } #ifndef _WIN32 if (str[0] != '/') { w_log(W_LOG_ERR, "invalid %s: %s", what, str); abort(); } #endif *strp = str; }
static int get_listener_socket(const char *path) { struct sockaddr_un un; mode_t perms = cfg_get_perms(NULL, "sock_access", true /* write bits */, false /* execute bits */); if (listener_fd != -1) { // Assume that it was prepped by w_listener_prep_inetd() w_log(W_LOG_ERR, "Using socket from inetd as listening socket\n"); return listener_fd; } #ifdef __APPLE__ listener_fd = w_get_listener_socket_from_launchd(); if (listener_fd != -1) { w_log(W_LOG_ERR, "Using socket from launchd as listening socket\n"); return listener_fd; } #endif if (strlen(path) >= sizeof(un.sun_path) - 1) { w_log(W_LOG_ERR, "%s: path is too long\n", path); return -1; } listener_fd = socket(PF_LOCAL, SOCK_STREAM, 0); if (listener_fd == -1) { w_log(W_LOG_ERR, "socket: %s\n", strerror(errno)); return -1; } un.sun_family = PF_LOCAL; strcpy(un.sun_path, path); unlink(path); if (bind(listener_fd, (struct sockaddr*)&un, sizeof(un)) != 0) { w_log(W_LOG_ERR, "bind(%s): %s\n", path, strerror(errno)); close(listener_fd); return -1; } // The permissions in the containing directory should be correct, so this // should be correct as well. But set the permissions in any case. if (chmod(path, perms) == -1) { w_log(W_LOG_ERR, "chmod(%s, %#o): %s", path, perms, strerror(errno)); close(listener_fd); return -1; } if (listen(listener_fd, 200) != 0) { w_log(W_LOG_ERR, "listen(%s): %s\n", path, strerror(errno)); close(listener_fd); return -1; } return listener_fd; }