/* * Parse a procedure parameter list. * Return head of linked list of parameters. */ void get_param_list(PARAM_LIST **param_head) { PARAM_LIST *list_ptr, *param_ptr; int token_class; TOKEN sep_token; *param_head = NULL; list_ptr = NULL; do { get_param_ptr(¶m_ptr); if (*param_head == NULL) *param_head = param_ptr; if (list_ptr) list_ptr->next_param = param_ptr; list_ptr = param_ptr; token_class = get_token(¶m_ptr->param); if (token_class != IDENTIFIER) { parse_error("Identifier expected"); free_param_list(*param_head); } /* Get ',' or ')' */ token_class = get_token(&sep_token); } while (token_class == COMMA); if (token_class != RIGHT_PAREN) { parse_error("')' expected"); free_param_list(*param_head); } }
MODRET limit_login_post_pass(cmd_rec *cmd) { /* * PASSを通過すると cmd->server->conf にユーザー名が入る様子 * get_param_ptr()で取れる */ char *user = get_param_ptr(cmd->server->conf, "UserName", FALSE); if(!user) { pr_log_auth(PR_LOG_NOTICE, "User unknown. Something Wrong"); pr_response_send(R_530, _("Login incorrect.")); end_login(0); } int dummy; if(session.dir_config && session.dir_config->subset && !login_check_limits(session.dir_config->subset, FALSE, TRUE ,&dummy)) { remove_config(cmd->server->conf, C_USER, FALSE); remove_config(cmd->server->conf, C_PASS, FALSE); pr_log_auth(PR_LOG_NOTICE, "%s: Limit access denies login.", user); pr_response_send(R_530, _("Login Denied.")); end_login(0); } pr_log_debug(DEBUG5, "%s: ok login_check_limits() post PASS", user); return PR_DECLINED(cmd); }
static int wrap_sess_init(void) { /* look up any configured TCPServiceName */ if ((wrap_service_name = get_param_ptr(main_server->conf, "TCPServiceName", FALSE)) == NULL) wrap_service_name = "proftpd"; return 0; }
MODRET lmd_deny_blacklist_post_pass(cmd_rec *cmd) { /* mod_authを通過するまでは session.userは空の様子 const char *account = session.user; */ const char *account = NULL; const char *remote_ip = NULL; /* return IP unless found hostname */ account = get_param_ptr(cmd->server->conf, "UserName", FALSE); remote_ip = pr_netaddr_get_ipstr(pr_netaddr_get_sess_remote_addr()); if(false == is_set_server) { pr_log_auth(PR_LOG_WARNING, "%s: memcached_server not set", MODULE_NAME); lmd_cleanup(); return PR_DECLINED(cmd); } if(is_allowed_user(cmd, account) == true) { pr_log_auth(PR_LOG_NOTICE, "%s: '%s' is allowed to login. skip last process", MODULE_NAME, account); lmd_cleanup(); return PR_DECLINED(cmd); } /* allow explicily */ if(is_allowed(cmd, session.c->remote_addr) == true) { return PR_DECLINED(cmd); } /* check whether account is registerd in blacklist or not */ if(is_cache_exits(memcached_deny_blacklist_mmc, account) == true) { pr_log_auth(PR_LOG_NOTICE, "%s: denied '%s@%s'. Account found in blacklist(memcached)", MODULE_NAME, account, remote_ip); pr_response_send(R_530, _("Login denied temporary (Account found in blacklist)")); end_login(0); } /* check whether remote IP is registerd in blacklist or not */ if(is_cache_exits(memcached_deny_blacklist_mmc, remote_ip) == true) { pr_log_auth(PR_LOG_NOTICE, "%s: denied '%s@%s'. IP found in blacklist(memcached)", MODULE_NAME, account, remote_ip); pr_response_send(R_530, _("Login denied temporary (IP found in blacklist)")); end_login(0); } pr_log_debug(DEBUG2, "%s: not found in blaclist. '%s@%s' is allowed to Login", MODULE_NAME, account, remote_ip); lmd_cleanup(); return PR_DECLINED(cmd); }
static int wrap_sess_init(void) { pr_event_register(&wrap_module, "core.session-reinit", wrap_sess_reinit_ev, NULL); /* look up any configured TCPServiceName */ wrap_service_name = get_param_ptr(main_server->conf, "TCPServiceName", FALSE); if (wrap_service_name == NULL) { wrap_service_name = "proftpd"; } return 0; }
static int site_misc_check_filters(cmd_rec *cmd, const char *path) { #if defined(HAVE_REGEX_H) && defined(HAVE_REGCOMP) regex_t *preg = get_param_ptr(CURRENT_CONF, "PathAllowFilter", FALSE); if (preg && regexec(preg, path, 0, NULL, 0) != 0) { pr_log_debug(DEBUG2, MOD_SITE_MISC_VERSION ": 'SITE %s' denied by PathAllowFilter", cmd->arg); return -1; } preg = get_param_ptr(CURRENT_CONF, "PathDenyFilter", FALSE); if (preg && regexec(preg, path, 0, NULL, 0) == 0) { pr_log_debug(DEBUG2, MOD_SITE_MISC_VERSION ": 'SITE %s' denied by PathDenyFilter", cmd->arg); return -1; } #endif return 0; }
MODRET site_misc_symlink(cmd_rec *cmd) { if (cmd->argc < 2) return DECLINED(cmd); if (strcasecmp(cmd->argv[1], "SYMLINK") == 0) { unsigned char *authenticated; if (cmd->argc < 4) return DECLINED(cmd); authenticated = get_param_ptr(cmd->server->conf, "authenticated", FALSE); if (!authenticated || *authenticated == FALSE) { pr_response_add_err(R_530, "Please login with USER and PASS"); return ERROR(cmd); } if (!dir_check(cmd->tmp_pool, "SITE_SYMLINK", G_WRITE, cmd->argv[2], NULL)) { pr_response_add_err(R_550, "%s: %s", cmd->arg, strerror(EPERM)); return ERROR(cmd); } if (!dir_check(cmd->tmp_pool, "SITE_SYMLINK", G_WRITE, cmd->argv[3], NULL)) { pr_response_add_err(R_550, "%s: %s", cmd->arg, strerror(EPERM)); return ERROR(cmd); } if (site_misc_check_filters(cmd, cmd->argv[3]) < 0) { pr_response_add_err(R_550, "%s: %s", cmd->arg, strerror(EPERM)); return ERROR(cmd); } if (pr_fsio_symlink(cmd->argv[2], cmd->argv[3]) < 0) { pr_response_add_err(R_550, "%s: %s", cmd->arg, strerror(errno)); return ERROR(cmd); } pr_response_add(R_200, "SITE %s command successful", cmd->argv[1]); return HANDLED(cmd); } if (strcasecmp(cmd->argv[1], "HELP") == 0) pr_response_add(R_214, "SYMLINK <sp> source <sp> destination"); return DECLINED(cmd); }
int pr_auth_banned_by_ftpusers(xaset_t *ctx, const char *user) { int res = FALSE; unsigned char *use_ftp_users; use_ftp_users = get_param_ptr(ctx, "UseFtpUsers", FALSE); if (use_ftp_users == NULL || *use_ftp_users == TRUE) { FILE *fh = NULL; char buf[256]; PRIVS_ROOT fh = fopen(PR_FTPUSERS_PATH, "r"); PRIVS_RELINQUISH if (fh == NULL) return res; memset(buf, '\0', sizeof(buf)); while (fgets(buf, sizeof(buf)-1, fh)) { char *ptr; pr_signals_handle(); buf[sizeof(buf)-1] = '\0'; CHOP(buf); ptr = buf; while (isspace((int) *ptr) && *ptr) { ptr++; } if (!*ptr || *ptr == '#') { continue; } if (strcmp(ptr, user) == 0 ) { res = TRUE; break; } memset(buf, '\0', sizeof(buf)); } fclose(fh); }
MODRET site_misc_mkdir(cmd_rec *cmd) { if (cmd->argc < 2) return DECLINED(cmd); if (strcasecmp(cmd->argv[1], "MKDIR") == 0) { register unsigned int i; char *path = ""; unsigned char *authenticated; if (cmd->argc < 3) return DECLINED(cmd); authenticated = get_param_ptr(cmd->server->conf, "authenticated", FALSE); if (!authenticated || *authenticated == FALSE) { pr_response_add_err(R_530, "Please login with USER and PASS"); return ERROR(cmd); } for (i = 2; i < cmd->argc; i++) path = pstrcat(cmd->tmp_pool, path, *path ? " " : "", cmd->argv[i], NULL); if (site_misc_check_filters(cmd, path) < 0) { pr_response_add_err(R_550, "%s: %s", cmd->arg, strerror(EPERM)); return ERROR(cmd); } if (!dir_check(cmd->tmp_pool, "SITE_MKDIR", G_WRITE, path, NULL)) { pr_response_add_err(R_550, "%s: %s", cmd->arg, strerror(EPERM)); return ERROR(cmd); } if (site_misc_create_path(cmd->tmp_pool, path) < 0) { pr_response_add_err(R_550, "%s: %s", cmd->arg, strerror(errno)); return ERROR(cmd); } pr_response_add(R_200, "SITE %s command successful", cmd->argv[1]); return HANDLED(cmd); } if (strcasecmp(cmd->argv[1], "HELP") == 0) pr_response_add(R_214, "MKDIR <sp> path"); return DECLINED(cmd); }
static int exec_openlog(void) { int res = 0; /* Sanity check */ if ((exec_logname = (char *) get_param_ptr(main_server->conf, "ExecLog", FALSE)) == NULL) return 0; /* Check for "none". */ if (!strcasecmp(exec_logname, "none")) { exec_logname = NULL; return 0; } pr_signals_block(); PRIVS_ROOT res = log_openfile(exec_logname, &exec_logfd, 0640); PRIVS_RELINQUISH pr_signals_unblock(); return res; }
MODRET site_chgrp(cmd_rec *cmd) { gid_t gid; char *path = NULL, *tmp = NULL, *arg = ""; register unsigned int i = 0; #if defined(HAVE_REGEX_H) && defined(HAVE_REGCOMP) regex_t *preg; #endif if (cmd->argc < 3) { pr_response_add_err(R_500, _("'SITE %s' not understood"), _get_full_cmd(cmd)); return NULL; } /* Construct the target file name by concatenating all the parameters after * the mode, separating them with spaces. */ for (i = 2; i <= cmd->argc-1; i++) arg = pstrcat(cmd->tmp_pool, arg, *arg ? " " : "", pr_fs_decode_path(cmd->tmp_pool, cmd->argv[i]), NULL); #if defined(HAVE_REGEX_H) && defined(HAVE_REGCOMP) preg = (regex_t *) get_param_ptr(CURRENT_CONF, "PathAllowFilter", FALSE); if (preg && regexec(preg, arg, 0, NULL, 0) != 0) { pr_log_debug(DEBUG2, "'%s %s' denied by PathAllowFilter", cmd->argv[0], arg); pr_response_add_err(R_550, _("%s: Forbidden filename"), cmd->arg); return PR_ERROR(cmd); } preg = (regex_t *) get_param_ptr(CURRENT_CONF, "PathDenyFilter", FALSE); if (preg && regexec(preg, arg, 0, NULL, 0) == 0) { pr_log_debug(DEBUG2, "'%s %s' denied by PathDenyFilter", cmd->argv[0], arg); pr_response_add_err(R_550, _("%s: Forbidden filename"), cmd->arg); return PR_ERROR(cmd); } #endif path = dir_realpath(cmd->tmp_pool, arg); if (!path) { pr_response_add_err(R_550, "%s: %s", arg, strerror(errno)); return PR_ERROR(cmd); } /* Map the given group argument, if a string, to a GID. If already a * number, pass through as is. */ gid = strtoul(cmd->argv[1], &tmp, 10); if (tmp && *tmp) { /* Try the parameter as a user name. */ gid = pr_auth_name2gid(cmd->tmp_pool, cmd->argv[1]); if (gid == (gid_t) -1) { pr_response_add_err(R_550, "%s: %s", arg, strerror(EINVAL)); return PR_ERROR(cmd); } } if (core_chgrp(cmd, path, (uid_t) -1, gid) == -1) { pr_response_add_err(R_550, "%s: %s", arg, strerror(errno)); return PR_ERROR(cmd); } else pr_response_add(R_200, _("SITE %s command successful"), cmd->argv[0]); return PR_HANDLED(cmd); }
static void log_write(int priority, int f, char *s) { unsigned int *max_priority = NULL; char serverinfo[PR_TUNABLE_BUFFER_SIZE] = {'\0'}; memset(serverinfo, '\0', sizeof(serverinfo)); if (main_server && main_server->ServerFQDN) { pr_netaddr_t *remote_addr = pr_netaddr_get_sess_remote_addr(); const char *remote_name = pr_netaddr_get_sess_remote_name(); snprintf(serverinfo, sizeof(serverinfo), "%s", main_server->ServerFQDN); serverinfo[sizeof(serverinfo)-1] = '\0'; if (remote_addr && remote_name) { snprintf(serverinfo + strlen(serverinfo), sizeof(serverinfo) - strlen(serverinfo), " (%s[%s])", remote_name, pr_netaddr_get_ipstr(remote_addr)); serverinfo[sizeof(serverinfo)-1] = '\0'; } } if (logstderr || !main_server) { fprintf(stderr, "%s - %s\n", serverinfo, s); return; } if (syslog_discard) return; if (systemlog_fd != -1) { char buf[LOGBUFFER_SIZE] = {'\0'}; time_t tt = time(NULL); struct tm *t; t = localtime(&tt); strftime(buf, sizeof(buf), "%b %d %H:%M:%S ", t); buf[sizeof(buf) - 1] = '\0'; if (*serverinfo) { snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "%s proftpd[%u] %s: %s\n", systemlog_host, (unsigned int) getpid(), serverinfo, s); } else { snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "%s proftpd[%u]: %s\n", systemlog_host, (unsigned int) getpid(), s); } buf[sizeof(buf) - 1] = '\0'; write(systemlog_fd, buf, strlen(buf)); return; } if (set_facility != -1) f = set_facility; if (!syslog_open) { syslog_sockfd = pr_openlog("proftpd", LOG_NDELAY|LOG_PID, f); } else if (f != facility) { (void) pr_setlogfacility(f); } max_priority = get_param_ptr(main_server->conf, "SyslogLevel", FALSE); if (max_priority != NULL && priority > *max_priority) return; if (*serverinfo) pr_syslog(syslog_sockfd, priority, "%s - %s\n", serverinfo, s); else pr_syslog(syslog_sockfd, priority, "%s\n", s); if (!syslog_open) { pr_closelog(syslog_sockfd); syslog_sockfd = -1; } else if (f != facility) { (void) pr_setlogfacility(f); } }
MODRET site_chmod(cmd_rec *cmd) { mode_t mode = 0; char *dir, *endp, *tmp, *arg = ""; register unsigned int i = 0; #if defined(HAVE_REGEX_H) && defined(HAVE_REGCOMP) regex_t *preg; #endif if (cmd->argc < 3) { pr_response_add_err(R_500, _("'SITE %s' not understood"), _get_full_cmd(cmd)); return NULL; } /* Construct the target file name by concatenating all the parameters after * the mode, separating them with spaces. */ for (i = 2; i <= cmd->argc-1; i++) arg = pstrcat(cmd->tmp_pool, arg, *arg ? " " : "", pr_fs_decode_path(cmd->tmp_pool, cmd->argv[i]), NULL); #if defined(HAVE_REGEX_H) && defined(HAVE_REGCOMP) preg = (regex_t *) get_param_ptr(CURRENT_CONF, "PathAllowFilter", FALSE); if (preg && regexec(preg, arg, 0, NULL, 0) != 0) { pr_log_debug(DEBUG2, "'%s %s %s' denied by PathAllowFilter", cmd->argv[0], cmd->argv[1], arg); pr_response_add_err(R_550, _("%s: Forbidden filename"), cmd->arg); return PR_ERROR(cmd); } preg = (regex_t *) get_param_ptr(CURRENT_CONF, "PathDenyFilter", FALSE); if (preg && regexec(preg, arg, 0, NULL, 0) == 0) { pr_log_debug(DEBUG2, "'%s %s %s' denied by PathDenyFilter", cmd->argv[0], cmd->argv[1], arg); pr_response_add_err(R_550, _("%s: Forbidden filename"), cmd->arg); return PR_ERROR(cmd); } #endif dir = dir_realpath(cmd->tmp_pool, arg); if (!dir) { pr_response_add_err(R_550, "%s: %s", arg, strerror(errno)); return PR_ERROR(cmd); } /* If the first character isn't '0', prepend it and attempt conversion. * This will fail if the chmod is a symbolic, but takes care of the * case where an octal number is sent without the leading '0'. */ if (cmd->argv[1][0] != '0') tmp = pstrcat(cmd->tmp_pool, "0", cmd->argv[1], NULL); else tmp = cmd->argv[1]; mode = strtol(tmp,&endp,0); if (endp && *endp) { /* It's not an absolute number, try symbolic */ char *cp = cmd->argv[1]; int mask = 0, mode_op = 0, curmode = 0, curumask = umask(0); int invalid = 0; char *who, *how, *what; struct stat st; umask(curumask); mode = 0; if (pr_fsio_stat(dir, &st) != -1) curmode = st.st_mode; while (TRUE) { who = pstrdup(cmd->tmp_pool, cp); tmp = strpbrk(who, "+-="); if (tmp != NULL) { how = pstrdup(cmd->tmp_pool, tmp); if (*how != '=') mode = curmode; *tmp = '\0'; } else { invalid++; break; } tmp = strpbrk(how, "rwxXstugo"); if (tmp != NULL) { what = pstrdup(cmd->tmp_pool, tmp); *tmp = '\0'; } else { invalid++; break; } cp = what; while (cp) { switch (*who) { case 'u': mask = 0077; break; case 'g': mask = 0707; break; case 'o': mask = 0770; break; case 'a': mask = 0000; break; case '\0': mask = curumask; break; default: invalid++; break; } if (invalid) break; switch (*how) { case '+': case '-': case '=': break; default: invalid++; } if (invalid) break; switch (*cp) { case 'r': mode_op |= (S_IRUSR|S_IRGRP|S_IROTH); break; case 'w': mode_op |= (S_IWUSR|S_IWGRP|S_IWOTH); break; case 'x': mode_op |= (S_IXUSR|S_IXGRP|S_IXOTH); break; /* 'X' not implemented */ case 's': /* setuid */ mode_op |= S_ISUID; break; case 't': /* sticky */ mode_op |= S_ISVTX; break; case 'o': mode_op |= curmode & S_IRWXO; mode_op |= (curmode & S_IRWXO) << 3; mode_op |= (curmode & S_IRWXO) << 6; break; case 'g': mode_op |= (curmode & S_IRWXG) >> 3; mode_op |= curmode & S_IRWXG; mode_op |= (curmode & S_IRWXG) << 3; break; case 'u': mode_op |= (curmode & S_IRWXO) >> 6; mode_op |= (curmode & S_IRWXO) >> 3; mode_op |= curmode & S_IRWXU; break; case '\0': /* Apply the mode and move on */ switch (*how) { case '+': case '=': mode |= (mode_op & ~mask); break; case '-': mode &= ~(mode_op & ~mask); break; } mode_op = 0; if (*who && *(who+1)) { who++; cp = what; continue; } else cp = NULL; break; default: invalid++; } if (invalid) break; if (cp) cp++; } break; } if (invalid) { pr_response_add_err(R_550, _("'%s': invalid mode"), cmd->argv[1]); return PR_ERROR(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); }
MODRET site_misc_utime(cmd_rec *cmd) { if (cmd->argc < 2) return DECLINED(cmd); if (strcasecmp(cmd->argv[1], "UTIME") == 0) { register unsigned int i; char c, *p, *path = ""; unsigned int year, month, day, hour, min; struct utimbuf tmbuf; unsigned char *authenticated; if (cmd->argc < 4) return DECLINED(cmd); authenticated = get_param_ptr(cmd->server->conf, "authenticated", FALSE); if (!authenticated || *authenticated == FALSE) { pr_response_add_err(R_530, "Please login with USER and PASS"); return ERROR(cmd); } if (strlen(cmd->argv[2]) != 12) { pr_response_add_err(R_500, "%s: %s", cmd->arg, strerror(EINVAL)); return ERROR(cmd); } for (i = 3; i < cmd->argc; i++) path = pstrcat(cmd->tmp_pool, path, *path ? " " : "", cmd->argv[i], NULL); if (!dir_check(cmd->tmp_pool, "SITE_UTIME", G_WRITE, path, NULL)) { pr_response_add_err(R_550, "%s: %s", cmd->arg, strerror(EPERM)); return ERROR(cmd); } if (site_misc_check_filters(cmd, path) < 0) { pr_response_add_err(R_550, "%s: %s", cmd->arg, strerror(EPERM)); return ERROR(cmd); } p = cmd->argv[2]; c = cmd->argv[2][4]; cmd->argv[2][4] = '\0'; year = atoi(p); cmd->argv[2][4] = c; p = &(cmd->argv[2][4]); c = cmd->argv[2][6]; cmd->argv[2][6] = '\0'; month = atoi(p); cmd->argv[2][6] = c; p = &(cmd->argv[2][6]); c = cmd->argv[2][8]; cmd->argv[2][8] = '\0'; day = atoi(p); cmd->argv[2][8] = c; p = &(cmd->argv[2][8]); c = cmd->argv[2][10]; cmd->argv[2][10] = '\0'; hour = atoi(p); cmd->argv[2][10] = c; p = &(cmd->argv[2][10]); min = atoi(p); tmbuf.actime = tmbuf.modtime = site_misc_mktime(year, month, day, hour, min); if (utime(path, &tmbuf) < 0) { pr_response_add_err(R_550, "%s: %s", cmd->arg, strerror(errno)); return ERROR(cmd); } pr_response_add(R_200, "SITE %s command successful", cmd->argv[1]); return HANDLED(cmd); } if (strcasecmp(cmd->argv[1], "HELP") == 0) pr_response_add(R_214, "UTIME <sp> YYYYMMDDhhmm <sp> path"); return DECLINED(cmd); }
void pr_session_send_banner(server_rec *s, int flags) { config_rec *c = NULL; char *display = NULL; const char *serveraddress = NULL; config_rec *masq = NULL; display = get_param_ptr(s->conf, "DisplayConnect", FALSE); if (display != NULL) { if (pr_display_file(display, NULL, R_220, flags) < 0) { pr_log_debug(DEBUG6, "unable to display DisplayConnect file '%s': %s", display, strerror(errno)); } } serveraddress = pr_netaddr_get_ipstr(session.c->local_addr); masq = find_config(s->conf, CONF_PARAM, "MasqueradeAddress", FALSE); if (masq != NULL) { pr_netaddr_t *masq_addr = (pr_netaddr_t *) masq->argv[0]; serveraddress = pr_netaddr_get_ipstr(masq_addr); } c = find_config(s->conf, CONF_PARAM, "ServerIdent", FALSE); if (c == NULL || *((unsigned char *) c->argv[0]) == TRUE) { unsigned char *defer_welcome; defer_welcome = get_param_ptr(s->conf, "DeferWelcome", FALSE); if (c && c->argc > 1) { char *server_ident = c->argv[1]; if (strstr(server_ident, "%L") != NULL) { server_ident = sreplace(session.pool, server_ident, "%L", serveraddress, NULL); } if (strstr(server_ident, "%V") != NULL) { server_ident = sreplace(session.pool, server_ident, "%V", main_server->ServerFQDN, NULL); } if (strstr(server_ident, "%v") != NULL) { server_ident = sreplace(session.pool, server_ident, "%v", main_server->ServerName, NULL); } if (flags & PR_DISPLAY_FL_SEND_NOW) { pr_response_send(R_220, "%s", server_ident); } else { pr_response_add(R_220, "%s", server_ident); } } else if (defer_welcome && *defer_welcome == TRUE) { if (flags & PR_DISPLAY_FL_SEND_NOW) { pr_response_send(R_220, "ProFTPD " PROFTPD_VERSION_TEXT " Server ready."); } else { pr_response_add(R_220, "ProFTPD " PROFTPD_VERSION_TEXT " Server ready."); } } else { if (flags & PR_DISPLAY_FL_SEND_NOW) { pr_response_send(R_220, "ProFTPD " PROFTPD_VERSION_TEXT " Server (%s) [%s]", s->ServerName, serveraddress); } else { pr_response_add(R_220, "ProFTPD " PROFTPD_VERSION_TEXT " Server (%s) [%s]", s->ServerName, serveraddress); } } } else { if (flags & PR_DISPLAY_FL_SEND_NOW) { pr_response_send(R_220, _("%s FTP server ready"), serveraddress); } else { pr_response_add(R_220, _("%s FTP server ready"), serveraddress); } } }
static void log_write(int priority, int f, char *s, int discard) { unsigned int max_priority = 0, *ptr = NULL; char serverinfo[PR_TUNABLE_BUFFER_SIZE] = {'\0'}; memset(serverinfo, '\0', sizeof(serverinfo)); if (main_server && main_server->ServerFQDN) { pr_netaddr_t *remote_addr = pr_netaddr_get_sess_remote_addr(); const char *remote_name = pr_netaddr_get_sess_remote_name(); snprintf(serverinfo, sizeof(serverinfo)-1, "%s", main_server->ServerFQDN); serverinfo[sizeof(serverinfo)-1] = '\0'; if (remote_addr && remote_name) { size_t serverinfo_len; serverinfo_len = strlen(serverinfo); snprintf(serverinfo + serverinfo_len, sizeof(serverinfo) - serverinfo_len, " (%s[%s])", remote_name, pr_netaddr_get_ipstr(remote_addr)); serverinfo[sizeof(serverinfo)-1] = '\0'; } } if (!discard && (logstderr || !main_server)) { char buf[LOGBUFFER_SIZE] = {'\0'}; size_t buflen, len; struct timeval now; struct tm *tm = NULL; unsigned long millis; gettimeofday(&now, NULL); tm = pr_localtime(NULL, (const time_t *) &(now.tv_sec)); if (tm == NULL) { return; } len = strftime(buf, sizeof(buf)-1, "%Y-%m-%d %H:%M:%S", tm); buflen = len; buf[sizeof(buf)-1] = '\0'; /* Convert microsecs to millisecs. */ millis = now.tv_usec / 1000; len = snprintf(buf + buflen, sizeof(buf) - len, ",%03lu ", millis); buflen += len; buf[sizeof(buf)-1] = '\0'; if (*serverinfo) { len = snprintf(buf + buflen, sizeof(buf) - buflen, "%s proftpd[%u] %s: %s\n", systemlog_host, (unsigned int) (session.pid ? session.pid : getpid()), serverinfo, s); } else { len = snprintf(buf + buflen, sizeof(buf) - buflen, "%s proftpd[%u]: %s\n", systemlog_host, (unsigned int) (session.pid ? session.pid : getpid()), s); } buflen += len; buf[sizeof(buf)-1] = '\0'; pr_log_event_generate(PR_LOG_TYPE_SYSTEMLOG, STDERR_FILENO, priority, buf, buflen); fprintf(stderr, "%s", buf); return; } if (syslog_discard) { /* Only return now if we don't have any log listeners. */ if (pr_log_event_listening(PR_LOG_TYPE_SYSLOG) <= 0 && pr_log_event_listening(PR_LOG_TYPE_SYSTEMLOG) <= 0) { return; } } ptr = get_param_ptr(main_server->conf, "SyslogLevel", FALSE); if (ptr != NULL) { max_priority = *ptr; } else { /* Default SyslogLevel */ max_priority = default_level; } if (priority > max_priority) { /* Only return now if we don't have any log listeners. */ if (pr_log_event_listening(PR_LOG_TYPE_SYSLOG) <= 0 && pr_log_event_listening(PR_LOG_TYPE_SYSTEMLOG) <= 0) { return; } } if (systemlog_fd != -1) { char buf[LOGBUFFER_SIZE] = {'\0'}; size_t buflen, len; struct timeval now; struct tm *tm; unsigned long millis; gettimeofday(&now, NULL); tm = pr_localtime(NULL, (const time_t *) &(now.tv_sec)); if (tm == NULL) { return; } len = strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", tm); buflen = len; buf[sizeof(buf) - 1] = '\0'; /* Convert microsecs to millisecs. */ millis = now.tv_usec / 1000; len = snprintf(buf + buflen, sizeof(buf) - len, ",%03lu ", millis); buflen += len; buf[sizeof(buf) - 1] = '\0'; if (*serverinfo) { len = snprintf(buf + buflen, sizeof(buf) - buflen, "%s proftpd[%u] %s: %s\n", systemlog_host, (unsigned int) (session.pid ? session.pid : getpid()), serverinfo, s); } else { len = snprintf(buf + buflen, sizeof(buf) - buflen, "%s proftpd[%u]: %s\n", systemlog_host, (unsigned int) (session.pid ? session.pid : getpid()), s); } buflen += len; buf[sizeof(buf)-1] = '\0'; pr_log_event_generate(PR_LOG_TYPE_SYSTEMLOG, systemlog_fd, priority, buf, buflen); /* Now we need to enforce the discard, syslog_discard and SyslogLevel * filtering. */ if (discard) { return; } if (syslog_discard) { return; } if (priority > max_priority) { return; } while (write(systemlog_fd, buf, buflen) < 0) { if (errno == EINTR) { pr_signals_handle(); continue; } return; } return; } pr_log_event_generate(PR_LOG_TYPE_SYSLOG, syslog_sockfd, priority, s, strlen(s)); if (set_facility != -1) f = set_facility; if (!syslog_open) { syslog_sockfd = pr_openlog("proftpd", LOG_NDELAY|LOG_PID, f); if (syslog_sockfd < 0) { (void) pr_trace_msg(trace_channel, 1, "error opening syslog fd: %s", strerror(errno)); return; } syslog_open = TRUE; } else if (f != facility) { /* If this message is to be sent to a different log facility than a * default one (or the facility configured via SyslogFacility), then * OR in the facility with the priority value, as per the syslog(3) * docs. */ priority |= f; } if (*serverinfo) { pr_syslog(syslog_sockfd, priority, "%s - %s\n", serverinfo, s); } else { pr_syslog(syslog_sockfd, priority, "%s\n", s); } }
MODRET copy_cpfr(cmd_rec *cmd) { register unsigned int i; int res; char *path = ""; unsigned char *authenticated = NULL; if (copy_engine == FALSE) { return PR_DECLINED(cmd); } if (cmd->argc < 3 || strncasecmp(cmd->argv[1], "CPFR", 5) != 0) { return PR_DECLINED(cmd); } authenticated = get_param_ptr(cmd->server->conf, "authenticated", FALSE); if (authenticated == NULL || *authenticated == FALSE) { pr_response_add_err(R_530, _("Please login with USER and PASS")); pr_cmd_set_errno(cmd, EPERM); errno = EPERM; return PR_ERROR(cmd); } CHECK_CMD_MIN_ARGS(cmd, 3); /* Construct the target file name by concatenating all the parameters after * the "SITE CPFR", separating them with spaces. */ for (i = 2; i <= cmd->argc-1; i++) { char *decoded_path; decoded_path = pr_fs_decode_path2(cmd->tmp_pool, cmd->argv[i], FSIO_DECODE_FL_TELL_ERRORS); if (decoded_path == NULL) { int xerrno = errno; pr_log_debug(DEBUG8, "'%s' failed to decode properly: %s", (char *) cmd->argv[i], strerror(xerrno)); pr_response_add_err(R_550, _("%s: Illegal character sequence in filename"), cmd->arg); pr_cmd_set_errno(cmd, xerrno); errno = xerrno; return PR_ERROR(cmd); } path = pstrcat(cmd->tmp_pool, path, *path ? " " : "", decoded_path, NULL); } res = pr_filter_allow_path(CURRENT_CONF, path); switch (res) { case 0: break; case PR_FILTER_ERR_FAILS_ALLOW_FILTER: pr_log_debug(DEBUG2, MOD_COPY_VERSION ": 'CPFR %s' denied by PathAllowFilter", path); pr_response_add_err(R_550, _("%s: Forbidden filename"), path); pr_cmd_set_errno(cmd, EPERM); errno = EPERM; return PR_ERROR(cmd); case PR_FILTER_ERR_FAILS_DENY_FILTER: pr_log_debug(DEBUG2, MOD_COPY_VERSION ": 'CPFR %s' denied by PathDenyFilter", path); pr_response_add_err(R_550, _("%s: Forbidden filename"), path); pr_cmd_set_errno(cmd, EPERM); errno = EPERM; return PR_ERROR(cmd); } /* Allow renaming a symlink, even a dangling one. */ path = dir_canonical_vpath(cmd->tmp_pool, path); if (!path || !dir_check_canon(cmd->tmp_pool, cmd, cmd->group, path, NULL) || !exists2(cmd->tmp_pool, path)) { int xerrno = errno; pr_response_add_err(R_550, "%s: %s", path, strerror(xerrno)); pr_cmd_set_errno(cmd, xerrno); errno = xerrno; return PR_ERROR(cmd); } if (pr_table_add(session.notes, "mod_copy.cpfr-path", pstrdup(session.pool, path), 0) < 0) { pr_trace_msg(trace_channel, 4, "error adding 'mod_copy.cpfr-path' note: %s", strerror(errno)); } pr_response_add(R_350, _("File or directory exists, ready for destination name")); return PR_HANDLED(cmd); }
static int copy_paths(pool *p, const char *from, const char *to) { struct stat st; int res; xaset_t *set; set = get_dir_ctxt(p, (char *) to); res = pr_filter_allow_path(set, to); switch (res) { case 0: break; case PR_FILTER_ERR_FAILS_ALLOW_FILTER: pr_log_debug(DEBUG7, MOD_COPY_VERSION ": path '%s' denied by PathAllowFilter", to); errno = EPERM; return -1; case PR_FILTER_ERR_FAILS_DENY_FILTER: pr_log_debug(DEBUG7, MOD_COPY_VERSION ": path '%s' denied by PathDenyFilter", to); errno = EPERM; return -1; } /* Check whether from is a file, a directory, a symlink, or something * unsupported. */ res = pr_fsio_lstat(from, &st); if (res < 0) { int xerrno = errno; pr_log_debug(DEBUG7, MOD_COPY_VERSION ": error checking '%s': %s", from, strerror(xerrno)); errno = xerrno; return -1; } if (S_ISREG(st.st_mode)) { char *abs_path; pr_fs_clear_cache2(to); res = pr_fsio_stat(to, &st); if (res == 0) { unsigned char *allow_overwrite; allow_overwrite = get_param_ptr(CURRENT_CONF, "AllowOverwrite", FALSE); if (allow_overwrite == NULL || *allow_overwrite == FALSE) { pr_log_debug(DEBUG6, MOD_COPY_VERSION ": AllowOverwrite permission denied for '%s'", to); errno = EACCES; return -1; } } res = pr_fs_copy_file(from, to); if (res < 0) { int xerrno = errno; pr_log_debug(DEBUG7, MOD_COPY_VERSION ": error copying file '%s' to '%s': %s", from, to, strerror(xerrno)); errno = xerrno; return -1; } pr_fs_clear_cache2(to); if (pr_fsio_stat(to, &st) < 0) { pr_trace_msg(trace_channel, 3, "error stat'ing '%s': %s", to, strerror(errno)); } /* Write a TransferLog entry as well. */ abs_path = dir_abs_path(p, to, TRUE); if (session.sf_flags & SF_ANON) { xferlog_write(0, session.c->remote_name, st.st_size, abs_path, (session.sf_flags & SF_ASCII ? 'a' : 'b'), 'd', 'a', session.anon_user, 'c', "_"); } else { xferlog_write(0, session.c->remote_name, st.st_size, abs_path, (session.sf_flags & SF_ASCII ? 'a' : 'b'), 'd', 'r', session.user, 'c', "_"); } } else if (S_ISDIR(st.st_mode)) { res = create_path(p, to); if (res < 0) { int xerrno = errno; pr_log_debug(DEBUG7, MOD_COPY_VERSION ": error creating path '%s': %s", to, strerror(xerrno)); errno = xerrno; return -1; } res = copy_dir(p, from, to); if (res < 0) { int xerrno = errno; pr_log_debug(DEBUG7, MOD_COPY_VERSION ": error copying directory '%s' to '%s': %s", from, to, strerror(xerrno)); errno = xerrno; return -1; } } else if (S_ISLNK(st.st_mode)) { pr_fs_clear_cache2(to); res = pr_fsio_stat(to, &st); if (res == 0) { unsigned char *allow_overwrite; allow_overwrite = get_param_ptr(CURRENT_CONF, "AllowOverwrite", FALSE); if (allow_overwrite == NULL || *allow_overwrite == FALSE) { pr_log_debug(DEBUG6, MOD_COPY_VERSION ": AllowOverwrite permission denied for '%s'", to); errno = EACCES; return -1; } } res = copy_symlink(p, from, to); if (res < 0) { int xerrno = errno; pr_log_debug(DEBUG7, MOD_COPY_VERSION ": error copying symlink '%s' to '%s': %s", from, to, strerror(xerrno)); errno = xerrno; return -1; } } else { pr_log_debug(DEBUG7, MOD_COPY_VERSION ": unsupported file type for '%s'", from); errno = EINVAL; return -1; } return 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) {
MODRET copy_copy(cmd_rec *cmd) { if (copy_engine == FALSE) { return PR_DECLINED(cmd); } if (cmd->argc < 2) { return PR_DECLINED(cmd); } if (strncasecmp(cmd->argv[1], "COPY", 5) == 0) { char *cmd_name, *decoded_path, *from, *to; unsigned char *authenticated; if (cmd->argc != 4) { return PR_DECLINED(cmd); } authenticated = get_param_ptr(cmd->server->conf, "authenticated", FALSE); if (authenticated == NULL || *authenticated == FALSE) { pr_response_add_err(R_530, _("Please login with USER and PASS")); pr_cmd_set_errno(cmd, EPERM); errno = EPERM; return PR_ERROR(cmd); } /* XXX What about paths which contain spaces? */ decoded_path = pr_fs_decode_path2(cmd->tmp_pool, cmd->argv[2], FSIO_DECODE_FL_TELL_ERRORS); if (decoded_path == NULL) { int xerrno = errno; pr_log_debug(DEBUG8, "'%s' failed to decode properly: %s", (char *) cmd->argv[2], strerror(xerrno)); pr_response_add_err(R_550, _("%s: Illegal character sequence in filename"), (char *) cmd->argv[2]); pr_cmd_set_errno(cmd, xerrno); errno = xerrno; return PR_ERROR(cmd); } from = dir_canonical_vpath(cmd->tmp_pool, decoded_path); decoded_path = pr_fs_decode_path2(cmd->tmp_pool, cmd->argv[3], FSIO_DECODE_FL_TELL_ERRORS); if (decoded_path == NULL) { int xerrno = errno; pr_log_debug(DEBUG8, "'%s' failed to decode properly: %s", (char *) cmd->argv[3], strerror(xerrno)); pr_response_add_err(R_550, _("%s: Illegal character sequence in filename"), (char *) cmd->argv[3]); pr_cmd_set_errno(cmd, xerrno); errno = xerrno; return PR_ERROR(cmd); } to = dir_canonical_vpath(cmd->tmp_pool, decoded_path); cmd_name = cmd->argv[0]; pr_cmd_set_name(cmd, "SITE_COPY"); if (!dir_check(cmd->tmp_pool, cmd, G_WRITE, to, NULL)) { int xerrno = EPERM; pr_cmd_set_name(cmd, cmd_name); pr_response_add_err(R_550, "%s: %s", (char *) cmd->argv[3], strerror(xerrno)); pr_cmd_set_errno(cmd, xerrno); errno = xerrno; return PR_ERROR(cmd); } pr_cmd_set_name(cmd, cmd_name); if (copy_paths(cmd->tmp_pool, from, to) < 0) { int xerrno = errno; pr_response_add_err(R_550, "%s: %s", (char *) cmd->argv[1], strerror(xerrno)); pr_cmd_set_errno(cmd, xerrno); errno = xerrno; return PR_ERROR(cmd); } pr_response_add(R_200, _("SITE %s command successful"), (char *) cmd->argv[1]); return PR_HANDLED(cmd); } if (strncasecmp(cmd->argv[1], "HELP", 5) == 0) { pr_response_add(R_214, _("CPFR <sp> pathname")); pr_response_add(R_214, _("CPTO <sp> pathname")); } return PR_DECLINED(cmd); }
/* 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; }
MODRET copy_cpto(cmd_rec *cmd) { register unsigned int i; const char *from, *to = ""; unsigned char *authenticated = NULL; if (copy_engine == FALSE) { return PR_DECLINED(cmd); } if (cmd->argc < 3 || strncasecmp(cmd->argv[1], "CPTO", 5) != 0) { return PR_DECLINED(cmd); } authenticated = get_param_ptr(cmd->server->conf, "authenticated", FALSE); if (authenticated == NULL || *authenticated == FALSE) { pr_response_add_err(R_530, _("Please login with USER and PASS")); pr_cmd_set_errno(cmd, EPERM); errno = EPERM; return PR_ERROR(cmd); } CHECK_CMD_MIN_ARGS(cmd, 3); from = pr_table_get(session.notes, "mod_copy.cpfr-path", NULL); if (from == NULL) { pr_response_add_err(R_503, _("Bad sequence of commands")); pr_cmd_set_errno(cmd, EPERM); errno = EPERM; return PR_ERROR(cmd); } /* Construct the target file name by concatenating all the parameters after * the "SITE CPTO", separating them with spaces. */ for (i = 2; i <= cmd->argc-1; i++) { char *decoded_path; decoded_path = pr_fs_decode_path2(cmd->tmp_pool, cmd->argv[i], FSIO_DECODE_FL_TELL_ERRORS); if (decoded_path == NULL) { int xerrno = errno; pr_log_debug(DEBUG8, "'%s' failed to decode properly: %s", (char *) cmd->argv[i], strerror(xerrno)); pr_response_add_err(R_550, _("%s: Illegal character sequence in filename"), cmd->arg); pr_cmd_set_errno(cmd, xerrno); errno = xerrno; return PR_ERROR(cmd); } to = pstrcat(cmd->tmp_pool, to, *to ? " " : "", decoded_path, NULL); } to = dir_canonical_vpath(cmd->tmp_pool, to); if (copy_paths(cmd->tmp_pool, from, to) < 0) { int xerrno = errno; pr_response_add_err(R_550, "%s: %s", (char *) cmd->argv[1], strerror(xerrno)); pr_cmd_set_errno(cmd, xerrno); errno = xerrno; return PR_ERROR(cmd); } pr_response_add(R_250, "%s", _("Copy successful")); return PR_HANDLED(cmd); }
static int init_inetd_bindings(void) { int res = 0; server_rec *serv = NULL; unsigned char *default_server = NULL, is_default = FALSE; /* We explicitly do NOT use the get_listening_conn() function here, since * inetd-run daemons will not a) handle restarts, and thus b) will not have * already-open connections to choose from. */ main_server->listen = pr_inet_create_conn(main_server->pool, STDIN_FILENO, NULL, INPORT_ANY, FALSE); if (main_server->listen == NULL) { return -1; } /* Note: Since we are being called via inetd/xinetd, any socket options * which may be attempted by listeners for this event may not work. */ pr_inet_generate_socket_event("core.ctrl-listen", main_server, main_server->addr, main_server->listen->listen_fd); /* Fill in all the important connection information. */ if (pr_inet_get_conn_info(main_server->listen, STDIN_FILENO) == -1) { int xerrno = errno; pr_log_pri(PR_LOG_WARNING, "fatal: unable to get connection info: %s", strerror(xerrno)); if (xerrno == ENOTSOCK) { pr_log_pri(PR_LOG_ERR, "(Running from command line? " "Use `ServerType standalone' in config file!)"); } exit(1); } default_server = get_param_ptr(main_server->conf, "DefaultServer", FALSE); if (default_server != NULL && *default_server == TRUE) { is_default = TRUE; } 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); /* Now attach the faked connection to all virtual servers. */ for (serv = main_server->next; serv; serv = serv->next) { /* 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. */ serv->listen = main_server->listen; register_cleanup(serv->listen->pool, &serv->listen, server_cleanup_cb, server_cleanup_cb); is_default = FALSE; default_server = get_param_ptr(serv->conf, "DefaultServer", FALSE); if (default_server != NULL && *default_server == TRUE) { is_default = TRUE; } 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); } return 0; }
int pr_log_openfile(const char *log_file, int *log_fd, mode_t log_mode) { int res; pool *tmp_pool = NULL; char *tmp = NULL, *lf; unsigned char have_stat = FALSE, *allow_log_symlinks = NULL; struct stat st; /* Sanity check */ if (!log_file || !log_fd) { errno = EINVAL; return -1; } /* Make a temporary copy of log_file in case it's a constant */ tmp_pool = make_sub_pool(permanent_pool); pr_pool_tag(tmp_pool, "log_openfile() tmp pool"); lf = pstrdup(tmp_pool, log_file); tmp = strrchr(lf, '/'); if (tmp == NULL) { pr_log_debug(DEBUG0, "inappropriate log file: %s", lf); destroy_pool(tmp_pool); errno = EINVAL; return -1; } /* Set the path separator to zero, in order to obtain the directory * name, so that checks of the directory may be made. */ *tmp = '\0'; if (stat(lf, &st) < 0) { int xerrno = errno; pr_log_debug(DEBUG0, "error: unable to stat() %s: %s", lf, strerror(errno)); destroy_pool(tmp_pool); errno = xerrno; return -1; } /* The path must be in a valid directory */ if (!S_ISDIR(st.st_mode)) { pr_log_debug(DEBUG0, "error: %s is not a directory", lf); destroy_pool(tmp_pool); errno = ENOTDIR; return -1; } /* Do not log to world-writable directories */ if (st.st_mode & S_IWOTH) { pr_log_pri(PR_LOG_NOTICE, "error: %s is a world-writable directory", lf); destroy_pool(tmp_pool); return PR_LOG_WRITABLE_DIR; } /* Restore the path separator so that checks on the file itself may be * done. */ *tmp = '/'; allow_log_symlinks = get_param_ptr(main_server->conf, "AllowLogSymlinks", FALSE); if (allow_log_symlinks == NULL || *allow_log_symlinks == FALSE) { int flags = O_APPEND|O_CREAT|O_WRONLY; #ifdef PR_USE_NONBLOCKING_LOG_OPEN /* Use the O_NONBLOCK flag when opening log files, as they might be * FIFOs whose other end is not currently running; we do not want to * block indefinitely in such cases. */ flags |= O_NONBLOCK; #endif /* PR_USE_NONBLOCKING_LOG_OPEN */ #ifdef O_NOFOLLOW /* On systems that support the O_NOFOLLOW flag (e.g. Linux and FreeBSD), * use it so that the path being opened, if it is a symlink, is not * followed. */ flags |= O_NOFOLLOW; #elif defined(SOLARIS2) /* Solaris doesn't support the O_NOFOLLOW flag. Instead, in their * wisdom (hah!), Solaris decided that if the given path is a symlink * and the flags O_CREAT and O_EXCL are set, the link is not followed. * Right. The problem here is the case where the path is not a symlink; * using O_CREAT|O_EXCL will then cause the open() to fail if the * file already exists. */ flags |= O_EXCL; #endif /* O_NOFOLLOW or SOLARIS2 */ *log_fd = open(lf, flags, log_mode); if (*log_fd < 0) { if (errno != EEXIST) { destroy_pool(tmp_pool); /* More portability fun: Linux likes to report ELOOP if O_NOFOLLOW * is used to open a symlink file; FreeBSD likes to return EMLINK. * Both would lead to rather misleading error messages being * logged. Catch these errnos, and return the value that properly * informs the caller that the given path was an illegal symlink. */ switch (errno) { #ifdef ELOOP case ELOOP: return PR_LOG_SYMLINK; #endif /* ELOOP */ #ifdef EMLINK case EMLINK: return PR_LOG_SYMLINK; #endif /* EMLINK */ } return -1; } else { #if defined(SOLARIS2) /* On Solaris, because of the stupid multiplexing of O_CREAT and * O_EXCL to get open() not to follow a symlink, it's possible that * the path already exists. Now, we'll try to open() without * O_EXCL, then lstat() the path to see if this pre-existing file is * a symlink or a regular file. * * Note that because this check cannot be done atomically on Solaris, * the possibility of a race condition/symlink attack still exists. * Solaris doesn't provide a good way around this situation. */ flags &= ~O_EXCL; *log_fd = open(lf, flags, log_mode); if (*log_fd < 0) { destroy_pool(tmp_pool); return -1; } /* The race condition on Solaris is here, between the open() call * above and the lstat() call below... */ if (lstat(lf, &st) != -1) have_stat = TRUE; #else destroy_pool(tmp_pool); return -1; #endif /* SOLARIS2 */ } } /* Stat the file using the descriptor, not the path */ if (!have_stat && fstat(*log_fd, &st) != -1) have_stat = TRUE; if (!have_stat || S_ISLNK(st.st_mode)) { pr_log_debug(DEBUG0, !have_stat ? "error: unable to stat %s" : "error: %s is a symbolic link", lf); close(*log_fd); *log_fd = -1; destroy_pool(tmp_pool); return PR_LOG_SYMLINK; } } else { int flags = O_CREAT|O_APPEND|O_WRONLY; #ifdef PR_USE_NONBLOCKING_LOG_OPEN /* Use the O_NONBLOCK flag when opening log files, as they might be * FIFOs whose other end is not currently running; we do not want to * block indefinitely in such cases. */ flags |= O_NONBLOCK; #endif /* PR_USE_NONBLOCKING_LOG_OPEN */ *log_fd = open(lf, flags, log_mode); if (*log_fd < 0) { destroy_pool(tmp_pool); return -1; } } /* Find a usable fd for the just-opened log fd. */ if (*log_fd <= STDERR_FILENO) { res = pr_fs_get_usable_fd(*log_fd); if (res < 0) { pr_log_debug(DEBUG0, "warning: unable to find good fd for logfd %d: %s", *log_fd, strerror(errno)); } else { close(*log_fd); *log_fd = res; } } if (fcntl(*log_fd, F_SETFD, FD_CLOEXEC) < 0) { pr_log_pri(PR_LOG_WARNING, "unable to set CLO_EXEC on log fd %d: %s", *log_fd, strerror(errno)); } #ifdef PR_USE_NONBLOCKING_LOG_OPEN /* Return the fd to blocking mode. */ (void) fd_set_block(*log_fd); #endif /* PR_USE_NONBLOCKING_LOG_OPEN */ destroy_pool(tmp_pool); return 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; }
/* 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; }
MODRET site_chgrp(cmd_rec *cmd) { int res; gid_t gid; char *path = NULL, *tmp = NULL, *arg = ""; register unsigned int i = 0; #ifdef PR_USE_REGEX pr_regex_t *pre; #endif if (cmd->argc < 3) { pr_response_add_err(R_500, _("'SITE %s' not understood"), _get_full_cmd(cmd)); return NULL; } /* Construct the target file name by concatenating all the parameters after * the mode, separating them with spaces. */ for (i = 2; i <= cmd->argc-1; i++) arg = pstrcat(cmd->tmp_pool, arg, *arg ? " " : "", pr_fs_decode_path(cmd->tmp_pool, cmd->argv[i]), NULL); #ifdef PR_USE_REGEX pre = get_param_ptr(CURRENT_CONF, "PathAllowFilter", FALSE); if (pre != NULL && pr_regexp_exec(pre, arg, 0, NULL, 0, 0, 0) != 0) { pr_log_debug(DEBUG2, "'%s %s' denied by PathAllowFilter", cmd->argv[0], arg); pr_response_add_err(R_550, _("%s: Forbidden filename"), cmd->arg); return PR_ERROR(cmd); } pre = get_param_ptr(CURRENT_CONF, "PathDenyFilter", FALSE); if (pre != NULL && pr_regexp_exec(pre, arg, 0, NULL, 0, 0, 0) == 0) { pr_log_debug(DEBUG2, "'%s %s' denied by PathDenyFilter", cmd->argv[0], arg); pr_response_add_err(R_550, _("%s: Forbidden filename"), cmd->arg); return PR_ERROR(cmd); } #endif path = dir_realpath(cmd->tmp_pool, arg); if (!path) { pr_response_add_err(R_550, "%s: %s", arg, strerror(errno)); return PR_ERROR(cmd); } /* Map the given group argument, if a string, to a GID. If already a * number, pass through as is. */ gid = strtoul(cmd->argv[1], &tmp, 10); if (tmp && *tmp) { /* Try the parameter as a group name. */ gid = pr_auth_name2gid(cmd->tmp_pool, cmd->argv[1]); if (gid == (gid_t) -1) { pr_log_debug(DEBUG9, "SITE CHGRP: Unable to resolve group name '%s' to GID", cmd->argv[1]); pr_response_add_err(R_550, "%s: %s", arg, strerror(EINVAL)); return PR_ERROR(cmd); } } res = core_chgrp(cmd, path, (uid_t) -1, gid); if (res < 0) { int xerrno = errno; (void) pr_trace_msg("fileperms", 1, "%s, user '%s' (UID %lu, GID %lu): " "error chown'ing '%s' to GID %lu: %s", cmd->argv[0], session.user, (unsigned long) session.uid, (unsigned long) session.gid, path, (unsigned long) gid, strerror(xerrno)); pr_response_add_err(R_550, "%s: %s", arg, strerror(xerrno)); errno = xerrno; return PR_ERROR(cmd); } else { pr_response_add(R_200, _("SITE %s command successful"), cmd->argv[0]); } return PR_HANDLED(cmd); }
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; }
END_TEST START_TEST (get_param_ptr_test) { void *res; int count; xaset_t *set = NULL; config_rec *c; const char *name = NULL; res = get_param_ptr(NULL, NULL, FALSE); fail_unless(res == NULL, "Failed to handle null arguments"); fail_unless(errno == ENOENT, "Failed to set errno to ENOENT, got %d (%s)", errno, strerror(errno)); mark_point(); name = "foo"; c = add_config_param_set(&set, name, 1, "bar"); fail_unless(c != NULL, "Failed to add config '%s': %s", name, strerror(errno)); name = "bar"; res = get_param_ptr(set, name, FALSE); fail_unless(res == 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. Note that we * need to reset the get_param_ptr tree. */ get_param_ptr(NULL, NULL, FALSE); name = "foo"; res = get_param_ptr(set, name, FALSE); fail_unless(res != NULL, "Failed to find config '%s': %s", name, strerror(errno)); mark_point(); res = get_param_ptr_next(name, FALSE); fail_unless(res == 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, 1, "baz"); fail_unless(c != NULL, "Failed to add config '%s': %s", name, strerror(errno)); get_param_ptr(NULL, NULL, FALSE); name = NULL; res = get_param_ptr(set, name, FALSE); fail_unless(res != NULL, "Failed to find any config: %s", strerror(errno)); mark_point(); res = get_param_ptr_next(name, FALSE); fail_unless(res != NULL, "Expected to find another config"); mark_point(); name = "foo"; count = remove_config(set, name, FALSE); fail_unless(count > 0, "Failed to remove config '%s': %s", name, strerror(errno)); mark_point(); res = get_param_ptr(set, name, FALSE); fail_unless(res == NULL, "Found config '%s' unexpectedly", name); fail_unless(errno == ENOENT, "Failed to set errno to ENOENT, got %d (%s)", errno, strerror(errno)); }