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; }
static void handle_port(struct vsf_session* p_sess) { static struct mystr s_tmp_str; unsigned short the_port; unsigned char vals[6]; int i; pasv_cleanup(p_sess); port_cleanup(p_sess); str_copy(&s_tmp_str, &p_sess->ftp_arg_str); for (i=0; i<6; i++) { static struct mystr s_rhs_comma_str; int this_number; /* This puts a single , delimited field in tmp_str */ str_split_char(&s_tmp_str, &s_rhs_comma_str, ','); /* Sanity - check for too many or two few commas! */ if ( (i<5 && str_isempty(&s_rhs_comma_str)) || (i==5 && !str_isempty(&s_rhs_comma_str))) { vsf_cmdio_write(p_sess, FTP_BADCMD, "Illegal PORT command."); return; } this_number = str_atoi(&s_tmp_str); if (this_number < 0 || this_number > 255) { vsf_cmdio_write(p_sess, FTP_BADCMD, "Illegal PORT command."); return; } /* If this truncates from int to uchar, we don't care */ vals[i] = (unsigned char) this_number; /* The right hand side of the comma now becomes the new string to * breakdown */ str_copy(&s_tmp_str, &s_rhs_comma_str); } the_port = vals[4] << 8; the_port |= vals[5]; vsf_sysutil_sockaddr_alloc_ipv4(&p_sess->p_port_sockaddr); vsf_sysutil_sockaddr_set_ipv4addr(p_sess->p_port_sockaddr, vals); vsf_sysutil_sockaddr_set_port(p_sess->p_port_sockaddr, the_port); /* SECURITY: * 1) Reject requests not connecting to the control socket IP * 2) Reject connects to privileged ports */ if (!tunable_port_promiscuous) { if (!vsf_sysutil_sockaddr_addr_equal(p_sess->p_remote_addr, p_sess->p_port_sockaddr) || vsf_sysutil_is_port_reserved(the_port)) { vsf_cmdio_write(p_sess, FTP_BADCMD, "Illegal PORT command."); port_cleanup(p_sess); return; } } vsf_cmdio_write(p_sess, FTP_PORTOK, "PORT command successful. Consider using PASV."); }
static void handle_eprt(struct vsf_session* p_sess) { static struct mystr s_part1_str; static struct mystr s_part2_str; int proto; int port; const unsigned char* p_raw_addr; int is_ipv6 = vsf_sysutil_sockaddr_is_ipv6(p_sess->p_local_addr); port_cleanup(p_sess); pasv_cleanup(p_sess); str_copy(&s_part1_str, &p_sess->ftp_arg_str); str_split_char(&s_part1_str, &s_part2_str, '|'); if (!str_isempty(&s_part1_str)) { goto bad_eprt; } /* Split out the protocol and check it */ str_split_char(&s_part2_str, &s_part1_str, '|'); proto = str_atoi(&s_part2_str); if (!is_ipv6 || proto != 2) { vsf_cmdio_write(p_sess, FTP_BADCMD, "Bad EPRT protocol."); return; } /* Split out address and parse it */ str_split_char(&s_part1_str, &s_part2_str, '|'); p_raw_addr = vsf_sysutil_parse_ipv6(&s_part1_str); if (!p_raw_addr) { goto bad_eprt; } /* Split out port and parse it */ str_split_char(&s_part2_str, &s_part1_str, '|'); if (!str_isempty(&s_part1_str) || str_isempty(&s_part2_str)) { goto bad_eprt; } port = str_atoi(&s_part2_str); if (port < 0 || port > 65535) { goto bad_eprt; } vsf_sysutil_sockaddr_alloc_ipv6(&p_sess->p_port_sockaddr); vsf_sysutil_sockaddr_set_ipv6addr(p_sess->p_port_sockaddr, p_raw_addr); vsf_sysutil_sockaddr_set_port(p_sess->p_port_sockaddr, (unsigned short)port); /* SECURITY: * 1) Reject requests not connecting to the control socket IP * 2) Reject connects to privileged ports */ if (!tunable_port_promiscuous) { if (!vsf_sysutil_sockaddr_addr_equal(p_sess->p_remote_addr, p_sess->p_port_sockaddr) || vsf_sysutil_is_port_reserved(port)) { vsf_cmdio_write(p_sess, FTP_BADCMD, "Illegal EPRT command."); port_cleanup(p_sess); return; } } vsf_cmdio_write(p_sess, FTP_EPRTOK, "EPRT command successful. Consider using EPSV."); return; bad_eprt: vsf_cmdio_write(p_sess, FTP_BADCMD, "Bad EPRT command."); }