Beispiel #1
0
static int wrap_is_usable_file(char *filename) {
  struct stat statbuf;
  pr_fh_t *fh = NULL;

  /* check the easy case first */
  if (filename == NULL)
    return FALSE;

  if (pr_fsio_stat(filename, &statbuf) == -1) {
    pr_log_pri(PR_LOG_INFO, MOD_WRAP_VERSION ": \"%s\": %s", filename,
      strerror(errno));
    return FALSE;
  }

  /* OK, the file exists.  Now, to make sure that the current process
   * can _read_ the file
   */
  fh = pr_fsio_open(filename, O_RDONLY);
  if (fh == NULL) {
    pr_log_pri(PR_LOG_INFO, MOD_WRAP_VERSION ": \"%s\": %s", filename,
      strerror(errno));
    return FALSE;
  }
  pr_fsio_close(fh);

  return TRUE;
}
Beispiel #2
0
static int wrap_is_usable_file(char *filename) {
  struct stat st;
  pr_fh_t *fh = NULL;

  /* check the easy case first */
  if (filename == NULL)
    return FALSE;

  /* Make sure that the current process can _read_ the file. */
  fh = pr_fsio_open(filename, O_RDONLY);
  if (fh == NULL) {
    int xerrno = errno;

    pr_log_pri(PR_LOG_NOTICE, MOD_WRAP_VERSION ": failed to read \"%s\": %s",
      filename, strerror(xerrno));

    errno = xerrno;
    return FALSE;
  }

  if (pr_fsio_fstat(fh, &st) < 0) {
    int xerrno = errno;

    pr_log_pri(PR_LOG_NOTICE, MOD_WRAP_VERSION ": failed to stat \"%s\": %s",
      filename, strerror(xerrno));

    pr_fsio_close(fh);
    errno = xerrno;
    return FALSE;
  }

  if (S_ISDIR(st.st_mode)) {
    int xerrno = EISDIR;

    pr_log_pri(PR_LOG_NOTICE, MOD_WRAP_VERSION ": unable to use \"%s\": %s",
      filename, strerror(xerrno));

    pr_fsio_close(fh);
    errno = xerrno;
    return FALSE;
  }

  pr_fsio_close(fh);
  return TRUE;
}
Beispiel #3
0
static int filetab_close_cb(wrap2_table_t *filetab) {
  int res = pr_fsio_close((pr_fh_t *) filetab->tab_handle);
  filetab->tab_handle = NULL;

  filetab_clients_list = NULL;
  filetab_daemons_list = NULL;
  filetab_options_list = NULL;

  filetab_service_name = NULL;

  return res;
}
Beispiel #4
0
static sftp_keystore_t *filestore_open(pool *parent_pool,
    int requested_key_type, const char *store_info, const char *user) {
  int xerrno;
  sftp_keystore_t *store;
  pool *filestore_pool;
  struct filestore_data *store_data;
  pr_fh_t *fh;
  char buf[PR_TUNABLE_PATH_MAX+1], *path;
  struct stat st;

  filestore_pool = make_sub_pool(parent_pool);
  pr_pool_tag(filestore_pool, "SFTP File-based Keystore Pool");

  store = pcalloc(filestore_pool, sizeof(sftp_keystore_t));
  store->keystore_pool = filestore_pool;

  /* Open the file.  The given path (store_info) may need to be
   * interpolated.
   */
  session.user = (char *) user;

  memset(buf, '\0', sizeof(buf));
  switch (pr_fs_interpolate(store_info, buf, sizeof(buf)-1)) {
    case 1:
      /* Interpolate occurred; make a copy of the interpolated path. */
      path = pstrdup(filestore_pool, buf);
      break;

    default:
      /* Otherwise, use the path as is. */
      path = pstrdup(filestore_pool, store_info);
      break;
  }

  session.user = NULL;

  PRIVS_ROOT
  fh = pr_fsio_open(path, O_RDONLY|O_NONBLOCK);
  xerrno = errno;
  PRIVS_RELINQUISH

  if (fh == NULL) {
    destroy_pool(filestore_pool);
    errno = xerrno;
    return NULL;
  }

  if (pr_fsio_set_block(fh) < 0) {
   xerrno = errno;

    destroy_pool(filestore_pool);
    (void) pr_fsio_close(fh);

    errno = xerrno;
    return NULL;
  }

  /* Stat the opened file to determine the optimal buffer size for IO. */
  memset(&st, 0, sizeof(st));
  if (pr_fsio_fstat(fh, &st) < 0) {
    xerrno = errno;

    destroy_pool(filestore_pool);
    (void) pr_fsio_close(fh);

    errno = xerrno;
    return NULL;
  }

  if (S_ISDIR(st.st_mode)) {
    destroy_pool(filestore_pool);
    (void) pr_fsio_close(fh);

    errno = EISDIR;
    return NULL;
  }

  fh->fh_iosz = st.st_blksize;

  store_data = pcalloc(filestore_pool, sizeof(struct filestore_data));
  store->keystore_data = store_data;

  store_data->path = path;
  store_data->fh = fh;
  store_data->lineno = 0;

  store->store_ktypes = requested_key_type;

  switch (requested_key_type) {
    case SFTP_SSH2_HOST_KEY_STORE:
      store->verify_host_key = filestore_verify_host_key;
      break;

    case SFTP_SSH2_USER_KEY_STORE:
      store->verify_user_key = filestore_verify_user_key; 
      break;
  }

  store->store_close = filestore_close;
  return store;
}
Beispiel #5
0
static int filestore_close(sftp_keystore_t *store) {
  struct filestore_data *store_data = store->keystore_data;

  pr_fsio_close(store_data->fh);
  return 0;
}
Beispiel #6
0
int pr_parser_parse_file(pool *p, const char *path, config_rec *start,
    int flags) {
  pr_fh_t *fh;
  struct stat st;
  struct config_src *cs;
  cmd_rec *cmd;
  pool *tmp_pool;
  char *buf, *report_path;
  size_t bufsz;

  if (path == NULL) {
    errno = EINVAL;
    return -1;
  }

  if (parser_servstack == NULL) {
    errno = EPERM;
    return -1;
  }

  tmp_pool = make_sub_pool(p ? p : permanent_pool);
  pr_pool_tag(tmp_pool, "parser file pool");

  report_path = (char *) path;
  if (session.chroot_path) {
    report_path = pdircat(tmp_pool, session.chroot_path, path, NULL);
  }

  if (!(flags & PR_PARSER_FL_DYNAMIC_CONFIG)) {
    pr_trace_msg(trace_channel, 3, "parsing '%s' configuration", report_path);
  }

  fh = pr_fsio_open(path, O_RDONLY);
  if (fh == NULL) {
    int xerrno = errno;

    destroy_pool(tmp_pool);

    errno = xerrno;
    return -1;
  }

  /* Stat the opened file to determine the optimal buffer size for IO. */
  memset(&st, 0, sizeof(st));
  if (pr_fsio_fstat(fh, &st) < 0) {
    int xerrno = errno;

    pr_fsio_close(fh);
    destroy_pool(tmp_pool);

    errno = xerrno;
    return -1;
  }

  if (S_ISDIR(st.st_mode)) {
    pr_fsio_close(fh);
    destroy_pool(tmp_pool);

    errno = EISDIR;
    return -1;
  }

  /* Advise the platform that we will be only reading this file
   * sequentially.
   */
  pr_fs_fadvise(PR_FH_FD(fh), 0, 0, PR_FS_FADVISE_SEQUENTIAL);

  /* Check for world-writable files (and later, files in world-writable
   * directories).
   *
   * For now, just warn about these; later, we will be more draconian.
   */
  if (st.st_mode & S_IWOTH) {
    pr_log_pri(PR_LOG_WARNING, "warning: config file '%s' is world-writable",
     path); 
  }

  fh->fh_iosz = st.st_blksize;

  /* Push the configuration information onto the stack of configuration
   * sources.
   */
  cs = add_config_source(fh);

  if (start != NULL) {
    (void) pr_parser_config_ctxt_push(start);
  }

  bufsz = PR_TUNABLE_PARSER_BUFFER_SIZE;
  buf = pcalloc(tmp_pool, bufsz + 1);

  while (pr_parser_read_line(buf, bufsz) != NULL) {
    pr_signals_handle();

    cmd = pr_parser_parse_line(tmp_pool, buf, 0);
    if (cmd == NULL) {
      continue;
    }

    if (cmd->argc) {
      conftable *conftab;
      char found = FALSE;

      cmd->server = *parser_curr_server;
      cmd->config = *parser_curr_config;

      conftab = pr_stash_get_symbol2(PR_SYM_CONF, cmd->argv[0], NULL,
        &cmd->stash_index, &cmd->stash_hash);
      while (conftab != NULL) {
        modret_t *mr;

        pr_signals_handle();

        cmd->argv[0] = conftab->directive;

        pr_trace_msg(trace_channel, 7,
          "dispatching directive '%s' to module mod_%s", conftab->directive,
          conftab->m->name);

        mr = pr_module_call(conftab->m, conftab->handler, cmd);
        if (mr != NULL) {
          if (MODRET_ISERROR(mr)) {
            if (!(flags & PR_PARSER_FL_DYNAMIC_CONFIG)) {
              pr_log_pri(PR_LOG_WARNING, "fatal: %s on line %u of '%s'",
                MODRET_ERRMSG(mr), cs->cs_lineno, report_path);
              destroy_pool(tmp_pool);
              errno = EPERM;
              return -1;
            }

            pr_log_pri(PR_LOG_WARNING, "warning: %s on line %u of '%s'",
              MODRET_ERRMSG(mr), cs->cs_lineno, report_path);
          }
        }

        if (!MODRET_ISDECLINED(mr)) {
          found = TRUE;
        }

        conftab = pr_stash_get_symbol2(PR_SYM_CONF, cmd->argv[0], conftab,
          &cmd->stash_index, &cmd->stash_hash);
      }

      if (cmd->tmp_pool) {
        destroy_pool(cmd->tmp_pool);
      }

      if (found == FALSE) {
        register unsigned int i;
        char *name;
        size_t namelen;
        int non_ascii = FALSE;

        /* I encountered a case where a particular configuration file had
         * what APPEARED to be a valid directive, but the parser kept reporting
         * that the directive was unknown.  I now suspect that the file in
         * question had embedded UTF8 characters (spaces, perhaps), which
         * would appear as normal spaces in e.g. UTF8-aware editors/terminals,
         * but which the parser would rightly refuse.
         *
         * So to indicate that this might be the case, check for any non-ASCII
         * characters in the "unknown" directive name, and if found, log
         * about them.
         */

        name = cmd->argv[0];
        namelen = strlen(name);

        for (i = 0; i < namelen; i++) {
          if (!isascii((int) name[i])) {
            non_ascii = TRUE;
            break;
          }
        }

        if (!(flags & PR_PARSER_FL_DYNAMIC_CONFIG)) {
          pr_log_pri(PR_LOG_WARNING, "fatal: unknown configuration directive "
            "'%s' on line %u of '%s'", name, cs->cs_lineno, report_path);
          if (non_ascii) {
            pr_log_pri(PR_LOG_WARNING, "fatal: malformed directive name "
              "'%s' (contains non-ASCII characters)", name);

          } else {
            array_header *directives, *similars;

            directives = get_all_directives(tmp_pool);
            similars = pr_str_get_similars(tmp_pool, name, directives, 0,
              PR_STR_FL_IGNORE_CASE);
            if (similars != NULL &&
                similars->nelts > 0) {
              unsigned int nelts;
              const char **names, *msg;

              names = similars->elts;
              nelts = similars->nelts;
              if (nelts > 4) {
                nelts = 4;
              }

              msg = "fatal: Did you mean:";

              if (nelts == 1) {
                msg = pstrcat(tmp_pool, msg, " ", names[0], NULL);

              } else {
                for (i = 0; i < nelts; i++) {
                  msg = pstrcat(tmp_pool, msg, "\n  ", names[i], NULL);
                }
              }

              pr_log_pri(PR_LOG_WARNING, "%s", msg);
            }
          }

          destroy_pool(tmp_pool);
          errno = EPERM;
          return -1;
        }

        pr_log_pri(PR_LOG_WARNING, "warning: unknown configuration directive "
          "'%s' on line %u of '%s'", name, cs->cs_lineno, report_path);
        if (non_ascii) {
          pr_log_pri(PR_LOG_WARNING, "warning: malformed directive name "
            "'%s' (contains non-ASCII characters)", name);
        }
      }
    }

    destroy_pool(cmd->pool);
    memset(buf, '\0', bufsz);
  }

  /* Pop this configuration stream from the stack. */
  remove_config_source();

  pr_fsio_close(fh);

  destroy_pool(tmp_pool);
  return 0;
}
static int counter_sess_init(void) {
  config_rec *c;

  c = find_config(main_server->conf, CONF_PARAM, "CounterEngine", FALSE);
  if (c != NULL) {
    counter_engine = *((int *) c->argv[0]);
  }

  if (counter_engine == FALSE) {
    return 0;
  }

  c = find_config(main_server->conf, CONF_PARAM, "CounterLog", FALSE);
  if (c != NULL) {
    const char *path = c->argv[0];

    if (strcasecmp(path, "none") != 0) {
      int res, xerrno;

      PRIVS_ROOT
      res = pr_log_openfile(path, &counter_logfd, 0660);
      xerrno = errno;
      PRIVS_RELINQUISH;

      if (res < 0) {
        pr_log_debug(DEBUG2, MOD_COUNTER_VERSION
          ": error opening CounterLog '%s': %s", path, strerror(xerrno));
        counter_logfd = -1;
      }
    }
  }

  /* Find all CounterFile directives for this vhost, and make sure they
   * have open handles.  We need to do this here, and not in a POST_CMD
   * PASS handler because of the need to open handles that may be outside
   * of a chroot.
   */
  c = find_config(main_server->conf, CONF_PARAM, "CounterFile", TRUE);
  while (c != NULL) {
    int xerrno = 0;
    const char *area = NULL, *path;
    pr_fh_t *fh;
    struct counter_fh *cfh;

    pr_signals_handle();

    path = c->argv[0];

    if (c->parent != NULL) {
      if (c->parent->config_type == CONF_ANON ||
          c->parent->config_type == CONF_DIR) {
        area = c->parent->name;

      } else {
        (void) pr_log_writefile(counter_logfd, MOD_COUNTER_VERSION,
          "unhandled configuration parent type (%d) for CounterFile, skipping",
          c->parent->config_type);
        c = find_config_next(c, c->next, CONF_PARAM, "CounterFile", TRUE);
        continue;
      }

    } else {
      /* Toplevel CounterFile directive, in "server config" or <VirtualHost>
       * sections.
       */
      area = "/";
    }

    PRIVS_ROOT
    fh = pr_fsio_open(path, O_RDWR|O_CREAT);
    xerrno = errno;
    PRIVS_RELINQUISH

    if (fh == NULL) {
      pr_log_debug(DEBUG1, MOD_COUNTER_VERSION
        ": error opening CounterFile '%s': %s", path, strerror(xerrno));
      counter_engine = FALSE;

      if (counter_fhs != NULL) {
        for (cfh = (struct counter_fh *) counter_fhs->xas_list; cfh;
            cfh = cfh->next) {
          (void) pr_fsio_close(cfh->fh);
        }
      }

      return 0;
    }

    (void) pr_log_writefile(counter_logfd, MOD_COUNTER_VERSION,
      "opened CounterFile '%s'", path);

    if (counter_fhs == NULL) {
      counter_fhs = xaset_create(counter_pool, NULL);
    }

    cfh = pcalloc(counter_pool, sizeof(struct counter_fh));

    /* Ignore any trailing slash. */
    cfh->arealen = strlen(area);
    if (cfh->arealen > 1 &&
        area[cfh->arealen-1] == '/') {
      cfh->arealen--;
    }

    cfh->area = pstrndup(counter_pool, area, cfh->arealen);

    /* Mark any areas that use glob(3) characters. */
    if (strpbrk(cfh->area, "[*?") != NULL) {
      cfh->isglob = TRUE;
    }

    cfh->fh = fh;

    xaset_insert(counter_fhs, (xasetmember_t *) cfh);

    c = find_config_next(c, c->next, CONF_PARAM, "CounterFile", TRUE);
  }

  if (counter_fhs == NULL) {
    (void) pr_log_writefile(counter_logfd, MOD_COUNTER_VERSION,
      "no CounterFiles configured, disabling module");
    counter_engine = FALSE;
    return 0;
  }

  pr_event_register(&counter_module, "core.exit", counter_exit_ev, NULL);

  /* If mod_vroot is present, we need to do a little more magic to counter
   * the mod_vroot magic.
   */
  if (pr_module_exists("mod_vroot.c") == TRUE) {
    pr_event_register(&counter_module, "core.chroot", counter_chroot_ev, NULL);
  }

  return 0;
}
Beispiel #8
0
int pr_parser_parse_file(pool *p, const char *path, config_rec *start,
    int flags) {
  pr_fh_t *fh;
  struct stat st;
  struct config_src *cs;
  cmd_rec *cmd;
  pool *tmp_pool;
  char *report_path;

  if (path == NULL) {
    errno = EINVAL;
    return -1;
  }

  tmp_pool = make_sub_pool(p ? p : permanent_pool);
  pr_pool_tag(tmp_pool, "parser file pool");

  report_path = (char *) path;
  if (session.chroot_path)
    report_path = pdircat(tmp_pool, session.chroot_path, path, NULL);

  if (!(flags & PR_PARSER_FL_DYNAMIC_CONFIG))
    pr_trace_msg(trace_channel, 3, "parsing '%s' configuration", report_path);

  fh = pr_fsio_open(path, O_RDONLY);
  if (fh == NULL) {
    int xerrno = errno;

    destroy_pool(tmp_pool);

    errno = xerrno;
    return -1;
  }

  /* Stat the opened file to determine the optimal buffer size for IO. */
  memset(&st, 0, sizeof(st));
  if (pr_fsio_fstat(fh, &st) < 0) {
    int xerrno = errno;

    pr_fsio_close(fh);
    destroy_pool(tmp_pool);

    errno = xerrno;
    return -1;
  }

  if (S_ISDIR(st.st_mode)) {
    pr_fsio_close(fh);
    destroy_pool(tmp_pool);

    errno = EISDIR;
    return -1;
  }

  /* Check for world-writable files (and later, files in world-writable
   * directories).
   *
   * For now, just warn about these; later, we will be more draconian.
   */
  if (st.st_mode & S_IWOTH) {
    pr_log_pri(PR_LOG_WARNING, "warning: config file '%s' is world-writable",
     path); 
  }

  fh->fh_iosz = st.st_blksize;

  /* Push the configuration information onto the stack of configuration
   * sources.
   */
  cs = add_config_source(fh);

  if (start) 
    add_config_ctxt(start);

  while ((cmd = pr_parser_parse_line(tmp_pool)) != NULL) {
    pr_signals_handle();

    if (cmd->argc) {
      conftable *conftab;
      char found = FALSE;

      cmd->server = *parser_curr_server;
      cmd->config = *parser_curr_config;

      conftab = pr_stash_get_symbol2(PR_SYM_CONF, cmd->argv[0], NULL,
        &cmd->stash_index, &cmd->stash_hash);

      while (conftab) {
        modret_t *mr;

        pr_signals_handle();

        cmd->argv[0] = conftab->directive;

        pr_trace_msg(trace_channel, 7,
          "dispatching directive '%s' to module mod_%s", conftab->directive,
          conftab->m->name);

        mr = pr_module_call(conftab->m, conftab->handler, cmd);
        if (mr != NULL) {
          if (MODRET_ISERROR(mr)) {

            if (!(flags & PR_PARSER_FL_DYNAMIC_CONFIG)) {
              pr_log_pri(PR_LOG_WARNING, "fatal: %s on line %u of '%s'",
                MODRET_ERRMSG(mr), cs->cs_lineno, report_path);
              exit(1);

            } else {
              pr_log_pri(PR_LOG_WARNING, "warning: %s on line %u of '%s'",
                MODRET_ERRMSG(mr), cs->cs_lineno, report_path);
            }
          }
        }

        if (!MODRET_ISDECLINED(mr)) {
          found = TRUE;
        }

        conftab = pr_stash_get_symbol2(PR_SYM_CONF, cmd->argv[0], conftab,
          &cmd->stash_index, &cmd->stash_hash);
      }

      if (cmd->tmp_pool)
        destroy_pool(cmd->tmp_pool);

      if (!found) {

        if (!(flags & PR_PARSER_FL_DYNAMIC_CONFIG)) {
          pr_log_pri(PR_LOG_WARNING, "fatal: unknown configuration directive "
            "'%s' on line %u of '%s'", cmd->argv[0], cs->cs_lineno,
            report_path);
          exit(1);

        } else {
          pr_log_pri(PR_LOG_WARNING, "warning: unknown configuration directive "
            "'%s' on line %u of '%s'", cmd->argv[0], cs->cs_lineno,
            report_path);
        }
      }
    }

    destroy_pool(cmd->pool);
  }

  /* Pop this configuration stream from the stack. */
  remove_config_source();

  pr_fsio_close(fh);

  destroy_pool(tmp_pool);
  return 0;
}