From: Marcin Krol Date: Wed, 13 Apr 2016 07:18:44 +0000 (+0000) Subject: - from PLD, updated to 3.0.3 X-Git-Url: https://git.tld-linux.org/?p=packages%2Fvsftpd.git;a=commitdiff_plain;h=00e86632cc94d75ff41ec93baed71fe685016731 - from PLD, updated to 3.0.3 --- 00e86632cc94d75ff41ec93baed71fe685016731 diff --git a/vsftpd-amd64-findlibs.patch b/vsftpd-amd64-findlibs.patch new file mode 100644 index 0000000..67b22b4 --- /dev/null +++ b/vsftpd-amd64-findlibs.patch @@ -0,0 +1,10 @@ +--- vsftpd-2.3.1/vsf_findlibs.sh~ 2009-10-19 04:05:21.000000000 +0200 ++++ vsftpd-2.3.1/vsf_findlibs.sh 2010-09-15 10:09:12.543414001 +0200 +@@ -13,7 +13,6 @@ + # Look for PAM (done weirdly due to distribution bugs (e.g. Debian) or the + # crypt library. + if find_func pam_start sysdeputil.o; then +- locate_library /lib/libpam.so.0 && echo "/lib/libpam.so.0"; + locate_library /usr/lib/libpam.so && echo "-lpam"; + locate_library /usr/lib64/libpam.so && echo "-lpam"; + # HP-UX ends shared libraries with .sl diff --git a/vsftpd-builddefs.patch b/vsftpd-builddefs.patch new file mode 100644 index 0000000..d350880 --- /dev/null +++ b/vsftpd-builddefs.patch @@ -0,0 +1,14 @@ +--- vsftpd-2.0.0/builddefs.h.orig 2004-06-30 03:30:53.000000000 +0200 ++++ vsftpd-2.0.0/builddefs.h 2004-07-02 09:33:54.694621160 +0200 +@@ -1,9 +1,9 @@ + #ifndef VSF_BUILDDEFS_H + #define VSF_BUILDDEFS_H + +-#undef VSF_BUILD_TCPWRAPPERS ++#define VSF_BUILD_TCPWRAPPERS + #define VSF_BUILD_PAM +-#undef VSF_BUILD_SSL ++#define VSF_BUILD_SSL + + #endif /* VSF_BUILDDEFS_H */ + diff --git a/vsftpd-clamav.patch b/vsftpd-clamav.patch new file mode 100644 index 0000000..80cdbaa --- /dev/null +++ b/vsftpd-clamav.patch @@ -0,0 +1,662 @@ +Add support for scanning uploaded files with clamav. Not all features are +implemented (ex. file inclusion/exclusion for scanning). Every uploaded file is +saved in random named file, and moved to destination file after scanning. Side +effects: when uploaded *new* file was infected, 0-size file left. + +Written by Marek Marczykowski + +diff -Naru vsftpd-2.2.2.orig/Makefile vsftpd-2.2.2/Makefile +--- vsftpd-2.2.2.orig/Makefile 2009-05-22 21:44:52.000000000 +0200 ++++ vsftpd-2.2.2/Makefile 2010-04-29 19:46:54.435448038 +0200 +@@ -14,7 +14,7 @@ + banner.o filestr.o parseconf.o secutil.o \ + ascii.o oneprocess.o twoprocess.o privops.o standalone.o hash.o \ + tcpwrap.o ipaddrparse.o access.o features.o readwrite.o opts.o \ +- ssl.o sslslave.o ptracesandbox.o ftppolicy.o sysutil.o sysdeputil.o ++ ssl.o sslslave.o ptracesandbox.o ftppolicy.o sysutil.o sysdeputil.o clamav.o + + + .c.o: +diff -Naru vsftpd-2.2.2.orig/clamav.c vsftpd-2.2.2/clamav.c +--- vsftpd-2.2.2.orig/clamav.c 1970-01-01 01:00:00.000000000 +0100 ++++ vsftpd-2.2.2/clamav.c 2010-04-29 19:46:54.435448038 +0200 +@@ -0,0 +1,221 @@ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include "clamav.h" ++#include "tunables.h" ++#include "utility.h" ++#include "sysutil.h" ++#include "logging.h" ++#include "sysstr.h" ++ ++regex_t av_include_files_regex, av_exclude_files_regex; ++ ++int av_init() { ++ int ret; ++ ++ if (tunable_av_enable) { ++ if (tunable_av_include_files) { ++ if ((ret=regcomp(&av_include_files_regex, tunable_av_include_files, REG_NOSUB)) != 0) ++ die("regex compilation failed for AvIncludeFiles"); ++ } ++ if (tunable_av_exclude_files) { ++ if ((ret=regcomp(&av_exclude_files_regex, tunable_av_exclude_files, REG_NOSUB)) != 0) ++ die("regex compilation failed for AvExcludeFiles"); ++ } ++ } ++ return 0; ++} ++ ++int av_will_scan(const char *filename) { ++ if (!tunable_av_enable) ++ return 0; ++ if (tunable_av_include_files && (regexec(&av_include_files_regex, filename, 0, 0, 0)!=0)) ++ return 0; ++ if (tunable_av_exclude_files && (regexec(&av_exclude_files_regex, filename, 0, 0, 0)==0)) ++ return 0; ++ return 1; ++} ++ ++int av_init_scanner (struct vsf_session* p_sess) { ++ struct mystr debug_str = INIT_MYSTR; ++ ++ if (p_sess->clamd_sock < 0) { ++ ++ /* connect to clamd through local unix socket */ ++ if (tunable_av_clamd_socket) { ++ struct sockaddr_un server_local; ++ ++ vsf_sysutil_memclr((char*)&server_local, sizeof(server_local)); ++ ++ server_local.sun_family = AF_UNIX; ++ vsf_sysutil_strcpy(server_local.sun_path, tunable_av_clamd_socket, sizeof(server_local.sun_path)); ++ if ((p_sess->clamd_sock = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) { ++ str_alloc_text(&debug_str, "av: error opening unix socket"); ++ vsf_log_line(p_sess, kVSFLogEntryDebug, &debug_str); ++ p_sess->clamd_sock = -2; ++ return 0; ++ } ++ ++ if (connect(p_sess->clamd_sock, (struct sockaddr *)&server_local, sizeof(struct sockaddr_un)) < 0) { ++ str_alloc_text(&debug_str, "av: error connecting to clamd"); ++ vsf_log_line(p_sess, kVSFLogEntryDebug, &debug_str); ++ p_sess->clamd_sock = -2; ++ return 0; ++ } ++ ++ } else if (tunable_av_clamd_host) { ++ struct sockaddr_in server_inet; ++ struct hostent *he; ++ ++ vsf_sysutil_memclr((char*)&server_inet, sizeof(server_inet)); ++ ++ /* Remote Socket */ ++ server_inet.sin_family = AF_INET; ++ server_inet.sin_port = htons(tunable_av_clamd_port); ++ ++ if ((p_sess->clamd_sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) { ++ str_alloc_text(&debug_str, "av: error opening inet socket"); ++ vsf_log_line(p_sess, kVSFLogEntryDebug, &debug_str); ++ p_sess->clamd_sock = -2; ++ return 0; ++ } ++ ++ if ((he = gethostbyname(tunable_av_clamd_host)) == 0) { ++ str_alloc_text(&debug_str, "av: unable to locate clamd host"); ++ vsf_log_line(p_sess, kVSFLogEntryDebug, &debug_str); ++ vsf_sysutil_close_failok(p_sess->clamd_sock); ++ p_sess->clamd_sock = -2; ++ return 0; ++ } ++ ++ server_inet.sin_addr = *(struct in_addr *) he->h_addr_list[0]; ++ ++ if (connect(p_sess->clamd_sock, (struct sockaddr *)&server_inet, sizeof(struct sockaddr_in)) < 0) { ++ str_alloc_text(&debug_str, "av: error connecting to clamd host"); ++ vsf_log_line(p_sess, kVSFLogEntryDebug, &debug_str); ++ vsf_sysutil_close_failok(p_sess->clamd_sock); ++ p_sess->clamd_sock = -2; ++ return 0; ++ } ++ } ++ ++ if (vsf_sysutil_write(p_sess->clamd_sock, "nIDSESSION\n", 11) <= 0) { ++ str_alloc_text(&debug_str, "av: error starting clamd session"); ++ vsf_log_line(p_sess, kVSFLogEntryDebug, &debug_str); ++ vsf_sysutil_close_failok(p_sess->clamd_sock); ++ p_sess->clamd_sock = -2; ++ return 0; ++ } ++ } ++ ++ return 1; ++} ++ ++int av_scan_file(struct vsf_session* p_sess, struct mystr *filename, struct mystr *virname) { ++ struct mystr cwd = INIT_MYSTR; ++ struct mystr clamcmd = INIT_MYSTR; ++ struct mystr response = INIT_MYSTR; ++ char recv_buff[4096]; ++ int recv_count; ++ struct str_locate_result locate_res; ++ struct mystr debug_str = INIT_MYSTR; ++ int retry = 0; ++ ++init_scan: ++ if (av_init_scanner(p_sess)) { ++ ++ str_alloc_text(&clamcmd, "nSCAN "); ++ if (!str_isempty(&p_sess->chroot_str)) { ++ str_append_str(&clamcmd, &p_sess->chroot_str); ++ } ++ if (str_get_char_at(filename, 0) != '/') { ++ str_getcwd(&cwd); ++ str_append_str(&clamcmd, &cwd); ++ } ++ if (str_get_char_at(&clamcmd, str_getlen(&clamcmd) - 1) != '/') { ++ str_append_char(&clamcmd, '/'); ++ } ++ str_append_str(&clamcmd, filename); ++ str_append_char(&clamcmd, '\n'); ++ ++// sprintf(recv_buff, "sockfd: %d", p_sess->clamd_sock); ++// str_alloc_text(&debug_str, recv_buff); ++// vsf_log_line(p_sess, kVSFLogEntryDebug, &p_sess->chroot_str); ++// vsf_log_line(p_sess, kVSFLogEntryDebug, &clamcmd); ++ ++ if (vsf_sysutil_write(p_sess->clamd_sock, str_getbuf(&clamcmd), str_getlen(&clamcmd)) <= 0) { ++ str_alloc_text(&debug_str, "av: failed to scan file"); ++ vsf_log_line(p_sess, kVSFLogEntryDebug, &debug_str); ++ vsf_sysutil_close_failok(p_sess->clamd_sock); ++ p_sess->clamd_sock = -2; ++ return 2; ++ } ++ ++ str_free(&clamcmd); ++ ++ /* receive and interpret answer */ ++ while ((recv_count=vsf_sysutil_read(p_sess->clamd_sock, recv_buff, 4095)) > 0) { ++ recv_buff[recv_count]=0; ++ str_append_text(&response, recv_buff); ++ if (recv_buff[recv_count-1] == '\n') ++ break; ++ } ++ if (recv_count < 0 || str_getlen(&response) == 0) { ++ if (!retry) { ++ retry = 1; ++ vsf_sysutil_close_failok(p_sess->clamd_sock); ++ p_sess->clamd_sock = -2; ++ goto init_scan; ++ } else { ++ str_alloc_text(&debug_str, "av: failed to scan file (read failed)"); ++ vsf_log_line(p_sess, kVSFLogEntryDebug, &debug_str); ++ vsf_sysutil_close(p_sess->clamd_sock); ++ p_sess->clamd_sock = -2; ++ return 2; ++ } ++ } ++ ++ if (str_equal_text(&response, "COMMAND READ TIMED OUT\n")) { ++ if (!retry) { ++ retry = 1; ++ vsf_sysutil_close_failok(p_sess->clamd_sock); ++ p_sess->clamd_sock = -2; ++ goto init_scan; ++ } else { ++ str_alloc_text(&debug_str, "av: got: "); ++ str_append_str(&debug_str, &response); ++ vsf_log_line(p_sess, kVSFLogEntryDebug, &debug_str); ++ return 2; ++ } ++ } ++ ++ ++ ++ locate_res = str_locate_text(&response, " FOUND\n"); ++ /* virus found */ ++ if (locate_res.found) { ++ str_trunc(&response, locate_res.index); ++ str_split_text_reverse(&response, virname, ": "); ++ return 1; ++ } ++ locate_res = str_locate_text(&response, " ERROR\n"); ++ if (locate_res.found) { ++ str_alloc_text(&debug_str, "av: got: "); ++ str_append_str(&debug_str, &response); ++ vsf_log_line(p_sess, kVSFLogEntryDebug, &debug_str); ++ return 2; ++ } ++ return 0; ++ } ++ ++ return 2; ++} ++ ++ ++ ++ +diff -Naru vsftpd-2.2.2.orig/clamav.h vsftpd-2.2.2/clamav.h +--- vsftpd-2.2.2.orig/clamav.h 1970-01-01 01:00:00.000000000 +0100 ++++ vsftpd-2.2.2/clamav.h 2010-04-29 19:46:54.435448038 +0200 +@@ -0,0 +1,12 @@ ++#ifndef _CLAMAV_H ++#define _CLAMAV_H ++ ++#include "str.h" ++#include "session.h" ++ ++extern int av_init(); ++extern int av_will_scan(const char *filename); ++extern int av_init_scanner (struct vsf_session* p_sess); ++extern int av_scan_file(struct vsf_session* p_sess, struct mystr *filename, struct mystr *virname); ++ ++#endif +diff -Naru vsftpd-2.2.2.orig/main.c vsftpd-2.2.2/main.c +--- vsftpd-2.2.2.orig/main.c 2009-07-18 07:55:53.000000000 +0200 ++++ vsftpd-2.2.2/main.c 2010-04-29 19:46:54.435448038 +0200 +@@ -64,7 +64,9 @@ + /* Secure connection state */ + 0, 0, 0, 0, 0, INIT_MYSTR, 0, -1, -1, + /* Login fails */ +- 0 ++ 0, ++ /* av */ ++ -1, INIT_MYSTR + }; + int config_loaded = 0; + int i; +diff -Naru vsftpd-2.2.2.orig/parseconf.c vsftpd-2.2.2/parseconf.c +--- vsftpd-2.2.2.orig/parseconf.c 2009-08-07 20:46:40.000000000 +0200 ++++ vsftpd-2.2.2/parseconf.c 2010-04-29 19:46:54.435448038 +0200 +@@ -100,6 +100,7 @@ + { "delete_failed_uploads", &tunable_delete_failed_uploads }, + { "implicit_ssl", &tunable_implicit_ssl }, + { "sandbox", &tunable_sandbox }, ++ { "av_enable", &tunable_av_enable }, + { "require_ssl_reuse", &tunable_require_ssl_reuse }, + { "isolate", &tunable_isolate }, + { "isolate_network", &tunable_isolate_network }, +@@ -133,6 +134,7 @@ + { "delay_successful_login", &tunable_delay_successful_login }, + { "max_login_fails", &tunable_max_login_fails }, + { "chown_upload_mode", &tunable_chown_upload_mode }, ++ { "av_clamd_port", &tunable_av_clamd_port }, + { 0, 0 } + }; + +@@ -175,6 +177,10 @@ + { "dsa_private_key_file", &tunable_dsa_private_key_file }, + { "ca_certs_file", &tunable_ca_certs_file }, + { "cmds_denied", &tunable_cmds_denied }, ++ { "av_clamd_socket", &tunable_av_clamd_socket }, ++ { "av_clamd_host", &tunable_av_clamd_host }, ++ { "av_include_files", &tunable_av_include_files }, ++ { "av_exclude_files", &tunable_av_exclude_files }, + { 0, 0 } + }; + +diff -Naru vsftpd-2.2.2.orig/postlogin.c vsftpd-2.2.2/postlogin.c +--- vsftpd-2.2.2.orig/postlogin.c 2009-11-07 05:55:12.000000000 +0100 ++++ vsftpd-2.2.2/postlogin.c 2010-04-29 19:46:54.438781445 +0200 +@@ -27,6 +27,7 @@ + #include "ssl.h" + #include "vsftpver.h" + #include "opts.h" ++#include "clamav.h" + + /* Private local functions */ + static void handle_pwd(struct vsf_session* p_sess); +@@ -972,12 +973,15 @@ + static struct vsf_sysutil_statbuf* s_p_statbuf; + static struct mystr s_filename; + struct mystr* p_filename; ++ struct mystr tmp_filename = INIT_MYSTR; + struct vsf_transfer_ret trans_ret; + int new_file_fd; ++ int av_orig_file_fd = -1; + int remote_fd; + int success = 0; + int created = 0; + int do_truncate = 0; ++ int do_av = 0; + filesize_t offset = p_sess->restart_pos; + p_sess->restart_pos = 0; + if (!data_transfer_checks_ok(p_sess)) +@@ -991,6 +995,7 @@ + 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); +@@ -1022,6 +1027,24 @@ + return; + } + created = 1; ++ ++ if (av_will_scan(str_getbuf(p_filename))) { ++ do_av = 1; ++ str_copy(&tmp_filename, p_filename); ++ str_append_text(&tmp_filename, ".XXXXXX"); ++ av_orig_file_fd = new_file_fd; ++ /* FIXME: various permissions issues... ex. writable file in non-writable directory */ ++ new_file_fd = mkstemp(str_getbuf(&tmp_filename)); ++ if (vsf_sysutil_retval_is_error(new_file_fd)) ++ { ++ vsf_sysutil_close(av_orig_file_fd); ++ vsf_cmdio_write(p_sess, FTP_UPLOADFAIL, "Could not create temp file."); ++ return; ++ } ++ /* mkstemp creates file with 0600 */ ++ vsf_sysutil_fchmod(new_file_fd, 0666 &(~vsf_sysutil_get_umask())); ++ } ++ + vsf_sysutil_fstat(new_file_fd, &s_p_statbuf); + if (vsf_sysutil_statbuf_is_regfile(s_p_statbuf)) + { +@@ -1047,6 +1070,8 @@ + if (tunable_lock_upload_files) + { + vsf_sysutil_lock_file_write(new_file_fd); ++ if (do_av) ++ vsf_sysutil_lock_file_write(av_orig_file_fd); + } + /* Must truncate the file AFTER locking it! */ + if (do_truncate) +@@ -1054,6 +1079,22 @@ + vsf_sysutil_ftruncate(new_file_fd); + vsf_sysutil_lseek_to(new_file_fd, 0); + } ++ if (do_av && (is_append || offset != 0)) { ++ char buf[4096]; ++ int count; ++ ++ /* copy original file */ ++ vsf_sysutil_lseek_to(av_orig_file_fd, 0); ++ while ((count=vsf_sysutil_read(av_orig_file_fd, buf, 4096)) > 0) { ++ if (vsf_sysutil_write_loop(new_file_fd, buf, count) < 0) { ++ vsf_cmdio_write(p_sess, FTP_UPLOADFAIL, "Could not copy temp file."); ++ vsf_sysutil_close(new_file_fd); ++ vsf_sysutil_close(av_orig_file_fd); ++ vsf_sysutil_unlink(str_getbuf(&tmp_filename)); ++ return; ++ } ++ } ++ } + if (!is_append && offset != 0) + { + /* XXX - warning, allows seek past end of file! Check for seek > size? */ +@@ -1077,6 +1118,7 @@ + } + if (vsf_sysutil_retval_is_error(remote_fd)) + { ++ vsf_sysutil_unlink(str_getbuf(&tmp_filename)); + goto port_pasv_cleanup_out; + } + if (tunable_ascii_upload_enable && p_sess->is_ascii) +@@ -1097,7 +1139,6 @@ + if (trans_ret.retval == 0) + { + success = 1; +- vsf_log_do_log(p_sess, 1); + } + if (trans_ret.retval == -1) + { +@@ -1109,7 +1150,43 @@ + } + else + { +- vsf_cmdio_write(p_sess, FTP_TRANSFEROK, "Transfer complete."); ++ if (do_av) { ++ struct mystr virname = INIT_MYSTR; ++ struct mystr resp_str = INIT_MYSTR; ++ ++ switch (av_scan_file(p_sess, &tmp_filename, &virname)) { ++ case 1: ++ str_alloc_text(&resp_str, "Virus found: "); ++ str_append_str(&resp_str, &virname); ++ vsf_log_line(p_sess, kVSFLogEntryUpload, &resp_str); ++ vsf_cmdio_write(p_sess, FTP_UPLOADFAIL, str_getbuf(&resp_str)); ++ str_free(&resp_str); ++ ++ str_unlink(&tmp_filename); ++ break; ++ case 2: ++ vsf_cmdio_write(p_sess, FTP_BADSENDFILE, "Failure scanning file."); ++ str_unlink(&tmp_filename); ++ break; ++ default: ++ /* FIXME: race condition */ ++ if (vsf_sysutil_rename(str_getbuf(&tmp_filename), str_getbuf(p_filename)) < 0) { ++ vsf_cmdio_write(p_sess, FTP_BADSENDFILE, "Failure writing to local file ."); ++ str_unlink(&tmp_filename); ++ } ++ else ++ { ++ vsf_log_do_log(p_sess, 1); ++ vsf_cmdio_write(p_sess, FTP_TRANSFEROK, "File receive OK."); ++ } ++ break; ++ } ++ } ++ else ++ { ++ vsf_log_do_log(p_sess, 1); ++ vsf_cmdio_write(p_sess, FTP_TRANSFEROK, "File receive OK."); ++ } + } + check_abor(p_sess); + port_pasv_cleanup_out: +@@ -1117,9 +1194,15 @@ + pasv_cleanup(p_sess); + if (tunable_delete_failed_uploads && created && !success) + { +- str_unlink(p_filename); ++ if (do_av) { ++ str_unlink(&tmp_filename); ++ } else { ++ str_unlink(p_filename); ++ } + } + vsf_sysutil_close(new_file_fd); ++ if (do_av) ++ vsf_sysutil_close(av_orig_file_fd); + } + + static void +@@ -1898,3 +1981,5 @@ + { + vsf_cmdio_write(p_sess, FTP_LOGINOK, "Already logged in."); + } ++ ++// vim: sw=2: +diff -Naru vsftpd-2.2.2.orig/secutil.c vsftpd-2.2.2/secutil.c +--- vsftpd-2.2.2.orig/secutil.c 2009-05-27 08:20:36.000000000 +0200 ++++ vsftpd-2.2.2/secutil.c 2010-04-29 19:46:54.438781445 +0200 +@@ -34,6 +34,7 @@ + if (p_dir_str == 0 || str_isempty(p_dir_str)) + { + str_alloc_text(&dir_str, vsf_sysutil_user_get_homedir(p_user)); ++ str_copy(p_dir_str, &dir_str); + } + else + { +diff -Naru vsftpd-2.2.2.orig/session.h vsftpd-2.2.2/session.h +--- vsftpd-2.2.2.orig/session.h 2008-02-12 03:39:38.000000000 +0100 ++++ vsftpd-2.2.2/session.h 2010-04-29 19:46:54.438781445 +0200 +@@ -93,6 +93,10 @@ + int ssl_slave_fd; + int ssl_consumer_fd; + unsigned int login_fails; ++ ++ /* data for av scanner */ ++ int clamd_sock; ++ struct mystr chroot_str; + }; + + #endif /* VSF_SESSION_H */ +diff -Naru vsftpd-2.2.2.orig/tunables.c vsftpd-2.2.2/tunables.c +--- vsftpd-2.2.2.orig/tunables.c 2009-07-15 22:08:27.000000000 +0200 ++++ vsftpd-2.2.2/tunables.c 2010-04-29 19:48:44.265437093 +0200 +@@ -85,6 +85,8 @@ + int tunable_isolate; + int tunable_isolate_network; + ++int tunable_av_enable; ++ + unsigned int tunable_accept_timeout; + unsigned int tunable_connect_timeout; + unsigned int tunable_local_umask; +@@ -105,6 +107,7 @@ + unsigned int tunable_delay_successful_login; + unsigned int tunable_max_login_fails; + unsigned int tunable_chown_upload_mode; ++unsigned int tunable_av_clamd_port; + + const char* tunable_secure_chroot_dir; + const char* tunable_ftp_username; +@@ -139,6 +142,11 @@ + const char* tunable_dsa_private_key_file; + const char* tunable_ca_certs_file; + ++const char* tunable_av_clamd_socket; ++const char* tunable_av_clamd_host; ++const char* tunable_av_include_files; ++const char* tunable_av_exclude_files; ++ + static void install_str_setting(const char* p_value, const char** p_storage); + + void +@@ -219,9 +227,10 @@ + tunable_sandbox = 0; + tunable_require_ssl_reuse = 1; + tunable_isolate = 1; +- tunable_isolate_network = 1; ++ tunable_isolate_network = 0; + tunable_ftp_enable = 1; + tunable_http_enable = 0; ++ tunable_av_enable = 0; + + tunable_accept_timeout = 60; + tunable_connect_timeout = 60; +@@ -245,6 +254,7 @@ + tunable_max_login_fails = 3; + /* -rw------- */ + tunable_chown_upload_mode = 0600; ++ tunable_av_clamd_port = 3310; + + install_str_setting("/usr/share/empty", &tunable_secure_chroot_dir); + install_str_setting("ftp", &tunable_ftp_username); +@@ -280,6 +290,11 @@ + install_str_setting(0, &tunable_rsa_private_key_file); + install_str_setting(0, &tunable_dsa_private_key_file); + install_str_setting(0, &tunable_ca_certs_file); ++ ++ install_str_setting(0, &tunable_av_clamd_socket); ++ install_str_setting("127.0.0.1", &tunable_av_clamd_host); ++ install_str_setting(0, &tunable_av_include_files); ++ install_str_setting(0, &tunable_av_exclude_files); + } + + void +diff -Naru vsftpd-2.2.2.orig/tunables.h vsftpd-2.2.2/tunables.h +--- vsftpd-2.2.2.orig/tunables.h 2009-07-07 03:37:28.000000000 +0200 ++++ vsftpd-2.2.2/tunables.h 2010-04-29 19:46:54.438781445 +0200 +@@ -83,6 +83,7 @@ + extern int tunable_implicit_ssl; /* Use implicit SSL protocol */ + extern int tunable_sandbox; /* Deploy ptrace sandbox */ + extern int tunable_require_ssl_reuse; /* Require re-used data conn */ ++extern int tunable_av_enable; /* Scan av incomming files */ + extern int tunable_isolate; /* Use container clone() flags */ + extern int tunable_isolate_network; /* Use CLONE_NEWNET */ + +@@ -107,6 +108,7 @@ + extern unsigned int tunable_delay_successful_login; + extern unsigned int tunable_max_login_fails; + extern unsigned int tunable_chown_upload_mode; ++extern unsigned int tunable_av_clamd_port; + + /* String defines */ + extern const char* tunable_secure_chroot_dir; +@@ -141,6 +143,10 @@ + extern const char* tunable_dsa_private_key_file; + extern const char* tunable_ca_certs_file; + extern const char* tunable_cmds_denied; ++extern const char* tunable_av_clamd_socket; ++extern const char* tunable_av_clamd_host; ++extern const char* tunable_av_include_files; ++extern const char* tunable_av_exclude_files; + + #endif /* VSF_TUNABLES_H */ + +diff -Naru vsftpd-2.2.2.orig/twoprocess.c vsftpd-2.2.2/twoprocess.c +--- vsftpd-2.2.2.orig/twoprocess.c 2009-07-18 07:56:44.000000000 +0200 ++++ vsftpd-2.2.2/twoprocess.c 2010-04-29 19:46:54.438781445 +0200 +@@ -428,6 +428,13 @@ + p_user_str, p_orig_user_str); + vsf_secutil_change_credentials(p_user_str, &userdir_str, &chroot_str, + 0, secutil_option); ++ ++ if (do_chroot) { ++ str_copy(&p_sess->chroot_str, &userdir_str); ++ } else { ++ str_empty(&p_sess->chroot_str); ++ } ++ + if (!str_isempty(&chdir_str)) + { + (void) str_chdir(&chdir_str); +diff -Naru vsftpd-2.2.2.orig/vsftpd.conf.5 vsftpd-2.2.2/vsftpd.conf.5 +--- vsftpd-2.2.2.orig/vsftpd.conf.5 2009-10-19 04:46:30.000000000 +0200 ++++ vsftpd-2.2.2/vsftpd.conf.5 2010-04-29 19:46:54.438781445 +0200 +@@ -105,6 +105,11 @@ + + Default: NO + .TP ++.B av_enable ++If enabled, all uploaded files are scanned with clamav (through clamd). ++ ++Default: NO ++.TP + .B background + When enabled, and vsftpd is started in "listen" mode, vsftpd will background + the listener process. i.e. control will immediately be returned to the shell +@@ -643,6 +648,11 @@ + + Default: 077 + .TP ++.B av_clamd_port ++Port number where clamd listen on. ++ ++Default: 3310 ++.TP + .B chown_upload_mode + The file mode to force for chown()ed anonymous uploads. (Added in v2.0.6). + +@@ -758,6 +768,18 @@ + + Default: (none) + .TP ++.B av_clamd_host ++IP where clamd listen. It must be on the same host (or have access to same ++filesystem). ++ ++Default: 127.0.0.1 ++.TP ++.B av_clamd_socket ++UNIX socket of clamd. Warning: When using chroot you should use TCP instead of ++UNIX socket. ++ ++Default: (none) ++.TP + .B banned_email_file + This option is the name of a file containing a list of anonymous e-mail + passwords which are not permitted. This file is consulted if the option diff --git a/vsftpd-findlibs-egrep.patch b/vsftpd-findlibs-egrep.patch new file mode 100644 index 0000000..6167406 --- /dev/null +++ b/vsftpd-findlibs-egrep.patch @@ -0,0 +1,11 @@ +--- vsftpd-3.0.2/vsf_findlibs.sh.orig 2014-04-11 12:18:03.231578533 +0200 ++++ vsftpd-3.0.2/vsf_findlibs.sh 2014-04-11 12:19:03.988273239 +0200 +@@ -2,7 +2,7 @@ + # Cheesy hacky location of additional link libraries. + + locate_library() { [ ! "$1*" = "`echo $1*`" ]; } +-find_func() { egrep $1 $2 >/dev/null; } ++find_func() { egrep -qa $1 $2; } + + if find_func hosts_access tcpwrap.o; then + echo "-lwrap"; diff --git a/vsftpd-ftpusers b/vsftpd-ftpusers new file mode 100644 index 0000000..856df2f --- /dev/null +++ b/vsftpd-ftpusers @@ -0,0 +1,14 @@ +root +bin +daemon +adm +lp +sync +shutdown +halt +mail +news +uucp +operator +games +nobody diff --git a/vsftpd-switch_sha256_to_sha1.patch b/vsftpd-switch_sha256_to_sha1.patch new file mode 100644 index 0000000..c9dddfa --- /dev/null +++ b/vsftpd-switch_sha256_to_sha1.patch @@ -0,0 +1,11 @@ +--- ./ssl.c.org 2009-10-19 04:34:08.000000000 +0200 ++++ ./ssl.c 2010-12-28 17:33:27.730241842 +0100 +@@ -608,7 +608,7 @@ ssl_cert_digest(SSL* p_ssl, struct vsf_s + str_reserve(p_str, EVP_MAX_MD_SIZE); + str_empty(p_str); + str_rpad(p_str, EVP_MAX_MD_SIZE); +- if (!X509_digest(p_cert, EVP_sha256(), (unsigned char*) str_getbuf(p_str), ++ if (!X509_digest(p_cert, EVP_sha1(), (unsigned char*) str_getbuf(p_str), + &num_bytes)) + { + die("X509_digest failed"); diff --git a/vsftpd-use-evp_sha1.patch b/vsftpd-use-evp_sha1.patch new file mode 100644 index 0000000..b76cb31 --- /dev/null +++ b/vsftpd-use-evp_sha1.patch @@ -0,0 +1,11 @@ +--- vsftpd-2.1.0/ssl.c~ 2009-01-09 21:47:05.000000000 +0100 ++++ vsftpd-2.1.0/ssl.c 2010-06-03 11:28:01.145540532 +0200 +@@ -593,7 +593,7 @@ + str_reserve(p_str, EVP_MAX_MD_SIZE); + str_empty(p_str); + str_rpad(p_str, EVP_MAX_MD_SIZE); +- if (!X509_digest(p_cert, EVP_sha256(), (unsigned char*) str_getbuf(p_str), ++ if (!X509_digest(p_cert, EVP_sha1(), (unsigned char*) str_getbuf(p_str), + &num_bytes)) + { + die("X509_digest failed"); diff --git a/vsftpd.inetd b/vsftpd.inetd new file mode 100644 index 0000000..5a4b76b --- /dev/null +++ b/vsftpd.inetd @@ -0,0 +1,10 @@ +SERVICE_NAME=ftp +SOCK_TYPE=stream +PROTOCOL=tcp +PORT=21 +FLAGS=nowait +USER=root +SERVER=tcpd +DAEMON=/usr/sbin/vsftpd +DAEMONARGS="-olisten=NO" +NICE=10 diff --git a/vsftpd.init b/vsftpd.init new file mode 100644 index 0000000..811b710 --- /dev/null +++ b/vsftpd.init @@ -0,0 +1,74 @@ +#!/bin/sh +# +# vsftpd vsftp server +# +# chkconfig: 345 85 15 +# description: VSFTPD is a Very Secure FTP Daemon +# + +# Source function library +. /etc/rc.d/init.d/functions + +# Get network config +. /etc/sysconfig/network + +# Check that networking is up. +if is_yes "${NETWORKING}"; then + if [ ! -f /var/lock/subsys/network -a "$1" != stop -a "$1" != status ]; then + msg_network_down vsftpd + exit 1 + fi +else + exit 0 +fi + +start() { + # Check if the service is already running? + if [ ! -f /var/lock/subsys/vsftpd ]; then + # Check if we have 'Listen=yes' in config + if ! egrep -q '^(listen|listen_ipv6)=([Yy][Ee][Ss]|[Tt][Rr][Uu][Ee]|1)' /etc/vsftpd.conf; then + echo "error: Missing 'listen=yes' or 'listen_ipv6=yes' directive in /etc/vsftpd.conf!" + exit 1 + fi; + # try to load capability module + _modprobe capability + msg_starting vsftpd + daemon --fork /usr/sbin/vsftpd + RETVAL=$? + [ $RETVAL -eq 0 ] && touch /var/lock/subsys/vsftpd + else + msg_already_running vsftpd + fi +} + +stop() { + # Stop daemons. + if [ -f /var/lock/subsys/vsftpd ]; then + msg_stopping vsftpd + killproc vsftpd + rm -f /var/lock/subsys/vsftpd > /dev/null 2>&1 + else + msg_not_running vsftpd + fi +} + +RETVAL=0 +# See how we were called. +case "$1" in + start) + start + ;; + stop) + stop + ;; + restart|force-reload) + stop + start + ;; + *) + msg_usage "$0 {start|stop|restart|force-reload}" + exit 3 + ;; +esac + +exit $RETVAL diff --git a/vsftpd.pamd b/vsftpd.pamd new file mode 100644 index 0000000..3aeb5ca --- /dev/null +++ b/vsftpd.pamd @@ -0,0 +1,6 @@ +#%PAM-1.0 +auth required pam_listfile.so item=user sense=deny file=/etc/ftpd/ftpusers onerr=succeed +auth include system-auth +account required pam_nologin.so +account include system-auth +session include system-auth diff --git a/vsftpd.spec b/vsftpd.spec new file mode 100644 index 0000000..c07f354 --- /dev/null +++ b/vsftpd.spec @@ -0,0 +1,194 @@ +# TODO: +# - default config does not work with inetd configuration +# +# Conditional build: +%bcond_with clamav # ClamAV scanning support + +%define _ftpdir /home/services/ftp +Summary: vsftpd - Very Secure FTP Daemon +Summary(pl.UTF-8): Bardzo Bezpieczny Demon FTP +Summary(pt_BR.UTF-8): vsftpd - Daemon FTP Muito Seguro +Name: vsftpd +Version: 3.0.3 +Release: 1 +License: GPL v2 +Group: Daemons +Source0: https://security.appspot.com/downloads/%{name}-%{version}.tar.gz +# Source0-md5: da119d084bd3f98664636ea05b5bb398 +Source1: %{name}.inetd +Source2: %{name}.pamd +Source3: %{name}-ftpusers +Source4: ftpusers.tar.bz2 +# Source4-md5: 76c80b6ec9f4d079a1e27316edddbe16 +Source5: %{name}.init +Patch0: %{name}-builddefs.patch +Patch1: %{name}-amd64-findlibs.patch +Patch2: %{name}-clamav.patch +Patch3: %{name}-switch_sha256_to_sha1.patch +Patch4: %{name}-findlibs-egrep.patch +URL: https://security.appspot.com/vsftpd.html +BuildRequires: libcap-devel +BuildRequires: libwrap-devel +%if "%{pld_release}" == "ac" +BuildRequires: openssl-devel >= 0.9.7d +%else +BuildRequires: openssl-devel >= 0.9.8 +%endif +BuildRequires: rpmbuild(macros) >= 1.268 +Requires: %{name}-init = %{version}-%{release} +Requires: filesystem >= 3.0-11 +Requires: pam >= 0.77.3 +Provides: ftpserver +Conflicts: man-pages < 1.51 +BuildRoot: %{tmpdir}/%{name}-%{version}-root-%(id -u -n) + +%define specflags -fpie -pipe -Wextra -Werror + +%description +A Very Secure FTP Daemon - written from scratch - by Chris "One Man +Security Audit Team" Evans. + +%description -l pl.UTF-8 +Bardzo Bezpieczny Demon FTP - napisany od zera przez Chrisa "One Man +Security Audit Team" Evansa. + +%description -l pt_BR.UTF-8 +A Very Secure FTP Daemon (vsftpd) - escrito do zero - por Chris "One +Man Security Audit Team" Evans. + +%package inetd +Summary: vsftpd - Very Secure FTP Daemon +Summary(pl.UTF-8): Bardzo Bezpieczny Demon FTP +Summary(pt_BR.UTF-8): vsftpd - Daemon FTP Muito Seguro +Group: Networking/Daemons +Requires: %{name} = %{version}-%{release} +Requires: rc-inetd +Provides: %{name}-init = %{version}-%{release} +Obsoletes: vsftpd-standalone +Conflicts: %{name} <= 2.0.3-1 + +%description inetd +This package allows to start vsftpd as inetd service. + +%description inetd -l pl.UTF-8 +Ten pakiet pozwala na wystartowanie vsftpd jako usługi inetd. + +%package standalone +Summary: vsftpd - Very Secure FTP Daemon +Summary(pl.UTF-8): Bardzo Bezpieczny Demon FTP +Summary(pt_BR.UTF-8): vsftpd - Daemon FTP Muito Seguro +Group: Networking/Daemons +Requires(post,preun): /sbin/chkconfig +Requires: %{name} = %{version}-%{release} +Requires: rc-scripts +Provides: %{name}-init = %{version}-%{release} +Obsoletes: vsftpd-inetd +Conflicts: %{name} <= 2.0.3-1 + +%description standalone +This package allows to start vsftpd as standalone daemon. + +%description standalone -l pl.UTF-8 +Ten pakiet pozwala na wystartowanie vsftpd jako samodzielnego demona. + +%prep +%setup -q +%patch0 -p1 +%patch1 -p1 +%if %{with clamav} +%patch2 -p1 +%endif +%if "%{pld_release}" == "ac" +%patch3 -p1 +%endif +%patch4 -p1 + +%build +%{__make} \ + CC="%{__cc}" \ + CFLAGS="%{rpmcflags}" \ + LIBS="-lwrap -lpam -lcap -lssl -lcrypto" \ + LINK="%{rpmldflags}" + +%install +rm -rf $RPM_BUILD_ROOT +install -d $RPM_BUILD_ROOT{%{_sbindir},%{_mandir}/man{5,8}} \ + $RPM_BUILD_ROOT/etc/{pam.d,sysconfig/rc-inetd,logrotate.d,ftpd,rc.d/init.d} \ + $RPM_BUILD_ROOT{%{_ftpdir}/pub/incoming,/var/log} + +install -p vsftpd $RPM_BUILD_ROOT%{_sbindir}/vsftpd +cp -p vsftpd.conf $RPM_BUILD_ROOT%{_sysconfdir}/vsftpd.conf +cp -p vsftpd.conf.5 $RPM_BUILD_ROOT%{_mandir}/man5/vsftpd.conf.5 +cp -p vsftpd.8 $RPM_BUILD_ROOT%{_mandir}/man8/vsftpd.8 +cp -p RedHat/vsftpd.log $RPM_BUILD_ROOT/etc/logrotate.d/vsftpd + +install -p %{SOURCE1} $RPM_BUILD_ROOT/etc/sysconfig/rc-inetd/vsftpd +cp -p %{SOURCE2} $RPM_BUILD_ROOT/etc/pam.d/ftp +cp -p %{SOURCE3} $RPM_BUILD_ROOT%{_sysconfdir}/ftpd/ftpusers +install -p %{SOURCE5} $RPM_BUILD_ROOT/etc/rc.d/init.d/vsftpd + +> $RPM_BUILD_ROOT/var/log/vsftpd.log + +bzip2 -dc %{SOURCE4} | tar xf - -C $RPM_BUILD_ROOT%{_mandir} +%{__rm} $RPM_BUILD_ROOT%{_mandir}/ftpusers-path.diff + +%clean +rm -rf $RPM_BUILD_ROOT + +%post +touch /var/log/vsftpd.log +chmod 640 /var/log/vsftpd.log + +%post inetd +%service -q rc-inetd reload + +%postun inetd +if [ "$1" = "0" ]; then + %service -q rc-inetd reload +fi + +%post standalone +/sbin/chkconfig --add %{name} +%service vsftpd restart "vsftpd server" + +%preun standalone +if [ "$1" = "0" ]; then + %service vsftpd stop + /sbin/chkconfig --del %{name} +fi + +%triggerin standalone -- glibc +# restart vsftpd if glibc is upgraded or downgraded +if [ "$2" != 1 ]; then + %service -q vsftpd restart +fi + +%files +%defattr(644,root,root,755) +%doc AUDIT BENCHMARKS BUGS Changelog FAQ README README.ssl REWARD SIZE SPEED TODO TUNING EXAMPLE SECURITY +%attr(755,root,root) %{_sbindir}/vsftpd +%dir %attr(750,root,ftp) %dir %{_sysconfdir}/ftpd +%attr(640,root,root) %config(noreplace) %verify(not md5 mtime size) %{_sysconfdir}/vsftpd.conf +%attr(640,root,root) %config(noreplace) %verify(not md5 mtime size) %{_sysconfdir}/ftpd/ftpusers +%attr(640,root,root) %config(noreplace) %verify(not md5 mtime size) /etc/pam.d/ftp +%attr(640,root,root) %config(noreplace) %verify(not md5 mtime size) /etc/logrotate.d/vsftpd +%attr(640,root,root) %ghost /var/log/vsftpd.log +%{_mandir}/man5/vsftpd.conf.5* +%{_mandir}/man8/vsftpd.8* +%{_mandir}/man5/ftpusers.5* +%lang(ja) %{_mandir}/ja/man5/ftpusers* +%lang(pl) %{_mandir}/pl/man5/ftpusers* +%lang(pt_BR) %{_mandir}/pt_BR/man5/ftpusers* +%lang(ru) %{_mandir}/ru/man5/ftpusers* +%dir %{_ftpdir} +%dir %{_ftpdir}/pub +# it's safe - by default anon_upload_enable=NO, anon_world_readable_only=YES +%attr(775,root,ftp) %dir %{_ftpdir}/pub/incoming + +%files inetd +%defattr(644,root,root,755) +%attr(640,root,root) %config(noreplace) %verify(not md5 mtime size) /etc/sysconfig/rc-inetd/vsftpd + +%files standalone +%defattr(644,root,root,755) +%attr(754,root,root) /etc/rc.d/init.d/vsftpd