Exemple #1
0
int pr_ipbind_add_binds(server_rec *serv) {
  int res = 0;
  config_rec *c = NULL;
  conn_t *listen_conn = NULL;
  const pr_netaddr_t *addr = NULL;

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

  c = find_config(serv->conf, CONF_PARAM, "_bind_", FALSE);
  while (c != NULL) {
    listen_conn = NULL;

    pr_signals_handle();

    addr = pr_netaddr_get_addr(serv->pool, c->argv[0], NULL);
    if (addr == NULL) {
      pr_log_pri(PR_LOG_WARNING,
       "notice: unable to determine IP address of '%s'", (char *) c->argv[0]);
      c = find_config_next(c, c->next, CONF_PARAM, "_bind_", FALSE);
      continue;
    }

    /* If the SocketBindTight directive is in effect, create a separate
     * listen socket for this address, and add it to the binding list.
     */
    if (SocketBindTight &&
        serv->ServerPort) {
      listen_conn = pr_ipbind_get_listening_conn(serv, addr, serv->ServerPort);
      if (listen_conn == NULL) {
        return -1;
      }

      PR_CREATE_IPBIND(serv, addr, serv->ServerPort);
      PR_OPEN_IPBIND(addr, serv->ServerPort, listen_conn, FALSE, FALSE, TRUE);

    } else {

      PR_CREATE_IPBIND(serv, addr, serv->ServerPort);
      PR_OPEN_IPBIND(addr, serv->ServerPort, serv->listen, FALSE, FALSE, TRUE);
    }

    c = find_config_next(c, c->next, CONF_PARAM, "_bind_", FALSE);
  }

  return 0;
}
Exemple #2
0
static void resolve_deferred_patterns(pool *p, const char *directive) {
#if PR_USE_REGEX
  config_rec *c;

  c = find_config(main_server->conf, CONF_PARAM, directive, FALSE);
  while (c != NULL) {
    register unsigned int i;
    array_header *deferred_filters, *filters;

    pr_signals_handle();

    filters = c->argv[0];
    deferred_filters = c->argv[1];

    for (i = 0; i < deferred_filters->nelts; i++) {
      const char *query_name;
      array_header *sql_filters;

      query_name = ((const char **) deferred_filters->elts)[i];

      sql_filters = get_sql_filters(p, query_name);
      if (sql_filters == NULL) {
        continue;
      }

      array_cat(filters, sql_filters);
    }

    c = find_config_next(c, c->next, CONF_PARAM, directive, FALSE);
  }
#endif /* PR_USE_REGEX */
}
/* usage: FailureLog path [logfmt-name] */
MODRET set_failurelog(cmd_rec *cmd) {
  config_rec *c;
  const char *path;
  char *log_fmt = NULL;

  if (cmd->argc < 2 ||
      cmd->argc > 3) {
    CONF_ERROR(cmd, "wrong number of parameters");
  }

  CHECK_CONF(cmd, CONF_ROOT|CONF_VIRTUAL|CONF_GLOBAL);

  path = cmd->argv[1];
  if (*path != '/') {
    CONF_ERROR(cmd, "must be an absolute path");
  }

  if (cmd->argc == 3) {
    const char *fmt_name;

    fmt_name = cmd->argv[2];

    /* Double-check that logfmt-name is valid, defined, etc. Look up the
     * format string, and stash a pointer to that in the config_rec (but NOT
     * a copy of the format string; don't need to use that much memory).
     */
    c = find_config(cmd->server->conf, CONF_PARAM, "LogFormat", FALSE);
    while (c != NULL) {
      if (strcmp(c->argv[0], fmt_name) == 0) {
        log_fmt = c->argv[1];
        break;
      }

      log_fmt = NULL;
      c = find_config_next(c, c->next, CONF_PARAM, "LogFormat", FALSE);
    }

    if (log_fmt == NULL) {
      CONF_ERROR(cmd, pstrcat(cmd->tmp_pool, "no such LogFormat '",
        cmd->argv[2], "' configured", NULL));
    }
  }

  c = add_config_param(cmd->argv[0], 2, NULL, NULL);
  c->argv[0] = pstrdup(c->pool, path);
  c->argv[1] = log_fmt;

  return PR_HANDLED(cmd);
}
Exemple #4
0
MODRET wrap_handle_request(cmd_rec *cmd) {

  /* these variables are names expected to be set by the TCP wrapper code
   */
  struct request_info request;

  char *user = NULL;
  config_rec *conf = NULL, *access_conf = NULL, *syslog_conf = NULL;
  hosts_allow_table = NULL;
  hosts_deny_table = NULL;

  /* hide passwords */
  session.hide_password = TRUE;

  /* Sneaky...found in mod_auth.c's cmd_pass() function.  Need to find the
   * login UID in order to resolve the possibly-login-dependent filename.
   */
  user = (char *) get_param_ptr(cmd->server->conf, C_USER, FALSE);

  /* It's possible that a PASS command came before USER.  This is a PRE_CMD
   * handler, so it won't be protected from this case; we'll need to do
   * it manually.
   */
  if (!user)
    return DECLINED(cmd);

  /* Use mod_auth's _auth_resolve_user() [imported for use here] to get the
   * right configuration set, since the user may be logging in anonymously,
   * and the session struct hasn't yet been set for that yet (thus short-
   * circuiting the easiest way to get the right context...the macros.
   */
  conf = wrap_resolve_user(cmd->pool, &user);

  /* Search first for user-specific access files.  Multiple TCPUserAccessFiles
   * directives are allowed.
   */
  if ((access_conf = find_config(conf ? conf->subset : CURRENT_CONF, CONF_PARAM,
      "TCPUserAccessFiles", FALSE)) != NULL) {
    int matched = FALSE;
    array_header *user_array = NULL;

    while (access_conf) {

      user_array = make_array(cmd->tmp_pool, 0, sizeof(char *));
      *((char **) push_array(user_array)) = pstrdup(cmd->tmp_pool, user);

      /* Check the user expression -- don't forget the offset, to skip
       * the access file name strings in argv
       */
      if (wrap_eval_expression(((char **) access_conf->argv) + 2,
          user_array)) {
        pr_log_debug(DEBUG4, MOD_WRAP_VERSION
          ": matched TCPUserAccessFiles expression");
        matched = TRUE;
        break;
      }

      access_conf = find_config_next(access_conf, access_conf->next,
        CONF_PARAM, "TCPUserAccessFiles", FALSE);
    }

    if (!matched)
      access_conf = NULL;
  }

  /* Next, search for group-specific access files.  Multiple
   * TCPGroupAccessFiles directives are allowed.
   */ 
  if (!access_conf && (access_conf = find_config(conf ? conf->subset :
        CURRENT_CONF, CONF_PARAM, "TCPGroupAccessFiles", FALSE)) != NULL) {
    unsigned char matched = FALSE;

    /* NOTE: this gid_array is only necessary until Bug#1461 is fixed */
    array_header *gid_array = make_array(cmd->pool, 0, sizeof(gid_t));

    array_header *group_array = make_array(cmd->pool, 0, sizeof(char *));

    while (access_conf) {
      if (pr_auth_getgroups(cmd->pool, user, &gid_array, &group_array) < 1) {
        pr_log_debug(DEBUG3, MOD_WRAP_VERSION
          ": no supplemental groups found for user '%s'", user);

      } else {

        /* Check the group expression -- don't forget the offset, to skip
         * the access file names strings in argv
         */
        if (wrap_eval_expression(((char **) access_conf->argv) + 2,
            group_array)) {
          pr_log_debug(DEBUG4, MOD_WRAP_VERSION
            ": matched TCPGroupAccessFiles expression");
          matched = TRUE;
          break;
        }
      }

      access_conf = find_config_next(access_conf, access_conf->next,
        CONF_PARAM, "TCPGroupAccessFiles", FALSE);
    }

    if (!matched)
      access_conf = NULL;
  }

  /* Finally for globally-applicable access files.  Only one such directive
   * is allowed.
   */
  if (!access_conf) {
    access_conf = find_config(conf ? conf->subset : CURRENT_CONF,
      CONF_PARAM, "TCPAccessFiles", FALSE);
  }

  if (access_conf) {
    hosts_allow_table = (char *) access_conf->argv[0];
    hosts_deny_table = (char *) access_conf->argv[1];
  }

  /* Now, check the retrieved filename, and see if it requires a login-time
   * file.
   */
  if (hosts_allow_table != NULL && hosts_allow_table[0] == '~' &&
      hosts_allow_table[1] == '/') {
    char *allow_real_table = NULL;

    allow_real_table = wrap_get_user_table(cmd, user, hosts_allow_table);

    if (!wrap_is_usable_file(allow_real_table)) {
      pr_log_pri(PR_LOG_WARNING, MOD_WRAP_VERSION
        ": configured TCPAllowFile %s is unusable", hosts_allow_table);
      hosts_allow_table = NULL;

    } else
      hosts_allow_table = allow_real_table;
  }

  if (hosts_deny_table != NULL && hosts_deny_table[0] == '~' &&
      hosts_deny_table[1] == '/') {
    char *deny_real_table = NULL;

    deny_real_table = dir_realpath(cmd->pool, hosts_deny_table);

    if (!wrap_is_usable_file(deny_real_table)) {
      pr_log_pri(PR_LOG_WARNING, MOD_WRAP_VERSION
        ": configured TCPDenyFile %s is unusable", hosts_deny_table);
      hosts_deny_table = NULL;

    } else 
      hosts_deny_table = deny_real_table;
  }

  /* Make sure that _both_ allow and deny TCPAccessFiles are present.
   * If not, log the missing file, and by default allow request to succeed.
   */
  if (hosts_allow_table != NULL && hosts_deny_table != NULL) {

    /* Most common case...nothing more necessary */

  } else if (hosts_allow_table == NULL && hosts_deny_table != NULL) {

    /* Log the missing file */
    pr_log_pri(PR_LOG_INFO, MOD_WRAP_VERSION ": no usable allow access file -- "
      "allowing connection");

    return DECLINED(cmd);

  } else if (hosts_allow_table != NULL && hosts_deny_table == NULL) {

    /* log the missing file */
    pr_log_pri(PR_LOG_INFO, MOD_WRAP_VERSION ": no usable deny access file -- "
      "allowing connection");

    return DECLINED(cmd);

  } else {

    /* Neither set -- assume the admin hasn't configured these directives
     * at all.
     */
    return DECLINED(cmd);
  }

  /* Log the names of the allow/deny files being used. */
  pr_log_pri(PR_LOG_DEBUG, MOD_WRAP_VERSION ": using access files: %s, %s",
    hosts_allow_table, hosts_deny_table);

  /* retrieve the user-defined syslog priorities, if any.  Fall back to the
   * defaults as seen in tcpd.h if not defined.
   */
  syslog_conf = find_config(main_server->conf, CONF_PARAM,
    "TCPAccessSyslogLevels", FALSE);

  if (syslog_conf) {
    allow_severity = (int) syslog_conf->argv[1];
    deny_severity = (int) syslog_conf->argv[2];

  } else {

    allow_severity = PR_LOG_INFO;
    deny_severity = PR_LOG_WARNING;
  }

  pr_log_debug(DEBUG4, MOD_WRAP_VERSION ": checking under service name '%s'",
    wrap_service_name);
  request_init(&request, RQ_DAEMON, wrap_service_name, RQ_FILE,
    session.c->rfd, 0);

  fromhost(&request);

  if (STR_EQ(eval_hostname(request.client), paranoid) ||
      !hosts_access(&request)) {
    char *denymsg = NULL;

    /* log the denied connection */
    wrap_log_request_denied(deny_severity, &request);

    /* check for AccessDenyMsg */
    if ((denymsg = (char *) get_param_ptr(TOPLEVEL_CONF, "AccessDenyMsg",
        FALSE)) != NULL)
      denymsg = sreplace(cmd->tmp_pool, denymsg, "%u", user, NULL);

    if (denymsg)
      return ERROR_MSG(cmd, R_530, denymsg);
    else
      return ERROR_MSG(cmd, R_530, "Access denied.");
  }

  /* If request is allowable, return DECLINED (for engine to act as if this
   * handler was never called, else ERROR (for engine to abort processing and
   * deny request.
   */
  wrap_log_request_allowed(allow_severity, &request);

  return DECLINED(cmd);
}
Exemple #5
0
/* yet more plagiarizing...this one raided from mod_auth's _auth_resolve_user()
 * function [in case you haven't noticed yet, I'm quite the hack, in the
 * _true_ sense of the world]. =) hmmm...I wonder if it'd be feasible
 * to make some of mod_auth's functions visible from src/auth.c?
 */
static config_rec *wrap_resolve_user(pool *pool, char **user) {
  config_rec *conf = NULL, *top_conf;
  char *ourname = NULL, *anonname = NULL;
  unsigned char is_alias = FALSE, force_anon = FALSE;

  /* Precendence rules:
   *   1. Search for UserAlias directive.
   *   2. Search for Anonymous directive.
   *   3. Normal user login
   */

  ourname = (char*) get_param_ptr(main_server->conf, "UserName", FALSE);

  conf = find_config(main_server->conf, CONF_PARAM, "UserAlias", TRUE);

  if (conf) do {
    if (!strcmp(conf->argv[0], "*") || !strcmp(conf->argv[0], *user)) {
      is_alias = TRUE;
      break;
    } 

  } while ((conf = find_config_next(conf, conf->next, CONF_PARAM,
    "UserAlias", TRUE)) != NULL);

  /* if AuthAliasOnly is set, ignore this one and continue */
  top_conf = conf;

  while (conf && conf->parent &&
      find_config(conf->parent->set, CONF_PARAM, "AuthAliasOnly", FALSE)) {

    is_alias = FALSE;
    find_config_set_top(top_conf);
    conf = find_config_next(conf, conf->next, CONF_PARAM, "UserAlias", TRUE);

    if (conf && (!strcmp(conf->argv[0], "*") || !strcmp(conf->argv[0], *user)))
      is_alias = TRUE;
  }

  if (conf) {
    *user = conf->argv[1];

    /* If the alias is applied inside an <Anonymous> context, we have found
     * our anon block
     */
    if (conf->parent && conf->parent->config_type == CONF_ANON)
      conf = conf->parent;
    else
      conf = NULL;
  }

  /* Next, search for an anonymous entry */
  if (!conf)
    conf = find_config(main_server->conf, CONF_ANON, NULL, FALSE);

  else
    find_config_set_top(conf);

  if (conf) do {
    anonname = (char*) get_param_ptr(conf->subset, "UserName", FALSE);

    if (!anonname)
      anonname = ourname;

    if (anonname && !strcmp(anonname, *user)) {
       break;
    }

  } while ((conf = find_config_next(conf, conf->next, CONF_ANON, NULL,
    FALSE)) != NULL);

  if (!is_alias && !force_anon) {

    if (find_config((conf ? conf->subset :
        main_server->conf), CONF_PARAM, "AuthAliasOnly", FALSE)) {

      if (conf && conf->config_type == CONF_ANON)
        conf = NULL;

      else
        *user = NULL;

      if (*user && find_config(main_server->conf, CONF_PARAM, "AuthAliasOnly",
          FALSE))
        *user = NULL;
    }
  }

  return conf;
}
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;
}
Exemple #7
0
static int init_standalone_bindings(void) {
  int res = 0;
  server_rec *serv = NULL;
  unsigned char *default_server = NULL, is_default = FALSE;

  /* If a port is set to zero, the address/port is not bound to a socket
   * at all.
   */
  if (main_server->ServerPort) {

    /* If SocketBindTight is off, then pr_inet_create_conn() will
     * create and bind to a wildcard socket.  However, should it be an
     * IPv4 or an IPv6 wildcard socket?
     */
    if (!SocketBindTight) {
#ifdef PR_USE_IPV6
      if (pr_netaddr_use_ipv6()) {
        pr_inet_set_default_family(NULL, AF_INET6);

      } else {
        int default_family;

        default_family = pr_netaddr_get_family(main_server->addr);
        pr_inet_set_default_family(NULL, default_family);
      }
#else
      pr_inet_set_default_family(NULL,
        pr_netaddr_get_family(main_server->addr));
#endif /* PR_USE_IPV6 */
    }

    main_server->listen = pr_ipbind_get_listening_conn(main_server,
      (SocketBindTight ? main_server->addr : NULL), main_server->ServerPort);
    if (main_server->listen == NULL) {
      return -1;
    }

  } else {
    main_server->listen = NULL;
  }

  default_server = get_param_ptr(main_server->conf, "DefaultServer", FALSE);
  if (default_server != NULL &&
      *default_server == TRUE) {
    is_default = TRUE;
  }

  if (main_server->ServerPort ||
      is_default) {
    PR_CREATE_IPBIND(main_server, main_server->addr, main_server->ServerPort);
    PR_OPEN_IPBIND(main_server->addr, main_server->ServerPort,
      main_server->listen, is_default, TRUE, TRUE);
    PR_ADD_IPBINDS(main_server);
  }

  for (serv = main_server->next; serv; serv = serv->next) {
    config_rec *c;
    int is_namebind = FALSE;

    /* See if this server is a namebind, to be part of an existing ipbind. */
    c = find_config(serv->conf, CONF_PARAM, "ServerAlias", FALSE);
    while (c != NULL) {
      pr_signals_handle();

      res = pr_namebind_create(serv, c->argv[0], serv->addr, serv->ServerPort);
      if (res == 0) {
        is_namebind = TRUE;

        res = pr_namebind_open(c->argv[0], serv->addr, serv->ServerPort);
        if (res < 0) {
          pr_log_pri(PR_LOG_NOTICE,
            "%s:%d: notice: unable to open namebind '%s': %s", __FILE__,
            __LINE__, (char *) c->argv[0], strerror(errno));
        }

      } else {
        pr_log_pri(PR_LOG_NOTICE,
          "unable to create namebind for '%s' to %s#%u: %s",
          (char *) c->argv[0], pr_netaddr_get_ipstr(serv->addr),
          serv->ServerPort, strerror(errno));
      }

      c = find_config_next(c, c->next, CONF_PARAM, "ServerAlias", FALSE);
    }

    if (is_namebind == TRUE) {
      continue;
    }

    if (serv->ServerPort != main_server->ServerPort ||
        SocketBindTight ||
        !main_server->listen) {
      is_default = FALSE;

      default_server = get_param_ptr(serv->conf, "DefaultServer", FALSE);
      if (default_server != NULL &&
          *default_server == TRUE) {
        is_default = TRUE;
      }

      if (serv->ServerPort) {
        if (!SocketBindTight) {
#ifdef PR_USE_IPV6
          if (pr_netaddr_use_ipv6()) {
            pr_inet_set_default_family(NULL, AF_INET6);

          } else {
            pr_inet_set_default_family(NULL, pr_netaddr_get_family(serv->addr));
          }
#else
          pr_inet_set_default_family(NULL, pr_netaddr_get_family(serv->addr));
#endif /* PR_USE_IPV6 */
        }

        serv->listen = pr_ipbind_get_listening_conn(serv,
          (SocketBindTight ? serv->addr : NULL), serv->ServerPort);
        if (serv->listen == NULL) {
          return -1;
        }

        PR_CREATE_IPBIND(serv, serv->addr, serv->ServerPort);
        PR_OPEN_IPBIND(serv->addr, serv->ServerPort, serv->listen, is_default,
          FALSE, TRUE);
        PR_ADD_IPBINDS(serv);

      } else if (is_default) {
        serv->listen = NULL;

        PR_CREATE_IPBIND(serv, serv->addr, serv->ServerPort);
        PR_OPEN_IPBIND(serv->addr, serv->ServerPort, serv->listen, is_default,
          FALSE, TRUE);
        PR_ADD_IPBINDS(serv);

      } else {
        serv->listen = NULL;
      }

    } else {
      /* Because this server is sharing the connection with the main server,
       * we need a cleanup handler to remove the server's reference when the
       * original connection's pool is destroyed.
       */

      is_default = FALSE;
      default_server = get_param_ptr(serv->conf, "DefaultServer", FALSE);
      if (default_server != NULL &&
          *default_server == TRUE) {
        is_default = TRUE;
      }

      serv->listen = main_server->listen;
      register_cleanup(serv->listen->pool, &serv->listen, server_cleanup_cb,
        server_cleanup_cb);

      PR_CREATE_IPBIND(serv, serv->addr, serv->ServerPort);
      PR_OPEN_IPBIND(serv->addr, serv->ServerPort, NULL, is_default, FALSE,
        TRUE);
      PR_ADD_IPBINDS(serv);
    }
  }

  /* Any "unclaimed" listening conns can be removed and closed. */
  if (listening_conn_list) {
    struct listener_rec *lr, *lrn;

    for (lr = (struct listener_rec *) listening_conn_list->xas_list; lr; lr = lrn) {
      lrn = lr->next;

      if (!lr->claimed) {
        xaset_remove(listening_conn_list, (xasetmember_t *) lr);
        destroy_pool(lr->pool);
      }
    }
  }

  return 0;
}
Exemple #8
0
/* This is one messy function.  Yuck.  Yay legacy code. */
config_rec *pr_auth_get_anon_config(pool *p, char **login_name,
    char **user_name, char **anon_name) {
  config_rec *c = NULL, *topc = NULL, *anon_c = NULL;
  char *config_user_name, *config_anon_name = NULL;
  unsigned char is_alias = FALSE, *auth_alias_only = NULL;

  /* Precendence rules:
   *   1. Search for UserAlias directive.
   *   2. Search for Anonymous directive.
   *   3. Normal user login
   */

  config_user_name = get_param_ptr(main_server->conf, "UserName", FALSE);
  if (config_user_name &&
      user_name) {
    *user_name = config_user_name;
  }

  /* If the main_server->conf->set list is large (e.g. there are many
   * config_recs in the list, as can happen if MANY <Directory> sections are
   * configured), the login can timeout because this find_config() call takes
   * a long time.  The reason this issue strikes HERE first in the login
   * process is that this appears to the first find_config() call which has
   * a TRUE recurse flag.
   *
   * The find_config() call below is looking for a UserAlias directive
   * anywhere in the configuration, no matter how deeply buried in nested
   * config contexts it might be.
   */

  c = find_config(main_server->conf, CONF_PARAM, "UserAlias", TRUE);
  if (c) {
    do {
      pr_signals_handle();

      if (strncmp(c->argv[0], "*", 2) == 0 ||
          strcmp(c->argv[0], *login_name) == 0) {
        is_alias = TRUE;
        break;
      }

    } while ((c = find_config_next(c, c->next, CONF_PARAM, "UserAlias",
      TRUE)) != NULL);
  }

  /* This is where things get messy, rapidly. */
  topc = c;

  while (c && c->parent &&
    (auth_alias_only = get_param_ptr(c->parent->set, "AuthAliasOnly", FALSE))) {

    /* while() loops should always handle signals. */
    pr_signals_handle();

    if (auth_alias_only) {
      /* If AuthAliasOnly is on, ignore this one and continue. */
      if (*auth_alias_only == TRUE) {
        c = find_config_next(c, c->next, CONF_PARAM, "UserAlias", TRUE);
        continue;
      }
    }

    /* At this point, we have found an "AuthAliasOnly off" config in
     * c->parent->set.  See if there's a UserAlias in the same config set.
     */

    is_alias = FALSE;

    find_config_set_top(topc);
    c = find_config_next(c, c->next, CONF_PARAM, "UserAlias", TRUE);

    if (c &&
        (strncmp(c->argv[0], "*", 2) == 0 ||
         strcmp(c->argv[0], *login_name) == 0)) {
      is_alias = TRUE;
    }
  }

  if (c) {
    *login_name = c->argv[1];

    /* If the alias is applied inside an <Anonymous> context, we have found
     * our anon block.
     */
    if (c->parent &&
        c->parent->config_type == CONF_ANON) {
      c = c->parent;

    } else {
      c = NULL;
    }
  }

  /* Next, search for an anonymous entry. */

  if (c == NULL) {
    c = find_config(main_server->conf, CONF_ANON, NULL, FALSE);

  } else {
    find_config_set_top(c);
    anon_c = c;
  }

  if (c) {
    do {
      pr_signals_handle();

      config_anon_name = get_param_ptr(c->subset, "UserName", FALSE);

      if (!config_anon_name)
        config_anon_name = config_user_name;

      if (config_anon_name &&
          strcmp(config_anon_name, *login_name) == 0) {
         if (anon_name)
           *anon_name = config_anon_name;
         break;
      }
 
    } while ((c = find_config_next(c, c->next, CONF_ANON, NULL,
      FALSE)) != NULL);
  }

  if (!is_alias) {
    /* Yes, we do want to be using c, not anon_c, here.  Otherwise, we
     * risk a regression of Bug#3501.
     */

    auth_alias_only = get_param_ptr(c ? c->subset : main_server->conf,
      "AuthAliasOnly", FALSE);

    if (auth_alias_only &&
        *auth_alias_only == TRUE) {
      if (c &&
          c->config_type == CONF_ANON) {
        c = NULL;

      } else {
        *login_name = NULL;
      }

      auth_alias_only = get_param_ptr(main_server->conf, "AuthAliasOnly",
        FALSE);
      if (*login_name &&
          auth_alias_only &&
          *auth_alias_only == TRUE)
        *login_name = NULL;

      if ((!login_name || !c) &&
          anon_name) {
        *anon_name = NULL;
      }
    }
  }

  return c;
}
Exemple #9
0
static void get_geoip_tables(array_header *geoips, int filter_flags) {
  config_rec *c;

  c = find_config(main_server->conf, CONF_PARAM, "GeoIPTable", FALSE);
  while (c) {
    GeoIP *gi;
    const char *path;
    int flags, use_utf8 = FALSE;

    pr_signals_handle();

    path = c->argv[0];
    flags = *((int *) c->argv[1]);
    use_utf8 = *((int *) c->argv[2]);

    /* Make sure we open tables that are marked with the default
     * GEOIP_STANDARD flag, which has a value of zero.
     */
    if ((flags == GEOIP_STANDARD && filter_flags != GEOIP_STANDARD) || 
        !(flags & filter_flags)) {
      c = find_config_next(c, c->next, CONF_PARAM, "GeoIPTable", FALSE);
      continue;
    } 

    PRIVS_ROOT
    gi = GeoIP_open(path, flags);
    if (gi == NULL &&
        (flags & GEOIP_INDEX_CACHE)) {
      /* Per Bug#3975, a common cause of this error is the fact that some
       * of the Maxmind GeoIP Lite database files simply do not have indexes.
       * So try to open them as standard databases as a fallback.
       */
      pr_log_debug(DEBUG8, MOD_GEOIP_VERSION
        ": unable to open GeoIPTable '%s' using the IndexCache flag "
        "(database lacks index?), retrying without IndexCache flag", path);
      flags &= ~GEOIP_INDEX_CACHE;
      gi = GeoIP_open(path, flags);
    }
    PRIVS_RELINQUISH

    if (gi != NULL) {
      if (use_utf8) {
        GeoIP_set_charset(gi, GEOIP_CHARSET_UTF8); 
      }

      *((GeoIP **) push_array(geoips)) = gi;

      pr_trace_msg(trace_channel, 15, "loaded GeoIP table '%s': %s (type %d)",
        path, GeoIP_database_info(gi), GeoIP_database_edition(gi));

    } else {
      /* XXX Sigh.  Stupid libGeoIP library logs to stdout/stderr, rather
       * than providing a strerror function.  Grr!
       */

      pr_log_pri(PR_LOG_WARNING, MOD_GEOIP_VERSION
        ": warning: unable to open/use GeoIPTable '%s'", path);
    }

    c = find_config_next(c, c->next, CONF_PARAM, "GeoIPTable", FALSE);
  }

  if (geoips->nelts == 0 &&
      static_geoips->nelts == 0 &&
      ((filter_flags == GEOIP_STANDARD) ||
       (filter_flags & GEOIP_CHECK_CACHE))) {
    GeoIP *gi;

    /* Let the library use its own default database file(s), if no others
     * have been configured.
     */

    PRIVS_ROOT
    gi = GeoIP_new(GEOIP_STANDARD);
    PRIVS_RELINQUISH

    if (gi != NULL) {
      *((GeoIP **) push_array(geoips)) = gi;

      pr_trace_msg(trace_channel, 15,
        "loaded default GeoIP table: %s (type %d)",
        GeoIP_database_info(gi), GeoIP_database_edition(gi));

    } else {
      pr_log_pri(PR_LOG_WARNING, MOD_GEOIP_VERSION
        ": warning: unable to open/use default GeoIP library database file(s)");
    }
  }
Exemple #10
0
static int check_geoip_filters(geoip_policy_e policy) {
  int matched_allow_filter = -1, allow_conn = 0;
#if PR_USE_REGEX
  config_rec *c;

  c = find_config(main_server->conf, CONF_PARAM, "GeoIPAllowFilter", FALSE);
  while (c) {
    int filter_id, res;
    pr_regex_t *filter_re;
    const char *filter_name, *filter_pattern, *filter_value;

    pr_signals_handle();

    if (matched_allow_filter == -1) {
      matched_allow_filter = FALSE;
    }

    filter_id = *((int *) c->argv[0]);
    filter_pattern = c->argv[1];
    filter_re = c->argv[2];

    filter_value = get_geoip_filter_value(filter_id);
    if (filter_value == NULL) {
      c = find_config_next(c, c->next, CONF_PARAM, "GeoIPAllowFilter", FALSE);
      continue;
    }

    filter_name = get_geoip_filter_name(filter_id);

    res = pr_regexp_exec(filter_re, filter_value, 0, NULL, 0, 0, 0);
    pr_trace_msg(trace_channel, 12,
      "%s filter value %s %s GeoIPAllowFilter pattern '%s'",
      filter_name, filter_value, res == 0 ? "matched" : "did not match",
      filter_pattern);

    if (res == 0) {
      matched_allow_filter = TRUE;
      break;
    }

    (void) pr_log_writefile(geoip_logfd, MOD_GEOIP_VERSION,
      "%s filter value '%s' did not match GeoIPAllowFilter pattern '%s'",
      filter_name, filter_value, filter_pattern);

    c = find_config_next(c, c->next, CONF_PARAM, "GeoIPAllowFilter", FALSE);
  }

  c = find_config(main_server->conf, CONF_PARAM, "GeoIPDenyFilter", FALSE);
  while (c) {
    int filter_id, res;
    pr_regex_t *filter_re;
    const char *filter_name, *filter_pattern, *filter_value;

    pr_signals_handle();

    filter_id = *((int *) c->argv[0]);
    filter_pattern = c->argv[1];
    filter_re = c->argv[2];

    filter_value = get_geoip_filter_value(filter_id);
    if (filter_value == NULL) {
      c = find_config_next(c, c->next, CONF_PARAM, "GeoIPDenyFilter", FALSE);
      continue;
    }

    filter_name = get_geoip_filter_name(filter_id);

    res = pr_regexp_exec(filter_re, filter_value, 0, NULL, 0, 0, 0);
    pr_trace_msg(trace_channel, 12,
      "%s filter value %s %s GeoIPDenyFilter pattern '%s'",
      filter_name, filter_value, res == 0 ? "matched" : "did not match",
      filter_pattern);

    if (res == 0) {
      (void) pr_log_writefile(geoip_logfd, MOD_GEOIP_VERSION,
        "%s filter value '%s' matched GeoIPDenyFilter pattern '%s'",
        filter_name, filter_value, filter_pattern);
      return -1;
    }

    c = find_config_next(c, c->next, CONF_PARAM, "GeoIPDenyFilter", FALSE);
  }
#endif /* !HAVE_REGEX_H or !HAVE_REGCOMP */

  switch (policy) {
    case GEOIP_POLICY_ALLOW_DENY:
      allow_conn = 0;
      break;

    case GEOIP_POLICY_DENY_ALLOW:
      if (matched_allow_filter == FALSE) {
        /* If we have not explicitly matched any allow filters, then
         * reject the connection.
         */
        allow_conn = -1;
      }
      break;
  }

  return allow_conn;
}
Exemple #11
0
END_TEST

START_TEST (find_config_test) {
  int res;
  config_rec *c;
  xaset_t *set = NULL;
  const char *name;

  c = find_config(NULL, -1, NULL, FALSE);
  fail_unless(c == NULL, "Failed to handle null arguments");
  fail_unless(errno == EINVAL, "Failed to set errno to EINVAL, got %d (%s)",
    errno, strerror(errno));

  mark_point();

  name = "foo";
  c = add_config_param_set(&set, name, 0);
  fail_unless(c != NULL, "Failed to add config '%s': %s", name,
    strerror(errno));

  name = "bar";
  c = find_config(set, -1, name, FALSE);
  fail_unless(c == NULL, "Failed to handle null arguments");
  fail_unless(errno == ENOENT, "Failed to set errno to ENOENT, got %d (%s)",
    errno, strerror(errno));

  mark_point();

  /* We expect to find "foo", but a 'next' should be empty. */
  name = "foo";
  c = find_config(set, -1, name, FALSE);
  fail_unless(c != NULL, "Failed to find config '%s': %s", name,
    strerror(errno));

  mark_point();

  c = find_config_next(c, c->next, -1, name, FALSE);
  fail_unless(c == NULL, "Found next config unexpectedly");
  fail_unless(errno == ENOENT, "Failed to set errno to ENOENT, got %d (%s)",
    errno, strerror(errno));

  /* Now add another config, find "foo" again; this time, a 'next' should
   * NOT be empty; it should find the 2nd config we added.
   */

  name = "foo2";
  c = add_config_param_set(&set, name, 0);
  fail_unless(c != NULL, "Failed to add config '%s': %s", name,
    strerror(errno));

  name = NULL;
  c = find_config(set, -1, name, FALSE);
  fail_unless(c != NULL, "Failed to find any config: %s", strerror(errno));

  mark_point();

  c = find_config_next(c, c->next, -1, name, FALSE);
  fail_unless(c != NULL, "Expected to find another config");

  mark_point();

  name = "foo";
  res = remove_config(set, name, FALSE);
  fail_unless(res > 0, "Failed to remove config '%s': %s", name,
    strerror(errno));

  mark_point();

  c = find_config(set, -1, name, FALSE);
  fail_unless(c == NULL, "Found config '%s' unexpectedly", name);
  fail_unless(errno == ENOENT, "Failed to set errno to ENOENT, got %d (%s)",
    errno, strerror(errno));
}
Exemple #12
0
static int display_fh(pr_fh_t *fh, const char *fs, const char *code,
    int flags) {
  struct stat st;
  char buf[PR_TUNABLE_BUFFER_SIZE] = {'\0'};
  int len, res;
  unsigned int *current_clients = NULL;
  unsigned int *max_clients = NULL;
  off_t fs_size = 0;
  pool *p;
  void *v;
  xaset_t *s;
  config_rec *c = NULL;
  const char *serverfqdn = main_server->ServerFQDN;
  char *outs, mg_size[12] = {'\0'}, mg_size_units[12] = {'\0'},
    mg_max[12] = "unlimited";
  char total_files_in[12] = {'\0'}, total_files_out[12] = {'\0'},
    total_files_xfer[12] = {'\0'};
  char mg_class_limit[12] = {'\0'}, mg_cur[12] = {'\0'},
    mg_xfer_bytes[12] = {'\0'}, mg_cur_class[12] = {'\0'};
  char mg_xfer_units[12] = {'\0'}, *user;
  const char *mg_time;
  char *rfc1413_ident = 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) {
    fh->fh_iosz = st.st_blksize;
  }

  /* Note: The size provided by pr_fs_getsize() is in KB, not bytes. */
  res = pr_fs_fgetsize(fh->fh_fd, &fs_size);
  if (res < 0 &&
      errno != ENOSYS) {
    (void) pr_log_debug(DEBUG7, "error getting filesystem size for '%s': %s",
      fh->fh_path, strerror(errno));
    fs_size = 0;
  }

  snprintf(mg_size, sizeof(mg_size), "%" PR_LU, (pr_off_t) fs_size);
  format_size_str(mg_size_units, sizeof(mg_size_units), fs_size);

  p = make_sub_pool(session.pool);
  pr_pool_tag(p, "Display Pool");

  s = (session.anon_config ? session.anon_config->subset : main_server->conf);

  mg_time = pr_strtime(time(NULL));

  max_clients = get_param_ptr(s, "MaxClients", FALSE);

  v = pr_table_get(session.notes, "client-count", NULL);
  if (v) {
    current_clients = v;
  }

  snprintf(mg_cur, sizeof(mg_cur), "%u", current_clients ? *current_clients: 1);

  if (session.conn_class != NULL &&
      session.conn_class->cls_name != NULL) {
    unsigned int *class_clients = NULL;
    config_rec *maxc = NULL;
    unsigned int maxclients = 0;

    v = pr_table_get(session.notes, "class-client-count", NULL);
    if (v) {
      class_clients = v;
    }

    snprintf(mg_cur_class, sizeof(mg_cur_class), "%u",
      class_clients ? *class_clients : 0);

    /* For the %z variable, first we scan through the MaxClientsPerClass,
     * and use the first applicable one.  If none are found, look for
     * any MaxClients set.
     */

    maxc = find_config(main_server->conf, CONF_PARAM, "MaxClientsPerClass",
      FALSE);

    while (maxc) {
      pr_signals_handle();

      if (strcmp(maxc->argv[0], session.conn_class->cls_name) != 0) {
        maxc = find_config_next(maxc, maxc->next, CONF_PARAM,
          "MaxClientsPerClass", FALSE);
        continue;
      }

      maxclients = *((unsigned int *) maxc->argv[1]);
      break;
    }

    if (maxclients == 0) {
      maxc = find_config(main_server->conf, CONF_PARAM, "MaxClients", FALSE);

      if (maxc)
        maxclients = *((unsigned int *) maxc->argv[0]);
    }

    snprintf(mg_class_limit, sizeof(mg_class_limit), "%u", maxclients);

  } else {
    snprintf(mg_class_limit, sizeof(mg_class_limit), "%u",
      max_clients ? *max_clients : 0);
    snprintf(mg_cur_class, sizeof(mg_cur_class), "%u", 0);
  }

  snprintf(mg_xfer_bytes, sizeof(mg_xfer_bytes), "%" PR_LU,
    (pr_off_t) session.total_bytes >> 10);
  snprintf(mg_xfer_units, sizeof(mg_xfer_units), "%" PR_LU "B",
    (pr_off_t) session.total_bytes);

  if (session.total_bytes >= 10240) {
    snprintf(mg_xfer_units, sizeof(mg_xfer_units), "%" PR_LU "kB",
      (pr_off_t) session.total_bytes >> 10);

  } else if ((session.total_bytes >> 10) >= 10240) {
Exemple #13
0
const char *sftp_display_fh_get_msg(pool *p, pr_fh_t *fh) {
  struct stat st;
  char buf[PR_TUNABLE_BUFFER_SIZE], *msg = "";
  int len, res;
  unsigned int *current_clients = NULL;
  unsigned int *max_clients = NULL;
  off_t fs_size = 0;
  void *v;
  const char *serverfqdn = main_server->ServerFQDN;
  char *outs, mg_size[12] = {'\0'}, mg_size_units[12] = {'\0'},
    mg_max[12] = "unlimited";
  char mg_class_limit[12] = {'\0'}, mg_cur[12] = {'\0'},
    mg_cur_class[12] = {'\0'};
  const char *mg_time;
  char *rfc1413_ident = NULL, *user = 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) {
    fh->fh_iosz = st.st_blksize;
  }

  res = pr_fs_fgetsize(fh->fh_fd, &fs_size);
  if (res < 0 &&
      errno != ENOSYS) {
    (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
      "error getting filesystem size for '%s': %s", fh->fh_path,
      strerror(errno));
    fs_size = 0;
  }

  snprintf(mg_size, sizeof(mg_size), "%" PR_LU, (pr_off_t) fs_size);
  format_size_str(mg_size_units, sizeof(mg_size_units), fs_size);

  mg_time = pr_strtime(time(NULL));

  max_clients = get_param_ptr(main_server->conf, "MaxClients", FALSE);

  v = pr_table_get(session.notes, "client-count", NULL);
  if (v) {
    current_clients = v;
  }

  snprintf(mg_cur, sizeof(mg_cur), "%u", current_clients ? *current_clients: 1);

  if (session.conn_class != NULL &&
      session.conn_class->cls_name) {
    unsigned int *class_clients = NULL;
    config_rec *maxc = NULL;
    unsigned int maxclients = 0;

    v = pr_table_get(session.notes, "class-client-count", NULL);
    if (v) {
      class_clients = v;
    }

    snprintf(mg_cur_class, sizeof(mg_cur_class), "%u",
      class_clients ? *class_clients : 0);

    /* For the %z variable, first we scan through the MaxClientsPerClass,
     * and use the first applicable one.  If none are found, look for
     * any MaxClients set.
     */

    maxc = find_config(main_server->conf, CONF_PARAM, "MaxClientsPerClass",
      FALSE);

    while (maxc) {
      pr_signals_handle();

      if (strcmp(maxc->argv[0], session.conn_class->cls_name) != 0) {
        maxc = find_config_next(maxc, maxc->next, CONF_PARAM,
          "MaxClientsPerClass", FALSE);
        continue;
      }

      maxclients = *((unsigned int *) maxc->argv[1]);
      break;
    }

    if (maxclients == 0) {
      maxc = find_config(main_server->conf, CONF_PARAM, "MaxClients", FALSE);

      if (maxc)
        maxclients = *((unsigned int *) maxc->argv[0]);
    }

    snprintf(mg_class_limit, sizeof(mg_class_limit), "%u", maxclients);

  } else {
    snprintf(mg_class_limit, sizeof(mg_class_limit), "%u",
      max_clients ? *max_clients : 0);
    snprintf(mg_cur_class, sizeof(mg_cur_class), "%u", 0);
  }

  snprintf(mg_max, sizeof(mg_max), "%u", max_clients ? *max_clients : 0);

  user = pr_table_get(session.notes, "mod_auth.orig-user", NULL);
  if (user == NULL)
    user = "";

  rfc1413_ident = pr_table_get(session.notes, "mod_ident.rfc1413-ident", NULL);
  if (rfc1413_ident == NULL) {
    rfc1413_ident = "UNKNOWN";
  }

  memset(buf, '\0', sizeof(buf));
  while (pr_fsio_gets(buf, sizeof(buf), fh) != NULL) {
    char *tmp;

    pr_signals_handle();

    buf[sizeof(buf)-1] = '\0';
    len = strlen(buf);

    while (len > 0 &&
           (buf[len-1] == '\r' || buf[len-1] == '\n')) {
      pr_signals_handle();

      buf[len-1] = '\0';
      len--;
    }

    /* Check for any Variable-type strings. */
    tmp = strstr(buf, "%{");
    while (tmp) {
      char *key, *tmp2;
      const char *val;

      pr_signals_handle();

      tmp2 = strchr(tmp, '}');
      if (tmp2 == NULL) {
        /* No closing '}' found in this string, so no need to look for any
         * aother '%{' opening sequence.  Just move on.
         */
        tmp = NULL;
        break;
      }

      key = pstrndup(p, tmp, tmp2 - tmp + 1);

      /* There are a couple of special-case keys to watch for:
       *
       *   env:$var
       *   time:$fmt
       *
       * The Var API does not easily support returning values for keys
       * where part of the value depends on part of the key.  That's why
       * these keys are handled here, instead of in pr_var_get().
       */

      if (strncmp(key, "%{time:", 7) == 0) {
        char time_str[128], *fmt;
        time_t now;
        struct tm *time_info;

        fmt = pstrndup(p, key + 7, strlen(key) - 8);

        now = time(NULL);
        time_info = pr_localtime(NULL, &now);

        memset(time_str, 0, sizeof(time_str));
        strftime(time_str, sizeof(time_str), fmt, time_info);

        val = pstrdup(p, time_str);

      } else if (strncmp(key, "%{env:", 6) == 0) {
        char *env_var;

        env_var = pstrndup(p, key + 6, strlen(key) - 7);
        val = pr_env_get(p, env_var);
        if (val == NULL) {
          pr_trace_msg("var", 4,
            "no value set for environment variable '%s', using \"(none)\"",
            env_var);
          val = "(none)";
        }

      } else {
        val = pr_var_get(key);
        if (val == NULL) {
          pr_trace_msg("var", 4,
            "no value set for name '%s', using \"(none)\"", key);
          val = "(none)";
        }
      }

      outs = sreplace(p, buf, key, val, NULL);
      sstrncpy(buf, outs, sizeof(buf));

      tmp = strstr(outs, "%{");
    }

    outs = sreplace(p, buf,
      "%C", (session.cwd[0] ? session.cwd : "(none)"),
      "%E", main_server->ServerAdmin,
      "%F", mg_size,
      "%f", mg_size_units,
      "%i", "0",
      "%K", "0",
      "%k", "0B",
      "%L", serverfqdn,
      "%M", mg_max,
      "%N", mg_cur,
      "%o", "0",
      "%R", (session.c && session.c->remote_name ?
        session.c->remote_name : "(unknown)"),
      "%T", mg_time,
      "%t", "0",
      "%U", user,
      "%u", rfc1413_ident,
      "%V", main_server->ServerName,
      "%x", session.conn_class ? session.conn_class->cls_name : "(unknown)",
      "%y", mg_cur_class,
      "%z", mg_class_limit,
      NULL);

    /* Always make sure that the lines we send are CRLF-terminated. */
    msg = pstrcat(p, msg, outs, "\r\n", NULL);

    /* Clear the buffer for the next read. */
    memset(buf, '\0', sizeof(buf));
  }

  return msg;
}
Exemple #14
0
static int sftppam_driver_open(sftp_kbdint_driver_t *driver, const char *user) {
  int res;
  config_rec *c;

  /* XXX Should we pay attention to AuthOrder here?  I.e. if AuthOrder
   * does not include mod_sftp_pam or mod_auth_pam, should we fail to
   * open this driver, since the AuthOrder indicates that no PAM check is
   * desired?  For this to work, AuthOrder needs to have been processed
   * prior to this callback being invoked...
   */

  /* Figure out our default return style: whether or not PAM should allow
   * other auth modules a shot at this user or not is controlled by adding
   * '*' to a module name in the AuthOrder directive.  By default, auth
   * modules are not authoritative, and allow other auth modules a chance at
   * authenticating the user.  This is not the most secure configuration, but
   * it allows things like AuthUserFile to work "out of the box".
   */
  if (sftppam_authtab[0].auth_flags & PR_AUTH_FL_REQUIRED) {
    sftppam_authoritative = TRUE;
  }

  sftppam_userlen = strlen(user) + 1;
  if (sftppam_userlen > (PAM_MAX_MSG_SIZE + 1)) {
    sftppam_userlen = PAM_MAX_MSG_SIZE + 1;
  }

#ifdef MAXLOGNAME
  /* Some platforms' PAM libraries do not handle login strings that exceed
   * this length.
   */
  if (sftppam_userlen > MAXLOGNAME) {
    pr_log_pri(PR_LOG_NOTICE,
      "PAM(%s): Name exceeds maximum login length (%u)", user, MAXLOGNAME);
    pr_trace_msg(trace_channel, 1,
      "user name '%s' exceeds maximum login length %u, declining", user,
      MAXLOGNAME);
    errno = EPERM;
    return -1;
  }
#endif

  sftppam_user = malloc(sftppam_userlen);
  if (sftppam_user == NULL) {
    pr_log_pri(PR_LOG_ALERT, MOD_SFTP_PAM_VERSION ": Out of memory!");
    exit(1);
  }

  memset(sftppam_user, '\0', sftppam_userlen);
  sstrncpy(sftppam_user, user, sftppam_userlen);

  c = find_config(main_server->conf, CONF_PARAM, "SFTPPAMOptions", FALSE);
  while (c != NULL) {
    unsigned long opts;

    pr_signals_handle();

    opts = *((unsigned long *) c->argv[0]);
    sftppam_opts |= opts;

    c = find_config_next(c, c->next, CONF_PARAM, "SFTPPAMOptions", FALSE);
  }
 
#ifdef SOLARIS2
  /* For Solaris environments, the TTY environment will always be set,
   * in order to workaround a bug (Solaris Bug ID 4250887) where
   * pam_open_session() will crash unless both PAM_RHOST and PAM_TTY are
   * set, and the PAM_TTY setting is at least greater than the length of
   * the string "/dev/".
   */
  sftppam_opts &= ~SFTP_PAM_OPT_NO_TTY;
#endif /* SOLARIS2 */
 
  pr_signals_block();
  PRIVS_ROOT

  res = pam_start(sftppam_service, sftppam_user, &sftppam_conv, &sftppam_pamh);
  if (res != PAM_SUCCESS) {
    PRIVS_RELINQUISH
    pr_signals_unblock();

    free(sftppam_user);
    sftppam_user = NULL;
    sftppam_userlen = 0;

    switch (res) {
      case PAM_SYSTEM_ERR:
        (void) pr_log_writefile(sftp_logfd, MOD_SFTP_PAM_VERSION,
          "error starting PAM service: %s", strerror(errno));
        break;

      case PAM_BUF_ERR:
        (void) pr_log_writefile(sftp_logfd, MOD_SFTP_PAM_VERSION,
          "error starting PAM service: Memory buffer error");
        break;
    }

    return -1;
  }

  pam_set_item(sftppam_pamh, PAM_RUSER, sftppam_user);
  pam_set_item(sftppam_pamh, PAM_RHOST, session.c->remote_name);

  if (!(sftppam_opts & SFTP_PAM_OPT_NO_TTY)) {
    memset(sftppam_tty, '\0', sizeof(sftppam_tty));
    snprintf(sftppam_tty, sizeof(sftppam_tty), "/dev/ftpd%02lu",
      (unsigned long) (session.pid ? session.pid : getpid()));
    sftppam_tty[sizeof(sftppam_tty)-1] = '\0';

    pr_trace_msg(trace_channel, 9, "setting PAM_TTY to '%s'", sftppam_tty);
    pam_set_item(sftppam_pamh, PAM_TTY, sftppam_tty);
  }

  PRIVS_RELINQUISH
  pr_signals_unblock();

  /* We need to disable mod_auth_pam, since both mod_auth_pam and us want
   * to talk to the PAM API, just in different fashions.
   */

  c = add_config_param_set(&(main_server->conf), "AuthPAM", 1, NULL);
  c->argv[0] = palloc(c->pool, sizeof(unsigned char));
  *((unsigned char *) c->argv[0]) = FALSE;

  if (pr_auth_remove_auth_only_module("mod_auth_pam.c") < 0) {
    if (errno != ENOENT) {
      pr_log_pri(PR_LOG_NOTICE, MOD_SFTP_PAM_VERSION
        ": error removing 'mod_auth_pam.c' from the auth-only module list: %s",
        strerror(errno));
    }
  }

  if (pr_auth_add_auth_only_module("mod_sftp_pam.c") < 0) {
    if (errno != EEXIST) {
      pr_log_pri(PR_LOG_NOTICE, MOD_SFTP_PAM_VERSION
        ": error adding 'mod_sftp_pam.c' to the auth-only module list: %s",
        strerror(errno));
    }
  }

  sftppam_handle_auth = TRUE;

  driver->driver_pool = make_sub_pool(permanent_pool);
  pr_pool_tag(driver->driver_pool, "PAM keyboard-interactive driver pool");

  return 0;
}
Exemple #15
0
void pr_throttle_init(cmd_rec *cmd) {
  config_rec *c = NULL;
  char *xfer_cmd = NULL;
  unsigned char have_user_rate = FALSE, have_group_rate = FALSE,
    have_class_rate = FALSE;
  unsigned int precedence = 0;

  /* Make sure the variables are (re)initialized */
  xfer_rate_kbps = xfer_rate_bps = 0.0;
  xfer_rate_freebytes = 0;
  xfer_rate_scoreboard_updates = 0;
  have_xfer_rate = FALSE;

  c = find_config(CURRENT_CONF, CONF_PARAM, "TransferRate", FALSE);

  /* Note: need to cycle through all the matching config_recs, and using
   * the information from the current config_rec only if it matches
   * the target *and* has a higher precedence than any of the previously
   * found config_recs.
   */
  while (c) {
    char **cmdlist = (char **) c->argv[0];
    int matched_cmd = FALSE;

    pr_signals_handle();

    /* Does this TransferRate apply to the current command?  Note: this
     * could be made more efficient by using bitmasks rather than string
     * comparisons.
     */
    for (xfer_cmd = *cmdlist; xfer_cmd; xfer_cmd = *(cmdlist++)) {
      if (strcasecmp(xfer_cmd, cmd->argv[0]) == 0) {
        matched_cmd = TRUE;
        break;
      }
    }

    /* No -- continue on to the next TransferRate. */
    if (!matched_cmd) {
      c = find_config_next(c, c->next, CONF_PARAM, "TransferRate", FALSE);
      continue;
    }

    if (c->argc > 4) {
      if (strncmp(c->argv[4], "user", 5) == 0) {

        if (pr_expr_eval_user_or((char **) &c->argv[5]) == TRUE &&
            *((unsigned int *) c->argv[3]) > precedence) {

          /* Set the precedence. */
          precedence = *((unsigned int *) c->argv[3]);

          xfer_rate_kbps = *((long double *) c->argv[1]);
          xfer_rate_freebytes = *((off_t *) c->argv[2]);
          have_xfer_rate = TRUE;
          have_user_rate = TRUE;
          have_group_rate = have_class_rate = FALSE;
        }

      } else if (strncmp(c->argv[4], "group", 6) == 0) {

        if (pr_expr_eval_group_and((char **) &c->argv[5]) == TRUE &&
            *((unsigned int *) c->argv[3]) > precedence) {

          /* Set the precedence. */
          precedence = *((unsigned int *) c->argv[3]);

          xfer_rate_kbps = *((long double *) c->argv[1]);
          xfer_rate_freebytes = *((off_t *) c->argv[2]);
          have_xfer_rate = TRUE;
          have_group_rate = TRUE;
          have_user_rate = have_class_rate = FALSE;
        }

      } else if (strncmp(c->argv[4], "class", 6) == 0) {

        if (pr_expr_eval_class_or((char **) &c->argv[5]) == TRUE &&
          *((unsigned int *) c->argv[3]) > precedence) {

          /* Set the precedence. */
          precedence = *((unsigned int *) c->argv[3]);

          xfer_rate_kbps = *((long double *) c->argv[1]);
          xfer_rate_freebytes = *((off_t *) c->argv[2]);
          have_xfer_rate = TRUE;
          have_class_rate = TRUE;
          have_user_rate = have_group_rate = FALSE;
        }
      }

    } else {

      if (*((unsigned int *) c->argv[3]) > precedence) {

        /* Set the precedence. */
        precedence = *((unsigned int *) c->argv[3]);

        xfer_rate_kbps = *((long double *) c->argv[1]);
        xfer_rate_freebytes = *((off_t *) c->argv[2]);
        have_xfer_rate = TRUE;
        have_user_rate = have_group_rate = have_class_rate = FALSE;
      }
    }

    c = find_config_next(c, c->next, CONF_PARAM, "TransferRate", FALSE);
  }

  /* Print out a helpful debugging message. */
  if (have_xfer_rate) {
    pr_log_debug(DEBUG3, "TransferRate (%.3Lf KB/s, %" PR_LU
        " bytes free) in effect%s", xfer_rate_kbps,
      (pr_off_t) xfer_rate_freebytes,
      have_user_rate ? " for current user" :
      have_group_rate ? " for current group" :
      have_class_rate ? " for current class" : "");

    /* Convert the configured Kbps to bytes per usec, for use later.
     * The 1024.0 factor converts for Kbytes to bytes, and the
     * 1000000.0 factor converts from secs to usecs.
     */
    xfer_rate_bps = xfer_rate_kbps * 1024.0;
  }
}
Exemple #16
0
static int check_geoip_filters(geoip_policy_e policy) {
  int allow_conn = 0, matched_allow_filter = -1, matched_deny_filter = -1;
#if PR_USE_REGEX
  config_rec *c;

  c = find_config(main_server->conf, CONF_PARAM, "GeoIPAllowFilter", FALSE);
  while (c != NULL) {
    register unsigned int i;
    int matched = TRUE;
    array_header *filters;

    pr_signals_handle();

    if (matched_allow_filter == -1) {
      matched_allow_filter = FALSE;
    }

    filters = c->argv[0];

    for (i = 0; i < filters->nelts; i++) {
      int filter_id, res;
      struct geoip_filter *filter;
      pr_regex_t *filter_re;
      const char *filter_name, *filter_pattern, *filter_value;

      filter = ((struct geoip_filter **) filters->elts)[i]; 
      filter_id = filter->filter_id;
      filter_pattern = filter->filter_pattern;
      filter_re = filter->filter_re;

      filter_value = get_geoip_filter_value(filter_id);
      if (filter_value == NULL) {
        matched = FALSE;
        break;
      }

      filter_name = get_geoip_filter_name(filter_id);

      res = pr_regexp_exec(filter_re, filter_value, 0, NULL, 0, 0, 0);
      pr_trace_msg(trace_channel, 12,
        "%s filter value %s %s GeoIPAllowFilter pattern '%s'",
        filter_name, filter_value, res == 0 ? "matched" : "did not match",
        filter_pattern);
      if (res == 0) {
        (void) pr_log_writefile(geoip_logfd, MOD_GEOIP_VERSION,
          "%s filter value '%s' matched GeoIPAllowFilter pattern '%s'",
          filter_name, filter_value, filter_pattern);

      } else {
        (void) pr_log_writefile(geoip_logfd, MOD_GEOIP_VERSION,
          "%s filter value '%s' did not match GeoIPAllowFilter pattern '%s'",
          filter_name, filter_value, filter_pattern);
          matched = FALSE;
          break;
      }
    }

    if (matched == TRUE) {
      matched_allow_filter = TRUE;
      break;
    }

    c = find_config_next(c, c->next, CONF_PARAM, "GeoIPAllowFilter", FALSE);
  }

  c = find_config(main_server->conf, CONF_PARAM, "GeoIPDenyFilter", FALSE);
  while (c != NULL) {
    register unsigned int i;
    int matched = TRUE;
    array_header *filters;

    pr_signals_handle();

    if (matched_deny_filter == -1) {
      matched_deny_filter = FALSE;
    }

    filters = c->argv[0];

    for (i = 0; i < filters->nelts; i++) {
      int filter_id, res;
      struct geoip_filter *filter;
      pr_regex_t *filter_re;
      const char *filter_name, *filter_pattern, *filter_value;

      filter = ((struct geoip_filter **) filters->elts)[i];
      filter_id = filter->filter_id;
      filter_pattern = filter->filter_pattern;
      filter_re = filter->filter_re;

      filter_value = get_geoip_filter_value(filter_id);
      if (filter_value == NULL) {
        matched = FALSE;
        break;
      }

      filter_name = get_geoip_filter_name(filter_id);

      res = pr_regexp_exec(filter_re, filter_value, 0, NULL, 0, 0, 0);
      pr_trace_msg(trace_channel, 12,
        "%s filter value %s %s GeoIPDenyFilter pattern '%s'",
        filter_name, filter_value, res == 0 ? "matched" : "did not match",
        filter_pattern);
      if (res == 0) {
        (void) pr_log_writefile(geoip_logfd, MOD_GEOIP_VERSION,
          "%s filter value '%s' matched GeoIPDenyFilter pattern '%s'",
          filter_name, filter_value, filter_pattern);
      } else {
        (void) pr_log_writefile(geoip_logfd, MOD_GEOIP_VERSION,
          "%s filter value '%s' did not match GeoIPDenyFilter pattern '%s'",
          filter_name, filter_value, filter_pattern);
        matched = FALSE;
        break;
      }
    }

    if (matched == TRUE) {
      matched_deny_filter = TRUE;
      break;
    }

    c = find_config_next(c, c->next, CONF_PARAM, "GeoIPDenyFilter", FALSE);
  }
#endif /* !HAVE_REGEX_H or !HAVE_REGCOMP */

  switch (policy) {
    case GEOIP_POLICY_ALLOW_DENY:
      if (matched_deny_filter == TRUE &&
          matched_allow_filter != TRUE) {
        /* If we explicitly matched any deny filters AND have NOT explicitly
         * matched any allow filters, the connection is rejected, otherwise,
         * it is allowed.
         */
        (void) pr_log_writefile(geoip_logfd, MOD_GEOIP_VERSION,
          "client matched GeoIPDenyFilter, rejecting connection");
        allow_conn = -1;

      } else {
        pr_trace_msg(trace_channel, 9,
          "allowing client connection (policy 'allow,deny')");
      }
      break;

    case GEOIP_POLICY_DENY_ALLOW:
      if (matched_allow_filter == FALSE) {
        /* If we have not explicitly matched any allow filters, then
         * reject the connection.
         */
        (void) pr_log_writefile(geoip_logfd, MOD_GEOIP_VERSION,
          "client did not match any GeoIPAllowFilters, rejecting connection");
        allow_conn = -1;

      } else {
        pr_trace_msg(trace_channel, 9,
          "allowing client connection (policy 'deny,allow')");
      }
      break;
  }

  return allow_conn;
}