int get_transfer_fd(session_t *pses) { int iret = 0; //可能是主动模式,或者被动模式 //检测是否收到PORT命令或者PASV命令 if((port_active(pses) < 0) && (pasv_active(pses) < 0)) { ftp_reply(pses->ctrl_fd, FTP_BADSENDCONN, "Use PORT or PASV first."); iret = -1; return iret; } //主动模式 if(port_active(pses) == 0) { //向nobody进程发送命令 priv_sock_send_cmd(pses->child_fd, PRIV_SOCK_GET_DATA_SOCK); unsigned short port = ntohs(pses->port_addr->sin_port); char *ip = inet_ntoa(pses->port_addr->sin_addr); //发送port priv_sock_send_int(pses->child_fd, (int)port); //发送ip priv_sock_send_buf(pses->child_fd, ip, strlen(ip)); //接收应答 char res = priv_sock_get_result(pses->child_fd); if(res == PRIV_SOCK_RESULT_BAD) { iret = -1; } else if(res == PRIV_SOCK_RESULT_OK) { //接收文件描述符 pses->data_fd = priv_sock_recv_fd(pses->child_fd); } } else if(pasv_active(pses) == 0)//被动模式 { //发送命令给nobody进程,完成客户端和服务端的连接 priv_sock_send_cmd(pses->child_fd, PRIV_SOCK_PASV_ACCEPT); //接收nobody进程的应答 char res = priv_sock_get_result(pses->child_fd); if(res == PRIV_SOCK_RESULT_BAD) { iret = -1; } else if(res == PRIV_SOCK_RESULT_OK) { pses->data_fd = priv_sock_recv_fd(pses->child_fd); } } //连接成功后,该内存空间就不需要了 if(pses->port_addr != NULL) { free(pses->port_addr); pses->port_addr = NULL; } return iret; }
int ftp_write_str(const struct vsf_session* p_sess, const struct mystr* p_str, enum EVSFRWTarget target) { if (target == kVSFRWData) { if (p_sess->data_use_ssl) { return ssl_write_str(p_sess->p_data_ssl, p_str); } else { return str_netfd_write(p_str, p_sess->data_fd); } } else { if (p_sess->control_use_ssl && p_sess->ssl_slave_active) { priv_sock_send_cmd(p_sess->ssl_consumer_fd, PRIV_SOCK_WRITE_USER_RESP); priv_sock_send_str(p_sess->ssl_consumer_fd, p_str); return priv_sock_get_int(p_sess->ssl_consumer_fd); } else if (p_sess->control_use_ssl) { return ssl_write_str(p_sess->p_control_ssl, p_str); } else { return str_netfd_write(p_str, VSFTP_COMMAND_FD); } } }
int ftp_getline(struct vsf_session* p_sess, struct mystr* p_str, char* p_buf) { if (p_sess->control_use_ssl && p_sess->ssl_slave_active) { int ret; priv_sock_send_cmd(p_sess->ssl_consumer_fd, PRIV_SOCK_GET_USER_CMD); ret = priv_sock_get_int(p_sess->ssl_consumer_fd); if (ret >= 0) { priv_sock_get_str(p_sess->ssl_consumer_fd, p_str); } return ret; } else { str_netfd_read_t p_peek = plain_peek_adapter; str_netfd_read_t p_read = plain_read_adapter; if (p_sess->control_use_ssl) { p_peek = ssl_peek_adapter; p_read = ssl_read_adapter; } return str_netfd_alloc(p_sess, p_str, '\n', p_buf, VSFTP_MAX_COMMAND_LINE, p_peek, p_read); } }
int vsf_ftpdataio_post_mark_connect(struct vsf_session* p_sess) { int ret = 0; if (!p_sess->data_use_ssl) { return 1; } if (!p_sess->ssl_slave_active) { ret = ssl_accept(p_sess, p_sess->data_fd); } else { int sock_ret; priv_sock_send_cmd(p_sess->ssl_consumer_fd, PRIV_SOCK_DO_SSL_HANDSHAKE); priv_sock_send_fd(p_sess->ssl_consumer_fd, p_sess->data_fd); sock_ret = priv_sock_get_result(p_sess->ssl_consumer_fd); if (sock_ret == PRIV_SOCK_RESULT_OK) { ret = 1; } } if (ret != 1) { if (tunable_require_ssl_reuse) { vsf_cmdio_write_exit(p_sess, FTP_DATATLSBAD, "SSL connection failed: session reuse required", 1); } else { vsf_cmdio_write(p_sess, FTP_DATATLSBAD, "SSL connection failed"); } } return ret; }
void vsf_two_process_login(struct vsf_session* p_sess, const struct mystr* p_pass_str) { char result; priv_sock_send_cmd(p_sess, PRIV_SOCK_LOGIN); priv_sock_send_str(p_sess, &p_sess->user_str); priv_sock_send_str(p_sess, p_pass_str); result = priv_sock_get_result(p_sess); if (result == PRIV_SOCK_RESULT_OK) { /* Miracle. We don't emit the success message here. That is left to * process_post_login(). * Exit normally, parent will wait for this and launch new child */ vsf_sysutil_exit(0); } else if (result == PRIV_SOCK_RESULT_BAD) { /* Continue the processing loop.. */ return; } else { die("priv_sock_get_result"); } }
static void _handle_pasv(session_t *sess) { if (!sess->is_login) { ftp_cmdio_write(sess->ctrl_fd, FTP_NLOGIN, "Please login first."); return; } if (sess->cliaddr != NULL) { free(sess->cliaddr); sess->cliaddr = NULL; } priv_sock_send_cmd(sess->child_fd, PRIV_SOCK_LISTEN); uint16_t port = priv_sock_recv_int(sess->child_fd); char c[6] = {0}; union { char cs[2]; uint16_t nport; } port_union; port_union.nport = htons(port); c[4] = port_union.cs[1]; c[5] = port_union.cs[0]; sscanf(tunable_listen_addr, "%c.%c.%c.%c", &c[0], &c[1], &c[2], &c[3]); char msg[1024] = {0}; sprintf(msg, "Entering Passive Mode (%c,%c,%c,%c,%c,%c).", c[0], c[1], c[2], c[3], c[4], c[5]); ftp_cmdio_write(sess->ctrl_fd, FTP_PASV, msg); }
static void _handle_port(session_t *sess) { if (!sess->is_login) { ftp_cmdio_write(sess->ctrl_fd, FTP_NLOGIN, "Please login first."); return; } // first check whether pasv is on, 0->null, 1->pasv priv_sock_send_cmd(sess->child_fd, PRIV_SOCK_CHECK); int res = priv_sock_recv_res(sess->child_fd); if (res == 1) { priv_sock_send_cmd(sess->child_fd, PRIV_SOCK_CLOSE); if (priv_sock_recv_res(sess->child_fd) == -1) ftp_cmdio_write(sess->ctrl_fd, FTP_NEXEC, "Port not succeed."); close(sess->data_fd); sess->data_fd = -1; } if (sess->cliaddr != NULL) { free(sess->cliaddr); sess->cliaddr = NULL; } char c[6] = {0}; if (sscanf(sess->ftp_cmd_arg, "%c,%c,%c,%c,%c,%c", &c[0], &c[1], &c[2], &c[3], &c[4], &c[5]) != 6) { ftp_cmdio_write(sess->ctrl_fd, FTP_ARGE, "Argument error."); return; } sess->cliaddr = (struct sockaddr_in *)malloc(sizeof(struct sockaddr_in)); memset(sess->cliaddr, 0, sizeof(struct sockaddr_in)); char *ip = (char *)&sess->cliaddr->sin_addr.s_addr; ip[0] = c[0]; ip[1] = c[1]; ip[2] = c[2]; ip[3] = c[3]; char *port = (char *)&sess->cliaddr->sin_port; port[0] = c[5]; port[1] = c[4]; ftp_cmdio_write(sess->ctrl_fd, FTP_SUCCESS, "Port command successful."); }
void vsf_two_process_pasv_cleanup(struct vsf_session* p_sess) { char res; priv_sock_send_cmd(p_sess->child_fd, PRIV_SOCK_PASV_CLEANUP); res = priv_sock_get_result(p_sess->child_fd); if (res != PRIV_SOCK_RESULT_OK) { die("could not clean up socket"); } }
void vsf_two_process_chown_upload(struct vsf_session* p_sess, int fd) { char res; priv_sock_send_cmd(p_sess, PRIV_SOCK_CHOWN); priv_sock_child_send_fd(p_sess, fd); res = priv_sock_get_result(p_sess); if (res != PRIV_SOCK_RESULT_OK) { die("unexpected failure in vsf_two_process_chown_upload"); } }
int vsf_ftpdataio_dispose_transfer_fd(struct vsf_session* p_sess) { int dispose_ret = 1; int retval; if (p_sess->data_fd == -1) { bug("no data descriptor in vsf_ftpdataio_dispose_transfer_fd"); } vsf_sysutil_uninstall_io_handler(); if (p_sess->data_use_ssl && p_sess->ssl_slave_active) { char result; start_data_alarm(p_sess); priv_sock_send_cmd(p_sess->ssl_consumer_fd, PRIV_SOCK_DO_SSL_CLOSE); result = priv_sock_get_result(p_sess->ssl_consumer_fd); if (result != PRIV_SOCK_RESULT_OK) { dispose_ret = 0; } } else if (p_sess->p_data_ssl) { start_data_alarm(p_sess); dispose_ret = ssl_data_close(p_sess); } if (!p_sess->abor_received && !p_sess->data_timeout && dispose_ret == 1) { /* If we didn't get a failure, linger on the close() in order to get more * accurate transfer times. */ start_data_alarm(p_sess); vsf_sysutil_activate_linger(p_sess->data_fd); } /* This close() blocks because we set SO_LINGER */ retval = vsf_sysutil_close_failok(p_sess->data_fd); if (vsf_sysutil_retval_is_error(retval)) { /* Do it again without blocking. */ vsf_sysutil_deactivate_linger_failok(p_sess->data_fd); (void) vsf_sysutil_close_failok(p_sess->data_fd); } p_sess->data_fd = -1; if (tunable_data_connection_timeout > 0) { vsf_sysutil_clear_alarm(); } if (p_sess->abor_received || p_sess->data_timeout) { dispose_ret = 0; } return dispose_ret; }
int vsf_two_process_get_priv_data_sock(struct vsf_session* p_sess) { char res; priv_sock_send_cmd(p_sess, PRIV_SOCK_GET_DATA_SOCK); res = priv_sock_get_result(p_sess); if (res != PRIV_SOCK_RESULT_OK) { die("could not get privileged socket"); } return priv_sock_child_recv_fd(p_sess); }
int get_pasv_fd(session_t* sess) { priv_sock_send_cmd(sess->child_fd, PRIV_SOCK_PASV_ACCEPT); char res = priv_sock_get_result(sess->child_fd); if(res == PRIV_SOCK_RESULT_BAD) return 0; else if(res == PRIV_SOCK_RESULT_OK) sess->data_fd = priv_sock_recv_fd(sess->child_fd); return 1; }
int pasv_active(session_t* sess) { priv_sock_send_cmd(sess->child_fd, PRIV_SOCK_PASV_ACTIVE); int active = priv_sock_get_int(sess->child_fd); if(active) { if(port_active(sess)) { fprintf(stderr, "both port and pasv are active"); exit(EXIT_FAILURE); } return 1; } return 0; }
int vsf_two_process_get_pasv_fd(struct vsf_session* p_sess) { char res; priv_sock_send_cmd(p_sess->child_fd, PRIV_SOCK_PASV_ACCEPT); res = priv_sock_get_result(p_sess->child_fd); if (res == PRIV_SOCK_RESULT_BAD) { return priv_sock_get_int(p_sess->child_fd); } else if (res != PRIV_SOCK_RESULT_OK) { die("could not accept on listening socket"); } return priv_sock_recv_fd(p_sess->child_fd); }
static void do_pasv(session_t *sess) { char ip[16] = {0}; getlocalip(ip); priv_sock_send_cmd(sess->child_fd, PRIV_SOCK_PASV_LISTEN); unsigned short port = (unsigned short)priv_sock_get_int(sess->child_fd); unsigned int v[4]; sscanf(ip, "%u.%u.%u.%u", &v[0], &v[1], &v[2], &v[3]); char text[1024] = {0}; sprintf(text, "Entering Passive Mode (%u,%u,%u,%u,%u,%u).", v[0], v[1], v[2], v[3], port >> 8, port & 0xFF); ftp_reply(sess, FTP_PASVOK, text); }
int get_port_fd(session_t* sess) { priv_sock_send_cmd(sess->child_fd, PRIV_SOCK_GET_DATA_SOCK); unsigned short port = ntohs(sess->port_addr->sin_port); char* ip = inet_ntoa(sess->port_addr->sin_addr); priv_sock_send_int(sess->child_fd, (int)port); priv_sock_send_buf(sess->child_fd, ip, strlen(ip)); char res = priv_sock_get_result(sess->child_fd); if(res == PRIV_SOCK_RESULT_BAD) return 0; else if(res == PRIV_SOCK_RESULT_OK) sess->data_fd = priv_sock_recv_fd(sess->child_fd); return 1; }
void ftp_getline(const struct vsf_session* p_sess, struct mystr* p_str, char* p_buf) { if (p_sess->control_use_ssl && p_sess->ssl_slave_active) { priv_sock_send_cmd(p_sess->ssl_consumer_fd, PRIV_SOCK_GET_USER_CMD); priv_sock_get_str(p_sess->ssl_consumer_fd, p_str); } else if (p_sess->control_use_ssl) { ssl_getline(p_sess, p_str, '\n', p_buf, VSFTP_MAX_COMMAND_LINE); } else { str_netfd_alloc( p_str, VSFTP_COMMAND_FD, '\n', p_buf, VSFTP_MAX_COMMAND_LINE); } }
int vsf_two_process_get_priv_data_sock(struct vsf_session* p_sess) { char res; unsigned short port = vsf_sysutil_sockaddr_get_port(p_sess->p_port_sockaddr); priv_sock_send_cmd(p_sess->child_fd, PRIV_SOCK_GET_DATA_SOCK); priv_sock_send_int(p_sess->child_fd, port); res = priv_sock_get_result(p_sess->child_fd); if (res == PRIV_SOCK_RESULT_BAD) { return -1; } else if (res != PRIV_SOCK_RESULT_OK) { die("could not get privileged socket"); } return priv_sock_recv_fd(p_sess->child_fd); }
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"); } }
int pasv_active(session_t *pses) { //向nobody进程发送命令,看看是否创建了监听套接字,如果是,被动模式处于激活状态 priv_sock_send_cmd(pses->child_fd, PRIV_SOCK_PASV_ACTIVE); int iret = priv_sock_get_int(pses->child_fd); if(iret != -1) { if(port_active(pses) == 0) //主被动模式不能同时处于激活状态 { handle_error_str("both port and pasv are active."); } return 0; } else { return -1; } }
int vsf_ftpdataio_dispose_transfer_fd(struct vsf_session* p_sess) { int dispose_ret = 1; int retval; if (p_sess->data_fd == -1) { bug("no data descriptor in vsf_ftpdataio_dispose_transfer_fd"); } /* Reset the data connection alarm so it runs anew with the blocking close */ start_data_alarm(p_sess); vsf_sysutil_uninstall_io_handler(); if (p_sess->data_use_ssl && p_sess->ssl_slave_active) { char result; priv_sock_send_cmd(p_sess->ssl_consumer_fd, PRIV_SOCK_DO_SSL_CLOSE); result = priv_sock_get_result(p_sess->ssl_consumer_fd); if (result != PRIV_SOCK_RESULT_OK) { dispose_ret = 0; } } else if (p_sess->p_data_ssl) { dispose_ret = ssl_data_close(p_sess); } /* This close() blocks because we set SO_LINGER */ retval = vsf_sysutil_close_failok(p_sess->data_fd); if (vsf_sysutil_retval_is_error(retval)) { /* Do it again without blocking. */ vsf_sysutil_deactivate_linger_failok(p_sess->data_fd); (void) vsf_sysutil_close_failok(p_sess->data_fd); } if (tunable_data_connection_timeout > 0) { vsf_sysutil_clear_alarm(); } p_sess->data_fd = -1; return dispose_ret; }
int ftp_read_data(struct vsf_session* p_sess, char* p_buf, unsigned int len) { if (p_sess->data_use_ssl && p_sess->ssl_slave_active) { int ret; priv_sock_send_cmd(p_sess->ssl_consumer_fd, PRIV_SOCK_DO_SSL_READ); ret = priv_sock_get_int(p_sess->ssl_consumer_fd); priv_sock_recv_buf(p_sess->ssl_consumer_fd, p_buf, len); /* Need to do this here too because it is useless in the slave process. */ vsf_sysutil_check_pending_actions(kVSFSysUtilIO, ret, p_sess->data_fd); return ret; } else if (p_sess->data_use_ssl) { return ssl_read(p_sess, p_sess->p_data_ssl, p_buf, len); } else { return vsf_sysutil_read(p_sess->data_fd, p_buf, len); } }
void do_cmd_pasv(session_t *pses) { char localip[16] = {0}; if(getlocalip(localip) < 0) { handle_error("getlocalip"); } //向nobody进程发送请求 priv_sock_send_cmd(pses->child_fd, PRIV_SOCK_PASV_LISTEN); //接收nobody进程返回的端口号 unsigned short port = (unsigned short)priv_sock_get_int(pses->child_fd); unsigned int v[4] = {0}; sscanf(localip, "%u.%u.%u.%u",&v[0],&v[1],&v[2],&v[3]); char iptext[1024] = {0}; sprintf(iptext, "Entering Passive Mode (%u,%u,%u,%u,%u,%u).", v[0],v[1],v[2],v[3],port>>8,port & 0xFF); ftp_reply(pses->ctrl_fd, FTP_PASVOK, iptext); }
int vsf_ftpdataio_post_mark_connect(struct vsf_session* p_sess) { int ret = 0; if (!p_sess->data_use_ssl) { return 1; } if (!p_sess->ssl_slave_active) { ret = ssl_accept(p_sess, p_sess->data_fd); } else { int sock_ret; priv_sock_send_cmd(p_sess->ssl_consumer_fd, PRIV_SOCK_DO_SSL_HANDSHAKE); priv_sock_send_fd(p_sess->ssl_consumer_fd, p_sess->data_fd); sock_ret = priv_sock_get_result(p_sess->ssl_consumer_fd); if (sock_ret == PRIV_SOCK_RESULT_OK) { ret = 1; } } if (ret != 1) { static struct mystr s_err_msg; str_alloc_text(&s_err_msg, "SSL connection failed"); if (tunable_require_ssl_reuse) { str_append_text(&s_err_msg, "; session reuse required"); str_append_text( &s_err_msg, ": see require_ssl_reuse option in vsftpd.conf man page"); } vsf_cmdio_write_str(p_sess, FTP_DATATLSBAD, &s_err_msg); } return ret; }
unsigned short vsf_two_process_listen(struct vsf_session* p_sess) { priv_sock_send_cmd(p_sess->child_fd, PRIV_SOCK_PASV_LISTEN); return (unsigned short) priv_sock_get_int(p_sess->child_fd); }
int vsf_two_process_pasv_active(struct vsf_session* p_sess) { priv_sock_send_cmd(p_sess->child_fd, PRIV_SOCK_PASV_ACTIVE); return priv_sock_get_int(p_sess->child_fd); }