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); } }
static void privop_pasv_get_data_sock(session_t *sess) { unsigned short port = (unsigned short)priv_sock_get_int(sess->parent_fd); char ip[16] = {0}; priv_sock_recv_buf(sess->parent_fd, ip, sizeof(ip)); printf("privop_pasv_get_data_sock port=%u and ip=%s\n", port, ip); struct sockaddr_in addr; memset(&addr, 0, sizeof(addr)); addr.sin_family = AF_INET; addr.sin_port = htons(port); addr.sin_addr.s_addr = inet_addr(ip); int fd = tcp_client(20); if(fd == -1) { printf("aaaaaaaaaaaaaaaaaaa\n"); priv_sock_send_result(sess->parent_fd, PRIV_SOCK_RESULT_BAD); return; } socklen_t len = sizeof(struct sockaddr_in);; if(connect(fd, (struct sockaddr*)&addr, len) < 0) { printf("bbbbbbbbbbbbbbbbb\n"); ERR_EXIT("ccccconect"); close(fd); priv_sock_send_result(sess->parent_fd, PRIV_SOCK_RESULT_BAD); ERR_EXIT("connect"); return; } priv_sock_send_result(sess->parent_fd, PRIV_SOCK_RESULT_OK); priv_sock_send_fd(sess->parent_fd, fd); close(fd); }
void priv_sock_recv_buf(int fd, char *buf, unsigned int len) { unsigned int recv_len = (unsigned int)priv_sock_get_int(fd); if (recv_len > len) { FTPD_LOG(ERROR,"priv_sock_recv_buf error\n"); } int ret = sysutil::readn(fd, buf, recv_len); if (ret != (int)recv_len) { FTPD_LOG(ERROR,"priv_sock_recv_buf error\n"); } }
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); }
void priv_sock_recv_buf(int fd, char *buf, unsigned int len) { unsigned int recv_len = (unsigned int)priv_sock_get_int(fd); if (recv_len > len) { fprintf(stderr, "priv_sock_recv_buf error\n"); exit(EXIT_FAILURE); } int ret = readn(fd, buf, recv_len); if (ret != (int)recv_len) { fprintf(stderr, "priv_sock_recv_buf error\n"); exit(EXIT_FAILURE); } }
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 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; } }
/** * 创建数据连接通道 * @param sess [description] */ void PrivPar::privop_pasv_get_data_sock(session_t *sess) { /* nobody进程接收PRIV_SOCK_GET_DATA_SOCK命令 进一步接收一个整数,也就是port 接收一个字符串,也就是ip fd = socket bind(20) connect(ip, port); OK send_fd BAD */ unsigned short port = (unsigned short)priv_sock_get_int(sess->parent_fd); char ip[16] = {0}; priv_sock_recv_buf(sess->parent_fd, ip, sizeof(ip)); //从ftp服务进程获取IP地址 struct sockaddr_in addr; memset(&addr, 0, sizeof(addr)); addr.sin_family = AF_INET; addr.sin_port = htons(port); addr.sin_addr.s_addr = inet_addr(ip); int fd = sysutil::tcp_client(20); if (fd == -1) { priv_sock_send_result(sess->parent_fd, PRIV_SOCK_RESULT_BAD); return; } if (sysutil::connect_timeout(fd, &addr, parseconfig->get_accept_timeout()) < 0) { close(fd); priv_sock_send_result(sess->parent_fd, PRIV_SOCK_RESULT_BAD); return; } priv_sock_send_result(sess->parent_fd, PRIV_SOCK_RESULT_OK); priv_sock_send_fd(sess->parent_fd, fd); close(fd); }
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); } }
static void privop_pasv_get_data_sock(session_t *sess) { /* socket bind 20 connect */ // tcp_client(20); /* */ char ip[16] = {0}; unsigned short port = (unsigned short)priv_sock_get_int(sess->parent_fd); priv_sock_recv_buf(sess->parent_fd, ip, sizeof(ip)); struct sockaddr_in addr; memset(&addr, 0, sizeof(addr)); addr.sin_family = AF_INET; addr.sin_port = htons(port); addr.sin_addr.s_addr = inet_addr(ip); int fd = tcp_client(20); if (fd == -1) { priv_sock_send_result(sess->parent_fd, PRIV_SOCK_RESULT_BAD); return; } if (connect_timeout(fd, &addr, tunable_connect_timeout) < 0) { close(fd); priv_sock_send_result(sess->parent_fd, PRIV_SOCK_RESULT_BAD); return; } priv_sock_send_result(sess->parent_fd, PRIV_SOCK_RESULT_OK); priv_sock_send_fd(sess->parent_fd, fd); close(fd); }
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); }
static void privop_port_get_data_sock(session_t *sess) { unsigned short port = (unsigned short)priv_sock_get_int(sess->nobody_fd); char ip[20] = {0}; priv_sock_recv_buf(sess->nobody_fd, ip, sizeof(ip)); struct sockaddr_in addr; memset(&addr, 0, sizeof(addr)); addr.sin_family = AF_INET; addr.sin_port = htons(port); addr.sin_addr.s_addr = inet_addr(ip); // 当多个客户端连接服务器时,可以同时有多个nobody进程bind 20端口+ip,因为此时客户端给出的端口是随机的,故 // 四元组还是能识别一个数据连接 // 当客户端位于NAT服务器之后使用PORT模式时,需要在NAT服务器上配置映射才能让服务器主动连接到客户端 // 所以采用的是标准固定的20端口,这样NAT服务器就不用维护很多的表目 int fd = tcp_client(20); if (fd == -1) { priv_sock_send_result(sess->nobody_fd, PRIV_SOCK_RESULT_BAD); return; } if (connect_timeout(fd, &addr, tunable_connect_timeout) < 0) { close(fd); priv_sock_send_result(sess->nobody_fd, PRIV_SOCK_RESULT_BAD); return; } priv_sock_send_result(sess->nobody_fd, PRIV_SOCK_RESULT_OK); priv_sock_send_fd(sess->nobody_fd, fd); close(fd); //父进程必须close(fd),否则子进程关闭close(data_fd)的时候也不会发送FIN段。 //因为通过unix域协议传递套接字等于是对方也打开套接字,而直接简单的赋值是没有这样的效果的。 }
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); }
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); }
static void process_login_req(struct vsf_session* p_sess) { enum EVSFPrivopLoginResult e_login_result = kVSFLoginNull; char cmd; /* Blocks */ cmd = priv_sock_get_cmd(p_sess->parent_fd); if (cmd != PRIV_SOCK_LOGIN) { die("bad request"); } /* Get username and password - we must distrust these */ { struct mystr password_str = INIT_MYSTR; priv_sock_get_str(p_sess->parent_fd, &p_sess->user_str); priv_sock_get_str(p_sess->parent_fd, &password_str); p_sess->control_use_ssl = priv_sock_get_int(p_sess->parent_fd); p_sess->data_use_ssl = priv_sock_get_int(p_sess->parent_fd); if (!tunable_ssl_enable) { p_sess->control_use_ssl = 0; p_sess->data_use_ssl = 0; } e_login_result = vsf_privop_do_login(p_sess, &password_str); str_free(&password_str); } switch (e_login_result) { case kVSFLoginFail: priv_sock_send_result(p_sess->parent_fd, PRIV_SOCK_RESULT_BAD); return; break; case kVSFLoginAnon: str_alloc_text(&p_sess->user_str, tunable_ftp_username); common_do_login(p_sess, &p_sess->user_str, 1, 1); break; case kVSFLoginReal: { int do_chroot = 0; if (tunable_chroot_local_user) { do_chroot = 1; } if (tunable_chroot_list_enable) { struct mystr chroot_list_file = INIT_MYSTR; int retval = str_fileread(&chroot_list_file, tunable_chroot_list_file, VSFTP_CONF_FILE_MAX); if (vsf_sysutil_retval_is_error(retval)) { die2("could not read chroot() list file:", tunable_chroot_list_file); } if (str_contains_line(&chroot_list_file, &p_sess->user_str)) { if (do_chroot) { do_chroot = 0; } else { do_chroot = 1; } } str_free(&chroot_list_file); } common_do_login(p_sess, &p_sess->user_str, do_chroot, 0); } break; case kVSFLoginNull: /* Fall through */ default: bug("weird state in process_login_request"); break; } /* NOTREACHED */ }