void vsf_privop_do_file_chown(struct vsf_session* p_sess, int fd) { static struct vsf_sysutil_statbuf* s_p_statbuf; vsf_sysutil_fstat(fd, &s_p_statbuf); /* Do nothing if it is already owned by the desired user. */ if (vsf_sysutil_statbuf_get_uid(s_p_statbuf) == p_sess->anon_upload_chown_uid) { return; } /* Drop it like a hot potato unless it's a regular file owned by * the the anonymous ftp user */ if (p_sess->anon_upload_chown_uid == -1 || !vsf_sysutil_statbuf_is_regfile(s_p_statbuf) || (vsf_sysutil_statbuf_get_uid(s_p_statbuf) != p_sess->anon_ftp_uid && vsf_sysutil_statbuf_get_uid(s_p_statbuf) != p_sess->guest_user_uid)) { die("invalid fd in cmd_process_chown"); } /* SECURITY! You need an OS which strips SUID/SGID bits on chown(), * otherwise a compromise of the FTP user will lead to compromise of * the "anon_upload_chown_uid" user (think chmod +s). */ vsf_sysutil_fchown(fd, p_sess->anon_upload_chown_uid, -1); }
static void do_sanity_checks(void) { { struct vsf_sysutil_statbuf* p_statbuf = 0; vsf_sysutil_fstat(VSFTP_COMMAND_FD, &p_statbuf); if (!vsf_sysutil_statbuf_is_socket(p_statbuf)) { die("vsftpd: not configured for standalone, must be started from inetd"); } vsf_sysutil_free(p_statbuf); } if (tunable_one_process_model) { if (tunable_local_enable) { die("vsftpd: security: 'one_process_model' is anonymous only"); } if (!vsf_sysdep_has_capabilities_as_non_root()) { die("vsftpd: security: 'one_process_model' needs a better OS"); } } if (!tunable_local_enable && !tunable_anonymous_enable) { die("vsftpd: both local and anonymous access disabled!"); } }
int str_fileread(struct mystr* p_str, const char* p_filename, unsigned int maxsize) { int fd; int retval = 0; filesize_t size; char* p_sec_buf = 0; struct vsf_sysutil_statbuf* p_stat = 0; /* In case we fail, make sure we return an empty string */ str_empty(p_str); fd = vsf_sysutil_open_file(p_filename, kVSFSysUtilOpenReadOnly); if (vsf_sysutil_retval_is_error(fd)) { return fd; } vsf_sysutil_fstat(fd, &p_stat); if (vsf_sysutil_statbuf_is_regfile(p_stat)) { size = vsf_sysutil_statbuf_get_size(p_stat); if (size > maxsize) { size = maxsize; } vsf_secbuf_alloc(&p_sec_buf, (unsigned int) size); retval = vsf_sysutil_read_loop(fd, p_sec_buf, (unsigned int) size); if (vsf_sysutil_retval_is_error(retval)) { goto free_out; } else if ((unsigned int) retval != size) { die("read size mismatch"); } str_alloc_memchunk(p_str, p_sec_buf, size); } free_out: vsf_sysutil_free(p_stat); vsf_secbuf_free(&p_sec_buf); vsf_sysutil_close(fd); return retval; }
static filesize_t calc_num_send(int file_fd, filesize_t init_offset) { static struct vsf_sysutil_statbuf* s_p_statbuf; filesize_t bytes_to_send; /* Work out how many bytes to send based on file size minus current offset */ vsf_sysutil_fstat(file_fd, &s_p_statbuf); bytes_to_send = vsf_sysutil_statbuf_get_size(s_p_statbuf); if (init_offset < 0 || bytes_to_send < 0) { die("calc_num_send: negative file offset or send count"); } /* Don't underflow if some bonehead sets a REST greater than the file size */ if (init_offset > bytes_to_send) { bytes_to_send = 0; } else { bytes_to_send -= init_offset; } return bytes_to_send; }
static void handle_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 retval; int remote_fd; int opened_file; int is_ascii = 0; filesize_t offset = p_sess->restart_pos; p_sess->restart_pos = 0; if (!pasv_active(p_sess) && !port_active(p_sess)) { vsf_cmdio_write(p_sess, FTP_BADSENDCONN, "Use PORT or PASV first."); return; } if (p_sess->is_ascii && offset != 0) { vsf_cmdio_write(p_sess, FTP_FILEFAIL, "No support for resume of ASCII transfer."); 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; } 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."); goto file_close_out; } /* 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); } remote_fd = get_remote_transfer_fd(p_sess); if (vsf_sysutil_retval_is_error(remote_fd)) { goto port_pasv_cleanup_out; } 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); 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)."); vsf_cmdio_write_str(p_sess, FTP_DATACONN, &s_mark_str); trans_ret = vsf_ftpdataio_transfer_file(p_sess, remote_fd, opened_file, 0, is_ascii); p_sess->transfer_size = trans_ret.transferred; retval = dispose_remote_transfer_fd(p_sess); /* Log _after_ the blocking dispose call, so we get transfer times right */ if (trans_ret.retval == 0 && retval == 0) { vsf_log_do_log(p_sess, 1); } else { vsf_log_do_log(p_sess, 0); } port_pasv_cleanup_out: port_cleanup(p_sess); pasv_cleanup(p_sess); file_close_out: vsf_sysutil_close(opened_file); }