?? postlogin.c
字號:
static intpasv_active(struct vsf_session* p_sess){ int ret = 0; if (p_sess->pasv_listen_fd != -1) { ret = 1; if (port_active(p_sess)) { bug("pasv and port both active"); } } return ret;}static voidport_cleanup(struct vsf_session* p_sess){ vsf_sysutil_sockaddr_clear(&p_sess->p_port_sockaddr);}static voidpasv_cleanup(struct vsf_session* p_sess){ if (p_sess->pasv_listen_fd != -1) { vsf_sysutil_close(p_sess->pasv_listen_fd); p_sess->pasv_listen_fd = -1; }}static voidhandle_pasv(struct vsf_session* p_sess, int is_epsv){ static struct mystr s_pasv_res_str; static struct vsf_sysutil_sockaddr* s_p_sockaddr; int bind_retries = 10; unsigned short the_port = 0; /* IPPORT_RESERVED */ unsigned short min_port = 1024; unsigned short max_port = 65535; int is_ipv6 = vsf_sysutil_sockaddr_is_ipv6(p_sess->p_local_addr); if (is_epsv && !str_isempty(&p_sess->ftp_arg_str)) { int argval; str_upper(&p_sess->ftp_arg_str); if (str_equal_text(&p_sess->ftp_arg_str, "ALL")) { p_sess->epsv_all = 1; vsf_cmdio_write(p_sess, FTP_EPSVALLOK, "EPSV ALL ok."); return; } argval = vsf_sysutil_atoi(str_getbuf(&p_sess->ftp_arg_str)); if (argval < 1 || argval > 2 || (!is_ipv6 && argval == 2)) { vsf_cmdio_write(p_sess, FTP_EPSVBAD, "Bad network protocol."); return; } } pasv_cleanup(p_sess); port_cleanup(p_sess); if (is_ipv6) { p_sess->pasv_listen_fd = vsf_sysutil_get_ipv6_sock(); } else { p_sess->pasv_listen_fd = vsf_sysutil_get_ipv4_sock(); } vsf_sysutil_activate_reuseaddr(p_sess->pasv_listen_fd); if (tunable_pasv_min_port > min_port && tunable_pasv_min_port <= max_port) { min_port = tunable_pasv_min_port; } if (tunable_pasv_max_port >= min_port && tunable_pasv_max_port < max_port) { max_port = tunable_pasv_max_port; } while (--bind_retries) { int retval; double scaled_port; the_port = vsf_sysutil_get_random_byte(); the_port <<= 8; the_port |= vsf_sysutil_get_random_byte(); scaled_port = (double) min_port; scaled_port += ((double) the_port / (double) 65536) * ((double) max_port - min_port + 1); the_port = (unsigned short) scaled_port; vsf_sysutil_sockaddr_clone(&s_p_sockaddr, p_sess->p_local_addr); vsf_sysutil_sockaddr_set_port(s_p_sockaddr, the_port); retval = vsf_sysutil_bind(p_sess->pasv_listen_fd, s_p_sockaddr); if (!vsf_sysutil_retval_is_error(retval)) { retval = vsf_sysutil_listen(p_sess->pasv_listen_fd, 1); if (!vsf_sysutil_retval_is_error(retval)) { break; } } if (vsf_sysutil_get_error() == kVSFSysUtilErrADDRINUSE) { continue; } die("vsf_sysutil_bind / listen"); } if (!bind_retries) { die("vsf_sysutil_bind"); } if (is_epsv) { str_alloc_text(&s_pasv_res_str, "Entering Extended Passive Mode (|||"); str_append_ulong(&s_pasv_res_str, (unsigned long) the_port); str_append_text(&s_pasv_res_str, "|)"); vsf_cmdio_write_str(p_sess, FTP_EPSVOK, &s_pasv_res_str); return; } if (tunable_pasv_address != 0) { /* Report passive address as specified in configuration */ if (vsf_sysutil_inet_aton(tunable_pasv_address, s_p_sockaddr) == 0) { die("invalid pasv_address"); } } str_alloc_text(&s_pasv_res_str, "Entering Passive Mode ("); if (!is_ipv6) { str_append_text(&s_pasv_res_str, vsf_sysutil_inet_ntop(s_p_sockaddr)); } else { const void* p_v4addr = vsf_sysutil_sockaddr_ipv6_v4(s_p_sockaddr); if (p_v4addr) { str_append_text(&s_pasv_res_str, vsf_sysutil_inet_ntoa(p_v4addr)); } else { str_append_text(&s_pasv_res_str, "0,0,0,0"); } } str_replace_char(&s_pasv_res_str, '.', ','); str_append_text(&s_pasv_res_str, ","); str_append_ulong(&s_pasv_res_str, the_port >> 8); str_append_text(&s_pasv_res_str, ","); str_append_ulong(&s_pasv_res_str, the_port & 255); str_append_text(&s_pasv_res_str, ")"); vsf_cmdio_write_str(p_sess, FTP_PASVOK, &s_pasv_res_str);}static voidhandle_retr(struct vsf_session* p_sess){ static struct mystr s_mark_str; static struct vsf_sysutil_statbuf* s_p_statbuf; struct vsf_transfer_ret trans_ret; int remote_fd; int opened_file; int is_ascii = 0; filesize_t offset = p_sess->restart_pos; p_sess->restart_pos = 0; if (!data_transfer_checks_ok(p_sess)) { return; } if (p_sess->is_ascii && offset != 0) { vsf_cmdio_write(p_sess, FTP_FILEFAIL, "No support for resume of ASCII transfer."); return; } resolve_tilde(&p_sess->ftp_arg_str, p_sess); vsf_log_start_entry(p_sess, kVSFLogEntryDownload); str_copy(&p_sess->log_str, &p_sess->ftp_arg_str); prepend_path_to_filename(&p_sess->log_str); if (!vsf_access_check_file(&p_sess->ftp_arg_str)) { vsf_cmdio_write(p_sess, FTP_NOPERM, "Permission denied."); return; } opened_file = str_open(&p_sess->ftp_arg_str, kVSFSysStrOpenReadOnly); if (vsf_sysutil_retval_is_error(opened_file)) { vsf_cmdio_write(p_sess, FTP_FILEFAIL, "Failed to open file."); return; } /* Lock file if required */ if (tunable_lock_upload_files) { vsf_sysutil_lock_file_read(opened_file); } vsf_sysutil_fstat(opened_file, &s_p_statbuf); /* No games please */ if (!vsf_sysutil_statbuf_is_regfile(s_p_statbuf)) { /* Note - pretend open failed */ vsf_cmdio_write(p_sess, FTP_FILEFAIL, "Failed to open file."); /* Irritating FireFox does RETR on directories, so avoid logging this * very common and noisy case. */ if (vsf_sysutil_statbuf_is_dir(s_p_statbuf)) { vsf_log_clear_entry(p_sess); } goto file_close_out; } /* Now deactive O_NONBLOCK, otherwise we have a problem on DMAPI filesystems * such as XFS DMAPI. */ vsf_sysutil_deactivate_noblock(opened_file); /* Optionally, we'll be paranoid and only serve publicly readable stuff */ if (p_sess->is_anonymous && tunable_anon_world_readable_only && !vsf_sysutil_statbuf_is_readable_other(s_p_statbuf)) { vsf_cmdio_write(p_sess, FTP_FILEFAIL, "Failed to open file."); goto file_close_out; } /* Set the download offset (from REST) if any */ if (offset != 0) { vsf_sysutil_lseek_to(opened_file, offset); } str_alloc_text(&s_mark_str, "Opening "); if (tunable_ascii_download_enable && p_sess->is_ascii) { str_append_text(&s_mark_str, "ASCII"); is_ascii = 1; } else { str_append_text(&s_mark_str, "BINARY"); } str_append_text(&s_mark_str, " mode data connection for "); str_append_str(&s_mark_str, &p_sess->ftp_arg_str); str_append_text(&s_mark_str, " ("); str_append_filesize_t(&s_mark_str, vsf_sysutil_statbuf_get_size(s_p_statbuf)); str_append_text(&s_mark_str, " bytes)."); remote_fd = get_remote_transfer_fd(p_sess, str_getbuf(&s_mark_str)); if (vsf_sysutil_retval_is_error(remote_fd)) { goto port_pasv_cleanup_out; } trans_ret = vsf_ftpdataio_transfer_file(p_sess, remote_fd, opened_file, 0, is_ascii); if (vsf_ftpdataio_dispose_transfer_fd(p_sess) != 1 && trans_ret.retval == 0) { trans_ret.retval = -2; } p_sess->transfer_size = trans_ret.transferred; /* Log _after_ the blocking dispose call, so we get transfer times right */ if (trans_ret.retval == 0) { vsf_log_do_log(p_sess, 1); } /* Emit status message _after_ blocking dispose call to avoid buggy FTP * clients truncating the transfer. */ if (trans_ret.retval == -1) { vsf_cmdio_write(p_sess, FTP_BADSENDFILE, "Failure reading local file."); } else if (trans_ret.retval == -2) { vsf_cmdio_write(p_sess, FTP_BADSENDNET, "Failure writing network stream."); } else { vsf_cmdio_write(p_sess, FTP_TRANSFEROK, "File send OK."); } check_abor(p_sess);port_pasv_cleanup_out: port_cleanup(p_sess); pasv_cleanup(p_sess);file_close_out: vsf_sysutil_close(opened_file);}static voidhandle_list(struct vsf_session* p_sess){ handle_dir_common(p_sess, 1, 0);}static voidhandle_dir_common(struct vsf_session* p_sess, int full_details, int stat_cmd){ static struct mystr s_option_str; static struct mystr s_filter_str; static struct mystr s_dir_name_str; static struct vsf_sysutil_statbuf* s_p_dirstat; int dir_allow_read = 1; struct vsf_sysutil_dir* p_dir = 0; int retval = 0; int use_control = 0; str_empty(&s_option_str); str_empty(&s_filter_str); /* By default open the current directory */ str_alloc_text(&s_dir_name_str, "."); if (!stat_cmd && !data_transfer_checks_ok(p_sess)) { return; } /* Do we have an option? Going to be strict here - the option must come * first. e.g. "ls -a .." fine, "ls .. -a" not fine */ if (!str_isempty(&p_sess->ftp_arg_str) && str_get_char_at(&p_sess->ftp_arg_str, 0) == '-') { /* Chop off the '-' */ str_mid_to_end(&p_sess->ftp_arg_str, &s_option_str, 1); /* A space will separate options from filter (if any) */ str_split_char(&s_option_str, &s_filter_str, ' '); } else { /* The argument, if any, is just a filter */ str_copy(&s_filter_str, &p_sess->ftp_arg_str); } if (!str_isempty(&s_filter_str)) { resolve_tilde(&s_filter_str, p_sess); if (!vsf_access_check_file(&s_filter_str)) { vsf_cmdio_write(p_sess, FTP_NOPERM, "Permission denied."); return; } /* First check - is it an outright directory, as in "ls /pub" */ p_dir = str_opendir(&s_filter_str); if (p_dir != 0) { /* Listing a directory! */ str_copy(&s_dir_name_str, &s_filter_str); str_free(&s_filter_str); } else { struct str_locate_result locate_result = str_locate_char(&s_filter_str, '/'); if (locate_result.found) { /* Includes a path! Reverse scan for / in the arg, to get the * base directory and filter (if any) */ str_copy(&s_dir_name_str, &s_filter_str); str_split_char_reverse(&s_dir_name_str, &s_filter_str, '/'); /* If we have e.g. "ls /.message", we just ripped off the leading * slash because it is the only one! */ if (str_isempty(&s_dir_name_str)) { str_alloc_text(&s_dir_name_str, "/"); } } } } if (p_dir == 0) { /* NOTE - failure check done below, it's not forgotten */ p_dir = str_opendir(&s_dir_name_str); } /* Fine, do it */ if (stat_cmd) { use_control = 1; str_append_char(&s_option_str, 'a'); vsf_cmdio_write_hyphen(p_sess, FTP_STATFILE_OK, "Status follows:"); } else { int remote_fd = get_remote_transfer_fd( p_sess, "Here comes the directory listing."); if (vsf_sysutil_retval_is_error(remote_fd)) { goto dir_close_out; } } if (p_sess->is_anonymous && p_dir && tunable_anon_world_readable_only) { vsf_sysutil_dir_stat(p_dir, &s_p_dirstat); if (!vsf_sysutil_statbuf_is_readable_other(s_p_dirstat)) { dir_allow_read = 0; } } if (p_dir != 0 && dir_allow_read) { retval = vsf_ftpdataio_transfer_dir(p_sess, use_control, p_dir, &s_dir_name_str, &s_option_str, &s_filter_str, full_details); } if (!stat_cmd) { if (vsf_ftpdataio_dispose_transfer_fd(p_sess) != 1 && retval == 0) { retval = -1; } } if (stat_cmd) { vsf_cmdio_write(p_sess, FTP_STATFILE_OK, "End of status"); } else if (p_dir == 0 || !dir_allow_read) { vsf_cmdio_write(p_sess, FTP_TRANSFEROK, "Transfer done (but failed to open directory)."); } else if (retval == 0) { vsf_cmdio_write(p_sess, FTP_TRANSFEROK, "Directory send OK."); } else { vsf_cmdio_write(p_sess, FTP_BADSENDNET, "Failure writing network stream."); } check_abor(p_sess);dir_close_out: if (p_dir) { vsf_sysutil_closedir(p_dir); } if (!stat_cmd) { port_cleanup(p_sess); pasv_cleanup(p_sess); }}static voidhandle_type(struct vsf_session* p_sess){ str_upper(&p_sess->ftp_arg_str); if (str_equal_text(&p_sess->ftp_arg_str, "I") || str_equal_text(&p_sess->ftp_arg_str, "L8") || str_equal_text(&p_sess->ftp_arg_str, "L 8")) { p_sess->is_ascii = 0; vsf_cmdio_write(p_sess, FTP_TYPEOK, "Switching to Binary mode."); } else if (str_equal_text(&p_sess->ftp_arg_str, "A") || str_equal_text(&p_sess->ftp_arg_str, "A N")) { p_sess->is_ascii = 1; vsf_cmdio_write(p_sess, FTP_TYPEOK, "Switching to ASCII mode."); } else { vsf_cmdio_write(p_sess, FTP_BADCMD, "Unrecognised TYPE command."); }}static voidhandle_port(struct vsf_session* p_sess){ unsigned short the_port; unsigned char vals[6]; const unsigned char* p_raw; pasv_cleanup(p_sess); port_cleanup(p_sess); p_raw = vsf_sysutil_parse_uchar_string_sep(&p_sess->ftp_arg_str, ',', vals, sizeof(vals)); if (p_raw == 0) { vsf_cmdio_write(p_sess, FTP_BADCMD, "Illegal PORT command."); return; } the_port = vals[4] << 8; the_port |= vals[5];
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -