diff -Nru linux-ftpd-ssl-0.17.36+0.3/debian/changelog linux-ftpd-ssl-0.17.36+0.3/debian/changelog --- linux-ftpd-ssl-0.17.36+0.3/debian/changelog 2016-12-17 14:41:43.000000000 +0000 +++ linux-ftpd-ssl-0.17.36+0.3/debian/changelog 2017-01-24 14:35:15.000000000 +0000 @@ -1,3 +1,17 @@ +linux-ftpd-ssl (0.17.36+0.3-2) unstable; urgency=low + + * Adaption to libssl of recent version. + + debian/patches/580-recent_libssl.diff: New file. + + debian/control: Reverse order between libssl-dev and libssl1.0-dev, + remove versioning of libssl-dev. + * Fulfill minimal requirements in RFC 2228. Accept CA-files, key files, + cipher selection, and chained certificates. Full verification of any + certificate is possible. + + Immediately forbid SSLv2 while initializing SSL. + + debian/patches/600-better_conformity.diff: New file. + + -- Mats Erik Andersson Tue, 24 Jan 2017 15:35:15 +0100 + linux-ftpd-ssl (0.17.36+0.3-1) unstable; urgency=low * Update to source version 0.17-36 of linux-ftpd. diff -Nru linux-ftpd-ssl-0.17.36+0.3/debian/control linux-ftpd-ssl-0.17.36+0.3/debian/control --- linux-ftpd-ssl-0.17.36+0.3/debian/control 2016-12-17 13:33:31.000000000 +0000 +++ linux-ftpd-ssl-0.17.36+0.3/debian/control 2017-01-16 20:04:22.000000000 +0000 @@ -3,7 +3,7 @@ Priority: extra Maintainer: Mats Erik Andersson Uploaders: Alberto Gonzalez Iniesta -Build-Depends: bison, debhelper (>= 9), libpam0g-dev | libpam-dev, libssl1.0-dev | libssl-dev (<< 1.1.0~) +Build-Depends: bison, debhelper (>= 9), libpam0g-dev | libpam-dev, libssl-dev | libssl1.0-dev Standards-Version: 3.9.8 Package: ftpd-ssl diff -Nru linux-ftpd-ssl-0.17.36+0.3/debian/NEWS linux-ftpd-ssl-0.17.36+0.3/debian/NEWS --- linux-ftpd-ssl-0.17.36+0.3/debian/NEWS 2016-12-17 13:25:33.000000000 +0000 +++ linux-ftpd-ssl-0.17.36+0.3/debian/NEWS 2017-01-24 14:35:15.000000000 +0000 @@ -1,3 +1,19 @@ +linux-ftpd-ssl (0.17.36+0.3-2) unstable; urgency=low + + This release implements a substantial improvement in the server's + ability to read a certificate chain as its own identity and also the + use of a CA certificate collection for verifying the peer. Complete + verification of certificates is now possible during conversation, + since 'certrequired' is now implemented. Debugging of SSL matters + into a file is a very useful new ability. + + The legacy patch set included a non-standard override of the outcome + during (shallow) certificate verification. It is not desirable now, + but can be activated by '-z legacy', and should only serve as a means + of easier transition. + + -- Mats Erik Andersson Tue, 24 Jan 2017 14:56:34 +0100 + linux-ftpd-ssl (0.17.31+0.3-1) unstable; urgency=low The recent IPv6 capability is handled in distinct ways diff -Nru linux-ftpd-ssl-0.17.36+0.3/debian/patches/580-recent_libssl.diff linux-ftpd-ssl-0.17.36+0.3/debian/patches/580-recent_libssl.diff --- linux-ftpd-ssl-0.17.36+0.3/debian/patches/580-recent_libssl.diff 1970-01-01 00:00:00.000000000 +0000 +++ linux-ftpd-ssl-0.17.36+0.3/debian/patches/580-recent_libssl.diff 2017-01-16 20:19:57.000000000 +0000 @@ -0,0 +1,20 @@ +Description: Make possible builds with libssl of version 1.1.0. + Protected access to an opaque structure was made mandatory + in version 1.1.0 of libssl. +Author: Mats Erik Andersson +Forwarded: not-needed +Last-Update: 2017-01-16 + +--- linux-ftpd-0.17.debian/ftpd/ftpd.c 2016-12-25 23:10:18.631245308 +0100 ++++ linux-ftpd-0.17/ftpd/ftpd.c 2017-01-16 21:10:30.207457125 +0100 +@@ -3572,8 +3572,8 @@ + int depth,error; + X509 *xs; + +- depth=ctx->error_depth; +- error=ctx->error; ++ depth = X509_STORE_CTX_get_error_depth(ctx); ++ error = X509_STORE_CTX_get_error(ctx); + xs=X509_STORE_CTX_get_current_cert(ctx); + + /* diff -Nru linux-ftpd-ssl-0.17.36+0.3/debian/patches/600-better_conformity.diff linux-ftpd-ssl-0.17.36+0.3/debian/patches/600-better_conformity.diff --- linux-ftpd-ssl-0.17.36+0.3/debian/patches/600-better_conformity.diff 1970-01-01 00:00:00.000000000 +0000 +++ linux-ftpd-ssl-0.17.36+0.3/debian/patches/600-better_conformity.diff 2017-01-24 14:12:24.000000000 +0000 @@ -0,0 +1,1029 @@ +Description: Better contemporary TLS abilities. + The commands PBSZ, PROT and CCC are implemented to the minimal extent + needed to fulfill RFC 2228 in the sense of negotiating with a client. + Thereby 'AUTH TLS' and 'AUTH SSL' are treated correctly. A client + call like 'curl --ftp-ssl' is now successfully handled. 'Minimal' + means in particular that the protected mode 'PROT P' is the only + supported level for data exchange, once SSL handshaking is complete. + . + There are new SSL options, or corrected to be functional: 'debug=file', + 'cipher=list', 'cacert=file', 'key=file', and 'certrequired'. The CA + list collected from 'cacert=file' will be sent to the client, which + is useful for advanced client software. + . + The option 'cert=file' reads a complete chain of certificates, which + together with 'cacert=file' makes the whole spectrum of verification + via 'verify=num' available. Either of 'certsok' and 'certrequired' + will set SSL_VERIFY_PEER, and 'certrequired' will also set + SSL_VERIFY_FAIL_IF_NO_PEER_CERT. + . + A temporary SSL option 'legacy' activates an ugly work around during + verification, controlled by SSL_VERIFY_FAIL_IF_NO_PEER_CERT. This + quirk was present in the legacy patch set, but should not be used + with the new ability to read chains and CA lists. Its introduction + should only be seen as a step in the transition to contemporary + standards. + . + Include SSL_OP_NO_SSLv2 when setting library options. + . + Much effort has gone into sensible and helpful messages during SSL debug. + . + TODO: Autologin based on 'certsok' could be considered in SSL-only + mode, or in secure mode. Presently the PAM code only is able to emit + debug messages as to whether certsok would accept or reject the claimed + username for a corresponding subject identifier. + . +Author: Mats Erik Andersson +Forwarded: not-needed +Last-Update: 2017-01-24 + +diff -Naurp linux-ftpd-0.17.debian/ftpd/ftpcmd.y linux-ftpd-0.17/ftpd/ftpcmd.y +--- linux-ftpd-0.17.debian/ftpd/ftpcmd.y 2016-12-25 23:10:18.631245308 +0100 ++++ linux-ftpd-0.17/ftpd/ftpcmd.y 2017-01-23 19:20:20.326466165 +0100 +@@ -110,16 +110,19 @@ extern struct sockaddr_storage his_addr; + + #ifdef USE_SSL + /*#include "ssl_port.h"*/ ++# include + typedef struct ssl_st SSL; +-int SSL_write(SSL *ssl,const char *buf,int num); + extern int do_ssl_start(void); + extern int ssl_getc(SSL *ssl_con); + extern int ssl_secure_flag; ++extern int ssl_debug_flag; + extern int ssl_active_flag; + extern SSL *ssl_con; ++extern BIO *bio_err; + #define FFLUSH(X) (ssl_active_flag && (((X)==cin)||((X)==cout)) ? 1 : fflush((X)) ) + #define GETC(X) (ssl_active_flag && (((X)==cin)||((X)==cout)) ? ssl_getc(ssl_con) : getc((X)) ) + extern FILE *cin, *cout; ++static int has_done_pbsz = 0; + #endif /* USE_SSL */ + + off_t restart_point; +@@ -197,7 +200,7 @@ cmp_addresses(struct sockaddr * left, st + CDUP STOU SMNT SYST SIZE MDTM + EPRT EPSV + +- UMASK IDLE CHMOD AUTH ++ UMASK IDLE CHMOD AUTH PBSZ PROT CCC + + LEXERR + +@@ -226,12 +229,14 @@ cmd_list + cmd + : AUTH SP auth_type CRLF + { +- if (!strncmp((char *) $3,"SSL",3)) { ++ if (!strncmp((char *) $3,"SSL",3) ++ || !strncmp((char *) $3, "TLS", 3)) { + #ifdef USE_SSL +- reply(234, "AUTH SSL OK."); ++ reply(234, "AUTH %3s OK.", $3); + + /* now do all the hard work :-) */ + do_ssl_start(); ++ has_done_pbsz = 0; + + #else /* !USE_SSL */ + reply(504,"AUTH type not supported."); +@@ -242,6 +247,60 @@ cmd + if ($3 != NULL) + free((char *)$3); + } ++ | PBSZ SP NUMBER CRLF ++ { ++#ifdef USE_SSL ++ if (!ssl_active_flag) { ++ reply(503, "Not valid without AUTH."); ++ break; ++ } ++ has_done_pbsz = 1; ++ reply(200, "PBSZ=0"); ++#else /* !USE_SSL */ ++ reply(502, "Not implemented"); ++#endif /* !USE_SSL */ ++ } ++ | PROT SP STRING CRLF ++ { ++#ifdef USE_SSL ++ if (!ssl_active_flag) { ++ reply(503, "Not valid without AUTH."); ++ free($3); ++ break; ++ } ++ if (!has_done_pbsz) { ++ reply(503, "Negotiate PBSZ first."); ++ free($3); ++ break; ++ } ++ if (strlen($3) > 1 ++ || strchr("CSEP", *$3) == NULL) { ++ reply(504, "Unknown protection level"); ++ free($3); ++ break; ++ } ++ if (*$3 != 'P') { ++ reply(534, "Only P will be accepted."); ++ free($3); ++ break; ++ } ++ reply(200, "Protection at level P."); ++#else /* !USE_SSL */ ++ reply(502, "Not implemented"); ++#endif /* !USE_SSL */ ++ free($3); ++ } ++ | CCC CRLF ++ { ++#ifdef USE_SSL ++ if (!ssl_active_flag) ++ reply(533, "Not in protected mode."); ++ else ++ reply(534, "Will not talk unprotected!"); ++#else /* !USE_SSL */ ++ reply(502, "Not implemented"); ++#endif ++ } + | USER SP username CRLF + { + #ifdef USE_SSL +@@ -1054,6 +1113,9 @@ struct tab cmdtab[] = { /* In order def + { "STOU", STOU, STR1, 1, " file-name" }, + { "SIZE", SIZE, OSTR, 1, " path-name" }, + { "MDTM", MDTM, OSTR, 1, " path-name" }, ++ { "PBSZ", PBSZ, ARGS, 1, " size" }, ++ { "PROT", PROT, STR1, 1, " level-char" }, ++ { "CCC", CCC, ARGS, 1, "(drop integrity protection)" }, + { NULL, 0, 0, 0, 0 } + }; + +@@ -1156,6 +1218,10 @@ int ftpd_getline(char *s, int n, FILE *i + if (c == '\n') + break; + } ++#ifdef USE_SSL ++ if (ssl_debug_flag && (c == EOF || (c == '\n'))) ++ (void) BIO_printf(bio_err, "\r\n"); ++#endif /* USE_SSL */ + if (c == EOF && cs == s) + return (-1); + *cs++ = '\0'; +diff -Naurp linux-ftpd-0.17.debian/ftpd/ftpd.8 linux-ftpd-0.17/ftpd/ftpd.8 +--- linux-ftpd-0.17.debian/ftpd/ftpd.8 2016-12-25 23:10:17.763285573 +0100 ++++ linux-ftpd-0.17/ftpd/ftpd.8 2017-01-24 14:47:02.648202400 +0100 +@@ -51,13 +51,17 @@ Internet File Transfer Protocol server + .Op Fl t Ar timeout + .Op Fl u Ar mask + .Op Fl z Ar debug ++.Op Fl z Ar debug=file + .Op Fl z Ar certsok + .Op Fl z Ar certrequired + .Op Fl z Ar secure ++.Op Fl z Ar ssl + .Op Fl z Ar verify=flags ++.Op Fl z Ar cacert=cafile + .Op Fl z Ar cert=certfile + .Op Fl z Ar key=keyfile +-.Op Fl z Ar ciper=list ++.Op Fl z Ar cipher=list ++.Op Fl z Ar legacy + .Sh DESCRIPTION + .Nm Ftpd + is the +@@ -161,47 +165,76 @@ This option is only valid if + .Nm ftpd + has been built with SSL (Secure Socket Layer) support. + .Bl -tag -width Fl +-.It Ic debug +-Enable SSL related debugging. ++.It Ic secure ++Don't fall back to unencrypted mode, that is without SSL, if the client ++is not explicitly asking for SSL mode. In this server mode ++.Nm ftpd ++only accepts connections from SSL enhanced ++.Ar FTP clients ++with an option similar to ++.Ic -z secure ++in active use. + .It Ic ssl +-Negotiate SSL at first, then use ftp protocol. In this mode ftpd +-only accepts connections from SSL enhanced ftp with option +-.Ic -z ssl . +-(Not yet implemented) ++Negotiate SSL at first, then fall back to legacy FTP protocol. + .It Ic nossl, !ssl + switch off SSL negotiation ++.It Ic debug ++Enable SSL related debugging. Useless in non-daemon mode. ++.It Ic debug=file ++Direct the debugging output to ++.Ar file . + .It Ic certsok +-Look username up in /etc/ssl.users. The format of this file is lines +-of this form: +-.Ar user1,user2:/C=US/..... +-where user1 and user2 are usernames. If client certificate is valid, +-authenticate without password. ++Look username up in ++.Pa /etc/ssl.users . ++The format of this file is lines of this form: ++.Ar user1,user2:/C=US/... ++.br ++where ++.Ar user1 ++and ++.Ar user2 ++are usernames. If the client certificate is valid, ++authenticate with any password. Use a command ++.Ar openssl x509 -noout -subject ++to extract the needed fields, all of which are needed. + .It Ic certrequired +-client certificate is mandatory +-.It Ic secure +-Don't switch back to unencrypted mode (no SSL) if SSL is not available. ++Client certificate is mandatory and the user must be matched to the ++corresponding subject identifier listed in ++.Pa /etc/ssl.users . + .It Ic verify=int +-.\" TODO +-Set the SSL verify flags (SSL_VERIFY_* in +-.Ar ssl/ssl.h ++Set the SSL verify flags (use combinations of SSL_VERIFY_* from ++.Ar openssl/ssl.h + ). +-.\" TODO ++.It Ic cacert=ca_file ++Use the CA certificates stored in ++.Ar ca_file ++to verify the identity of the peer client. ++The subject names found herein are given to the client for ++whatever use they may present. A clever client software is able ++to choose its identity hinted by this list. + .It Ic cert=cert_file +-.\" TODO + Use the certificate(s) in +-.Ar cert_file . ++.Ar cert_file ++instead of the default location ++.Pa /etc/ftpd-ssl/ftpd.pem . ++This is a PEM formatted file. The first certificate identifies the ++server and the rest of the chain is used for verification purposes ++while talking to the peer client. + .It Ic key=key_file +-.\" TODO +-Use the key(s) in +-.Ar key_file . ++Use the key stored in ++.Ar key_file , ++should the certificate file not contain the required private key. + .It Ic cipher=ciph_list +-.\" TODO + Set the preferred ciphers to + .Ar ciph_list . +-.\" TODO: possible values; comma-separated list? +-(See +-.Ar ssl/ssl.h +-). ++See ++.Ar openssl/ssl.h ++for more information). ++.It Ic legacy ++This is a compatibility option, which activates a work around during ++verification, which the legacy code depended on. ++It should not be used now that chains and CA lists are available, ++but is introduced to ease the transition to the better implementation. + .El + .El + .Pp +@@ -460,6 +493,17 @@ Displayed and access refused. + List of users on the system. + .It Pa /var/log/ftpd + Log file for anonymous transfers. ++.It Pa /etc/ftpd-ssl/ftpd.pem ++Default certificate and key for SSL authentication. ++.It Pa /etc/ssl.users ++List of trusted users and their subject identifiers. ++.El ++.Sh ENVIRONMENT ++.Nm Ftpd ++accesses a single environment variable: ++.Bl -tag -width Fl ++.It Ev SSL_CIPHER ++containing a list of acceptable cipher combinations. + .El + .Sh SEE ALSO + .Xr ftp 1 , +diff -Naurp linux-ftpd-0.17.debian/ftpd/ftpd.c linux-ftpd-0.17/ftpd/ftpd.c +--- linux-ftpd-0.17.debian/ftpd/ftpd.c 2017-01-16 21:10:30.207457125 +0100 ++++ linux-ftpd-0.17/ftpd/ftpd.c 2017-01-24 14:36:24.478784363 +0100 +@@ -181,8 +181,12 @@ char ssl_file_path[1024]; /* don't lo + X509 *ssl_public_cert; + RSA *ssl_private_key; + ++static int ssl_legacy_flag = 0; ++ + static char *my_ssl_key_file=NULL; ++static char *my_ssl_cacert_file=NULL; + static char *my_ssl_cert_file=NULL; ++static char *my_ssl_log_file = NULL; + + #include "ssl_port.h" + +@@ -227,6 +231,7 @@ ssl_putc_flush(SSL *ssl_con); + static char versionpre[] = "Version 6.4/OpenBSD/Linux"; + static char version[sizeof(versionpre)+sizeof(pkg)]; + ++static int silence_flag = 0; /* Suppress debugging of something. */ + + extern off_t restart_point; + extern char cbuf[]; +@@ -568,9 +573,16 @@ main(int argc, char *argv[], char **envp + + #ifdef USE_SSL + case 'z': ++ if (strcmp(optarg, "legacy") == 0) { ++ ssl_legacy_flag = 1; ++ } + if (strcmp(optarg, "debug") == 0 ) { + ssl_debug_flag=1; + } ++ if (strncmp(optarg, "debug=", strlen("debug=")) == 0 ) { ++ ssl_debug_flag=1; ++ my_ssl_log_file = optarg + strlen("debug="); ++ } + if (strcmp(optarg, "verbose") == 0 ) { + ssl_verbose_flag=1; + } +@@ -583,16 +595,25 @@ main(int argc, char *argv[], char **envp + if (strcmp(optarg, "certsok") == 0) { + ssl_certsok_flag=1; + } ++ if (strcmp(optarg, "certrequired") == 0) { ++ ssl_cert_required = 1; ++ } + if (strncmp(optarg, "verify=", strlen("verify=")) == 0 ) { + ssl_verify_flag=atoi(optarg+strlen("verify=")); + + } ++ if (strncmp(optarg, "cacert=", strlen("cacert=")) == 0 ) { ++ my_ssl_cacert_file = optarg + strlen("cacert="); ++ } + if (strncmp(optarg, "cert=", strlen("cert=")) == 0 ) { + my_ssl_cert_file=optarg+strlen("cert="); + } + if (strncmp(optarg, "key=", strlen("key=")) == 0 ) { + my_ssl_key_file=optarg+strlen("key="); + } ++ if (strncmp(optarg, "cipher=", strlen("cipher=")) == 0 ) { ++ ssl_cipher_list = optarg + strlen("cipher="); ++ } + /* we have swallowed an extra arg */ + /*argc--; + argv++;*/ +@@ -625,14 +646,30 @@ main(int argc, char *argv[], char **envp + cin=stdin; + cout=stderr; + ++ if (my_ssl_cacert_file && *my_ssl_cacert_file) { ++ ssl_cacert_file = my_ssl_cacert_file; ++ } + if (my_ssl_cert_file==NULL) { + strcpy(ssl_file_path,DEFAULT_SSL_FILE); + ssl_cert_file=ssl_file_path; + } else { + ssl_cert_file=my_ssl_cert_file; + } ++ if (my_ssl_key_file && *my_ssl_key_file) { ++ ssl_key_file = my_ssl_key_file; ++ } ++ if (my_ssl_log_file && *my_ssl_log_file) ++ ssl_log_file = my_ssl_log_file; ++ ++ if (ssl_certsok_flag || ssl_cert_required) ++ ssl_verify_flag |= SSL_VERIFY_PEER; ++ ++ if (ssl_cert_required) ++ ssl_verify_flag |= SSL_VERIFY_FAIL_IF_NO_PEER_CERT; + + if (!do_ssleay_init(1)) { ++ if (ssl_debug_flag) ++ (void) BIO_printf(bio_err, "SSLeay initialisation failed\n"); + fprintf(stderr,"ftpd: SSLeay initialisation failed\n"); + fflush(stderr); + sleep(1); +@@ -751,8 +788,18 @@ main(int argc, char *argv[], char **envp + fprintf(SSL_LOG,"ftpd: got private key\n"); + fflush(SSL_LOG); + } +-#endif ++#endif /* 0 */ + ++ if (ssl_debug_flag) { ++ (void) BIO_printf(bio_err, "Init of SSL is complete.\r\n"); ++ (void) BIO_printf(bio_err, "Flags: ssl %d, secure %d, verify %d, certsok %d, certreq %d\r\n", ++ ssl_only_flag, ssl_secure_flag, ++ ssl_verify_flag, ssl_certsok_flag, ++ ssl_cert_required); ++ if (ssl_legacy_flag) ++ (void) BIO_printf(bio_err, "Warning: Legacy mode in use!\r\n"); ++ (void) BIO_flush(bio_err); ++ } + } + #endif /* USE_SSL */ + +@@ -1085,7 +1132,7 @@ void user(char *name) + + #ifdef USE_PAM + authentication_setup(name); +-#else ++#else /* !USE_PAM */ + guest = 0; + if (strcmp(name, "ftp") == 0 || strcmp(name, "anonymous") == 0) { + if (checkuser(_PATH_FTPUSERS, "ftp") || +@@ -1142,7 +1189,7 @@ void user(char *name) + } else + #endif + reply(331, "Password required for %s.", name); +-#endif ++#endif /* !USE_PAM */ + if (logging) { + strncpy(curname, name, sizeof(curname)-1); + curname[sizeof(curname)-1] = '\0'; +@@ -1291,11 +1338,13 @@ static int PAM_conv (int num_msg, const + + static struct pam_conv PAM_conversation = { + &PAM_conv, +- NULL ++ &auth_ssl_name + }; + + static int pam_doit(void) + { ++ static old_silence_flag = 0; ++ static silent_password = 0; + int error; + + error = pam_authenticate(pamh, 0); +@@ -1312,8 +1361,40 @@ static int pam_doit(void) + free(PAM_message); + PAM_message = 0; + } ++ ++ silent_password = 1; ++ old_silence_flag = silence_flag; ++ silence_flag = 1; /* Suppress debug exposure. */ ++ + return 1; + } ++ ++ if (silent_password) { ++ silence_flag = old_silence_flag; ++ silent_password = 0; ++ } ++ ++ /* Should a user be allowed entry when present in ++ * '/etc/ssl.users' despite giving an incorrect password? ++ */ ++ if (ssl_certsok_flag && (error == PAM_AUTH_ERR) ++ && *((char **) PAM_conversation.appdata_ptr)) { ++ /* XXX: Only issue debugging for now. ++ */ ++ if (good_ssl_user(PAM_username)) { ++ if (ssl_debug_flag) ++ BIO_printf(bio_err, "Certsok accepts: %s as %s\r\n", ++ PAM_username, auth_ssl_name); ++ // error = PAM_SUCCESS; ++ // PAM_accepted = 1; ++ } else { ++ if (ssl_debug_flag) ++ BIO_printf(bio_err, "Certsok rejects: %s as %s\r\n", ++ PAM_username, auth_ssl_name); ++ // PAM_accepted = 0; ++ } ++ } ++ + if (error == PAM_SUCCESS) { + const void *vp; + +@@ -1381,6 +1462,7 @@ static int authenticate(char *passwd) + PAM_password = passwd; + pam_doit(); + PAM_password = 0; ++ + return PAM_accepted; + } + +@@ -1437,7 +1519,7 @@ void pass(char *passwd) + && !ssl_auto_login + #endif + ) { /* "ftp" is only account allowed no password */ +-#endif ++#endif /* !USE_PAM */ + /* + * Try to authenticate the user + */ +@@ -1462,7 +1544,7 @@ void pass(char *passwd) + || ssl_auto_login + #endif + ) { +-#else ++#else /* !USE_PAM */ + } else { + #endif + /* Save anonymous' password. */ +@@ -1633,7 +1715,8 @@ void pass(char *passwd) + if (logging) + syslog(LOG_FTP | LOG_INFO, + "ANONYMOUS FTP LOGIN FROM %s, %s", +- remotehost, passwd); ++ remotehost, ++ passwd && *passwd ? passwd : "(no passwd)"); + } else { + reply(230, "User %s logged in.", pw->pw_name); + #ifdef HASSETPROCTITLE +@@ -1957,6 +2040,7 @@ static FILE * dataconn(const char *name, + ssl_data_active_flag=0; + if (ssl_active_flag && ssl_encrypt_data) { + /* do SSL */ ++ int ret; + + reply(150, "Opening %s mode SSL data connection for %s%s.", + type == TYPE_A ? "ASCII" : "BINARY", name, sizebuf); +@@ -1973,7 +2057,9 @@ static FILE * dataconn(const char *name, + /* for 0.5.2 - want to change the timeout value etc ... */ + + SSL_set_fd(ssl_data_con,pdata); +- SSL_set_verify(ssl_data_con,ssl_verify_flag,NULL); ++ ++ /* No reason to expect client to send certificate. */ ++ SSL_set_verify(ssl_data_con, SSL_VERIFY_NONE, NULL); + + /* if is "safe" to read ahead */ + /* SSL_set_read_ahead(ssl_data_con,1); */ +@@ -1981,11 +2067,21 @@ static FILE * dataconn(const char *name, + if (ssl_debug_flag) + BIO_printf(bio_err,"===>START SSL_accept on DATA\n"); + +- if (SSL_accept(ssl_data_con)<=0) { ++ ret = SSL_accept(ssl_data_con); ++ if (ret <= 0) { + static char errbuf[1024]; ++ int err = SSL_get_error(ssl_data_con, ret); + +- sprintf(errbuf,"ftpd: SSL_accept DATA error %s\n", +- ERR_error_string(ERR_get_error(),NULL)); ++ *errbuf = 0; ++ ++ if (err == SSL_ERROR_SSL) { ++ sprintf(errbuf, "ftpd: Verify %s", ++ X509_verify_cert_error_string(SSL_get_verify_result(ssl_data_con))); ++ reply(425, errbuf); ++ } ++ sprintf(errbuf,"ftpd: SSL_accept DATA %s", ++ ERR_reason_error_string(ERR_peek_error())); ++ errno = errno ? errno : 103; /* ECONNABORTED */ + perror_reply(425, errbuf); + /* abort time methinks ... */ + if(file != NULL){ +@@ -1996,7 +2092,7 @@ static FILE * dataconn(const char *name, + } else { + if (ssl_debug_flag) { + BIO_printf(bio_err,"[SSL DATA Cipher %s]\n", +- SSL_get_cipher(ssl_con)); ++ SSL_get_cipher(ssl_data_con)); + } + ssl_data_active_flag=1; + } +@@ -2094,6 +2190,7 @@ static FILE * dataconn(const char *name, + ssl_data_active_flag=0; + if (ssl_active_flag && ssl_encrypt_data) { + /* do SSL */ ++ int ret; + + reply(150, "Opening %s mode SSL data connection for %s%s.", + type == TYPE_A ? "ASCII" : "BINARY", name, sizebuf); +@@ -2110,7 +2207,9 @@ static FILE * dataconn(const char *name, + /* for 0.5.2 - want to change the timeout value etc ... */ + + SSL_set_fd(ssl_data_con,data); +- SSL_set_verify(ssl_data_con,ssl_verify_flag,NULL); ++ ++ /* No reason to expect client to send certificate. */ ++ SSL_set_verify(ssl_data_con, SSL_VERIFY_NONE, NULL); + + /* if is "safe" to read ahead */ + /* SSL_set_read_ahead(ssl_data_con,1); */ +@@ -2118,11 +2217,21 @@ static FILE * dataconn(const char *name, + if (ssl_debug_flag) + BIO_printf(bio_err,"===>START SSL_accept on DATA\n"); + +- if (SSL_accept(ssl_data_con)<=0) { ++ ret = SSL_accept(ssl_data_con); ++ if (ret <= 0) { + static char errbuf[1024]; ++ int err = SSL_get_error(ssl_data_con, ret); + +- sprintf(errbuf,"ftpd: SSL_accept DATA error %s\n", +- ERR_error_string(ERR_get_error(),NULL)); ++ *errbuf = 0; ++ ++ if (err == SSL_ERROR_SSL) { ++ sprintf(errbuf, "ftpd: Verify %s", ++ X509_verify_cert_error_string(SSL_get_verify_result(ssl_data_con))); ++ reply(425, errbuf); ++ } ++ sprintf(errbuf,"ftpd: SSL_accept DATA %s", ++ ERR_reason_error_string(ERR_peek_error())); ++ errno = errno ? errno : 103; /* ECONNABORTED */ + perror_reply(425, errbuf); + /* abort time methinks ... */ + fclose(file); +@@ -2130,7 +2239,7 @@ static FILE * dataconn(const char *name, + } else { + if (ssl_debug_flag) + BIO_printf(bio_err,"[SSL DATA Cipher %s]\n", +- SSL_get_cipher(ssl_con)); ++ SSL_get_cipher(ssl_data_con)); + ssl_data_active_flag=1; + } + +@@ -2643,8 +2752,10 @@ reply(int n, char *fmt, va_dcl va_alist) + vsnprintf(outputbuf+strlen(outputbuf),2048-(strlen(outputbuf) + 3),fmt,ap); + strcat(outputbuf,"\r\n"); + +- if (ssl_debug_flag) +- BIO_printf(bio_err,"\n<--- %s",outputbuf); ++ if (ssl_debug_flag) { ++ (void) BIO_printf(bio_err,"<--- %s",outputbuf); ++ (void) BIO_flush(bio_err); ++ } + + if (ssl_active_flag) { + SSL_write(ssl_con,outputbuf,strlen(outputbuf)); +@@ -3444,8 +3555,10 @@ do_ssl_start(void) + { + static char errstr[1024]; + +- if (ssl_debug_flag) +- BIO_printf(bio_err,"do_ssl_start triggered\n"); ++ if (ssl_debug_flag) { ++ (void) BIO_printf(bio_err,"do_ssl_start triggered\n"); ++ (void) BIO_flush(bio_err); ++ } + + /* do the SSL stuff now ... before we play with pty's */ + ssl_con=(SSL *)SSL_new(ssl_ctx); +@@ -3467,8 +3580,11 @@ do_ssl_start(void) + } + #endif + ++ if (ssl_debug_flag && ssl_verify_flag) ++ (void) BIO_printf(bio_err, "Setting callback for verification: flag 0x%02x\n", ssl_verify_flag); ++ + SSL_set_verify(ssl_con,ssl_verify_flag, +- ssl_certsok_flag ? verify_callback : NULL); ++ ssl_verify_flag ? verify_callback : NULL); + + if (SSL_accept(ssl_con)<=0) { + sprintf(errstr,"ftpd: SSL_accept %s",ERR_error_string(ERR_get_error(),NULL)); +@@ -3498,6 +3614,11 @@ do_ssl_start(void) + else + syslog(LOG_NOTICE, "SSL SUCCEEDED WITH %s", remotehost); + } ++ ++ if (ssl_debug_flag) ++ BIO_printf(bio_err, "SSL Cipher %s, protocol %s\r\n", ++ SSL_get_cipher_name(ssl_con), ++ SSL_get_version(ssl_con)); + } + + /* ssl_fprintf calls require that this be null to test +@@ -3520,10 +3641,11 @@ ssl_getc(SSL *ssl_con) + char onebyte; + + if (SSL_read(ssl_con,&onebyte,1)!=1) +- return -1; ++ return EOF; + else { +- if (ssl_debug_flag) +- BIO_printf(bio_err,"ssl_getc: SSL_read %d (%c) ",onebyte & 0xff,isprint(onebyte)?onebyte:'.'); ++ if (ssl_debug_flag && !silence_flag) ++ BIO_printf(bio_err, "SSL_read %d (%c) ", ++ onebyte & 0xff, isprint(onebyte) ? onebyte : '.'); + return onebyte & 0xff; + } + } +@@ -3576,6 +3698,21 @@ verify_callback(int ok, + error = X509_STORE_CTX_get_error(ctx); + xs=X509_STORE_CTX_get_current_cert(ctx); + ++ if (ssl_debug_flag) { ++ char *p = (char *) ONELINE_NAME(X509_get_subject_name(xs)); ++ ++ (void) BIO_printf(bio_err, "Subject %d: %s\r\n", depth, p); ++ ++ if (!ok || error) { ++ free(p); ++ p = (char *) ONELINE_NAME(X509_get_issuer_name(xs)); ++ (void) BIO_printf(bio_err, "Issuer %d: %s\r\n", depth, p); ++ (void) BIO_printf(bio_err, "At depth %d: %s\r\n", ++ depth, X509_verify_cert_error_string(error)); ++ } ++ free(p); ++ } ++ + /* + * If the verification fails, then don't remember the name. However, + * if we don't require a certificate, then return success which will +@@ -3588,12 +3725,26 @@ verify_callback(int ok, + free(auth_ssl_name); + auth_ssl_name = 0; + } ++ ++ /* The following manipulation was used up to Debian packaging ++ * of version 0.17.36+0.3-1. It should not be used now that ++ * full verification is available, but is kept for now if the ++ * option '-z legacy' is applied. ++ * Keep old indentation for visibility in the patch file. ++ */ ++ if (ssl_legacy_flag) { + ok=ssl_verify_flag & SSL_VERIFY_FAIL_IF_NO_PEER_CERT ? 0 : 1; +- goto done; ++ ++ if (ssl_debug_flag) ++ (void) BIO_printf(bio_err, ++ "Forcing 'ok' to be %d for legacy.\r\n", ok); ++ } + } +- if (depth == 0) ++ if (depth == 0) { ++ free(auth_ssl_name); + auth_ssl_name = + (char *)ONELINE_NAME(X509_get_subject_name(xs)); ++ } + done: ; + + if (ssl_debug_flag) +diff -Naurp linux-ftpd-0.17.debian/ftpd/sslapp.c linux-ftpd-0.17/ftpd/sslapp.c +--- linux-ftpd-0.17.debian/ftpd/sslapp.c 2016-12-25 23:10:18.059271835 +0100 ++++ linux-ftpd-0.17/ftpd/sslapp.c 2017-01-23 20:16:33.057913180 +0100 +@@ -14,8 +14,12 @@ + + #ifdef USE_SSL + ++#include ++#include + #include "sslapp.h" + ++#include ++ + SSL_CTX *ssl_ctx; + SSL *ssl_con; + int ssl_debug_flag=0; +@@ -27,6 +31,7 @@ int ssl_certsok_flag=0; + int ssl_cert_required=0; + int ssl_verbose_flag=0; + int ssl_disabled_flag=0; ++char *ssl_cacert_file=NULL; + char *ssl_cert_file=NULL; + char *ssl_key_file=NULL; + char *ssl_cipher_list=NULL; +@@ -40,6 +45,7 @@ int + do_ssleay_init(int server) + { + char *p; ++ int ret; + + /* make sure we have somewhere we can log errors to */ + if (bio_err==NULL) { +@@ -48,6 +54,11 @@ do_ssleay_init(int server) + BIO_set_fp(bio_err,stderr,BIO_NOCLOSE); + else { + if (BIO_write_filename(bio_err,ssl_log_file)<=0) { ++ if (server) ++ syslog(LOG_ERR | LOG_DAEMON, "No access to log file %s.", ++ ssl_log_file); ++ else ++ fprintf(stderr, "No logging allowed to %s.\n", ssl_log_file); + /* not a lot we can do */ + } + } +@@ -58,9 +69,10 @@ do_ssleay_init(int server) + * vars are long gone now SSLeay8 has rolled around and we have + * a clean interface for doing things + */ +- if (ssl_debug_flag) ++ if (ssl_debug_flag) { + BIO_printf(bio_err,"SSL_DEBUG_FLAG on\r\n"); +- ++ BIO_flush(bio_err); ++ } + + /* init things so we will get meaningful error messages + * rather than numbers +@@ -68,19 +80,46 @@ do_ssleay_init(int server) + SSL_load_error_strings(); + + SSLeay_add_ssl_algorithms(); +- ssl_ctx=(SSL_CTX *)SSL_CTX_new(SSLv23_method()); + ++ ssl_ctx=(SSL_CTX *)SSL_CTX_new(server ? SSLv23_server_method() ++ : SSLv23_method()); ++ ++# ifndef BUILD_SSL_CLIENT + /* we may require a temp 512 bit RSA key because of the + * wonderful way export things work ... if so we generate + * one now! + */ + if (server) { + if (SSL_CTX_need_tmp_RSA(ssl_ctx)) { +- RSA *rsa; ++ RSA *rsa = NULL; ++ BIGNUM *exp = NULL; + + if (ssl_debug_flag) + BIO_printf(bio_err,"Generating temp (512 bit) RSA key ...\r\n"); ++ ++# if OPENSSL_VERSION_NUMBER > 0x00090800fL ++ rsa = RSA_new(); ++ if (rsa == NULL) ++ return(0); ++ ++ if (ssl_debug_flag && RAND_status() != 1) { ++ BIO_printf(bio_err, "Insufficient seeding of PRNG.\r\n"); ++ BIO_flush(bio_err); ++ } ++ ++ exp = BN_new(); ++ if (exp) { ++ if (BN_set_word(exp, RSA_F4) == 1) ++ RSA_generate_key_ex(rsa, 512, exp, NULL); ++ ++ BN_free(exp); ++ } ++# else /* Not later than 0.9.8. */ + rsa=RSA_generate_key(512,RSA_F4,NULL,NULL); ++# endif ++ if (rsa == NULL) ++ return(0); ++ + if (ssl_debug_flag) + BIO_printf(bio_err,"Generation of temp (512 bit) RSA key done\r\n"); + +@@ -92,20 +131,28 @@ do_ssleay_init(int server) + BIO_printf(bio_err,"Assigned temp (512 bit) RSA key\r\n"); + } + } ++# endif /* !BUILD_SSL_CLIENT */ + + /* also switch on all the interoperability and bug + * workarounds so that we will communicate with people + * that cannot read poorly written specs :-) + */ +- SSL_CTX_set_options(ssl_ctx,SSL_OP_ALL); ++ SSL_CTX_set_options(ssl_ctx, SSL_OP_ALL | SSL_OP_NO_SSLv2); + + /* the user can set whatever ciphers they want to use */ ++ ret = 1; + if (ssl_cipher_list==NULL) { + p=getenv("SSL_CIPHER"); + if (p!=NULL) +- SSL_CTX_set_cipher_list(ssl_ctx,p); ++ ret = SSL_CTX_set_cipher_list(ssl_ctx,p); + } else +- SSL_CTX_set_cipher_list(ssl_ctx,ssl_cipher_list); ++ ret = SSL_CTX_set_cipher_list(ssl_ctx,ssl_cipher_list); ++ ++ if (!ret) { ++ BIO_printf(bio_err, "Cipher choice: %s\r\n", ++ ERR_reason_error_string(ERR_peek_error())); ++ return(0); ++ } + + /* for verbose we use the 0.6.x info callback that I got + * eric to finally add into the code :-) --tjh +@@ -114,27 +161,94 @@ do_ssleay_init(int server) + SSL_CTX_set_info_callback(ssl_ctx,client_info_callback); + } + ++ /* Add any requested CA certificates. */ ++ if (ssl_cacert_file) { ++ errno = 0; ++ ++ if (!SSL_CTX_load_verify_locations(ssl_ctx, ssl_cacert_file, NULL)) { ++ if (errno) ++ BIO_printf(bio_err, "Error loading CA, %s: %s\r\n", ++ strerror(errno), ssl_cacert_file); ++ else { ++ const char *e = ERR_func_error_string(ERR_peek_error()); ++ ++ if (e) ++ BIO_printf(bio_err, "Error loading CA %s: %s, %s\r\n", ++ ssl_cacert_file, e, ++ ERR_reason_error_string(ERR_peek_error())); ++ else ++ BIO_printf(bio_err, "Broken CA file: %s\r\n", ++ ssl_cacert_file); ++ BIO_flush(bio_err); ++ } ++ /* This condition is not desirable, but can only make the ++ chance of later success decrease, not increase! ++ */ ++ if (server) ++ syslog(LOG_NOTICE | LOG_DAEMON, ++ "Error while loading CA file %s.", ssl_cacert_file); ++ } ++# ifndef BUILD_SSL_CLIENT ++ else if (server) { ++ STACK_OF(X509_NAME) *names; ++ ++ if (ssl_debug_flag) ++ BIO_printf(bio_err, "Preparing client CA list.\r\n"); ++ ++ names = SSL_load_client_CA_file(ssl_cacert_file); ++ if (names) ++ SSL_CTX_set_client_CA_list(ssl_ctx, names); ++ else ++ BIO_printf(bio_err, "Failed to load client CA list.\r\n"); ++ } ++# endif /* !BUILD_SSL_CLIENT */ ++ } ++ + /* Add in any certificates if you want to here ... */ + if (ssl_cert_file) { +- if (!SSL_CTX_use_certificate_file(ssl_ctx, ssl_cert_file, +- X509_FILETYPE_PEM)) { +- BIO_printf(bio_err,"Error loading %s: ",ssl_cert_file); +- ERR_print_errors(bio_err); +- BIO_printf(bio_err,"\r\n"); ++ errno = 0; ++ ++ if (!SSL_CTX_use_certificate_chain_file(ssl_ctx, ssl_cert_file)) { ++ if (errno) { ++ BIO_printf(bio_err, "Error loading CRT, %s: %s\r\n", ++ strerror(errno), ssl_cert_file); ++ } else { ++ BIO_printf(bio_err, "Error loading CRT %s: %s, %s\r\n", ++ ssl_cert_file, ++ ERR_func_error_string(ERR_peek_error()), ++ ERR_reason_error_string(ERR_peek_error())); ++ } ++ BIO_flush(bio_err); + return(0); + } else { + if (!ssl_key_file) + ssl_key_file = ssl_cert_file; + if (!SSL_CTX_use_RSAPrivateKey_file(ssl_ctx, ssl_key_file, + X509_FILETYPE_PEM)) { +- BIO_printf(bio_err,"Error loading %s: ",ssl_key_file); +- ERR_print_errors(bio_err); +- BIO_printf(bio_err,"\r\n"); ++ if (errno) { ++ BIO_printf(bio_err, "Error loading KEY, %s: %s\r\n", ++ strerror(errno), ssl_key_file); ++ } else { ++ BIO_printf(bio_err, "Error loading KEY %s: %s, %s\r\n", ++ ssl_key_file, ++ ERR_func_error_string(ERR_peek_error()), ++ ERR_reason_error_string(ERR_peek_error())); ++ } ++ BIO_flush(bio_err); + return(0); + } + } + } + ++# ifndef BUILD_SSL_CLIENT ++ if (server) { ++ const char *id_ctx = "ftpd-ssl"; ++ ++ SSL_CTX_set_session_id_context(ssl_ctx, (const unsigned char *) id_ctx, ++ strlen(id_ctx)); ++ } ++# endif /* !BUILD_SSL_CLIENT */ ++ + /* make sure we will find certificates in the standard + * location ... otherwise we don't look anywhere for + * these things which is going to make client certificate +@@ -150,6 +264,9 @@ do_ssleay_init(int server) + SSL_set_verify(ssl_con,ssl_verify_flag,client_verify_callback); + #endif + ++ if (ssl_debug_flag) ++ BIO_flush(bio_err); ++ + return(1); + } + +diff -Naurp linux-ftpd-0.17.debian/ftpd/sslapp.h linux-ftpd-0.17/ftpd/sslapp.h +--- linux-ftpd-0.17.debian/ftpd/sslapp.h 2016-12-25 23:10:16.619338683 +0100 ++++ linux-ftpd-0.17/ftpd/sslapp.h 2017-01-23 15:24:03.266036030 +0100 +@@ -47,6 +47,7 @@ extern int ssl_cert_required; + extern int ssl_certsok_flag; + + extern char *ssl_log_file; ++extern char *ssl_cacert_file; + extern char *ssl_cert_file; + extern char *ssl_key_file; + extern char *ssl_cipher_list; diff -Nru linux-ftpd-ssl-0.17.36+0.3/debian/patches/series linux-ftpd-ssl-0.17.36+0.3/debian/patches/series --- linux-ftpd-ssl-0.17.36+0.3/debian/patches/series 2016-12-17 13:25:33.000000000 +0000 +++ linux-ftpd-ssl-0.17.36+0.3/debian/patches/series 2017-01-16 21:30:20.000000000 +0000 @@ -24,3 +24,8 @@ 550-fix_warnings.diff 560-set_default_key_and_cert.diff 570-redirect_ssl_output.diff +580-recent_libssl.diff +# +# Upgrading of legacy SSL code. +# +600-better_conformity.diff