static void handle_size(struct vsf_session* p_sess) { /* Note - in ASCII mode, are supposed to return the size after taking into * account ASCII linefeed conversions. At least this is what wu-ftpd does in * version 2.6.1. Proftpd-1.2.0pre fails to do this. * I will not do it because it is a potential I/O DoS. */ static struct vsf_sysutil_statbuf* s_p_statbuf; int retval; if (!vsf_access_check_file(&p_sess->ftp_arg_str)) { vsf_cmdio_write(p_sess, FTP_NOPERM, "Permission denied."); return; } retval = str_stat(&p_sess->ftp_arg_str, &s_p_statbuf); if (retval != 0 || !vsf_sysutil_statbuf_is_regfile(s_p_statbuf)) { vsf_cmdio_write(p_sess, FTP_FILEFAIL, "Could not get file size."); } else { static struct mystr s_size_res_str; str_alloc_filesize_t(&s_size_res_str, vsf_sysutil_statbuf_get_size(s_p_statbuf)); vsf_cmdio_write_str(p_sess, FTP_SIZEOK, &s_size_res_str); } }
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); }
static void build_dir_line(struct mystr* p_str, const struct mystr* p_filename_str, const struct vsf_sysutil_statbuf* p_stat, long curr_time) { static struct mystr s_tmp_str; char *tmp_filename=NULL; filesize_t size = vsf_sysutil_statbuf_get_size(p_stat); /* Permissions */ str_alloc_text(p_str, vsf_sysutil_statbuf_get_perms(p_stat)); str_append_char(p_str, ' '); /* Hard link count */ str_alloc_ulong(&s_tmp_str, vsf_sysutil_statbuf_get_links(p_stat)); str_lpad(&s_tmp_str, 4); str_append_str(p_str, &s_tmp_str); str_append_char(p_str, ' '); /* User */ if (tunable_hide_ids) { str_alloc_text(&s_tmp_str, "ftp"); } else { int uid = vsf_sysutil_statbuf_get_uid(p_stat); struct vsf_sysutil_user* p_user = 0; if (tunable_text_userdb_names) { p_user = vsf_sysutil_getpwuid(uid); } if (p_user == 0) { str_alloc_ulong(&s_tmp_str, (unsigned long) uid); } else { str_alloc_text(&s_tmp_str, vsf_sysutil_user_getname(p_user)); } } str_rpad(&s_tmp_str, 8); str_append_str(p_str, &s_tmp_str); str_append_char(p_str, ' '); /* Group */ if (tunable_hide_ids) { str_alloc_text(&s_tmp_str, "ftp"); } else { int gid = vsf_sysutil_statbuf_get_gid(p_stat); struct vsf_sysutil_group* p_group = 0; if (tunable_text_userdb_names) { p_group = vsf_sysutil_getgrgid(gid); } if (p_group == 0) { str_alloc_ulong(&s_tmp_str, (unsigned long) gid); } else { str_alloc_text(&s_tmp_str, vsf_sysutil_group_getname(p_group)); } } str_rpad(&s_tmp_str, 8); str_append_str(p_str, &s_tmp_str); str_append_char(p_str, ' '); /* Size in bytes */ str_alloc_filesize_t(&s_tmp_str, size); str_lpad(&s_tmp_str, 8); str_append_str(p_str, &s_tmp_str); str_append_char(p_str, ' '); /* Date stamp */ str_append_text(p_str, vsf_sysutil_statbuf_get_date(p_stat, tunable_use_localtime, curr_time)); str_append_char(p_str, ' '); /* Filename */ tmp_filename = local2remote(str_getbuf(p_filename_str)); if (tmp_filename == NULL) str_append_str(p_str, p_filename_str); else { str_append_text(p_str, tmp_filename); vsf_sysutil_free(tmp_filename); } str_append_text(p_str, "\r\n"); }