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; }
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); }
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); }
/* 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; }
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; }
/* 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; }
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)"); } }
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; }
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)); }
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) {
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; }
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; }
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; } }
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; }