commit bd5cdd5f2ddf4e9c26ff9353d15324dd0bbda37c
Author: Jeremy Harris <jgh146exb@wizmail.org>
Date:   Mon Feb 12 17:29:22 2018 +0000

    ACL: Enforce non-usability of control=utf8_downconvert in MAIL ACL.  Bug 2239

diff --git a/src/src/acl.c b/src/src/acl.c
index 750fd2da..95ee2667 100644
--- a/src/src/acl.c
+++ b/src/src/acl.c
@@ -533,7 +533,9 @@ static control_def controls_list[] = {
   },
 #ifdef SUPPORT_I18N
 [CONTROL_UTF8_DOWNCONVERT] =
-  { US"utf8_downconvert",        TRUE, 0 }
+  { US"utf8_downconvert",        TRUE,
+    (unsigned) ~((1<<ACL_WHERE_RCPT) | (1<<ACL_WHERE_VRFY))
+  }
 #endif
 };
 

commit 695a7097d5f737350c6bbb007f9f8a3b7cad5c24
Author: Jeremy Harris <jgh146exb@wizmail.org>
Date:   Sat Feb 17 16:53:27 2018 +0000

    Fix memory leak during multi-message reception using STARTTLS
    
    Reported-by: Wolfgang Breyha

diff --git a/src/src/tls-gnu.c b/src/src/tls-gnu.c
index fc3aba59..58f50510 100644
--- a/src/src/tls-gnu.c
+++ b/src/src/tls-gnu.c
@@ -2202,9 +2202,10 @@ gnutls_certificate_free_credentials(state->x509_cred);
 
 
 state->tlsp->active = -1;
+if (state->xfer_buffer) store_free(state->xfer_buffer);
 memcpy(state, &exim_gnutls_state_init, sizeof(exim_gnutls_state_init));
 
-if ((state_server.session == NULL) && (state_client.session == NULL))
+if (!state_server.session && !state_client.session)
   {
   gnutls_global_deinit();
   exim_gnutls_base_init_done = FALSE;
diff --git a/src/src/tls-openssl.c b/src/src/tls-openssl.c
index b225eb76..03b9023d 100644
--- a/src/src/tls-openssl.c
+++ b/src/src/tls-openssl.c
@@ -2073,7 +2073,7 @@ DEBUG(D_tls)
    smtp_read_response()/ip_recv().
    Hence no need to duplicate for _in and _out.
  */
-ssl_xfer_buffer = store_malloc(ssl_xfer_buffer_size);
+if (!ssl_xfer_buffer) ssl_xfer_buffer = store_malloc(ssl_xfer_buffer_size);
 ssl_xfer_buffer_lwm = ssl_xfer_buffer_hwm = 0;
 ssl_xfer_eof = ssl_xfer_error = 0;
 

commit 2a8bf6ec7eb5ef9760bae9c8b104966d25cfb510
Author: Wolfgang Breyha <wbreyha@gmx.net>
Date:   Mon Feb 19 18:27:55 2018 +0000

    OpenSSL: Fix memory leak during multi-message connections using STARTTLS
    
    Reported-by: Wolfgang Breyha
    Fix-by: Wolfgang Breyha, with additions from Jeremy Harris

diff --git a/src/src/daemon.c b/src/src/daemon.c
index 37fefd4b..f7a27477 100644
--- a/src/src/daemon.c
+++ b/src/src/daemon.c
@@ -653,7 +653,7 @@ if (pid == 0)
         the data structures if necessary. */
 
 #ifdef SUPPORT_TLS
-        tls_close(TRUE, FALSE);
+        tls_close(TRUE, TLS_NO_SHUTDOWN);
 #endif
 
         /* Reset SIGHUP and SIGCHLD in the child in both cases. */
diff --git a/src/src/deliver.c b/src/src/deliver.c
index 9f9990be..2dfa9e38 100644
--- a/src/src/deliver.c
+++ b/src/src/deliver.c
@@ -4990,7 +4990,7 @@ all pipes, so I do not see a reason to use non-blocking IO here
   if (cutthrough.fd >= 0 && cutthrough.callout_hold_only)
     {
 #ifdef SUPPORT_TLS
-    tls_close(FALSE, FALSE);
+    tls_close(FALSE, TLS_NO_SHUTDOWN);
 #endif
     (void) close(cutthrough.fd);
     release_cutthrough_connection(US"passed to transport proc");
diff --git a/src/src/exim.c b/src/src/exim.c
index d71af0ac..b18d3688 100644
--- a/src/src/exim.c
+++ b/src/src/exim.c
@@ -543,7 +543,7 @@ close_unwanted(void)
 if (smtp_input)
   {
   #ifdef SUPPORT_TLS
-  tls_close(TRUE, FALSE);      /* Shut down the TLS library */
+  tls_close(TRUE, TLS_NO_SHUTDOWN);      /* Shut down the TLS library */
   #endif
   (void)close(fileno(smtp_in));
   (void)close(fileno(smtp_out));
diff --git a/src/src/functions.h b/src/src/functions.h
index e50fa6f9..53891162 100644
--- a/src/src/functions.h
+++ b/src/src/functions.h
@@ -50,7 +50,7 @@ extern int     tls_client_start(int, host_item *, address_item *,
 		dns_answer *,
 # endif
 		uschar **);
-extern void    tls_close(BOOL, BOOL);
+extern void    tls_close(BOOL, int);
 extern BOOL    tls_could_read(void);
 extern int     tls_export_cert(uschar *, size_t, void *);
 extern int     tls_feof(void);
diff --git a/src/src/macros.h b/src/src/macros.h
index 764c65b8..5f9c7422 100644
--- a/src/src/macros.h
+++ b/src/src/macros.h
@@ -991,5 +991,10 @@ enum { FILTER_UNSET, FILTER_FORWARD, FILTER_EXIM, FILTER_SIEVE };
 #define UTF8_VERT_2DASH		"\xE2\x95\x8E"
 
 
+/* Options on tls_close */
+#define TLS_NO_SHUTDOWN		0
+#define TLS_SHUTDOWN_NOWAIT	1
+#define TLS_SHUTDOWN_WAIT	2
+
 
 /* End of macros.h */
diff --git a/src/src/smtp_in.c b/src/src/smtp_in.c
index 2603da25..3339f9a1 100644
--- a/src/src/smtp_in.c
+++ b/src/src/smtp_in.c
@@ -3732,7 +3732,7 @@ else
   smtp_printf("221 %s closing connection\r\n", FALSE, smtp_active_hostname);
 
 #ifdef SUPPORT_TLS
-tls_close(TRUE, TRUE);
+tls_close(TRUE, TLS_SHUTDOWN_NOWAIT);
 #endif
 
 log_write(L_smtp_connection, LOG_MAIN, "%s closed by QUIT",
@@ -5417,7 +5417,7 @@ while (done <= 0)
 	smtp_printf("554 Security failure\r\n", FALSE);
 	break;
       }
-    tls_close(TRUE, TRUE);
+    tls_close(TRUE, TLS_SHUTDOWN_NOWAIT);
     break;
     #endif
 
diff --git a/src/src/tls-gnu.c b/src/src/tls-gnu.c
index 58f50510..ffadd96b 100644
--- a/src/src/tls-gnu.c
+++ b/src/src/tls-gnu.c
@@ -2180,12 +2180,15 @@ return OK;
 daemon, to shut down the TLS library, without actually doing a shutdown (which
 would tamper with the TLS session in the parent process).
 
-Arguments:   TRUE if gnutls_bye is to be called
+Arguments:
+  shutdown	1 if TLS close-alert is to be sent,
+ 		2 if also response to be waited for
+
 Returns:     nothing
 */
 
 void
-tls_close(BOOL is_server, BOOL shutdown)
+tls_close(BOOL is_server, int shutdown)
 {
 exim_gnutls_state_st *state = is_server ? &state_server : &state_client;
 
@@ -2193,8 +2196,12 @@ if (!state->tlsp || state->tlsp->active < 0) return;  /* TLS was not active */
 
 if (shutdown)
   {
-  DEBUG(D_tls) debug_printf("tls_close(): shutting down TLS\n");
-  gnutls_bye(state->session, GNUTLS_SHUT_WR);
+  DEBUG(D_tls) debug_printf("tls_close(): shutting down TLS%s\n",
+    shutdown > 1 ? " (with response-wait)" : "");
+
+  alarm(2);
+  gnutls_bye(state->session, shutdown > 1 ? GNUTLS_SHUT_RDWR : GNUTLS_SHUT_WR);
+  alarm(0);
   }
 
 gnutls_deinit(state->session);
diff --git a/src/src/tls-openssl.c b/src/src/tls-openssl.c
index 03b9023d..da7eb8a4 100644
--- a/src/src/tls-openssl.c
+++ b/src/src/tls-openssl.c
@@ -152,6 +152,7 @@ typedef struct tls_ext_ctx_cb {
   uschar *certificate;
   uschar *privatekey;
   BOOL is_server;
+  STACK_OF(X509_NAME) * acceptable_certnames;
 #ifndef DISABLE_OCSP
   STACK_OF(X509) *verify_stack;		/* chain for verifying the proof */
   union {
@@ -1488,6 +1489,7 @@ cbinfo = store_malloc(sizeof(tls_ext_ctx_cb));
 cbinfo->certificate = certificate;
 cbinfo->privatekey = privatekey;
 cbinfo->is_server = host==NULL;
+cbinfo->acceptable_certnames = NULL;
 #ifndef DISABLE_OCSP
 cbinfo->verify_stack = NULL;
 if (!host)
@@ -1732,6 +1734,9 @@ chain_from_pem_file(const uschar * file, STACK_OF(X509) * verify_stack)
 BIO * bp;
 X509 * x;
 
+while (sk_X509_num(verify_stack) > 0)
+  X509_free(sk_X509_pop(verify_stack));
+
 if (!(bp = BIO_new_file(CS file, "r"))) return FALSE;
 while ((x = PEM_read_bio_X509(bp, NULL, 0, NULL)))
   sk_X509_push(verify_stack, x);
@@ -1741,7 +1746,8 @@ return TRUE;
 
 
 
-/* Called by both client and server startup
+/* Called by both client and server startup; on the server possibly
+repeated after a Server Name Indication.
 
 Arguments:
   sctx          SSL_CTX* to initialise
@@ -1791,6 +1797,7 @@ if (expcerts && *expcerts)
 	{ file = NULL; dir = expcerts; }
       else
 	{
+	/*XXX somewhere down here we leak memory per-STARTTLS, on a multi-message conn, server-side */
 	file = expcerts; dir = NULL;
 #ifndef DISABLE_OCSP
 	/* In the server if we will be offering an OCSP proof, load chain from
@@ -1831,11 +1838,21 @@ if (expcerts && *expcerts)
       */
       if (file)
 	{
-	STACK_OF(X509_NAME) * names = SSL_load_client_CA_file(CS file);
+	tls_ext_ctx_cb * cbinfo = host
+	  ? client_static_cbinfo : server_static_cbinfo;
+	STACK_OF(X509_NAME) * names;
 
+	if ((names = cbinfo->acceptable_certnames))
+	  {
+	  sk_X509_NAME_pop_free(names, X509_NAME_free);
+	  cbinfo->acceptable_certnames = NULL;
+	  }
+	names = SSL_load_client_CA_file(CS file);
+
+	SSL_CTX_set_client_CA_list(sctx, names);
 	DEBUG(D_tls) debug_printf("Added %d certificate authorities.\n",
 				    sk_X509_NAME_num(names));
-	SSL_CTX_set_client_CA_list(sctx, names);
+	cbinfo->acceptable_certnames = names;
 	}
       }
     }
@@ -2446,7 +2463,16 @@ if (error == SSL_ERROR_ZERO_RETURN)
   receive_ferror = smtp_ferror;
   receive_smtp_buffered = smtp_buffered;
 
+  if (SSL_get_shutdown(server_ssl) == SSL_RECEIVED_SHUTDOWN)
+ 	SSL_shutdown(server_ssl);
+
+  sk_X509_pop_free(server_static_cbinfo->verify_stack, X509_free);
+  sk_X509_NAME_pop_free(server_static_cbinfo->acceptable_certnames, X509_NAME_free);
   SSL_free(server_ssl);
+  SSL_CTX_free(server_ctx);
+  server_static_cbinfo->verify_stack = NULL;
+  server_static_cbinfo->acceptable_certnames = NULL;
+  server_ctx = NULL;
   server_ssl = NULL;
   tls_in.active = -1;
   tls_in.bits = 0;
@@ -2680,15 +2706,19 @@ return len;
 daemon, to shut down the TLS library, without actually doing a shutdown (which
 would tamper with the SSL session in the parent process).
 
-Arguments:   TRUE if SSL_shutdown is to be called
+Arguments:
+  shutdown	1 if TLS close-alert is to be sent,
+ 		2 if also response to be waited for
+
 Returns:     nothing
 
 Used by both server-side and client-side TLS.
 */
 
 void
-tls_close(BOOL is_server, BOOL shutdown)
+tls_close(BOOL is_server, int shutdown)
 {
+SSL_CTX **ctxp = is_server ? &server_ctx : &client_ctx;
 SSL **sslp = is_server ? &server_ssl : &client_ssl;
 int *fdp = is_server ? &tls_in.active : &tls_out.active;
 
@@ -2696,13 +2726,38 @@ if (*fdp < 0) return;  /* TLS was not active */
 
 if (shutdown)
   {
-  DEBUG(D_tls) debug_printf("tls_close(): shutting down SSL\n");
-  SSL_shutdown(*sslp);
+  int rc;
+  DEBUG(D_tls) debug_printf("tls_close(): shutting down TLS%s\n",
+    shutdown > 1 ? " (with response-wait)" : "");
+
+  if (  (rc = SSL_shutdown(*sslp)) == 0	/* send "close notify" alert */
+     && shutdown > 1)
+    {
+    alarm(2);
+    rc = SSL_shutdown(*sslp);		/* wait for response */
+    alarm(0);
+    }
+
+  if (rc < 0) DEBUG(D_tls)
+    {
+    ERR_error_string(ERR_get_error(), ssl_errstring);
+    debug_printf("SSL_shutdown: %s\n", ssl_errstring);
+    }
+  }
+
+if (is_server)
+  {
+  sk_X509_pop_free(server_static_cbinfo->verify_stack, X509_free);
+  sk_X509_NAME_pop_free(server_static_cbinfo->acceptable_certnames,
+    X509_NAME_free);
+  server_static_cbinfo->verify_stack = NULL;
+  server_static_cbinfo->acceptable_certnames = NULL;
   }
 
+SSL_CTX_free(*ctxp);
 SSL_free(*sslp);
+*ctxp = NULL;
 *sslp = NULL;
-
 *fdp = -1;
 }
 
diff --git a/src/src/transports/smtp.c b/src/src/transports/smtp.c
index 5d351dd7..acfec506 100644
--- a/src/src/transports/smtp.c
+++ b/src/src/transports/smtp.c
@@ -2233,7 +2233,7 @@ if (sx->send_quit)
   (void)smtp_write_command(&sx->outblock, SCMD_FLUSH, "QUIT\r\n");
 
 #ifdef SUPPORT_TLS
-tls_close(FALSE, TRUE);
+tls_close(FALSE, TLS_SHUTDOWN_NOWAIT);
 #endif
 
 /* Close the socket, and return the appropriate value, first setting
@@ -2667,7 +2667,7 @@ for (fd_bits = 3; fd_bits; )
     if ((rc = read(pfd[0], buf, bsize)) <= 0)
       {
       fd_bits = 0;
-      tls_close(FALSE, TRUE);
+      tls_close(FALSE, TLS_SHUTDOWN_NOWAIT);
       }
     else
       {
@@ -3457,7 +3457,7 @@ if (sx.completed_addr && sx.ok && sx.send_quit)
 	  a new EHLO. If we don't get a good response, we don't attempt to pass
 	  the socket on. */
 
-	  tls_close(FALSE, TRUE);
+	  tls_close(FALSE, TLS_SHUTDOWN_WAIT);
 	  smtp_peer_options = smtp_peer_options_wrap;
 	  sx.ok = !sx.smtps
 	    && smtp_write_command(&sx.outblock, SCMD_FLUSH,
@@ -3522,7 +3522,7 @@ propagate it from the initial
 	    close(pfd[0]);
 	    /* tidy the inter-proc to disconn the proxy proc */
 	    waitpid(pid, NULL, 0);
-	    tls_close(FALSE, FALSE);
+	    tls_close(FALSE, TLS_NO_SHUTDOWN);
 	    (void)close(sx.inblock.sock);
 	    continue_transport = NULL;
 	    continue_hostname = NULL;
@@ -3568,7 +3568,7 @@ if (sx.send_quit) (void)smtp_write_command(&sx.outblock, SCMD_FLUSH, "QUIT\r\n")
 END_OFF:
 
 #ifdef SUPPORT_TLS
-tls_close(FALSE, TRUE);
+tls_close(FALSE, TLS_SHUTDOWN_NOWAIT);
 #endif
 
 /* Close the socket, and return the appropriate value, first setting
@@ -4540,7 +4540,7 @@ retry_non_continued:
     if (tls_out.active == fd)
       {
       (void) tls_write(FALSE, US"QUIT\r\n", 6, FALSE);
-      tls_close(FALSE, TRUE);
+      tls_close(FALSE, TLS_SHUTDOWN_NOWAIT);
       }
     else
 #else
diff --git a/src/src/verify.c b/src/src/verify.c
index 5486ca23..544069bb 100644
--- a/src/src/verify.c
+++ b/src/src/verify.c
@@ -821,7 +821,7 @@ tls_retry_connection:
 	      debug_printf_indent("problem after random/rset/mfrom; reopen conn\n");
 	    random_local_part = NULL;
 #ifdef SUPPORT_TLS
-	    tls_close(FALSE, TRUE);
+	    tls_close(FALSE, TLS_SHUTDOWN_NOWAIT);
 #endif
 	    HDEBUG(D_transport|D_acl|D_v) debug_printf_indent("  SMTP(close)>>\n");
 	    (void)close(sx.inblock.sock);
@@ -1088,7 +1088,7 @@ no_conn:
       if (sx.inblock.sock >= 0)
 	{
 #ifdef SUPPORT_TLS
-	tls_close(FALSE, TRUE);
+	tls_close(FALSE, TLS_SHUTDOWN_NOWAIT);
 #endif
 	HDEBUG(D_transport|D_acl|D_v) debug_printf_indent("  SMTP(close)>>\n");
 	(void)close(sx.inblock.sock);
@@ -1389,7 +1389,7 @@ if(fd >= 0)
   cutthrough_response(fd, '2', NULL, 1);
 
 #ifdef SUPPORT_TLS
-  tls_close(FALSE, TRUE);
+  tls_close(FALSE, TLS_SHUTDOWN_NOWAIT);
 #endif
   HDEBUG(D_transport|D_acl|D_v) debug_printf_indent("  SMTP(close)>>\n");
   (void)close(fd);

commit 8b17525025ccd7af1299c9fee2bd43595ab3de09
Author: Jeremy Harris <jgh146exb@wizmail.org>
Date:   Thu Feb 22 11:26:34 2018 +0000

    Fix exim_dbmbuild to permit directoryless filenames.  Bug 2242
    
    Broken-by: 0a6c178c6c

diff --git a/src/src/exim_dbmbuild.c b/src/src/exim_dbmbuild.c
index 2dcc40f3..fb5317b8 100644
--- a/src/src/exim_dbmbuild.c
+++ b/src/src/exim_dbmbuild.c
@@ -210,6 +210,8 @@ Ustrcat(temp_dbmname, ".dbmbuild_temp");
 Ustrcpy(dirname, temp_dbmname);
 if ((bptr = Ustrrchr(dirname, '/')))
   *bptr = '\0';
+else
+  Ustrcpy(dirname, ".");
 
 /* It is apparently necessary to open with O_RDWR for this to work
 with gdbm-1.7.3, though no reading is actually going to be done. */
