void init_connection(struct vsf_session* p_sess) { if (tunable_setproctitle_enable) { vsf_sysutil_setproctitle("not logged in"); } /* Before we talk to the remote, make sure an alarm is set up in case * writing the initial greetings should block. */ vsf_cmdio_set_alarm(p_sess); /* Check limits before doing an implicit SSL handshake, to avoid DoS * attacks. This will result in plain text messages being sent to the SSL * client, but we can live with that. */ check_limits(p_sess); if (tunable_ssl_enable && tunable_implicit_ssl) { ssl_control_handshake(p_sess); } if (tunable_ftp_enable) { emit_greeting(p_sess); } parse_username_password(p_sess); }
void init_connection(struct vsf_session* p_sess) { if (tunable_setproctitle_enable) { vsf_sysutil_setproctitle("not logged in"); } #ifdef VSF_BUILD_SQLITE /* In stealth mode we wont answer the connection unless the remote host * is known to our database. */ if (tunable_sqlite_enable && tunable_stealth_mode) { int retval = vsf_db_check_remote_host(&p_sess->remote_ip_str); if (retval == 0) { /* The IP check failed we drop the connection silently. */ vsf_sysutil_shutdown_read_failok(VSFTP_COMMAND_FD); vsf_sysutil_exit(0); } } #endif /* Before we talk to the remote, make sure an alarm is set up in case * writing the initial greetings should block. */ vsf_cmdio_set_alarm(p_sess); emit_greeting(p_sess); parse_username_password(p_sess); }
void init_connection(struct vsf_session* p_sess) { if (tunable_setproctitle_enable) { vsf_sysutil_setproctitle("not logged in"); } /* Before we talk to the remote, make sure an alarm is set up in case * writing the initial greetings should block. */ vsf_cmdio_set_alarm(p_sess); emit_greeting(p_sess); parse_username_password(p_sess); }
void init_connection(struct vsf_session* p_sess) { if (tunable_setproctitle_enable) { vsf_sysutil_setproctitle("not logged in"); } /* Before we talk to the remote, make sure an alarm is set up in case * writing the initial greetings should block. */ vsf_cmdio_set_alarm(p_sess); /* Kitsune, prevent printing greeting if just updated */ if (!kitsune_is_updating()) { emit_greeting(p_sess); } parse_username_password(p_sess); }
void vsf_two_process_login(struct vsf_session* p_sess, const struct mystr* p_pass_str) { char result; priv_sock_send_cmd(p_sess->child_fd, PRIV_SOCK_LOGIN); priv_sock_send_str(p_sess->child_fd, &p_sess->user_str); priv_sock_send_str(p_sess->child_fd, p_pass_str); priv_sock_send_int(p_sess->child_fd, p_sess->control_use_ssl); priv_sock_send_int(p_sess->child_fd, p_sess->data_use_ssl); result = priv_sock_get_result(p_sess->child_fd); if (result == PRIV_SOCK_RESULT_OK) { /* Miracle. We don't emit the success message here. That is left to * process_post_login(). * Exit normally, unless we are remaining as the SSL read / write child. */ if (!p_sess->control_use_ssl) { vsf_sysutil_exit(0); } else { vsf_sysutil_clear_alarm(); vsf_sysutil_close(p_sess->child_fd); if (tunable_setproctitle_enable) { vsf_sysutil_setproctitle("SSL handler"); } process_ssl_slave_req(p_sess); } /* NOTREACHED */ } else if (result == PRIV_SOCK_RESULT_BAD) { /* Continue the processing loop.. */ return; } else { die("priv_sock_get_result"); } }
void process_post_login(struct vsf_session* p_sess) { int retval; if (p_sess->is_anonymous) { vsf_sysutil_set_umask(tunable_anon_umask); p_sess->bw_rate_max = tunable_anon_max_rate; } else { vsf_sysutil_set_umask(tunable_local_umask); p_sess->bw_rate_max = tunable_local_max_rate; } if (tunable_async_abor_enable) { vsf_sysutil_install_sighandler(kVSFSysUtilSigURG, handle_sigurg, p_sess); vsf_sysutil_activate_sigurg(VSFTP_COMMAND_FD); } /* Kitsune */ vsf_sysutil_kitsune_set_update_point("postlogin.c"); if(!kitsune_is_updating()) { /* Handle any login message */ vsf_banner_dir_changed(p_sess, FTP_LOGINOK); vsf_cmdio_write(p_sess, FTP_LOGINOK, "Login successful. Have fun."); } else { /* Set sigchld function pointer (normally done in twoprocess.c) */ vsf_sysutil_default_sig(kVSFSysUtilSigCHLD); vsf_sysutil_install_async_sighandler(kVSFSysUtilSigCHLD, twoproc_handle_sigchld); } /* End Kitsune */ while(1) { if (tunable_setproctitle_enable) { vsf_sysutil_setproctitle("IDLE"); } /* Kitsune update point */ kitsune_update("postlogin.c"); /**DSU updatepoint */ /* Blocks */ vsf_cmdio_get_cmd_and_arg(p_sess, &p_sess->ftp_cmd_str, &p_sess->ftp_arg_str, 1); if (tunable_setproctitle_enable) { struct mystr proctitle_str = INIT_MYSTR; str_copy(&proctitle_str, &p_sess->ftp_cmd_str); if (!str_isempty(&p_sess->ftp_arg_str)) { str_append_char(&proctitle_str, ' '); str_append_str(&proctitle_str, &p_sess->ftp_arg_str); } /* Suggestion from Solar */ str_replace_unprintable(&proctitle_str, '?'); vsf_sysutil_setproctitle_str(&proctitle_str); str_free(&proctitle_str); } if (str_equal_text(&p_sess->ftp_cmd_str, "QUIT")) { vsf_cmdio_write(p_sess, FTP_GOODBYE, "Goodbye."); vsf_sysutil_exit(0); } else if (str_equal_text(&p_sess->ftp_cmd_str, "PWD") || str_equal_text(&p_sess->ftp_cmd_str, "XPWD")) { handle_pwd(p_sess); } else if (str_equal_text(&p_sess->ftp_cmd_str, "CWD") || str_equal_text(&p_sess->ftp_cmd_str, "XCWD")) { handle_cwd(p_sess); } else if (str_equal_text(&p_sess->ftp_cmd_str, "CDUP") || str_equal_text(&p_sess->ftp_cmd_str, "XCUP")) { handle_cdup(p_sess); } else if (tunable_pasv_enable && str_equal_text(&p_sess->ftp_cmd_str, "PASV")) { handle_pasv(p_sess); } else if (str_equal_text(&p_sess->ftp_cmd_str, "RETR")) { handle_retr(p_sess); } else if (str_equal_text(&p_sess->ftp_cmd_str, "NOOP")) { vsf_cmdio_write(p_sess, FTP_NOOPOK, "NOOP ok."); } else if (str_equal_text(&p_sess->ftp_cmd_str, "SYST")) { vsf_cmdio_write(p_sess, FTP_SYSTOK, "UNIX Type: L8"); } else if (str_equal_text(&p_sess->ftp_cmd_str, "HELP")) { vsf_cmdio_write(p_sess, FTP_BADHELP, "Sorry, I don't have help."); } else if (str_equal_text(&p_sess->ftp_cmd_str, "LIST")) { handle_list(p_sess); } else if (str_equal_text(&p_sess->ftp_cmd_str, "TYPE")) { handle_type(p_sess); } else if (tunable_port_enable && str_equal_text(&p_sess->ftp_cmd_str, "PORT")) { handle_port(p_sess); } else if (tunable_write_enable && (tunable_anon_upload_enable || !p_sess->is_anonymous) && str_equal_text(&p_sess->ftp_cmd_str, "STOR")) { handle_stor(p_sess); } else if (tunable_write_enable && (tunable_anon_mkdir_write_enable || !p_sess->is_anonymous) && (str_equal_text(&p_sess->ftp_cmd_str, "MKD") || str_equal_text(&p_sess->ftp_cmd_str, "XMKD"))) { handle_mkd(p_sess); } else if (tunable_write_enable && (tunable_anon_other_write_enable || !p_sess->is_anonymous) && (str_equal_text(&p_sess->ftp_cmd_str, "RMD") || str_equal_text(&p_sess->ftp_cmd_str, "XRMD"))) { handle_rmd(p_sess); } else if (tunable_write_enable && (tunable_anon_other_write_enable || !p_sess->is_anonymous) && str_equal_text(&p_sess->ftp_cmd_str, "DELE")) { handle_dele(p_sess); } else if (str_equal_text(&p_sess->ftp_cmd_str, "REST")) { handle_rest(p_sess); } else if (tunable_write_enable && (tunable_anon_other_write_enable || !p_sess->is_anonymous) && str_equal_text(&p_sess->ftp_cmd_str, "RNFR")) { handle_rnfr(p_sess); } else if (tunable_write_enable && (tunable_anon_other_write_enable || !p_sess->is_anonymous) && str_equal_text(&p_sess->ftp_cmd_str, "RNTO")) { handle_rnto(p_sess); } else if (str_equal_text(&p_sess->ftp_cmd_str, "NLST")) { handle_nlst(p_sess); } else if (str_equal_text(&p_sess->ftp_cmd_str, "SIZE")) { handle_size(p_sess); } else if (!p_sess->is_anonymous && str_equal_text(&p_sess->ftp_cmd_str, "SITE")) { handle_site(p_sess); } else if (str_equal_text(&p_sess->ftp_cmd_str, "ABOR")) { vsf_cmdio_write(p_sess, FTP_ABOR_NOCONN, "No transfer to ABOR."); } else if (tunable_write_enable && (tunable_anon_other_write_enable || !p_sess->is_anonymous) && str_equal_text(&p_sess->ftp_cmd_str, "APPE")) { handle_appe(p_sess); } else if (str_equal_text(&p_sess->ftp_cmd_str, "MDTM")) { handle_mdtm(p_sess); } else if (str_equal_text(&p_sess->ftp_cmd_str, "PASV") || str_equal_text(&p_sess->ftp_cmd_str, "PORT") || str_equal_text(&p_sess->ftp_cmd_str, "STOR") || str_equal_text(&p_sess->ftp_cmd_str, "MKD") || str_equal_text(&p_sess->ftp_cmd_str, "XMKD") || str_equal_text(&p_sess->ftp_cmd_str, "RMD") || str_equal_text(&p_sess->ftp_cmd_str, "XRMD") || str_equal_text(&p_sess->ftp_cmd_str, "DELE") || str_equal_text(&p_sess->ftp_cmd_str, "RNFR") || str_equal_text(&p_sess->ftp_cmd_str, "RNTO") || str_equal_text(&p_sess->ftp_cmd_str, "SITE") || str_equal_text(&p_sess->ftp_cmd_str, "APPE")) { vsf_cmdio_write(p_sess, FTP_NOPERM, "Permission denied."); } else { vsf_cmdio_write(p_sess, FTP_BADCMD, "Unknown command."); } } }
int main(int argc, const char* argv[]) { struct vsf_session the_session = { /* Control connection */ 0, 0, 0, 0, 0, /* Data connection */ -1, 0, -1, 0, 0, 0, 0, /* Login */ 1, 0, INIT_MYSTR, INIT_MYSTR, /* Protocol state */ 0, 1, INIT_MYSTR, 0, 0, /* HTTP hacks */ 0, INIT_MYSTR, /* Session state */ 0, /* Userids */ -1, -1, -1, /* Pre-chroot() cache */ INIT_MYSTR, INIT_MYSTR, INIT_MYSTR, INIT_MYSTR, 1, /* Logging */ -1, -1, INIT_MYSTR, 0, 0, 0, INIT_MYSTR, 0, /* Buffers */ INIT_MYSTR, INIT_MYSTR, 0, INIT_MYSTR, /* Parent <-> child comms */ -1, -1, /* Number of clients */ 0, 0, /* Home directory */ INIT_MYSTR, /* Secure connection state */ 0, 0, 0, 0, 0, INIT_MYSTR, 0, -1, -1, /* Login fails */ 0, /* write_enable */ 0 }; int config_loaded = 0; int i; tunables_load_defaults(); /* This might need to open /dev/zero on systems lacking MAP_ANON. Needs * to be done early (i.e. before config file parse, which may use * anonymous pages */ vsf_sysutil_map_anon_pages_init(); /* Argument parsing. Any argument not starting with "-" is a config file, * loaded in the order encountered. -o opt=value options are loading in the * order encountered, including correct ordering with respect intermingled * config files. * If we see -v (version) or an unknown option, parsing bails and exits. */ if (argc == 0) { die("vsftpd: missing argv[0]"); } for (i = 1; i < argc; ++i) { const char* p_arg = argv[i]; if (p_arg[0] != '-') { config_loaded = 1; vsf_parseconf_load_file(p_arg, 1); } else { if (p_arg[1] == 'v') { vsf_exit("vsftpd: version " VSF_VERSION "\n"); } else if (p_arg[1] == 'o') { vsf_parseconf_load_setting(&p_arg[2], 1); } else { die2("unrecognise option: ", p_arg); } } } /* Parse default config file if necessary */ if (!config_loaded) { struct vsf_sysutil_statbuf* p_statbuf = 0; int retval = vsf_sysutil_stat(VSFTP_DEFAULT_CONFIG, &p_statbuf); if (!vsf_sysutil_retval_is_error(retval)) { vsf_parseconf_load_file(VSFTP_DEFAULT_CONFIG, 1); } vsf_sysutil_free(p_statbuf); } /* Resolve pasv_address if required */ if (tunable_pasv_address && tunable_pasv_addr_resolve) { struct vsf_sysutil_sockaddr* p_addr = 0; const char* p_numeric_addr; vsf_sysutil_dns_resolve(&p_addr, tunable_pasv_address); vsf_sysutil_free((char*) tunable_pasv_address); p_numeric_addr = vsf_sysutil_inet_ntop(p_addr); tunable_pasv_address = vsf_sysutil_strdup(p_numeric_addr); vsf_sysutil_free(p_addr); } if (!tunable_run_as_launching_user) { /* Just get out unless we start with requisite privilege */ die_unless_privileged(); } if (tunable_setproctitle_enable) { /* Warning -- warning -- may nuke argv, environ */ vsf_sysutil_setproctitle_init(argc, argv); } /* Initialize the SSL system here if needed - saves the overhead of each * child doing this itself. */ if (tunable_ssl_enable) { ssl_init(&the_session); } if (tunable_listen || tunable_listen_ipv6) { /* Standalone mode */ struct vsf_client_launch ret = vsf_standalone_main(); the_session.num_clients = ret.num_children; the_session.num_this_ip = ret.num_this_ip; } if (tunable_tcp_wrappers) { the_session.tcp_wrapper_ok = vsf_tcp_wrapper_ok(VSFTP_COMMAND_FD); } { const char* p_load_conf = vsf_sysutil_getenv("VSFTPD_LOAD_CONF"); if (p_load_conf) { vsf_parseconf_load_file(p_load_conf, 1); } } /* Sanity checks - exit with a graceful error message if our STDIN is not * a socket. Also check various config options don't collide. */ do_sanity_checks(); /* Initializes session globals - e.g. IP addr's etc. */ session_init(&the_session); /* Set up "environment", e.g. process group etc. */ env_init(); /* Set up resource limits. */ limits_init(); /* Set up logging - must come after global init because we need the remote * address to convert into text */ vsf_log_init(&the_session); str_alloc_text(&the_session.remote_ip_str, vsf_sysutil_inet_ntop(the_session.p_remote_addr)); /* Set up options on the command socket */ vsf_cmdio_sock_setup(); if (tunable_setproctitle_enable) { vsf_sysutil_set_proctitle_prefix(&the_session.remote_ip_str); vsf_sysutil_setproctitle("connected"); } /* We might chroot() very soon (one process model), so we need to open * any required config files here. */ /* SSL may have been enabled by a per-IP configuration.. */ if (tunable_ssl_enable) { ssl_init(&the_session); ssl_add_entropy(&the_session); } if (tunable_deny_email_enable) { int retval = -1; if (tunable_banned_email_file) { retval = str_fileread(&the_session.banned_email_str, tunable_banned_email_file, VSFTP_CONF_FILE_MAX); } if (vsf_sysutil_retval_is_error(retval)) { die2("cannot read anon e-mail list file:", tunable_banned_email_file); } } if (tunable_banner_file) { int retval = str_fileread(&the_session.banner_str, tunable_banner_file, VSFTP_CONF_FILE_MAX); if (vsf_sysutil_retval_is_error(retval)) { die2("cannot read banner file:", tunable_banner_file); } } if (tunable_secure_email_list_enable) { int retval = -1; if (tunable_email_password_file) { retval = str_fileread(&the_session.email_passwords_str, tunable_email_password_file, VSFTP_CONF_FILE_MAX); } if (vsf_sysutil_retval_is_error(retval)) { die2("cannot read email passwords file:", tunable_email_password_file); } } if (tunable_run_as_launching_user) { tunable_one_process_model = 1; if (!vsf_sysutil_running_as_root()) { tunable_connect_from_port_20 = 0; tunable_chown_uploads = 0; } } if (tunable_one_process_model) { vsf_one_process_start(&the_session); } else { vsf_two_process_start(&the_session); } /* NOTREACHED */ bug("should not get here: main"); return 1; }
int main(int argc, const char* argv[]) { struct vsf_session the_session = { /* Control connection */ 0, 0, 0, /* Data connection */ -1, 0, -1, 0, 0, 0, 0, /* Login */ 1, INIT_MYSTR, INIT_MYSTR, /* Protocol state */ 0, 1, INIT_MYSTR, 0, 0, /* Session state */ 0, /* Userids */ -1, -1, -1, /* Pre-chroot() cache */ INIT_MYSTR, INIT_MYSTR, INIT_MYSTR, INIT_MYSTR, 1, /* Logging */ -1, -1, INIT_MYSTR, 0, 0, 0, INIT_MYSTR, 0, /* Buffers */ INIT_MYSTR, INIT_MYSTR, /* Parent <-> child comms */ -1, -1, /* Number of clients */ 0, 0, /* Home directory */ INIT_MYSTR, /* Secure connection state */ 0, 0, 0, 0, 0, 0, -1, -1 }; int config_specified = 0; const char* p_config_name = VSFTP_DEFAULT_CONFIG; /* Zero or one argument supported. If one argument is passed, it is the * path to the config file */ if (argc > 2) { die("vsftpd: too many arguments (I take an optional config file only)"); } else if (argc == 0) { die("vsftpd: missing argv[0]"); } if (argc == 2) { if (!vsf_sysutil_strcmp(argv[1], "-v")) { vsf_exit("vsftpd: version " VSF_VERSION "\n"); } p_config_name = argv[1]; config_specified = 1; } /* This might need to open /dev/zero on systems lacking MAP_ANON. Needs * to be done early (i.e. before config file parse, which may use * anonymous pages */ vsf_sysutil_map_anon_pages_init(); /* Parse config file if it's there */ { struct vsf_sysutil_statbuf* p_statbuf = 0; int retval = vsf_sysutil_stat(p_config_name, &p_statbuf); if (!vsf_sysutil_retval_is_error(retval)) { vsf_parseconf_load_file(p_config_name, 1); } else if (config_specified) { die2("vsftpd: cannot open config file:", p_config_name); } vsf_sysutil_free(p_statbuf); } if (!tunable_run_as_launching_user) { /* Just get out unless we start with requisite privilege */ die_unless_privileged(); } if (tunable_setproctitle_enable) { /* Warning -- warning -- may nuke argv, environ */ vsf_sysutil_setproctitle_init(argc, argv); } /* Initialize the SSL system here if needed - saves the overhead of each * child doing this itself. */ if (tunable_ssl_enable) { ssl_init(&the_session); } if (tunable_listen || tunable_listen_ipv6) { /* Standalone mode */ struct vsf_client_launch ret = vsf_standalone_main(); the_session.num_clients = ret.num_children; the_session.num_this_ip = ret.num_this_ip; } /* Sanity checks - exit with a graceful error message if our STDIN is not * a socket. Also check various config options don't collide. */ do_sanity_checks(); /* Initializes session globals - e.g. IP addr's etc. */ session_init(&the_session); /* Set up "environment", e.g. process group etc. */ env_init(); /* Set up logging - must come after global init because we need the remote * address to convert into text */ vsf_log_init(&the_session); str_alloc_text(&the_session.remote_ip_str, vsf_sysutil_inet_ntop(the_session.p_remote_addr)); /* Set up options on the command socket */ vsf_cmdio_sock_setup(); if (tunable_setproctitle_enable) { vsf_sysutil_set_proctitle_prefix(&the_session.remote_ip_str); vsf_sysutil_setproctitle("connected"); } /* We might chroot() very soon (one process model), so we need to open * any required config files here. */ if (tunable_tcp_wrappers) { the_session.tcp_wrapper_ok = vsf_tcp_wrapper_ok(VSFTP_COMMAND_FD); } { const char* p_load_conf = vsf_sysutil_getenv("VSFTPD_LOAD_CONF"); if (p_load_conf) { vsf_parseconf_load_file(p_load_conf, 1); } } /* SSL may have been enabled by a per-IP configuration.. */ if (tunable_ssl_enable) { ssl_init(&the_session); } if (tunable_deny_email_enable) { int retval = str_fileread(&the_session.banned_email_str, tunable_banned_email_file, VSFTP_CONF_FILE_MAX); if (vsf_sysutil_retval_is_error(retval)) { die2("cannot open anon e-mail list file:", tunable_banned_email_file); } } if (tunable_banner_file) { int retval = str_fileread(&the_session.banner_str, tunable_banner_file, VSFTP_CONF_FILE_MAX); if (vsf_sysutil_retval_is_error(retval)) { die2("cannot open banner file:", tunable_banner_file); } } if (tunable_secure_email_list_enable) { int retval = str_fileread(&the_session.email_passwords_str, tunable_email_password_file, VSFTP_CONF_FILE_MAX); if (vsf_sysutil_retval_is_error(retval)) { die2("cannot open email passwords file:", tunable_email_password_file); } } /* Special case - can force one process model if we've got a setup * needing _no_ privs */ if (!tunable_local_enable && !tunable_connect_from_port_20 && !tunable_chown_uploads) { tunable_one_process_model = 1; } if (tunable_run_as_launching_user) { tunable_one_process_model = 1; if (!vsf_sysutil_running_as_root()) { tunable_connect_from_port_20 = 0; tunable_chown_uploads = 0; } } if (tunable_one_process_model) { vsf_one_process_start(&the_session); } else { vsf_two_process_start(&the_session); } /* NOTREACHED */ bug("should not get here: main"); return 1; }
/* This delegation is common to all setproctitle() implementations */ void vsf_sysutil_setproctitle_str(const struct mystr* p_str) { vsf_sysutil_setproctitle(str_getbuf(p_str)); }
void process_post_login(struct vsf_session* p_sess) { if (p_sess->is_anonymous) { vsf_sysutil_set_umask(tunable_anon_umask); p_sess->bw_rate_max = tunable_anon_max_rate; } else { vsf_sysutil_set_umask(tunable_local_umask); p_sess->bw_rate_max = tunable_local_max_rate; } if (tunable_async_abor_enable) { vsf_sysutil_install_sighandler(kVSFSysUtilSigURG, handle_sigurg, p_sess); vsf_sysutil_activate_sigurg(VSFTP_COMMAND_FD); } /* Handle any login message */ vsf_banner_dir_changed(p_sess, FTP_LOGINOK); vsf_cmdio_write(p_sess, FTP_LOGINOK, "Login successful."); while(1) { int cmd_ok = 1; if (tunable_setproctitle_enable) { vsf_sysutil_setproctitle("IDLE"); } /* Blocks */ vsf_cmdio_get_cmd_and_arg(p_sess, &p_sess->ftp_cmd_str, &p_sess->ftp_arg_str, 1); if (tunable_setproctitle_enable) { struct mystr proctitle_str = INIT_MYSTR; str_copy(&proctitle_str, &p_sess->ftp_cmd_str); if (!str_isempty(&p_sess->ftp_arg_str)) { str_append_char(&proctitle_str, ' '); str_append_str(&proctitle_str, &p_sess->ftp_arg_str); } /* Suggestion from Solar */ str_replace_unprintable(&proctitle_str, '?'); vsf_sysutil_setproctitle_str(&proctitle_str); str_free(&proctitle_str); } /* Test command against the allowed list.. */ if (tunable_cmds_allowed) { static struct mystr s_src_str; static struct mystr s_rhs_str; str_alloc_text(&s_src_str, tunable_cmds_allowed); while (1) { str_split_char(&s_src_str, &s_rhs_str, ','); if (str_isempty(&s_src_str)) { cmd_ok = 0; break; } else if (str_equal(&s_src_str, &p_sess->ftp_cmd_str)) { break; } str_copy(&s_src_str, &s_rhs_str); } } if (!cmd_ok) { vsf_cmdio_write(p_sess, FTP_NOPERM, "Permission denied."); } else if (str_equal_text(&p_sess->ftp_cmd_str, "QUIT")) { vsf_cmdio_write(p_sess, FTP_GOODBYE, "Goodbye."); vsf_sysutil_exit(0); } else if (str_equal_text(&p_sess->ftp_cmd_str, "PWD") || str_equal_text(&p_sess->ftp_cmd_str, "XPWD")) { handle_pwd(p_sess); } else if (str_equal_text(&p_sess->ftp_cmd_str, "CWD") || str_equal_text(&p_sess->ftp_cmd_str, "XCWD")) { handle_cwd(p_sess); } else if (str_equal_text(&p_sess->ftp_cmd_str, "CDUP") || str_equal_text(&p_sess->ftp_cmd_str, "XCUP")) { handle_cdup(p_sess); } else if (tunable_pasv_enable && !p_sess->epsv_all && (str_equal_text(&p_sess->ftp_cmd_str, "PASV") || str_equal_text(&p_sess->ftp_cmd_str, "P@SW"))) { handle_pasv(p_sess, 0); } else if (tunable_pasv_enable && str_equal_text(&p_sess->ftp_cmd_str, "EPSV")) { handle_pasv(p_sess, 1); } else if (tunable_download_enable && str_equal_text(&p_sess->ftp_cmd_str, "RETR")) { handle_retr(p_sess); } else if (str_equal_text(&p_sess->ftp_cmd_str, "NOOP")) { vsf_cmdio_write(p_sess, FTP_NOOPOK, "NOOP ok."); } else if (str_equal_text(&p_sess->ftp_cmd_str, "SYST")) { vsf_cmdio_write(p_sess, FTP_SYSTOK, "UNIX Type: L8"); } else if (str_equal_text(&p_sess->ftp_cmd_str, "HELP")) { handle_help(p_sess); } else if (tunable_dirlist_enable && str_equal_text(&p_sess->ftp_cmd_str, "LIST")) { handle_list(p_sess); } else if (str_equal_text(&p_sess->ftp_cmd_str, "TYPE")) { handle_type(p_sess); } else if (tunable_port_enable && !p_sess->epsv_all && str_equal_text(&p_sess->ftp_cmd_str, "PORT")) { handle_port(p_sess); } else if (tunable_write_enable && (tunable_anon_upload_enable || !p_sess->is_anonymous) && str_equal_text(&p_sess->ftp_cmd_str, "STOR")) { handle_stor(p_sess); } else if (tunable_write_enable && (tunable_anon_mkdir_write_enable || !p_sess->is_anonymous) && (str_equal_text(&p_sess->ftp_cmd_str, "MKD") || str_equal_text(&p_sess->ftp_cmd_str, "XMKD"))) { handle_mkd(p_sess); } else if (tunable_write_enable && (tunable_anon_other_write_enable || !p_sess->is_anonymous) && (str_equal_text(&p_sess->ftp_cmd_str, "RMD") || str_equal_text(&p_sess->ftp_cmd_str, "XRMD"))) { handle_rmd(p_sess); } else if (tunable_write_enable && (tunable_anon_other_write_enable || !p_sess->is_anonymous) && str_equal_text(&p_sess->ftp_cmd_str, "DELE")) { handle_dele(p_sess); } else if (str_equal_text(&p_sess->ftp_cmd_str, "REST")) { handle_rest(p_sess); } else if (tunable_write_enable && (tunable_anon_other_write_enable || !p_sess->is_anonymous) && str_equal_text(&p_sess->ftp_cmd_str, "RNFR")) { handle_rnfr(p_sess); } else if (tunable_write_enable && (tunable_anon_other_write_enable || !p_sess->is_anonymous) && str_equal_text(&p_sess->ftp_cmd_str, "RNTO")) { handle_rnto(p_sess); } else if (tunable_dirlist_enable && str_equal_text(&p_sess->ftp_cmd_str, "NLST")) { handle_nlst(p_sess); } else if (str_equal_text(&p_sess->ftp_cmd_str, "SIZE")) { handle_size(p_sess); } else if (!p_sess->is_anonymous && str_equal_text(&p_sess->ftp_cmd_str, "SITE")) { handle_site(p_sess); } /* Note - the weird ABOR string is checking for an async ABOR arriving * without a SIGURG condition. */ else if (str_equal_text(&p_sess->ftp_cmd_str, "ABOR") || str_equal_text(&p_sess->ftp_cmd_str, "\377\364\377\362ABOR")) { vsf_cmdio_write(p_sess, FTP_ABOR_NOCONN, "No transfer to ABOR."); } else if (tunable_write_enable && (tunable_anon_other_write_enable || !p_sess->is_anonymous) && str_equal_text(&p_sess->ftp_cmd_str, "APPE")) { handle_appe(p_sess); } else if (str_equal_text(&p_sess->ftp_cmd_str, "MDTM")) { handle_mdtm(p_sess); } else if (tunable_port_enable && str_equal_text(&p_sess->ftp_cmd_str, "EPRT")) { handle_eprt(p_sess); } else if (str_equal_text(&p_sess->ftp_cmd_str, "STRU")) { str_upper(&p_sess->ftp_arg_str); if (str_equal_text(&p_sess->ftp_arg_str, "F")) { vsf_cmdio_write(p_sess, FTP_STRUOK, "Structure set to F."); } else { vsf_cmdio_write(p_sess, FTP_BADSTRU, "Bad STRU command."); } } else if (str_equal_text(&p_sess->ftp_cmd_str, "MODE")) { str_upper(&p_sess->ftp_arg_str); if (str_equal_text(&p_sess->ftp_arg_str, "S")) { vsf_cmdio_write(p_sess, FTP_MODEOK, "Mode set to S."); } else { vsf_cmdio_write(p_sess, FTP_BADMODE, "Bad MODE command."); } } else if (str_equal_text(&p_sess->ftp_cmd_str, "STOU")) { handle_stou(p_sess); } else if (str_equal_text(&p_sess->ftp_cmd_str, "ALLO")) { vsf_cmdio_write(p_sess, FTP_ALLOOK, "ALLO command ignored."); } else if (str_equal_text(&p_sess->ftp_cmd_str, "REIN")) { vsf_cmdio_write(p_sess, FTP_COMMANDNOTIMPL, "REIN not implemented."); } else if (str_equal_text(&p_sess->ftp_cmd_str, "ACCT")) { vsf_cmdio_write(p_sess, FTP_COMMANDNOTIMPL, "ACCT not implemented."); } else if (str_equal_text(&p_sess->ftp_cmd_str, "SMNT")) { vsf_cmdio_write(p_sess, FTP_COMMANDNOTIMPL, "SMNT not implemented."); } else if (str_equal_text(&p_sess->ftp_cmd_str, "FEAT")) { vsf_cmdio_write_hyphen(p_sess, FTP_FEAT, "Features:"); vsf_cmdio_write_raw(p_sess, " MDTM\r\n"); vsf_cmdio_write_raw(p_sess, " REST STREAM\r\n"); vsf_cmdio_write_raw(p_sess, " SIZE\r\n"); vsf_cmdio_write(p_sess, FTP_FEAT, "End"); } else if (str_equal_text(&p_sess->ftp_cmd_str, "OPTS")) { vsf_cmdio_write(p_sess, FTP_BADOPTS, "Option not understood."); } else if (str_equal_text(&p_sess->ftp_cmd_str, "STAT") && str_isempty(&p_sess->ftp_arg_str)) { handle_stat(p_sess); } else if (tunable_dirlist_enable && str_equal_text(&p_sess->ftp_cmd_str, "STAT")) { handle_stat_file(p_sess); } else if (str_equal_text(&p_sess->ftp_cmd_str, "PASV") || str_equal_text(&p_sess->ftp_cmd_str, "PORT") || str_equal_text(&p_sess->ftp_cmd_str, "STOR") || str_equal_text(&p_sess->ftp_cmd_str, "MKD") || str_equal_text(&p_sess->ftp_cmd_str, "XMKD") || str_equal_text(&p_sess->ftp_cmd_str, "RMD") || str_equal_text(&p_sess->ftp_cmd_str, "XRMD") || str_equal_text(&p_sess->ftp_cmd_str, "DELE") || str_equal_text(&p_sess->ftp_cmd_str, "RNFR") || str_equal_text(&p_sess->ftp_cmd_str, "RNTO") || str_equal_text(&p_sess->ftp_cmd_str, "SITE") || str_equal_text(&p_sess->ftp_cmd_str, "APPE") || str_equal_text(&p_sess->ftp_cmd_str, "EPSV") || str_equal_text(&p_sess->ftp_cmd_str, "EPRT") || str_equal_text(&p_sess->ftp_cmd_str, "RETR") || str_equal_text(&p_sess->ftp_cmd_str, "LIST") || str_equal_text(&p_sess->ftp_cmd_str, "NLST") || str_equal_text(&p_sess->ftp_cmd_str, "STOU") || str_equal_text(&p_sess->ftp_cmd_str, "ALLO") || str_equal_text(&p_sess->ftp_cmd_str, "REIN") || str_equal_text(&p_sess->ftp_cmd_str, "ACCT") || str_equal_text(&p_sess->ftp_cmd_str, "SMNT") || str_equal_text(&p_sess->ftp_cmd_str, "FEAT") || str_equal_text(&p_sess->ftp_cmd_str, "OPTS") || str_equal_text(&p_sess->ftp_cmd_str, "STAT")) { vsf_cmdio_write(p_sess, FTP_NOPERM, "Permission denied."); } else { vsf_cmdio_write(p_sess, FTP_BADCMD, "Unknown command."); } } }
struct vsf_client_launch vsf_standalone_main(void) { struct vsf_sysutil_sockaddr* p_sockaddr = 0; struct vsf_sysutil_ipv4addr listen_ipaddr; int listen_sock = vsf_sysutil_get_ipv4_sock(); int retval; s_p_ip_count_hash = hash_alloc(256, sizeof(struct vsf_sysutil_ipv4addr), sizeof(unsigned int), hash_ip); s_p_pid_ip_hash = hash_alloc(256, sizeof(int), sizeof(struct vsf_sysutil_ipv4addr), hash_pid); if (tunable_setproctitle_enable) { vsf_sysutil_setproctitle("LISTENER"); } vsf_sysutil_install_sighandler(kVSFSysUtilSigCHLD, handle_sigchld, 0); vsf_sysutil_install_async_sighandler(kVSFSysUtilSigHUP, handle_sighup); vsf_sysutil_activate_reuseaddr(listen_sock); vsf_sysutil_sockaddr_alloc_ipv4(&p_sockaddr); vsf_sysutil_sockaddr_set_port( p_sockaddr, vsf_sysutil_ipv4port_from_int(tunable_listen_port)); if (!tunable_listen_address || vsf_sysutil_inet_aton(tunable_listen_address, &listen_ipaddr) == 0) { listen_ipaddr = vsf_sysutil_sockaddr_get_any(); } vsf_sysutil_sockaddr_set_ipaddr(p_sockaddr, listen_ipaddr); retval = vsf_sysutil_bind(listen_sock, p_sockaddr); vsf_sysutil_free(p_sockaddr); if (vsf_sysutil_retval_is_error(retval)) { die("could not bind listening socket"); } vsf_sysutil_listen(listen_sock, VSFTP_LISTEN_BACKLOG); while (1) { struct vsf_client_launch child_info; static struct vsf_sysutil_sockaddr* p_accept_addr; int new_child; struct vsf_sysutil_ipv4addr ip_addr; /* NOTE - wake up every 10 seconds to make sure we notice child exit * in a timely manner (the sync signal framework race) */ int new_client_sock = vsf_sysutil_accept_timeout( listen_sock, &p_accept_addr, 10); if (s_reload_needed) { s_reload_needed = 0; do_reload(); } if (vsf_sysutil_retval_is_error(new_client_sock)) { continue; } ip_addr = vsf_sysutil_sockaddr_get_ipaddr(p_accept_addr); ++s_children; child_info.num_children = s_children; child_info.num_this_ip = handle_ip_count(&ip_addr); new_child = vsf_sysutil_fork_failok(); if (new_child != 0) { /* Parent context */ vsf_sysutil_close(new_client_sock); if (new_child > 0) { hash_add_entry(s_p_pid_ip_hash, (void*)&new_child, (void*)&ip_addr); } else { /* fork() failed, clear up! */ --s_children; drop_ip_count(&ip_addr); } /* Fall through to while() loop and accept() again */ } else { /* Child context */ vsf_sysutil_close(listen_sock); prepare_child(new_client_sock); /* By returning here we "launch" the child process with the same * contract as xinetd would provide. */ return child_info; } } }
struct vsf_client_launch vsf_standalone_main(void) { struct vsf_sysutil_sockaddr* p_accept_addr = 0; int listen_sock = -1; int retval; s_ipaddr_size = vsf_sysutil_get_ipaddr_size(); if (tunable_listen && tunable_listen_ipv6) { die("run two copies of vsftpd for IPv4 and IPv6"); } if (tunable_background) { int forkret = vsf_sysutil_fork(); if (forkret > 0) { /* Parent, just exit */ vsf_sysutil_exit(0); } vsf_sysutil_make_session_leader(); } if (tunable_listen) { listen_sock = vsf_sysutil_get_ipv4_sock(); } else { listen_sock = vsf_sysutil_get_ipv6_sock(); } vsf_sysutil_activate_reuseaddr(listen_sock); s_p_ip_count_hash = hash_alloc(256, s_ipaddr_size, sizeof(unsigned int), hash_ip); s_p_pid_ip_hash = hash_alloc(256, sizeof(int), s_ipaddr_size, hash_pid); if (tunable_setproctitle_enable) { vsf_sysutil_setproctitle("LISTENER"); } vsf_sysutil_install_async_sighandler(kVSFSysUtilSigCHLD, handle_sigchld); vsf_sysutil_install_async_sighandler(kVSFSysUtilSigHUP, handle_sighup); if (tunable_listen) { struct vsf_sysutil_sockaddr* p_sockaddr = 0; vsf_sysutil_sockaddr_alloc_ipv4(&p_sockaddr); vsf_sysutil_sockaddr_set_port(p_sockaddr, tunable_listen_port); if (!tunable_listen_address) { vsf_sysutil_sockaddr_set_any(p_sockaddr); } else { if (!vsf_sysutil_inet_aton(tunable_listen_address, p_sockaddr)) { die2("bad listen_address: ", tunable_listen_address); } } retval = vsf_sysutil_bind(listen_sock, p_sockaddr); vsf_sysutil_free(p_sockaddr); if (vsf_sysutil_retval_is_error(retval)) { die("could not bind listening IPv4 socket"); } } else { struct vsf_sysutil_sockaddr* p_sockaddr = 0; vsf_sysutil_sockaddr_alloc_ipv6(&p_sockaddr); vsf_sysutil_sockaddr_set_port(p_sockaddr, tunable_listen_port); if (!tunable_listen_address6) { vsf_sysutil_sockaddr_set_any(p_sockaddr); } else { struct mystr addr_str = INIT_MYSTR; const unsigned char* p_raw_addr; str_alloc_text(&addr_str, tunable_listen_address6); p_raw_addr = vsf_sysutil_parse_ipv6(&addr_str); str_free(&addr_str); if (!p_raw_addr) { die2("bad listen_address6: ", tunable_listen_address6); } vsf_sysutil_sockaddr_set_ipv6addr(p_sockaddr, p_raw_addr); } retval = vsf_sysutil_bind(listen_sock, p_sockaddr); vsf_sysutil_free(p_sockaddr); if (vsf_sysutil_retval_is_error(retval)) { die("could not bind listening IPv6 socket"); } } vsf_sysutil_listen(listen_sock, VSFTP_LISTEN_BACKLOG); vsf_sysutil_sockaddr_alloc(&p_accept_addr); while (1) { struct vsf_client_launch child_info; void* p_raw_addr; int new_child; int new_client_sock; vsf_sysutil_unblock_sig(kVSFSysUtilSigCHLD); vsf_sysutil_unblock_sig(kVSFSysUtilSigHUP); new_client_sock = vsf_sysutil_accept_timeout( listen_sock, p_accept_addr, 0); vsf_sysutil_block_sig(kVSFSysUtilSigCHLD); vsf_sysutil_block_sig(kVSFSysUtilSigHUP); if (vsf_sysutil_retval_is_error(new_client_sock)) { continue; } ++s_children; child_info.num_children = s_children; child_info.num_this_ip = 0; p_raw_addr = vsf_sysutil_sockaddr_get_raw_addr(p_accept_addr); child_info.num_this_ip = handle_ip_count(p_raw_addr); new_child = vsf_sysutil_fork_failok(); if (new_child != 0) { /* Parent context */ vsf_sysutil_close(new_client_sock); if (new_child > 0) { hash_add_entry(s_p_pid_ip_hash, (void*)&new_child, p_raw_addr); } else { /* fork() failed, clear up! */ --s_children; drop_ip_count(p_raw_addr); } /* Fall through to while() loop and accept() again */ } else { /* Child context */ vsf_sysutil_close(listen_sock); prepare_child(new_client_sock); /* By returning here we "launch" the child process with the same * contract as xinetd would provide. */ return child_info; } } }
void ssl_slave(struct vsf_session* p_sess) { struct mystr data_str = INIT_MYSTR; str_reserve(&data_str, VSFTP_DATA_BUFSIZE); /* Before becoming the slave, clear the alarm for the FTP protocol. */ vsf_sysutil_clear_alarm(); /* No need for any further communications with the privileged parent. */ priv_sock_set_parent_context(p_sess); if (tunable_setproctitle_enable) { vsf_sysutil_setproctitle("SSL handler"); } while (1) { char cmd = priv_sock_get_cmd(p_sess->ssl_slave_fd); int ret; if (cmd == PRIV_SOCK_GET_USER_CMD) { ret = ftp_getline(p_sess, &p_sess->ftp_cmd_str, p_sess->p_control_line_buf); priv_sock_send_int(p_sess->ssl_slave_fd, ret); if (ret >= 0) { priv_sock_send_str(p_sess->ssl_slave_fd, &p_sess->ftp_cmd_str); } } else if (cmd == PRIV_SOCK_WRITE_USER_RESP) { priv_sock_get_str(p_sess->ssl_slave_fd, &p_sess->ftp_cmd_str); ret = ftp_write_str(p_sess, &p_sess->ftp_cmd_str, kVSFRWControl); priv_sock_send_int(p_sess->ssl_slave_fd, ret); } else if (cmd == PRIV_SOCK_DO_SSL_HANDSHAKE) { char result = PRIV_SOCK_RESULT_BAD; if (p_sess->data_fd != -1 || p_sess->p_data_ssl != 0) { bug("state not clean"); } p_sess->data_fd = priv_sock_recv_fd(p_sess->ssl_slave_fd); ret = ssl_accept(p_sess, p_sess->data_fd); if (ret == 1) { result = PRIV_SOCK_RESULT_OK; } else { vsf_sysutil_close(p_sess->data_fd); p_sess->data_fd = -1; } priv_sock_send_result(p_sess->ssl_slave_fd, result); } else if (cmd == PRIV_SOCK_DO_SSL_READ) { str_trunc(&data_str, VSFTP_DATA_BUFSIZE); ret = ssl_read_into_str(p_sess, p_sess->p_data_ssl, &data_str); priv_sock_send_int(p_sess->ssl_slave_fd, ret); priv_sock_send_str(p_sess->ssl_slave_fd, &data_str); } else if (cmd == PRIV_SOCK_DO_SSL_WRITE) { priv_sock_get_str(p_sess->ssl_slave_fd, &data_str); ret = ssl_write(p_sess->p_data_ssl, str_getbuf(&data_str), str_getlen(&data_str)); priv_sock_send_int(p_sess->ssl_slave_fd, ret); } else if (cmd == PRIV_SOCK_DO_SSL_CLOSE) { char result = PRIV_SOCK_RESULT_BAD; if (p_sess->data_fd == -1 && p_sess->p_data_ssl == 0) { result = PRIV_SOCK_RESULT_OK; } else { ret = ssl_data_close(p_sess); if (ret == 1) { result = PRIV_SOCK_RESULT_OK; } vsf_sysutil_close(p_sess->data_fd); p_sess->data_fd = -1; } priv_sock_send_result(p_sess->ssl_slave_fd, result); } else { die("bad request in process_ssl_slave_req"); } } }