?? postlogin.c
字號:
vsf_sysutil_sockaddr_clone(&p_sess->p_port_sockaddr, p_sess->p_local_addr); 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 voidhandle_stor(struct vsf_session* p_sess){ handle_upload_common(p_sess, 0, 0);}static voidhandle_upload_common(struct vsf_session* p_sess, int is_append, int is_unique){ static struct vsf_sysutil_statbuf* s_p_statbuf; static struct mystr s_filename; struct mystr* p_filename; struct vsf_transfer_ret trans_ret; int new_file_fd; int remote_fd; int success = 0; int created = 0; filesize_t offset = p_sess->restart_pos; p_sess->restart_pos = 0; if (!data_transfer_checks_ok(p_sess)) { return; } resolve_tilde(&p_sess->ftp_arg_str, p_sess); p_filename = &p_sess->ftp_arg_str; if (is_unique) { get_unique_filename(&s_filename, p_filename); p_filename = &s_filename; } vsf_log_start_entry(p_sess, kVSFLogEntryUpload); 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_filename)) { vsf_cmdio_write(p_sess, FTP_NOPERM, "Permission denied."); return; } /* NOTE - actual file permissions will be governed by the tunable umask */ /* XXX - do we care about race between create and chown() of anonymous * upload? */ if (is_unique || (p_sess->is_anonymous && !tunable_anon_other_write_enable)) { new_file_fd = str_create(p_filename); } else { /* For non-anonymous, allow open() to overwrite or append existing files */ if (!is_append && offset == 0) { new_file_fd = str_create_overwrite(p_filename); } else { new_file_fd = str_create_append(p_filename); } } if (vsf_sysutil_retval_is_error(new_file_fd)) { vsf_cmdio_write(p_sess, FTP_UPLOADFAIL, "Could not create file."); return; } created = 1; vsf_sysutil_fstat(new_file_fd, &s_p_statbuf); if (vsf_sysutil_statbuf_is_regfile(s_p_statbuf)) { /* Now deactive O_NONBLOCK, otherwise we have a problem on DMAPI filesystems * such as XFS DMAPI. */ vsf_sysutil_deactivate_noblock(new_file_fd); } /* Are we required to chown() this file for security? */ if (p_sess->is_anonymous && tunable_chown_uploads) { vsf_sysutil_fchmod(new_file_fd, tunable_chown_upload_mode); if (tunable_one_process_model) { vsf_one_process_chown_upload(p_sess, new_file_fd); } else { vsf_two_process_chown_upload(p_sess, new_file_fd); } } /* Are we required to lock this file? */ if (tunable_lock_upload_files) { vsf_sysutil_lock_file_write(new_file_fd); } if (!is_append && offset != 0) { /* XXX - warning, allows seek past end of file! Check for seek > size? */ vsf_sysutil_lseek_to(new_file_fd, offset); } if (is_unique) { struct mystr resp_str = INIT_MYSTR; str_alloc_text(&resp_str, "FILE: "); str_append_str(&resp_str, p_filename); remote_fd = get_remote_transfer_fd(p_sess, str_getbuf(&resp_str)); str_free(&resp_str); } else { remote_fd = get_remote_transfer_fd(p_sess, "Ok to send data."); } if (vsf_sysutil_retval_is_error(remote_fd)) { goto port_pasv_cleanup_out; } if (tunable_ascii_upload_enable && p_sess->is_ascii) { trans_ret = vsf_ftpdataio_transfer_file(p_sess, remote_fd, new_file_fd, 1, 1); } else { trans_ret = vsf_ftpdataio_transfer_file(p_sess, remote_fd, new_file_fd, 1, 0); } if (vsf_ftpdataio_dispose_transfer_fd(p_sess) != 1 && trans_ret.retval == 0) { trans_ret.retval = -2; } p_sess->transfer_size = trans_ret.transferred; if (trans_ret.retval == 0) { success = 1; vsf_log_do_log(p_sess, 1); } if (trans_ret.retval == -1) { vsf_cmdio_write(p_sess, FTP_BADSENDFILE, "Failure writing to local file."); } else if (trans_ret.retval == -2) { vsf_cmdio_write(p_sess, FTP_BADSENDNET, "Failure reading network stream."); } else { vsf_cmdio_write(p_sess, FTP_TRANSFEROK, "File receive OK."); } check_abor(p_sess);port_pasv_cleanup_out: port_cleanup(p_sess); pasv_cleanup(p_sess); if (tunable_delete_failed_uploads && created && !success) { str_unlink(p_filename); } vsf_sysutil_close(new_file_fd);}static voidhandle_mkd(struct vsf_session* p_sess){ int retval; resolve_tilde(&p_sess->ftp_arg_str, p_sess); vsf_log_start_entry(p_sess, kVSFLogEntryMkdir); 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; } /* NOTE! Actual permissions will be governed by the tunable umask */ retval = str_mkdir(&p_sess->ftp_arg_str, 0777); if (retval != 0) { vsf_cmdio_write(p_sess, FTP_FILEFAIL, "Create directory operation failed."); return; } vsf_log_do_log(p_sess, 1); { static struct mystr s_mkd_res; static struct mystr s_tmp_str; str_copy(&s_tmp_str, &p_sess->ftp_arg_str); prepend_path_to_filename(&s_tmp_str); /* Double up double quotes */ str_replace_text(&s_tmp_str, "\"", "\"\""); /* Build result string */ str_alloc_text(&s_mkd_res, "\""); str_append_str(&s_mkd_res, &s_tmp_str); str_append_text(&s_mkd_res, "\" created"); vsf_cmdio_write_str(p_sess, FTP_MKDIROK, &s_mkd_res); }}static voidhandle_rmd(struct vsf_session* p_sess){ int retval; resolve_tilde(&p_sess->ftp_arg_str, p_sess); vsf_log_start_entry(p_sess, kVSFLogEntryRmdir); 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; } retval = str_rmdir(&p_sess->ftp_arg_str); if (retval != 0) { vsf_cmdio_write(p_sess, FTP_FILEFAIL, "Remove directory operation failed."); } else { vsf_log_do_log(p_sess, 1); vsf_cmdio_write(p_sess, FTP_RMDIROK, "Remove directory operation successful."); }}static voidhandle_dele(struct vsf_session* p_sess){ int retval; resolve_tilde(&p_sess->ftp_arg_str, p_sess); vsf_log_start_entry(p_sess, kVSFLogEntryDelete); 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; } retval = str_unlink(&p_sess->ftp_arg_str); if (retval != 0) { vsf_cmdio_write(p_sess, FTP_FILEFAIL, "Delete operation failed."); } else { vsf_log_do_log(p_sess, 1); vsf_cmdio_write(p_sess, FTP_DELEOK, "Delete operation successful."); }}static voidhandle_rest(struct vsf_session* p_sess){ static struct mystr s_rest_str; filesize_t val = str_a_to_filesize_t(&p_sess->ftp_arg_str); if (val < 0) { val = 0; } p_sess->restart_pos = val; str_alloc_text(&s_rest_str, "Restart position accepted ("); str_append_filesize_t(&s_rest_str, val); str_append_text(&s_rest_str, ")."); vsf_cmdio_write_str(p_sess, FTP_RESTOK, &s_rest_str);}static voidhandle_rnfr(struct vsf_session* p_sess){ static struct vsf_sysutil_statbuf* p_statbuf; int retval; /* Clear old value */ str_free(&p_sess->rnfr_filename_str); resolve_tilde(&p_sess->ftp_arg_str, p_sess); if (!vsf_access_check_file(&p_sess->ftp_arg_str)) { vsf_log_start_entry(p_sess, kVSFLogEntryRename); str_copy(&p_sess->log_str, &p_sess->ftp_arg_str); prepend_path_to_filename(&p_sess->log_str); vsf_cmdio_write(p_sess, FTP_NOPERM, "Permission denied."); return; } /* Does it exist? */ retval = str_stat(&p_sess->ftp_arg_str, &p_statbuf); if (retval == 0) { /* Yes */ str_copy(&p_sess->rnfr_filename_str, &p_sess->ftp_arg_str); vsf_cmdio_write(p_sess, FTP_RNFROK, "Ready for RNTO."); } else { vsf_log_start_entry(p_sess, kVSFLogEntryRename); str_copy(&p_sess->log_str, &p_sess->ftp_arg_str); prepend_path_to_filename(&p_sess->log_str); vsf_cmdio_write(p_sess, FTP_FILEFAIL, "RNFR command failed."); }}static voidhandle_rnto(struct vsf_session* p_sess){ static struct mystr s_tmp_str; int retval; /* If we didn't get a RNFR, throw a wobbly */ if (str_isempty(&p_sess->rnfr_filename_str)) { vsf_cmdio_write(p_sess, FTP_NEEDRNFR, "RNFR required first."); return; } resolve_tilde(&p_sess->ftp_arg_str, p_sess); vsf_log_start_entry(p_sess, kVSFLogEntryRename); str_copy(&p_sess->log_str, &p_sess->rnfr_filename_str); prepend_path_to_filename(&p_sess->log_str); str_append_char(&p_sess->log_str, ' '); str_copy(&s_tmp_str, &p_sess->ftp_arg_str); prepend_path_to_filename(&s_tmp_str); str_append_str(&p_sess->log_str, &s_tmp_str); if (!vsf_access_check_file(&p_sess->ftp_arg_str)) { vsf_cmdio_write(p_sess, FTP_NOPERM, "Permission denied."); return; } /* NOTE - might overwrite destination file. Not a concern because the same * could be accomplished with DELE. */ retval = str_rename(&p_sess->rnfr_filename_str, &p_sess->ftp_arg_str); /* Clear the RNFR filename; start the two stage process again! */ str_free(&p_sess->rnfr_filename_str); if (retval == 0) { vsf_log_do_log(p_sess, 1); vsf_cmdio_write(p_sess, FTP_RENAMEOK, "Rename successful."); } else { vsf_cmdio_write(p_sess, FTP_FILEFAIL, "Rename failed."); }}static voidhandle_nlst(struct vsf_session* p_sess){ handle_dir_common(p_sess, 0, 0);}static voidprepend_path_to_filename(struct mystr* p_str){ static struct mystr s_tmp_str; /* Only prepend current working directory if the incoming filename is * relative */ str_empty(&s_tmp_str); if (str_isempty(p_str) || str_get_char_at(p_str, 0) != '/') { str_getcwd(&s_tmp_str); /* Careful to not emit // if we are in directory / (common with chroot) */ if (str_isempty(&s_tmp_str) || str_get_char_at(&s_tmp_str, str_getlen(&s_tmp_str) - 1) != '/') { str_append_char(&s_tmp_str, '/'); } } str_append_str(&s_tmp_str, p_str); str_copy(p_str, &s_tmp_str);}static voidhandle_sigurg(void* p_private){ struct mystr async_cmd_str = INIT_MYSTR; struct mystr async_arg_str = INIT_MYSTR; struct mystr real_cmd_str = INIT_MYSTR; unsigned int len; struct vsf_session* p_sess = (struct vsf_session*) p_private; /* Did stupid client sent something OOB without a data connection? */ if (p_sess->data_fd == -1) { return; } /* Get the async command - blocks (use data timeout alarm) */ vsf_cmdio_get_cmd_and_arg(p_sess, &async_cmd_str, &async_arg_str, 0); /* Chop off first four characters; they are telnet characters. The client * should have sent the first two normally and the second two as urgent * data. */ len = str_getlen(&async_cmd_str); if (len >= 4) { str_right(&async_cmd_str, &real_cmd_str, len - 4); } if (str_equal_text(&real_cmd_str, "ABOR")) { p_sess->abor_received = 1; /* This is failok because of a small race condition; the SIGURG might * be raised after the data socket is closed, but before data_fd is * set to -1. */ vsf_sysutil_shutdown_failok(p_sess->data_fd); } else { /* Sorry! */ vsf_cmdio_write(p_sess, FTP_BADCMD, "Unknown command."); } str_free(&async_cmd_str); str_free(&async_arg_str); str_free(&real_cmd_str);}static intget_remote_transfer_fd(struct vsf_session* p_sess, const char* p_status_msg){ int remote_fd; if (!pasv_active(p_sess) && !port_active(p_sess)) { bug("neither PORT nor PASV active in get_remote_transfer_fd"); } p_sess->abor_received = 0; if (pasv_active(p_sess)) { remote_fd = vsf_ftpdataio_get_pasv_fd(p_sess); } else { remote_fd = vsf_ftpdataio_get_port_fd(p_sess); } if (vsf_sysutil_retval_is_error(remote_fd)) { return remote_fd; } vsf_cmdio_write(p_sess, FTP_DATACONN, p_status_msg); if (vsf_ftpdataio_post_mark_connect(p_sess) != 1) { vsf_ftpdataio_dispose_transfer_fd(p_sess); return -1; } return remote_fd;}static voidcheck_abor(struct vsf_session* p_sess){ /* If the client sent ABOR, respond to it here */ if (p_sess->abor_received) { p_sess->abor_received = 0; vsf_cmdio_write(p_sess, FTP_ABOROK, "ABOR successful."); }}static voidhandle_size(struct vsf_session* p_sess){ /* Note - in ASCII mode, are supposed to return the size after taking into
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -