Forgotten diff... For https connections which involve redirections, ftp(1) needlessly re-initializes libssl/libcrypto. It also creates, but doesn't free, a new SSL_CTX structure at each url_get() call.
This diff makes ftp(1) perform this work lazily, and reuses the same SSL_CTX for subsequent HTTPS connections. I don't have the code anymore but using atexit(3) hooks to deallocate the libcrypto/libssl structures showed that indeed no leak was left there. Last hunk: as noticed by Mike Small and Maxime Villard, this patch adds a X509_free call for the server cert, in case the server hostname can't be validated. No functional change, just for consistency. Tests, comments and oks are welcome. Index: fetch.c =================================================================== RCS file: /cvs/src/usr.bin/ftp/fetch.c,v retrieving revision 1.118 diff -u -p -p -u -r1.118 fetch.c --- fetch.c 9 Apr 2014 10:10:57 -0000 1.118 +++ fetch.c 22 Apr 2014 23:54:22 -0000 @@ -87,6 +87,7 @@ int ssl_match_hostname(char *, char *); int ssl_check_subject_altname(X509 *, char *); int ssl_check_common_name(X509 *, char *); int ssl_check_hostname(X509 *, char *); +SSL_CTX *ssl_get_ssl_ctx(void); #endif /* !SMALL */ #define FTP_URL "ftp://" /* ftp URL prefix */ @@ -329,6 +330,52 @@ ssl_check_hostname(X509 *cert, char *hos return ssl_check_common_name(cert, host); } + +SSL_CTX * +ssl_get_ssl_ctx(void) +{ + static SSL_CTX *ssl_ctx; + static int libssl_loaded; + + if (ssl_ctx != NULL) + return ssl_ctx; + + if (!libssl_loaded) { + SSL_library_init(); + SSL_load_error_strings(); + libssl_loaded = 1; + } + + ssl_ctx = SSL_CTX_new(SSLv23_client_method()); + if (ssl_ctx == NULL) + goto err; + + if (ssl_verify) { + if (ssl_ca_file == NULL && ssl_ca_path == NULL) + ssl_ca_file = _PATH_SSL_CAFILE; + + if (SSL_CTX_load_verify_locations(ssl_ctx, + ssl_ca_file, ssl_ca_path) != 1) + goto err; + + SSL_CTX_set_verify(ssl_ctx, SSL_VERIFY_PEER, NULL); + if (ssl_verify_depth != -1) + SSL_CTX_set_verify_depth(ssl_ctx, + ssl_verify_depth); + } + + if (ssl_ciphers != NULL && + SSL_CTX_set_cipher_list(ssl_ctx, ssl_ciphers) == -1) + goto err; + + return ssl_ctx; +err: + if (ssl_ctx != NULL) { + SSL_CTX_free(ssl_ctx); + ssl_ctx = NULL; + } + return NULL; +} #endif /* @@ -769,31 +816,11 @@ again: proxyurl = NULL; path = sslpath; } - SSL_library_init(); - SSL_load_error_strings(); - ssl_ctx = SSL_CTX_new(SSLv23_client_method()); + ssl_ctx = ssl_get_ssl_ctx(); if (ssl_ctx == NULL) { ERR_print_errors_fp(ttyout); goto cleanup_url_get; } - if (ssl_verify) { - if (ssl_ca_file == NULL && ssl_ca_path == NULL) - ssl_ca_file = _PATH_SSL_CAFILE; - if (SSL_CTX_load_verify_locations(ssl_ctx, - ssl_ca_file, ssl_ca_path) != 1) { - ERR_print_errors_fp(ttyout); - goto cleanup_url_get; - } - SSL_CTX_set_verify(ssl_ctx, SSL_VERIFY_PEER, NULL); - if (ssl_verify_depth != -1) - SSL_CTX_set_verify_depth(ssl_ctx, - ssl_verify_depth); - } - if (ssl_ciphers != NULL && - SSL_CTX_set_cipher_list(ssl_ctx, ssl_ciphers) == -1) { - ERR_print_errors_fp(ttyout); - goto cleanup_url_get; - } ssl = SSL_new(ssl_ctx); if (ssl == NULL) { ERR_print_errors_fp(ttyout); @@ -829,6 +856,7 @@ again: } if (ssl_check_hostname(cert, host) != 0) { + X509_free(cert); fprintf(ttyout, "%s: host `%s' not present in" " server certificate\n", getprogname(), host); -- jca | PGP : 0x1524E7EE / 5135 92C1 AD36 5293 2BDF DDCC 0DFA 74AE 1524 E7EE