Beispiel #1
0
int pr_auth_authorize(pool *p, const char *name) {
  cmd_rec *cmd = NULL;
  modret_t *mr = NULL;
  module *m = NULL;
  int res = PR_AUTH_OK;

  cmd = make_cmd(p, 1, name);

  if (auth_tab) {

    /* Fetch the specific module to be used for authenticating this user. */
    void *v = pr_table_get(auth_tab, name, NULL);
    if (v) {
      m = *((module **) v);

      pr_trace_msg(trace_channel, 4,
        "using module 'mod_%s.c' from authcache to authorize user '%s'",
        m->name, name);
    }
  }

  mr = dispatch_auth(cmd, "authorize", m ? &m : NULL);

  /* Unlike the other auth calls, we assume here that unless the handlers
   * explicitly return ERROR, the user is authorized.  Thus HANDLED and
   * DECLINED are both treated as "yes, this user is authorized".  This
   * handles the case where the authenticating module (e.g. mod_sql)
   * does NOT provide an 'authorize' handler.
   */

  if (MODRET_ISERROR(mr)) {
    res = MODRET_ERROR(mr);
  }

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

  return res;
}
Beispiel #2
0
int pr_auth_requires_pass(pool *p, const char *name) {
  cmd_rec *cmd;
  modret_t *mr;
  int res = TRUE;

  cmd = make_cmd(p, 1, name);
  mr = dispatch_auth(cmd, "requires_pass", NULL);

  if (MODRET_ISHANDLED(mr))
    res = FALSE;

  else if (MODRET_ISERROR(mr))
    res = MODRET_ERROR(mr);

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

  return res;
}
Beispiel #3
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;
}
Beispiel #4
0
int pr_auth_check(pool *p, const char *cpw, const char *name, const char *pw) {
  cmd_rec *cmd = NULL;
  modret_t *mr = NULL;
  module *m = NULL;
  int res = PR_AUTH_BADPWD;

  cmd = make_cmd(p, 3, cpw, name, pw);

  /* First, check for any of the modules in the "authenticating only" list
   * of modules.  This is usually only mod_auth_pam, but other modules
   * might also add themselves (e.g. mod_radius under certain conditions).
   */
  if (auth_module_list) {
    struct auth_module_elt *elt;

    for (elt = (struct auth_module_elt *) auth_module_list->xas_list; elt;
        elt = elt->next) {

      m = pr_module_get(elt->name);
      if (m) {
        mr = dispatch_auth(cmd, "check", &m);

        if (MODRET_ISHANDLED(mr)) {
          pr_trace_msg(trace_channel, 4,
            "module '%s' used for authenticating user '%s'", elt->name, name);

          res = MODRET_HASDATA(mr) ? PR_AUTH_RFC2228_OK : PR_AUTH_OK;

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

          return res;
        }

        if (MODRET_ISERROR(mr)) {
          res = MODRET_ERROR(mr);

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

          return res;
        }

        m = NULL;
      }
    }
  }

  if (auth_tab) {

    /* Fetch the specific module to be used for authenticating this user. */
    void *v = pr_table_get(auth_tab, name, NULL);
    if (v) {
      m = *((module **) v);

      pr_trace_msg(trace_channel, 4,
        "using module 'mod_%s.c' from authcache to authenticate user '%s'",
        m->name, name);
    }
  }

  mr = dispatch_auth(cmd, "check", m ? &m : NULL);

  if (MODRET_ISHANDLED(mr))
    res = MODRET_HASDATA(mr) ? PR_AUTH_RFC2228_OK : PR_AUTH_OK;

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

  return res;
}
Beispiel #5
0
static modret_t *dispatch_auth(cmd_rec *cmd, char *match, module **m) {
  authtable *start_tab = NULL, *iter_tab = NULL;
  modret_t *mr = NULL;

  start_tab = pr_stash_get_symbol(PR_SYM_AUTH, match, NULL,
    &cmd->stash_index);
  iter_tab = start_tab;

  while (iter_tab) {
    pr_signals_handle();

    if (m && *m && *m != iter_tab->m) {
      goto next;
    }

    pr_trace_msg(trace_channel, 6,
      "dispatching auth request \"%s\" to module mod_%s",
      match, iter_tab->m->name);

    mr = pr_module_call(iter_tab->m, iter_tab->handler, cmd);

    /* Return a pointer, if requested, to the module which answered the
     * auth request.  This is used, for example, by auth_getpwnam() for
     * associating the answering auth module with the data looked up.
     */

    if (iter_tab->auth_flags & PR_AUTH_FL_REQUIRED) {
      pr_trace_msg(trace_channel, 6,
        "\"%s\" response from module mod_%s is authoritative", match,
        iter_tab->m->name);

      if (m) {
        *m = iter_tab->m;
      }

      break;
    }

    if (MODRET_ISHANDLED(mr) ||
        MODRET_ISERROR(mr)) {

      if (m) {
        *m = iter_tab->m;
      }

      break;
    }

  next:
    iter_tab = pr_stash_get_symbol(PR_SYM_AUTH, match, iter_tab,
      &cmd->stash_index);

    if (iter_tab == start_tab) {
      /* We have looped back to the start.  Break out now and do not loop
       * around again (and again, and again...)
       */
      mr = PR_DECLINED(cmd);
      break;
    }
  }

  return mr;
}
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 *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;
}
Beispiel #7
0
static array_header *sqltab_fetch_clients_cb(wrap2_table_t *sqltab,
    const char *name) {
  pool *tmp_pool = NULL;
  cmdtable *sql_cmdtab = NULL;
  cmd_rec *sql_cmd = NULL;
  modret_t *sql_res = NULL;
  array_header *sql_data = NULL;
  char *query = NULL, **vals = NULL;
  array_header *clients_list = NULL;

  /* Allocate a temporary pool for the duration of this read. */
  tmp_pool = make_sub_pool(sqltab->tab_pool);

  query = ((char **) sqltab->tab_data)[0];

  /* Find the cmdtable for the sql_lookup command. */
  sql_cmdtab = pr_stash_get_symbol(PR_SYM_HOOK, "sql_lookup", NULL, NULL);
  if (sql_cmdtab == NULL) {
    wrap2_log("error: unable to find SQL hook symbol 'sql_lookup'");
    destroy_pool(tmp_pool);
    return NULL;
  }

  /* Prepare the SELECT query. */
  sql_cmd = sql_cmd_create(tmp_pool, 3, "sql_lookup", query, name);

  /* Call the handler. */
  sql_res = call_module(sql_cmdtab->m, sql_cmdtab->handler, sql_cmd);

  /* Check the results. */
  if (!sql_res) {
    wrap2_log("NamedQuery '%s' returned no data", query);
    destroy_pool(tmp_pool);
    return NULL;
  }

  if (MODRET_ISERROR(sql_res)) {
    wrap2_log("error processing NamedQuery '%s'", query);
    destroy_pool(tmp_pool);
    return NULL;
  }

  /* Construct a single string, concatenating the returned client tokens
   * together.
   */
  sql_data = (array_header *) sql_res->data;
  vals = (char **) sql_data->elts;

  if (sql_data->nelts < 1) {
    wrap2_log("NamedQuery '%s' returned no data", query);
    destroy_pool(tmp_pool);
    return NULL;
  }

  clients_list = make_array(sqltab->tab_pool, sql_data->nelts, sizeof(char *));
  *((char **) push_array(clients_list)) = pstrdup(sqltab->tab_pool, vals[0]);

  if (sql_data->nelts > 1) {
    register unsigned int i = 0;

    for (i = 1; i < sql_data->nelts; i++) {
      *((char **) push_array(clients_list)) = pstrdup(sqltab->tab_pool,
        vals[i]);
    }
  }

  destroy_pool(tmp_pool);
  return clients_list;
}
Beispiel #8
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;
}