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

Reply via email to