示例#1
0
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;
}
示例#2
0
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;
}