int vsf_privop_accept_pasv(struct vsf_session* p_sess) { struct vsf_sysutil_sockaddr* p_accept_addr = 0; int remote_fd; vsf_sysutil_sockaddr_alloc(&p_accept_addr); remote_fd = vsf_sysutil_accept_timeout(p_sess->pasv_listen_fd, p_accept_addr, tunable_accept_timeout); if (vsf_sysutil_retval_is_error(remote_fd)) { vsf_sysutil_sockaddr_clear(&p_accept_addr); return -1; } /* SECURITY: * Reject the connection if it wasn't from the same IP as the * control connection. */ if (!tunable_pasv_promiscuous) { if (!vsf_sysutil_sockaddr_addr_equal(p_sess->p_remote_addr, p_accept_addr)) { vsf_sysutil_close(remote_fd); vsf_sysutil_sockaddr_clear(&p_accept_addr); return -2; } } vsf_sysutil_sockaddr_clear(&p_accept_addr); return remote_fd; }
int vsf_ftpdataio_get_pasv_fd(struct vsf_session* p_sess) { int remote_fd; struct vsf_sysutil_sockaddr* p_accept_addr = 0; vsf_sysutil_sockaddr_alloc(&p_accept_addr); remote_fd = vsf_sysutil_accept_timeout(p_sess->pasv_listen_fd, p_accept_addr, tunable_accept_timeout); if (vsf_sysutil_retval_is_error(remote_fd)) { vsf_cmdio_write(p_sess, FTP_BADSENDCONN, "Failed to establish connection."); vsf_sysutil_sockaddr_clear(&p_accept_addr); return remote_fd; } /* SECURITY: * Reject the connection if it wasn't from the same IP as the * control connection. */ if (!tunable_pasv_promiscuous) { if (!vsf_sysutil_sockaddr_addr_equal(p_sess->p_remote_addr, p_accept_addr)) { vsf_cmdio_write(p_sess, FTP_BADSENDCONN, "Security: Bad IP connecting."); vsf_sysutil_close(remote_fd); vsf_sysutil_sockaddr_clear(&p_accept_addr); return -1; } } vsf_sysutil_sockaddr_clear(&p_accept_addr); init_data_sock_params(p_sess, remote_fd); vsf_sysutil_set_lfp(remote_fd); return remote_fd; }
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; } } }