Example #1
0
/* Return an array of all supported/known configuration directives. */
static array_header *get_all_directives(pool *p) {
  array_header *names;
  conftable *tab;
  int idx;
  unsigned int hash;

  names = make_array(p, 1, sizeof(const char *));

  idx = -1;
  hash = 0;
  tab = pr_stash_get_symbol2(PR_SYM_CONF, NULL, NULL, &idx, &hash);
  while (idx != -1) {
    pr_signals_handle();

    if (tab != NULL) {
      *((const char **) push_array(names)) = pstrdup(p, tab->directive);

    } else {
      idx++;
    }

    tab = pr_stash_get_symbol2(PR_SYM_CONF, NULL, tab, &idx, &hash);
  }

  return names;
}
Example #2
0
/* Sentinel values:
 *
 *  cmd_type = 0
 *  cmd_group = NULL
 *  cmd_class = -1
 */
int pr_stash_remove_cmd(const char *cmd_name, module *m,
    unsigned char cmd_type, const char *cmd_group, int cmd_class) {
  int count = 0, prev_idx, symtab_idx = 0;
  size_t cmd_namelen = 0;
  unsigned int hash;
  cmdtable *tab = NULL;

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

  /* Don't forget to include one for the terminating NUL. */
  cmd_namelen = strlen(cmd_name) + 1;

  hash = sym_type_hash(PR_SYM_CMD, cmd_name, cmd_namelen);
  symtab_idx = hash % PR_TUNABLE_HASH_TABLE_SIZE;
  prev_idx = -1;

  tab = pr_stash_get_symbol2(PR_SYM_CMD, cmd_name, NULL, &prev_idx, &hash);
  while (tab) {
    cmdtable *cmd_sym;

    pr_signals_handle();

    /* Note: this works because of a hack: the symbol lookup functions set a
     * static pointer, cmd_curr_sym, to point to the struct stash just looked
     * up.  cmd_curr_sym will not be NULL if pr_stash_get_symbol2() returns
     * non-NULL.
     */

    cmd_sym = cmd_curr_sym->ptr.sym_cmd;
    if ((m == NULL || cmd_curr_sym->sym_module == m) &&
        (cmd_type == 0 || cmd_sym->cmd_type == cmd_type) &&
        (cmd_group == NULL ||
         (cmd_group != NULL &&
          cmd_sym->group != NULL &&
          strcmp(cmd_sym->group, cmd_group) == 0)) &&
        (cmd_class == -1 || cmd_sym->cmd_class == cmd_class)) {
      xaset_remove(cmd_symbol_table[symtab_idx],
        (xasetmember_t *) cmd_curr_sym);
      destroy_pool(cmd_curr_sym->sym_pool);
      cmd_curr_sym = NULL;
      tab = NULL;
      count++;
    }

    tab = pr_stash_get_symbol2(PR_SYM_CMD, cmd_name, tab, &prev_idx, &hash);
  }

  return count;
}
Example #3
0
unsigned char command_exists(char *name) {
  int idx = -1;
  unsigned int hash = 0;
  cmdtable *cmdtab;

  cmdtab = pr_stash_get_symbol2(PR_SYM_CMD, name, NULL, &idx, &hash);
  while (cmdtab && cmdtab->cmd_type != CMD) {
    pr_signals_handle();
    cmdtab = pr_stash_get_symbol2(PR_SYM_CMD, name, cmdtab, &idx, &hash);
  }

  return (cmdtab ? TRUE : FALSE);
}
Example #4
0
int pr_stash_remove_conf(const char *directive_name, module *m) {
  int count = 0, prev_idx, symtab_idx = 0;
  size_t directive_namelen = 0;
  unsigned int hash;
  conftable *tab = NULL;

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

  /* Don't forget to include one for the terminating NUL. */
  directive_namelen = strlen(directive_name) + 1;

  hash = sym_type_hash(PR_SYM_CONF, directive_name, directive_namelen);
  symtab_idx = hash % PR_TUNABLE_HASH_TABLE_SIZE;
  prev_idx = -1;

  tab = pr_stash_get_symbol2(PR_SYM_CONF, directive_name, NULL, &prev_idx,
    &hash);
  while (tab) {
    pr_signals_handle();

    /* Note: this works because of a hack: the symbol lookup functions set a
     * static pointer, conf_curr_sym, to point to the struct stash just looked
     * up.  conf_curr_sym will not be NULL if pr_stash_get_symbol2() returns
     * non-NULL.
     */

    if (m == NULL ||
        conf_curr_sym->sym_module == m) {
      xaset_remove(conf_symbol_table[symtab_idx],
        (xasetmember_t *) conf_curr_sym);
      destroy_pool(conf_curr_sym->sym_pool);
      conf_curr_sym = NULL;
      tab = NULL;
      count++;
    }

    tab = pr_stash_get_symbol2(PR_SYM_CONF, directive_name, tab, &prev_idx,
      &hash);
  }

  return count;
}
Example #5
0
void *pr_stash_get_symbol(pr_stash_type_t sym_type, const char *name,
    void *prev, int *idx_cache) {
  return pr_stash_get_symbol2(sym_type, name, prev, idx_cache, NULL);
}
Example #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;
}
Example #7
0
END_TEST

START_TEST (stash_get_symbol2_test) {
  int res;
  void *sym;
  conftable conftab;
  cmdtable cmdtab, hooktab;
  authtable authtab;

  sym = pr_stash_get_symbol2(0, NULL, NULL, NULL, NULL);
  fail_unless(sym == NULL, "Failed to handle null arguments");
  fail_unless(errno == EINVAL, "Failed to set errno to EINVAL, got %d (%s)",
    errno, strerror(errno));

  sym = pr_stash_get_symbol2(0, "foo", NULL, NULL, NULL);
  fail_unless(sym == NULL, "Failed to handle bad type argument");
  fail_unless(errno == EINVAL, "Failed to set errno to EINVAL, got %d (%s)",
    errno, strerror(errno));

  sym = pr_stash_get_symbol2(PR_SYM_CONF, "foo", NULL, NULL, NULL);
  fail_unless(sym == NULL, "Failed to handle nonexistent CONF symbol");
  fail_unless(errno == ENOENT, "Failed to set errno to ENOENT, got %d (%s)",
    errno, strerror(errno));

  sym = pr_stash_get_symbol2(PR_SYM_CMD, "foo", NULL, NULL, NULL);
  fail_unless(sym == NULL, "Failed to handle nonexistent CMD symbol");
  fail_unless(errno == ENOENT, "Failed to set errno to ENOENT, got %d (%s)",
    errno, strerror(errno));

  sym = pr_stash_get_symbol2(PR_SYM_AUTH, "foo", NULL, NULL, NULL);
  fail_unless(sym == NULL, "Failed to handle nonexistent AUTH symbol");
  fail_unless(errno == ENOENT, "Failed to set errno to ENOENT, got %d (%s)",
    errno, strerror(errno));

  sym = pr_stash_get_symbol2(PR_SYM_HOOK, "foo", NULL, NULL, NULL);
  fail_unless(sym == NULL, "Failed to handle nonexistent HOOK symbol");
  fail_unless(errno == ENOENT, "Failed to set errno to ENOENT, got %d (%s)",
    errno, strerror(errno));

  memset(&conftab, 0, sizeof(conftab));
  conftab.directive = pstrdup(p, "foo");
  res = pr_stash_add_symbol(PR_SYM_CONF, &conftab);
  fail_unless(res == 0, "Failed to add CONF symbol: %s", strerror(errno));

  sym = pr_stash_get_symbol2(PR_SYM_CONF, "foo", NULL, NULL, NULL);
  fail_unless(sym != NULL, "Failed to get CONF symbol: %s", strerror(errno));
  fail_unless(sym == &conftab, "Expected %p, got %p", &conftab, sym);

  sym = pr_stash_get_symbol2(PR_SYM_CONF, "foo", sym, NULL, NULL);
  fail_unless(sym == NULL, "Unexpectedly found CONF symbol");
  fail_unless(errno == ENOENT, "Failed to set errno to ENOENT, got %d (%s)",
    errno, strerror(errno));

  memset(&cmdtab, 0, sizeof(cmdtab));
  cmdtab.command = pstrdup(p, "foo");
  res = pr_stash_add_symbol(PR_SYM_CMD, &cmdtab);
  fail_unless(res == 0, "Failed to add CMD symbol: %s", strerror(errno));

  sym = pr_stash_get_symbol2(PR_SYM_CMD, "foo", NULL, NULL, NULL);
  fail_unless(sym != NULL, "Failed to get CMD symbol: %s", strerror(errno));
  fail_unless(sym == &cmdtab, "Expected %p, got %p", &cmdtab, sym);

  sym = pr_stash_get_symbol2(PR_SYM_CMD, "foo", sym, NULL, NULL);
  fail_unless(sym == NULL, "Unexpectedly found CMD symbol");
  fail_unless(errno == ENOENT, "Failed to set errno to ENOENT, got %d (%s)",
    errno, strerror(errno));

  memset(&authtab, 0, sizeof(authtab));
  authtab.name = pstrdup(p, "foo");
  res = pr_stash_add_symbol(PR_SYM_AUTH, &authtab);
  fail_unless(res == 0, "Failed to add AUTH symbol: %s", strerror(errno));

  sym = pr_stash_get_symbol2(PR_SYM_AUTH, "foo", NULL, NULL, NULL);
  fail_unless(sym != NULL, "Failed to get AUTH symbol: %s", strerror(errno));
  fail_unless(sym == &authtab, "Expected %p, got %p", &authtab, sym);

  sym = pr_stash_get_symbol2(PR_SYM_AUTH, "foo", sym, NULL, NULL);
  fail_unless(sym == NULL, "Unexpectedly found AUTH symbol");
  fail_unless(errno == ENOENT, "Failed to set errno to ENOENT, got %d (%s)",
    errno, strerror(errno));

  memset(&hooktab, 0, sizeof(hooktab));
  hooktab.command = pstrdup(p, "foo");
  res = pr_stash_add_symbol(PR_SYM_HOOK, &hooktab);
  fail_unless(res == 0, "Failed to add HOOK symbol: %s", strerror(errno));

  sym = pr_stash_get_symbol2(PR_SYM_HOOK, "foo", NULL, NULL, NULL);
  fail_unless(sym != NULL, "Failed to get HOOK symbol: %s", strerror(errno));
  fail_unless(sym == &hooktab, "Expected %p, got %p", &hooktab, sym);

  sym = pr_stash_get_symbol2(PR_SYM_HOOK, "foo", sym, NULL, NULL);
  fail_unless(sym == NULL, "Unexpectedly found HOOK symbol");
  fail_unless(errno == ENOENT, "Failed to set errno to ENOENT, got %d (%s)",
    errno, strerror(errno));
}
Example #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;
}
Example #9
0
static array_header *get_sql_filters(pool *p, const char *query_name) {
  register unsigned int i;
  cmdtable *sql_cmdtab = NULL;
  cmd_rec *sql_cmd = NULL;
  modret_t *sql_res = NULL;
  array_header *sql_data = NULL;
  const char **values = NULL;
  array_header *sql_filters = NULL;

  sql_cmdtab = pr_stash_get_symbol2(PR_SYM_HOOK, "sql_lookup", NULL, NULL,
    NULL);
  if (sql_cmdtab == NULL) {
    (void) pr_log_writefile(geoip_logfd, MOD_GEOIP_VERSION,
      "unable to execute SQLNamedQuery '%s': mod_sql not loaded", query_name);
    errno = EPERM;
    return NULL;
  }

  sql_cmd = pr_cmd_alloc(p, 2, "sql_lookup", query_name);

  sql_res = pr_module_call(sql_cmdtab->m, sql_cmdtab->handler, sql_cmd);
  if (sql_res == NULL ||
      MODRET_ISERROR(sql_res)) {
    (void) pr_log_writefile(geoip_logfd, MOD_GEOIP_VERSION,
      "error processing SQLNamedQuery '%s'; check mod_sql logs for details",
      query_name);
    errno = EPERM;
    return NULL;
  }

  sql_data = sql_res->data;
  pr_trace_msg(trace_channel, 9, "SQLNamedQuery '%s' returned item count %d",
    query_name, sql_data->nelts);

  if (sql_data->nelts == 0) {
    (void) pr_log_writefile(geoip_logfd, MOD_GEOIP_VERSION,
      "SQLNamedQuery '%s' returned no values", query_name);
    errno = ENOENT;
    return NULL;
  }

  if (sql_data->nelts % 2 == 1) {
    (void) pr_log_writefile(geoip_logfd, MOD_GEOIP_VERSION,
      "SQLNamedQuery '%s' returned odd number of values (%d), "
      "expected even number", query_name, sql_data->nelts);
    errno = EINVAL;
    return NULL;
  }

  values = sql_data->elts;
  sql_filters = make_array(p, 0, sizeof(struct geoip_filter));

  for (i = 0; i < sql_data->nelts; i += 2) {
    const char *filter_name, *pattern = NULL;
    struct geoip_filter *filter;

    filter_name = values[i];
    pattern = values[i+1];

    filter = make_filter(p, filter_name, pattern);
    if (filter == NULL) {
      pr_trace_msg(trace_channel, 3, "unable to use '%s %s' as filter: %s",
        filter_name, pattern, strerror(errno));
      continue;
    }

    *((struct geoip_filter **) push_array(sql_filters)) = filter;
  }

  return sql_filters;
}