From 72b11624b38bc9cfa9d3cfd626b4843dc1cf54c7 Mon Sep 17 00:00:00 2001 From: Jiri Skala Date: Wed, 18 Jun 2014 14:05:28 +0200 Subject: [PATCH] - improves DH cipher - implements ECDH cipher - adds isolate* options to man vsftpd.conf - corrects max_clients, max_per_ip default values in man vsftd.conf - adds return code 450 when a file is temporarily unavailable --- vsftpd-3.0.2-dh.patch | 209 +++++++++++++++++++++++++++----------- vsftpd-3.0.2-docupd.patch | 48 +++++++++ vsftpd-3.0.2-ecdh.patch | 113 +++++++++++++++++++++ vsftpd-3.0.2-rc450.patch | 56 ++++++++++ vsftpd.spec | 15 ++- 5 files changed, 378 insertions(+), 63 deletions(-) create mode 100644 vsftpd-3.0.2-docupd.patch create mode 100644 vsftpd-3.0.2-ecdh.patch create mode 100644 vsftpd-3.0.2-rc450.patch diff --git a/vsftpd-3.0.2-dh.patch b/vsftpd-3.0.2-dh.patch index 17639a9..10feef3 100644 --- a/vsftpd-3.0.2-dh.patch +++ b/vsftpd-3.0.2-dh.patch @@ -1,6 +1,17 @@ +diff -up vsftpd-3.0.2/parseconf.c.dh vsftpd-3.0.2/parseconf.c +--- vsftpd-3.0.2/parseconf.c.dh 2014-06-04 09:54:43.364747051 +0200 ++++ vsftpd-3.0.2/parseconf.c 2014-06-04 09:54:43.368747052 +0200 +@@ -176,6 +176,7 @@ parseconf_str_array[] = + { "email_password_file", &tunable_email_password_file }, + { "rsa_cert_file", &tunable_rsa_cert_file }, + { "dsa_cert_file", &tunable_dsa_cert_file }, ++ { "dh_param_file", &tunable_dh_param_file }, + { "ssl_ciphers", &tunable_ssl_ciphers }, + { "rsa_private_key_file", &tunable_rsa_private_key_file }, + { "dsa_private_key_file", &tunable_dsa_private_key_file }, diff -up vsftpd-3.0.2/ssl.c.dh vsftpd-3.0.2/ssl.c --- vsftpd-3.0.2/ssl.c.dh 2012-04-03 02:23:42.000000000 +0200 -+++ vsftpd-3.0.2/ssl.c 2014-05-13 12:36:26.790953361 +0200 ++++ vsftpd-3.0.2/ssl.c 2014-06-04 09:55:59.443770325 +0200 @@ -28,6 +28,8 @@ #include #include @@ -18,44 +29,103 @@ diff -up vsftpd-3.0.2/ssl.c.dh vsftpd-3.0.2/ssl.c static int ssl_cert_digest( SSL* p_ssl, struct vsf_session* p_sess, struct mystr* p_str); static void maybe_log_shutdown_state(struct vsf_session* p_sess); -@@ -51,6 +54,36 @@ static int ssl_read_common(struct vsf_se +@@ -51,6 +54,60 @@ static int ssl_read_common(struct vsf_se static int ssl_inited; static struct mystr debug_str; + -+// Grab DH parameters from OpenSSL; ++// Grab prime number from OpenSSL; +// (get_rfc*) for all available primes. -+#define make_get_dh(rfc,size) \ -+static DH *get_dh##size(void) \ -+{ \ -+ DH *dh = DH_new(); \ -+ if (!dh) { \ -+ return NULL; \ -+ } \ -+ dh->p = get_##rfc##_prime_##size(NULL); \ -+ BN_dec2bn(&dh->g, "2"); \ -+ if (!dh->p || !dh->g) { \ -+ DH_free(dh); \ -+ return NULL; \ -+ } \ -+ return dh; \ ++// wraps selection of comparable algorithm strength ++#if !defined(match_dh_bits) ++ #define match_dh_bits(keylen) \ ++ keylen >= 8191 ? 8192 : \ ++ keylen >= 6143 ? 6144 : \ ++ keylen >= 4095 ? 4096 : \ ++ keylen >= 3071 ? 3072 : \ ++ keylen >= 2047 ? 2048 : \ ++ keylen >= 1535 ? 1536 : \ ++ keylen >= 1023 ? 1024 : 768 ++#endif ++ ++#if !defined(DH_get_prime) ++ BIGNUM * ++ DH_get_prime(int bits) ++ { ++ switch (bits) { ++ case 768: return get_rfc2409_prime_768(NULL); ++ case 1024: return get_rfc2409_prime_1024(NULL); ++ case 1536: return get_rfc3526_prime_1536(NULL); ++ case 2048: return get_rfc3526_prime_2048(NULL); ++ case 3072: return get_rfc3526_prime_3072(NULL); ++ case 4096: return get_rfc3526_prime_4096(NULL); ++ case 6144: return get_rfc3526_prime_6144(NULL); ++ case 8192: return get_rfc3526_prime_8192(NULL); ++ // shouldn't happen when used match_dh_bits; strict compiler ++ default: return NULL; ++ } +} ++#endif + -+// Prepare DH parameters from 768 to 8192 bits -+make_get_dh(rfc2409, 768) -+make_get_dh(rfc2409, 1024) -+make_get_dh(rfc3526, 1536) -+make_get_dh(rfc3526, 2048) -+make_get_dh(rfc3526, 3072) -+make_get_dh(rfc3526, 4096) -+make_get_dh(rfc3526, 6144) -+make_get_dh(rfc3526, 8192) -+ ++#if !defined(DH_get_dh) ++ // Grab DH parameters ++ DH * ++ DH_get_dh(int size) ++ { ++ DH *dh = DH_new(); ++ if (!dh) { ++ return NULL; ++ } ++ dh->p = DH_get_prime(match_dh_bits(size)); ++ BN_dec2bn(&dh->g, "2"); ++ if (!dh->p || !dh->g) ++ { ++ DH_free(dh); ++ return NULL; ++ } ++ return dh; ++ } ++#endif + void ssl_init(struct vsf_session* p_sess) { -@@ -156,6 +189,9 @@ ssl_init(struct vsf_session* p_sess) +@@ -65,7 +122,7 @@ ssl_init(struct vsf_session* p_sess) + { + die("SSL: could not allocate SSL context"); + } +- options = SSL_OP_ALL; ++ options = SSL_OP_ALL | SSL_OP_SINGLE_DH_USE; + if (!tunable_sslv2) + { + options |= SSL_OP_NO_SSLv2; +@@ -111,6 +168,25 @@ ssl_init(struct vsf_session* p_sess) + die("SSL: cannot load DSA private key"); + } + } ++ if (tunable_dh_param_file) ++ { ++ BIO *bio; ++ DH *dhparams = NULL; ++ if ((bio = BIO_new_file(tunable_dh_param_file, "r")) == NULL) ++ { ++ die("SSL: cannot load custom DH params"); ++ } ++ else ++ { ++ dhparams = PEM_read_bio_DHparams(bio, NULL, NULL, NULL); ++ BIO_free(bio); ++ ++ if (!SSL_CTX_set_tmp_dh(p_ctx, dhparams)) ++ { ++ die("SSL: setting custom DH params failed"); ++ } ++ } ++ } + if (tunable_ssl_ciphers && + SSL_CTX_set_cipher_list(p_ctx, tunable_ssl_ciphers) != 1) + { +@@ -156,6 +232,9 @@ ssl_init(struct vsf_session* p_sess) /* Ensure cached session doesn't expire */ SSL_CTX_set_timeout(p_ctx, INT_MAX); } @@ -65,7 +135,7 @@ diff -up vsftpd-3.0.2/ssl.c.dh vsftpd-3.0.2/ssl.c p_sess->p_ssl_ctx = p_ctx; ssl_inited = 1; } -@@ -675,6 +711,49 @@ ssl_verify_callback(int verify_ok, X509_ +@@ -675,6 +754,18 @@ ssl_verify_callback(int verify_ok, X509_ return 1; } @@ -74,44 +144,59 @@ diff -up vsftpd-3.0.2/ssl.c.dh vsftpd-3.0.2/ssl.c +static DH * +ssl_tmp_dh_callback(SSL *ssl, int is_export, int keylength) +{ -+ DH *dh_tmp=NULL; -+ + // strict compiler bypassing + UNUSED(ssl); + UNUSED(is_export); -+ -+ switch (keylength) { -+ case 768: -+ dh_tmp = get_dh768(); -+ break; -+ case 1024: -+ dh_tmp = get_dh1024(); -+ break; -+ case 1536: -+ dh_tmp = get_dh1536(); -+ break; -+ case 2048: -+ dh_tmp = get_dh2048(); -+ break; -+ case 3072: -+ dh_tmp = get_dh3072(); -+ break; -+ case 4096: -+ dh_tmp = get_dh4096(); -+ break; -+ case 6144: -+ dh_tmp = get_dh6144(); -+ break; -+ case 8192: -+ dh_tmp = get_dh8192(); -+ break; -+ default: -+ dh_tmp = get_dh1024(); -+ break; -+ } -+ return dh_tmp; ++ ++ return DH_get_dh(keylength); +} + void ssl_add_entropy(struct vsf_session* p_sess) { +diff -up vsftpd-3.0.2/tunables.c.dh vsftpd-3.0.2/tunables.c +--- vsftpd-3.0.2/tunables.c.dh 2014-06-04 09:54:43.364747051 +0200 ++++ vsftpd-3.0.2/tunables.c 2014-06-04 09:54:43.369747052 +0200 +@@ -140,6 +140,7 @@ const char* tunable_user_sub_token; + const char* tunable_email_password_file; + const char* tunable_rsa_cert_file; + const char* tunable_dsa_cert_file; ++const char* tunable_dh_param_file; + const char* tunable_ssl_ciphers; + const char* tunable_rsa_private_key_file; + const char* tunable_dsa_private_key_file; +@@ -288,6 +289,7 @@ tunables_load_defaults() + install_str_setting("/usr/share/ssl/certs/vsftpd.pem", + &tunable_rsa_cert_file); + install_str_setting(0, &tunable_dsa_cert_file); ++ install_str_setting(0, &tunable_dh_param_file); + install_str_setting("AES128-SHA:DES-CBC3-SHA", &tunable_ssl_ciphers); + install_str_setting(0, &tunable_rsa_private_key_file); + install_str_setting(0, &tunable_dsa_private_key_file); +diff -up vsftpd-3.0.2/tunables.h.dh vsftpd-3.0.2/tunables.h +--- vsftpd-3.0.2/tunables.h.dh 2014-06-04 09:54:43.364747051 +0200 ++++ vsftpd-3.0.2/tunables.h 2014-06-04 09:54:43.369747052 +0200 +@@ -142,6 +142,7 @@ extern const char* tunable_user_sub_toke + extern const char* tunable_email_password_file; + extern const char* tunable_rsa_cert_file; + extern const char* tunable_dsa_cert_file; ++extern const char* tunable_dh_param_file; + extern const char* tunable_ssl_ciphers; + extern const char* tunable_rsa_private_key_file; + extern const char* tunable_dsa_private_key_file; +diff -up vsftpd-3.0.2/vsftpd.conf.5.dh vsftpd-3.0.2/vsftpd.conf.5 +--- vsftpd-3.0.2/vsftpd.conf.5.dh 2014-06-04 09:54:43.364747051 +0200 ++++ vsftpd-3.0.2/vsftpd.conf.5 2014-06-04 09:54:43.369747052 +0200 +@@ -893,6 +893,12 @@ to be in the same file as the certificat + + Default: (none) + .TP ++.B dh_param_file ++This option specifies the location of the custom parameters used for ++ephemeral Diffie-Hellman key exchange in SSL. ++ ++Default: (none - use built in parameters appropriate for certificate key size) ++.TP + .B email_password_file + This option can be used to provide an alternate file for usage by the + .BR secure_email_list_enable diff --git a/vsftpd-3.0.2-docupd.patch b/vsftpd-3.0.2-docupd.patch new file mode 100644 index 0000000..71f7f9a --- /dev/null +++ b/vsftpd-3.0.2-docupd.patch @@ -0,0 +1,48 @@ +diff -up vsftpd-3.0.2/vsftpd.conf.5.docupd vsftpd-3.0.2/vsftpd.conf.5 +--- vsftpd-3.0.2/vsftpd.conf.5.docupd 2014-06-05 09:47:27.987876849 +0200 ++++ vsftpd-3.0.2/vsftpd.conf.5 2014-06-05 09:47:27.989876848 +0200 +@@ -652,6 +652,21 @@ change it with the setting + .BR xferlog_file . + + Default: NO ++.TP ++.B isolate_network ++If enabled, use CLONE_NEWNET to isolate the untrusted processes so that ++they can't do arbitrary connect() and instead have to ask the privileged ++process for sockets ( ++.BR port_promiscuous ++have to be disabled). ++ ++Default: YES ++.TP ++.B isolate ++If enabled, use CLONE_NEWPID and CLONE_NEWIPC to isolate processes to their ++ipc and pid namespaces. So separated processes can not interact with each other. ++ ++Default: YES + + .SH NUMERIC OPTIONS + Below is a list of numeric options. A numeric option must be set to a non +@@ -749,8 +764,9 @@ Default: 077 + .B max_clients + If vsftpd is in standalone mode, this is the maximum number of clients which + may be connected. Any additional clients connecting will get an error message. ++The value 0 switches off the limit. + +-Default: 0 (unlimited) ++Default: 2000 + .TP + .B max_login_fails + After this many login failures, the session is killed. +@@ -760,9 +776,9 @@ Default: 3 + .B max_per_ip + If vsftpd is in standalone mode, this is the maximum number of clients which + may be connected from the same source internet address. A client will get an +-error message if they go over this limit. ++error message if they go over this limit. The value 0 switches off the limit. + +-Default: 0 (unlimited) ++Default: 50 + .TP + .B pasv_max_port + The maximum port to allocate for PASV style data connections. Can be used to diff --git a/vsftpd-3.0.2-ecdh.patch b/vsftpd-3.0.2-ecdh.patch new file mode 100644 index 0000000..571d820 --- /dev/null +++ b/vsftpd-3.0.2-ecdh.patch @@ -0,0 +1,113 @@ +diff -up vsftpd-3.0.2/parseconf.c.ecdh vsftpd-3.0.2/parseconf.c +--- vsftpd-3.0.2/parseconf.c.ecdh 2014-06-04 09:56:56.358788746 +0200 ++++ vsftpd-3.0.2/parseconf.c 2014-06-04 09:56:56.360788747 +0200 +@@ -177,6 +177,7 @@ parseconf_str_array[] = + { "rsa_cert_file", &tunable_rsa_cert_file }, + { "dsa_cert_file", &tunable_dsa_cert_file }, + { "dh_param_file", &tunable_dh_param_file }, ++ { "ecdh_param_file", &tunable_ecdh_param_file }, + { "ssl_ciphers", &tunable_ssl_ciphers }, + { "rsa_private_key_file", &tunable_rsa_private_key_file }, + { "dsa_private_key_file", &tunable_dsa_private_key_file }, +diff -up vsftpd-3.0.2/ssl.c.ecdh vsftpd-3.0.2/ssl.c +--- vsftpd-3.0.2/ssl.c.ecdh 2014-06-04 09:56:56.358788746 +0200 ++++ vsftpd-3.0.2/ssl.c 2014-06-04 09:56:56.360788747 +0200 +@@ -122,7 +122,7 @@ ssl_init(struct vsf_session* p_sess) + { + die("SSL: could not allocate SSL context"); + } +- options = SSL_OP_ALL | SSL_OP_SINGLE_DH_USE; ++ options = SSL_OP_ALL | SSL_OP_SINGLE_DH_USE | SSL_OP_SINGLE_ECDH_USE; + if (!tunable_sslv2) + { + options |= SSL_OP_NO_SSLv2; +@@ -235,6 +235,41 @@ ssl_init(struct vsf_session* p_sess) + + SSL_CTX_set_tmp_dh_callback(p_ctx, ssl_tmp_dh_callback); + ++ if (tunable_ecdh_param_file) ++ { ++ BIO *bio; ++ int nid; ++ EC_GROUP *ecparams = NULL; ++ EC_KEY *eckey; ++ ++ if ((bio = BIO_new_file(tunable_ecdh_param_file, "r")) == NULL) ++ die("SSL: cannot load custom ec params"); ++ else ++ { ++ ecparams = PEM_read_bio_ECPKParameters(bio, NULL, NULL, NULL); ++ BIO_free(bio); ++ ++ if (ecparams && (nid = EC_GROUP_get_curve_name(ecparams)) && ++ (eckey = EC_KEY_new_by_curve_name(nid))) ++ { ++ if (!SSL_CTX_set_tmp_ecdh(p_ctx, eckey)) ++ die("SSL: setting custom EC params failed"); ++ } ++ else ++ { ++ die("SSL: getting ec group or key failed"); ++ } ++ } ++ } ++ else ++ { ++#if defined(SSL_CTX_set_ecdh_auto) ++ SSL_CTX_set_ecdh_auto(p_ctx, 1); ++#else ++ SSL_CTX_set_tmp_ecdh(p_ctx, EC_KEY_new_by_curve_name(NID_X9_62_prime256v1)); ++#endif ++ } ++ + p_sess->p_ssl_ctx = p_ctx; + ssl_inited = 1; + } +diff -up vsftpd-3.0.2/tunables.c.ecdh vsftpd-3.0.2/tunables.c +--- vsftpd-3.0.2/tunables.c.ecdh 2014-06-04 09:56:56.358788746 +0200 ++++ vsftpd-3.0.2/tunables.c 2014-06-04 09:56:56.361788747 +0200 +@@ -141,6 +141,7 @@ const char* tunable_email_password_file; + const char* tunable_rsa_cert_file; + const char* tunable_dsa_cert_file; + const char* tunable_dh_param_file; ++const char* tunable_ecdh_param_file; + const char* tunable_ssl_ciphers; + const char* tunable_rsa_private_key_file; + const char* tunable_dsa_private_key_file; +@@ -290,6 +291,7 @@ tunables_load_defaults() + &tunable_rsa_cert_file); + install_str_setting(0, &tunable_dsa_cert_file); + install_str_setting(0, &tunable_dh_param_file); ++ install_str_setting(0, &tunable_ecdh_param_file); + install_str_setting("AES128-SHA:DES-CBC3-SHA", &tunable_ssl_ciphers); + install_str_setting(0, &tunable_rsa_private_key_file); + install_str_setting(0, &tunable_dsa_private_key_file); +diff -up vsftpd-3.0.2/tunables.h.ecdh vsftpd-3.0.2/tunables.h +--- vsftpd-3.0.2/tunables.h.ecdh 2014-06-04 09:56:56.359788746 +0200 ++++ vsftpd-3.0.2/tunables.h 2014-06-04 09:56:56.361788747 +0200 +@@ -143,6 +143,7 @@ extern const char* tunable_email_passwor + extern const char* tunable_rsa_cert_file; + extern const char* tunable_dsa_cert_file; + extern const char* tunable_dh_param_file; ++extern const char* tunable_ecdh_param_file; + extern const char* tunable_ssl_ciphers; + extern const char* tunable_rsa_private_key_file; + extern const char* tunable_dsa_private_key_file; +diff -up vsftpd-3.0.2/vsftpd.conf.5.ecdh vsftpd-3.0.2/vsftpd.conf.5 +--- vsftpd-3.0.2/vsftpd.conf.5.ecdh 2014-06-04 09:56:56.359788746 +0200 ++++ vsftpd-3.0.2/vsftpd.conf.5 2014-06-04 09:56:56.361788747 +0200 +@@ -899,6 +899,14 @@ ephemeral Diffie-Hellman key exchange in + + Default: (none - use built in parameters appropriate for certificate key size) + .TP ++.B ecdh_param_file ++This option specifies the location of custom parameters for ephemeral ++Elliptic Curve Diffie-Hellman (ECDH) key exchange. ++ ++Default: (none - use built in parameters, NIST P-256 with OpenSSL 1.0.1 and ++automatically selected curve based on client preferences with OpenSSL 1.0.2 ++and later) ++.TP + .B email_password_file + This option can be used to provide an alternate file for usage by the + .BR secure_email_list_enable diff --git a/vsftpd-3.0.2-rc450.patch b/vsftpd-3.0.2-rc450.patch new file mode 100644 index 0000000..63d6d01 --- /dev/null +++ b/vsftpd-3.0.2-rc450.patch @@ -0,0 +1,56 @@ +diff -up vsftpd-3.0.2/ftpcodes.h.rc450 vsftpd-3.0.2/ftpcodes.h +--- vsftpd-3.0.2/ftpcodes.h.rc450 2008-02-12 01:30:46.000000000 +0100 ++++ vsftpd-3.0.2/ftpcodes.h 2014-06-18 13:41:02.238821708 +0200 +@@ -52,6 +52,7 @@ + #define FTP_TLS_FAIL 421 + #define FTP_BADSENDCONN 425 + #define FTP_BADSENDNET 426 ++#define FTP_FILETMPFAIL 450 + #define FTP_BADSENDFILE 451 + + #define FTP_BADCMD 500 +diff -up vsftpd-3.0.2/postlogin.c.rc450 vsftpd-3.0.2/postlogin.c +--- vsftpd-3.0.2/postlogin.c.rc450 2012-09-18 11:59:37.000000000 +0200 ++++ vsftpd-3.0.2/postlogin.c 2014-06-18 13:41:02.238821708 +0200 +@@ -670,7 +670,14 @@ handle_retr(struct vsf_session* p_sess, + 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."); ++ if (kVSFSysUtilErrAGAIN == vsf_sysutil_get_error()) ++ { ++ vsf_cmdio_write(p_sess, FTP_FILETMPFAIL, "Temporarily failed to open file"); ++ } ++ else ++ { ++ vsf_cmdio_write(p_sess, FTP_FILEFAIL, "Failed to open file."); ++ } + return; + } + /* Lock file if required */ +diff -up vsftpd-3.0.2/sysutil.c.rc450 vsftpd-3.0.2/sysutil.c +--- vsftpd-3.0.2/sysutil.c.rc450 2014-06-18 13:41:02.231821807 +0200 ++++ vsftpd-3.0.2/sysutil.c 2014-06-18 13:41:02.238821708 +0200 +@@ -1632,6 +1632,9 @@ vsf_sysutil_get_error(void) + case ENOENT: + retval = kVSFSysUtilErrNOENT; + break; ++ case EAGAIN: ++ retval = kVSFSysUtilErrAGAIN; ++ break; + default: + break; + } +diff -up vsftpd-3.0.2/sysutil.h.rc450 vsftpd-3.0.2/sysutil.h +--- vsftpd-3.0.2/sysutil.h.rc450 2014-06-18 13:41:02.231821807 +0200 ++++ vsftpd-3.0.2/sysutil.h 2014-06-18 13:41:02.239821694 +0200 +@@ -18,7 +18,8 @@ enum EVSFSysUtilError + kVSFSysUtilErrINVAL, + kVSFSysUtilErrOPNOTSUPP, + kVSFSysUtilErrACCES, +- kVSFSysUtilErrNOENT ++ kVSFSysUtilErrNOENT, ++ kVSFSysUtilErrAGAIN + }; + enum EVSFSysUtilError vsf_sysutil_get_error(void); + diff --git a/vsftpd.spec b/vsftpd.spec index 0c9c6c9..e1143a6 100644 --- a/vsftpd.spec +++ b/vsftpd.spec @@ -3,7 +3,7 @@ Name: vsftpd Version: 3.0.2 -Release: 9%{?dist} +Release: 10%{?dist} Summary: Very Secure Ftp Daemon Group: System Environment/Daemons @@ -62,6 +62,9 @@ Patch25: vsftpd-3.0.0-logrotate.patch Patch26: vsftpd-3.0.2-lookup.patch Patch27: vsftpd-3.0.2-uint-uidgid.patch Patch28: vsftpd-3.0.2-dh.patch +Patch29: vsftpd-3.0.2-ecdh.patch +Patch30: vsftpd-3.0.2-docupd.patch +Patch31: vsftpd-3.0.2-rc450.patch %description vsftpd is a Very Secure FTP daemon. It was written completely from @@ -95,6 +98,9 @@ cp %{SOURCE1} . %patch26 -p1 -b .lookup %patch27 -p1 -b .uint-uidgid %patch28 -p1 -b .dh +%patch29 -p1 -b .ecdh +%patch30 -p1 -b .docupd +%patch31 -p1 -b .rc450 %build %ifarch s390x sparcv9 sparc64 @@ -161,6 +167,13 @@ rm -rf $RPM_BUILD_ROOT %{_var}/ftp %changelog +* Wed Jun 18 2014 Jiri Skala - 3.0.2-10 +- improves DH cipher +- implements ECDH cipher +- adds isolate* options to man vsftpd.conf +- corrects max_clients, max_per_ip default values in man vsftd.conf +- adds return code 450 when a file is temporarily unavailable + * Sun Jun 08 2014 Fedora Release Engineering - 3.0.2-9 - Rebuilt for https://fedoraproject.org/wiki/Fedora_21_Mass_Rebuild