commit b394e1bf3000fc0c50753c51018e859de48ccc8f
Author: Jeremy Harris <jgh146exb@wizmail.org>
Date:   Sat Feb 9 16:56:59 2019 +0000

    Fix json extract operator for unfound case
    
    (cherry picked from commit e73798976812e652320f096870359ef35ed069ff)
    (cherry picked from commit b2734f7b45111f9b7de790c7b334a2ece47675b5)
    (cherry picked from commit b88b6f6f3a29b70cd0b314da8ceab18b0b34eed6)
    (cherry picked from commit f07c22772581c167112540af35b997e6829eef64)

diff --git a/src/src/expand.c b/src/src/expand.c
index 1bcfbe8d..c2eba072 100644
--- a/src/src/expand.c
+++ b/src/src/expand.c
@@ -5861,10 +5861,11 @@ while (*s != 0)
 	      }
 	    while (field_number > 0 && (item = json_nextinlist(&list)))
 	      field_number--;
-	    s = item;
-	    lookup_value = s;
-	    while (*s) s++;
-	    while (--s >= lookup_value && isspace(*s)) *s = '\0';
+	    if ((lookup_value = s = item))
+	      {
+	      while (*s) s++;
+	      while (--s >= lookup_value && isspace(*s)) *s = '\0';
+	      }
 	    }
 	  else
 	    {

commit 38a2fdc289898efa380dcc16f43efe5fc55ab07e
Author: Jeremy Harris <jgh146exb@wizmail.org>
Date:   Tue Feb 12 16:52:51 2019 +0000

    Fix transport buffer size handling
    
    Broken-by: 59932f7dcd
    
    (cherry picked from commit 05bf16f6217e93594929c8bbbbbc852caf3ed374)
    (cherry picked from commit 1cfa7822ca8928f95160df8742af11fff888ae7e)
    (cherry picked from commit 0654d3440d8735221a58f96f5343fbe243171711)
    (cherry picked from commit 926fce6aaacb525c10c864d4064b1cd086e0dd5a)

diff --git a/src/src/transport.c b/src/src/transport.c
index 8ccdd038..a069b883 100644
--- a/src/src/transport.c
+++ b/src/src/transport.c
@@ -1115,13 +1115,13 @@ DEBUG(D_transport)
 
 if (!(tctx->options & topt_no_body))
   {
-  int size = size_limit;
+  unsigned long size = size_limit > 0 ? size_limit : ULONG_MAX;
 
   nl_check_length = abs(nl_check_length);
   nl_partial_match = 0;
   if (lseek(deliver_datafile, SPOOL_DATA_START_OFFSET, SEEK_SET) < 0)
     return FALSE;
-  while (  (len = MAX(DELIVER_IN_BUFFER_SIZE, size)) > 0
+  while (  (len = MIN(DELIVER_IN_BUFFER_SIZE, size)) > 0
 	&& (len = read(deliver_datafile, deliver_in_buffer, len)) > 0)
     {
     if (!write_chunk(tctx, deliver_in_buffer, len))

commit e26ad9f422a597d4116c1cd55f9f2cea542bd828
Author: Jeremy Harris <jgh146exb@wizmail.org>
Date:   Thu Feb 14 17:14:34 2019 +0000

    Fix info on using local_scan() in the default Makefile
    
    Broken-by: 9723f96673
    (cherry picked from commit 882bc1704d33aa34873e3a0f72e657b0cc2985e5)
    (cherry picked from commit cb25b75af850d664fc005d24fbad0e58bf79d4c7)
    (cherry picked from commit 2c7c4a9c23950044507a78956ca2c23f9c6a9491)
    (cherry picked from commit 0799ba118b9c83731c1db34affcf9fecc10fd627)

diff --git a/src/OS/Makefile-Default b/src/OS/Makefile-Default
index b3990fe8..41a4dbbd 100644
--- a/src/OS/Makefile-Default
+++ b/src/OS/Makefile-Default
@@ -232,6 +232,11 @@ RANLIB=ranlib
 EXIM_CHMOD=@true
 
 
+# If you want to use local_scan() at all, the support code must be included
+# by uncommenting this line.
+
+# HAVE_LOCAL_SCAN=yes
+
 # LOCAL_SCAN_SOURCE defines the file in which the function local_scan() is
 # defined. This provides the administrator with a hook for including C code
 # for scanning incoming mails. The path that is defined must be relative to
@@ -239,8 +244,9 @@ EXIM_CHMOD=@true
 
 # LOCAL_SCAN_SOURCE=Local/local_scan.c
 
-# The default setting points to a template function that doesn't actually do
-# any scanning, but just accepts the message.
+# A very simple example points to a template function that doesn't actually do
+# any scanning, but just accepts the message.  A compilable file must be
+# included in the build even if HAVE_LOCAL_SCAN is not defined.
 
 LOCAL_SCAN_SOURCE=src/local_scan.c
 

commit 74675f834e5c7ebd58090c886793fff58427e2dc
Author: Jeremy Harris <jgh146exb@wizmail.org>
Date:   Sat Feb 16 12:59:23 2019 +0000

    GnuTLS: Fix client detection of server reject of client cert under TLS1.3
    
    (cherry picked from commit fc243e944ec00b59b75f41d07494116f925d58b4)
    (cherry picked from commit c15523829ba17cce5829e2976aa1ff928965d948)
    (cherry picked from commit c18e2c3b059f6bfd1c6e9a65ffc8243a4d8034fe)
    (cherry picked from commit c07419f2eda0c1a3f2fe7282de9da2e661b8b068)

diff --git a/src/src/deliver.c b/src/src/deliver.c
index 664d0045..e1799411 100644
--- a/src/src/deliver.c
+++ b/src/src/deliver.c
@@ -7433,7 +7433,7 @@ if (addr_senddsn)
 
     tctx.u.fd = fd;
     tctx.options = topt_add_return_path | topt_no_body;
-    /*XXX hmm, retval ignored.
+    /*XXX hmm, FALSE(fail) retval ignored.
     Could error for any number of reasons, and they are not handled. */
     transport_write_message(&tctx, 0);
     fflush(f);
diff --git a/src/src/smtp_out.c b/src/src/smtp_out.c
index 9bd90c77..b194e804 100644
--- a/src/src/smtp_out.c
+++ b/src/src/smtp_out.c
@@ -688,20 +688,22 @@ Returns:    TRUE if a valid, non-error response was received; else FALSE
 /*XXX could move to smtp transport; no other users */
 
 BOOL
-smtp_read_response(void * sx0, uschar *buffer, int size, int okdigit,
+smtp_read_response(void * sx0, uschar * buffer, int size, int okdigit,
    int timeout)
 {
 smtp_context * sx = sx0;
-uschar *ptr = buffer;
-int count = 0;
+uschar * ptr = buffer;
+int count = 0, rc;
 
 errno = 0;  /* Ensure errno starts out zero */
 
 #ifdef EXPERIMENTAL_PIPE_CONNECT
 if (sx->pending_BANNER || sx->pending_EHLO)
-  if (smtp_reap_early_pipe(sx, &count) != OK)
+  if ((rc = smtp_reap_early_pipe(sx, &count)) != OK)
     {
     DEBUG(D_transport) debug_printf("failed reaping pipelined cmd responsess\n");
+    buffer[0] = '\0';
+    if (rc == DEFER) errno = ERRNO_TLSFAILURE;
     return FALSE;
     }
 #endif
diff --git a/src/src/tls-gnu.c b/src/src/tls-gnu.c
index c404dc29..de2d70c0 100644
--- a/src/src/tls-gnu.c
+++ b/src/src/tls-gnu.c
@@ -229,7 +229,7 @@ static gnutls_dh_params_t dh_server_params = NULL;
 
 static const int ssl_session_timeout = 200;
 
-static const char * const exim_default_gnutls_priority = "NORMAL";
+static const uschar * const exim_default_gnutls_priority = US"NORMAL";
 
 /* Guard library core initialisation */
 
@@ -1278,7 +1278,6 @@ int rc;
 size_t sz;
 const char *errpos;
 uschar *p;
-BOOL want_default_priorities;
 
 if (!exim_gnutls_base_init_done)
   {
@@ -1387,32 +1386,24 @@ and replaces gnutls_require_kx, gnutls_require_mac & gnutls_require_protocols.
 This was backwards incompatible, but means Exim no longer needs to track
 all algorithms and provide string forms for them. */
 
-want_default_priorities = TRUE;
-
+p = NULL;
 if (state->tls_require_ciphers && *state->tls_require_ciphers)
   {
   if (!expand_check_tlsvar(tls_require_ciphers, errstr))
     return DEFER;
   if (state->exp_tls_require_ciphers && *state->exp_tls_require_ciphers)
     {
-    DEBUG(D_tls) debug_printf("GnuTLS session cipher/priority \"%s\"\n",
-        state->exp_tls_require_ciphers);
-
-    rc = gnutls_priority_init(&state->priority_cache,
-        CS state->exp_tls_require_ciphers, &errpos);
-    want_default_priorities = FALSE;
     p = state->exp_tls_require_ciphers;
+    DEBUG(D_tls) debug_printf("GnuTLS session cipher/priority \"%s\"\n", p);
     }
   }
-if (want_default_priorities)
+if (!p)
   {
+  p = exim_default_gnutls_priority;
   DEBUG(D_tls)
-    debug_printf("GnuTLS using default session cipher/priority \"%s\"\n",
-        exim_default_gnutls_priority);
-  rc = gnutls_priority_init(&state->priority_cache,
-      exim_default_gnutls_priority, &errpos);
-  p = US exim_default_gnutls_priority;
+    debug_printf("GnuTLS using default session cipher/priority \"%s\"\n", p);
   }
+rc = gnutls_priority_init(&state->priority_cache, CCS p, &errpos);
 
 exim_gnutls_err_check(rc, string_sprintf(
       "gnutls_priority_init(%s) failed at offset %ld, \"%.6s..\"",
diff --git a/src/src/transports/lmtp.c b/src/src/transports/lmtp.c
index 240d78b2..57b346d4 100644
--- a/src/src/transports/lmtp.c
+++ b/src/src/transports/lmtp.c
@@ -122,7 +122,8 @@ Arguments:
 Returns:       TRUE if a "QUIT" command should be sent, else FALSE
 */
 
-static BOOL check_response(int *errno_value, int more_errno, uschar *buffer,
+static BOOL
+check_response(int *errno_value, int more_errno, uschar *buffer,
   int *yield, uschar **message)
 {
 *yield = '4';    /* Default setting is to give a temporary error */
diff --git a/src/src/transports/smtp.c b/src/src/transports/smtp.c
index a351da84..bfd6018d 100644
--- a/src/src/transports/smtp.c
+++ b/src/src/transports/smtp.c
@@ -594,6 +594,11 @@ switch(*errno_value)
 	  pl, smtp_command, s);
     return FALSE;
 
+  case ERRNO_TLSFAILURE:	/* Handle bad first read; can happen with
+				GnuTLS and TLS1.3 */
+    *message = US"bad first read from TLS conn";
+    return TRUE;
+
   case ERRNO_FILTER_FAIL:	/* Handle a failed filter process error;
 			  can't send QUIT as we mustn't end the DATA. */
     *message = string_sprintf("transport filter process failed (%d)%s",
@@ -942,6 +947,7 @@ Arguments:
 
 Return:
  OK	all well
+ DEFER	error on first read of TLS'd conn
  FAIL	SMTP error in response
 */
 int
@@ -949,6 +955,7 @@ smtp_reap_early_pipe(smtp_context * sx, int * countp)
 {
 BOOL pending_BANNER = sx->pending_BANNER;
 BOOL pending_EHLO = sx->pending_EHLO;
+int rc = FAIL;
 
 sx->pending_BANNER = FALSE;	/* clear early to avoid recursion */
 sx->pending_EHLO = FALSE;
@@ -960,6 +967,7 @@ if (pending_BANNER)
   if (!smtp_reap_banner(sx))
     {
     DEBUG(D_transport) debug_printf("bad banner\n");
+    if (tls_out.active.sock >= 0) rc = DEFER;
     goto fail;
     }
   }
@@ -974,6 +982,7 @@ if (pending_EHLO)
   if (!smtp_reap_ehlo(sx))
     {
     DEBUG(D_transport) debug_printf("bad response for EHLO\n");
+    if (tls_out.active.sock >= 0) rc = DEFER;
     goto fail;
     }
 
@@ -1011,7 +1020,7 @@ return OK;
 fail:
   invalidate_ehlo_cache_entry(sx);
   (void) smtp_discard_responses(sx, sx->conn_args.ob, *countp);
-  return FAIL;
+  return rc;
 }
 #endif
 
@@ -1056,6 +1065,7 @@ Returns:      3 if at least one address had 2xx and one had 5xx
              -2 I/O or other non-response error for RCPT
              -3 DATA or MAIL failed - errno and buffer set
 	     -4 banner or EHLO failed (early-pipelining)
+	     -5 banner or EHLO failed (early-pipelining, TLS)
 */
 
 static int
@@ -1064,10 +1074,11 @@ sync_responses(smtp_context * sx, int count, int pending_DATA)
 address_item * addr = sx->sync_addr;
 smtp_transport_options_block * ob = sx->conn_args.ob;
 int yield = 0;
+int rc;
 
 #ifdef EXPERIMENTAL_PIPE_CONNECT
-if (smtp_reap_early_pipe(sx, &count) != OK)
-  return -4;
+if ((rc = smtp_reap_early_pipe(sx, &count)) != OK)
+  return rc == FAIL ? -4 : -5;
 #endif
 
 /* Handle the response for a MAIL command. On error, reinstate the original
@@ -1083,6 +1094,8 @@ if (sx->pending_MAIL)
     {
     DEBUG(D_transport) debug_printf("bad response for MAIL\n");
     Ustrcpy(big_buffer, mail_command);  /* Fits, because it came from there! */
+    if (errno == ERRNO_TLSFAILURE)
+      return -5;
     if (errno == 0 && sx->buffer[0] != 0)
       {
       int save_errno = 0;
@@ -1141,6 +1154,11 @@ while (count-- > 0)
       }
     }
 
+  /* Error on first TLS read */
+
+  else if (errno == ERRNO_TLSFAILURE)
+    return -5;
+
   /* Timeout while reading the response */
 
   else if (errno == ETIMEDOUT)
@@ -1253,6 +1271,10 @@ if (pending_DATA != 0)
     int code;
     uschar *msg;
     BOOL pass_message;
+
+    if (errno == ERRNO_TLSFAILURE)	/* Error on first TLS read */
+      return -5;
+
     if (pending_DATA > 0 || (yield & 1) != 0)
       {
       if (errno == 0 && sx->buffer[0] == '4')
@@ -1802,7 +1824,9 @@ Args:
    tc_chunk_last	add LAST option to SMTP BDAT command
    tc_reap_prev		reap response to previous SMTP commands
 
-Returns:	OK or ERROR
+Returns:
+  OK or ERROR
+  DEFER			TLS error on first read (EHLO-resp); errno set
 */
 
 static int
@@ -1859,10 +1883,12 @@ if (flags & tc_reap_prev  &&  prev_cmd_count > 0)
     case 2: sx->completed_addr = TRUE;	/* 5xx (only) => progress made */
     case 0: break;			/* No 2xx or 5xx, but no probs */
 
-    case -1:				/* Timeout on RCPT */
+    case -5: errno = ERRNO_TLSFAILURE;
+	     return DEFER;
 #ifdef EXPERIMENTAL_PIPE_CONNECT
     case -4:				/* non-2xx for pipelined banner or EHLO */
 #endif
+    case -1:				/* Timeout on RCPT */
     default: return ERROR;		/* I/O error, or any MAIL/DATA error */
     }
   cmd_count = 1;
@@ -1933,6 +1959,9 @@ BOOL pass_message = FALSE;
 uschar * message = NULL;
 int yield = OK;
 int rc;
+#ifdef SUPPORT_TLS
+uschar * tls_errstr;
+#endif
 
 sx->conn_args.ob = ob;
 
@@ -2474,27 +2503,27 @@ if (  smtp_peer_options & OPTION_TLS
   TLS_NEGOTIATE:
     {
     address_item * addr;
-    uschar * errstr;
     sx->cctx.tls_ctx = tls_client_start(sx->cctx.sock, sx->conn_args.host,
 			    sx->addrlist, sx->conn_args.tblock,
 # ifdef SUPPORT_DANE
 			     sx->dane ? &tlsa_dnsa : NULL,
 # endif
-			     &tls_out, &errstr);
+			     &tls_out, &tls_errstr);
 
     if (!sx->cctx.tls_ctx)
       {
       /* TLS negotiation failed; give an error. From outside, this function may
       be called again to try in clear on a new connection, if the options permit
       it for this host. */
-      DEBUG(D_tls) debug_printf("TLS session fail: %s\n", errstr);
+GNUTLS_CONN_FAILED:
+      DEBUG(D_tls) debug_printf("TLS session fail: %s\n", tls_errstr);
 
 # ifdef SUPPORT_DANE
       if (sx->dane)
         {
 	log_write(0, LOG_MAIN,
 	  "DANE attempt failed; TLS connection to %s [%s]: %s",
-	  sx->conn_args.host->name, sx->conn_args.host->address, errstr);
+	  sx->conn_args.host->name, sx->conn_args.host->address, tls_errstr);
 #  ifndef DISABLE_EVENT
 	(void) event_raise(sx->conn_args.tblock->event_action,
 	  US"dane:fail", US"validation-failure");	/* could do with better detail */
@@ -2503,7 +2532,7 @@ if (  smtp_peer_options & OPTION_TLS
 # endif
 
       errno = ERRNO_TLSFAILURE;
-      message = string_sprintf("TLS session: %s", errstr);
+      message = string_sprintf("TLS session: %s", tls_errstr);
       sx->send_quit = FALSE;
       goto TLS_FAILED;
       }
@@ -2601,7 +2630,22 @@ if (tls_out.active.sock >= 0)
 #endif
     {
     if (!smtp_reap_ehlo(sx))
+#ifdef USE_GNUTLS
+      {
+      /* The GnuTLS layer in Exim only spots a server-rejection of a client
+      cert late, under TLS1.3 - which means here; the first time we try to
+      receive crypted data.  Treat it as if it was a connect-time failure.
+      See also the early-pipe equivalent... which will be hard; every call
+      to sync_responses will need to check the result.
+      It would be nicer to have GnuTLS check the cert during the handshake.
+      Can it do that, with all the flexibility we need? */
+
+      tls_errstr = US"error on first read";
+      goto GNUTLS_CONN_FAILED;
+      }
+#else
       goto RESPONSE_FAILED;
+#endif
     smtp_peer_options = 0;
     }
   }
@@ -3261,6 +3305,7 @@ for (addr = sx->first_addr, address_count = 0;
 
 #ifdef EXPERIMENTAL_PIPE_CONNECT
       case -4: return -1;			/* non-2xx for pipelined banner or EHLO */
+      case -5: return -1;			/* TLS first-read error */
 #endif
       }
     sx->pending_MAIL = FALSE;            /* Dealt with MAIL */
@@ -3589,11 +3634,12 @@ if (  !(sx.peer_offered & OPTION_CHUNKING)
 
     case 1: sx.ok = TRUE;            /* 2xx (only) => OK, but if LMTP, */
     if (!sx.lmtp) sx.completed_addr = TRUE; /* can't tell about progress yet */
-    case 0: break;                       /* No 2xx or 5xx, but no probs */
+    case 0: break;			/* No 2xx or 5xx, but no probs */
 
-    case -1: goto END_OFF;               /* Timeout on RCPT */
+    case -1: goto END_OFF;		/* Timeout on RCPT */
 
 #ifdef EXPERIMENTAL_PIPE_CONNECT
+    case -5:				/* TLS first-read error */
     case -4:  HDEBUG(D_transport)
 		debug_printf("failed reaping pipelined cmd responses\n");
 #endif
@@ -3730,19 +3776,20 @@ else
       {
       case 3: sx.ok = TRUE;            /* 2xx & 5xx => OK & progress made */
       case 2: sx.completed_addr = TRUE;    /* 5xx (only) => progress made */
-      break;
+	      break;
 
-      case 1: sx.ok = TRUE;            /* 2xx (only) => OK, but if LMTP, */
+      case 1: sx.ok = TRUE;		/* 2xx (only) => OK, but if LMTP, */
       if (!sx.lmtp) sx.completed_addr = TRUE; /* can't tell about progress yet */
-      case 0: break;                       /* No 2xx or 5xx, but no probs */
+      case 0: break;			/* No 2xx or 5xx, but no probs */
 
-      case -1: goto END_OFF;               /* Timeout on RCPT */
+      case -1: goto END_OFF;		/* Timeout on RCPT */
 
 #ifdef EXPERIMENTAL_PIPE_CONNECT
+      case -5:				/* TLS first-read error */
       case -4:  HDEBUG(D_transport)
 		  debug_printf("failed reaping pipelined cmd responses\n");
 #endif
-      default: goto RESPONSE_FAILED;       /* I/O error, or any MAIL/DATA error */
+      default: goto RESPONSE_FAILED;	/* I/O error, or any MAIL/DATA error */
       }
     }
 

commit cea25fe38b1be5ec9f71a39d6fa9b5d14fcd7d2b
Author: Jasen Betts <jasen@xnet.co.nz>
Date:   Mon Feb 18 13:52:16 2019 +0000

    Fix expansions for RFC 822 addresses having comments in local-part and/or domain.  Bug 2375
    
    (cherry picked from commit e2ff8e24f41caca3623228b1ec66a3f3961ecad6)
    (cherry picked from commit f634b80846cc7ffcab65c9855bcb35312f0232e8)
    (cherry picked from commit cebd5bd2ab84c7815a9b99c0f0f16e829af7b4bc)
    (cherry picked from commit 27662d806b99c9369e564f6f33769836c27085df)

diff --git a/src/src/expand.c b/src/src/expand.c
index c2eba072..fbb2dfb1 100644
--- a/src/src/expand.c
+++ b/src/src/expand.c
@@ -7151,16 +7151,11 @@ while (*s != 0)
         uschar * t = parse_extract_address(sub, &error, &start, &end, &domain,
           FALSE);
         if (t)
-          if (c != EOP_DOMAIN)
-            {
-            if (c == EOP_LOCAL_PART && domain != 0) end = start + domain - 1;
-            yield = string_catn(yield, sub+start, end-start);
-            }
-          else if (domain != 0)
-            {
-            domain += start;
-            yield = string_catn(yield, sub+domain, end-domain);
-            }
+	  yield = c == EOP_DOMAIN
+	    ? string_cat(yield, t + domain)
+	    : c == EOP_LOCAL_PART && domain > 0
+	    ? string_catn(yield, t, domain - 1 )
+	    : string_cat(yield, t);
         continue;
         }
 
@@ -7184,7 +7179,7 @@ while (*s != 0)
 
         for (;;)
           {
-          uschar *p = parse_find_address_end(sub, FALSE);
+          uschar * p = parse_find_address_end(sub, FALSE);
           uschar saveend = *p;
           *p = '\0';
           address = parse_extract_address(sub, &error, &start, &end, &domain,
@@ -7197,7 +7192,7 @@ while (*s != 0)
           list, add in a space if the new address begins with the separator
           character, or is an empty string. */
 
-          if (address != NULL)
+          if (address)
             {
             if (yield->ptr != save_ptr && address[0] == *outsep)
               yield = string_catn(yield, US" ", 1);

commit c7900b7efb260d8b5c2f63d34e4d40b6a37a3948
Author: Jeremy Harris <jgh146exb@wizmail.org>
Date:   Thu Mar 14 12:26:34 2019 +0000

    Fix crash from SRV lookup hitting a CNAME
    
    (cherry picked from commit 14bc9cf085aff7bd5147881e5b7068769a29b026)
    (cherry picked from commit 09720dd9506176294154dad7152f5f40554046a4)
    (cherry picked from commit a189eb636256833f3053d8f2fbb95e51dc0f936c)
    (cherry picked from commit 97229a2119f27f735ba4f02c131aac116ee0d5d5)

diff --git a/src/src/dns.c b/src/src/dns.c
index 0f0b435d..b7978c52 100644
--- a/src/src/dns.c
+++ b/src/src/dns.c
@@ -716,7 +716,11 @@ lookup, which constructs the names itself, so they should be OK. Besides,
 bitstring labels don't conform to normal name syntax. (But the aren't used any
 more.)
 
-For SRV records, we omit the initial _smtp._tcp. components at the start. */
+For SRV records, we omit the initial _smtp._tcp. components at the start.
+The check has been seen to bite on the destination of a SRV lookup that
+initiall hit a CNAME, for which the next name had only two components.
+RFC2782 makes no mention of the possibiility of CNAMES, but the Wikipedia
+article on SRV says they are not a valid configuration. */
 
 #ifndef STAND_ALONE   /* Omit this for stand-alone tests */
 
@@ -732,8 +736,8 @@ if (check_dns_names_pattern[0] != 0 && type != T_PTR && type != T_TXT)
 
   if (type == T_SRV || type == T_TLSA)
     {
-    while (*checkname++ != '.');
-    while (*checkname++ != '.');
+    while (*checkname && *checkname++ != '.') ;
+    while (*checkname && *checkname++ != '.') ;
     }
 
   if (pcre_exec(regex_check_dns_names, NULL, CCS checkname, Ustrlen(checkname),

commit 2a53dc2703b3867db40c61d4603332203c38d19e
Author: Jeremy Harris <jgh146exb@wizmail.org>
Date:   Mon Mar 18 00:31:43 2019 +0000

    Logging: fix initial listening-on log line
    
    (cherry picked from commit 254f38d1c5ada5e4df0bccb385dc466549620c71)
    (cherry picked from commit e5be948a65fe601024e5d4256f64efbfed3dd72e)
    (cherry picked from commit 8b81ffe198b36c7d3dcaa1697ab71eefa78946ed)
    (cherry picked from commit c0c781e2cabb7746a49edc88043db91f9e869c0b)

diff --git a/src/src/daemon.c b/src/src/daemon.c
index a852192e..01da3936 100644
--- a/src/src/daemon.c
+++ b/src/src/daemon.c
@@ -1627,8 +1627,8 @@ else if (f.daemon_listen)
   int i, j;
   int smtp_ports = 0;
   int smtps_ports = 0;
-  ip_address_item * ipa, * i2;
-  uschar * p = big_buffer;
+  ip_address_item * ipa;
+  uschar * p;
   uschar * qinfo = queue_interval > 0
     ? string_sprintf("-q%s", readconf_printtime(queue_interval))
     : US"no queue runs";
@@ -1640,27 +1640,19 @@ else if (f.daemon_listen)
   deprecated protocol that starts TLS without using STARTTLS), and others
   listening for standard SMTP. Keep their listings separate. */
 
-  for (j = 0; j < 2; j++)
+  for (int j = 0, i; j < 2; j++)
     {
     for (i = 0, ipa = addresses; i < 10 && ipa; i++, ipa = ipa->next)
       {
       /* First time round, look for SMTP ports; second time round, look for
-      SMTPS ports. For the first one of each, insert leading text. */
+      SMTPS ports. Build IP+port strings. */
 
       if (host_is_tls_on_connect_port(ipa->port) == (j > 0))
 	{
 	if (j == 0)
-	  {
-	  if (smtp_ports++ == 0)
-	    {
-	    memcpy(p, "SMTP on", 8);
-	    p += 7;
-	    }
-	  }
+	  smtp_ports++;
 	else
-	  if (smtps_ports++ == 0)
-	    p += sprintf(CS p, "%sSMTPS on",
-	      smtp_ports == 0 ? "" : " and for ");
+	  smtps_ports++;
 
 	/* Now the information about the port (and sometimes interface) */
 
@@ -1669,40 +1661,67 @@ else if (f.daemon_listen)
 	  if (ipa->next && ipa->next->address[0] == 0 &&
 	      ipa->next->port == ipa->port)
 	    {
-	    p += sprintf(CS p, " port %d (IPv6 and IPv4)", ipa->port);
-	    ipa = ipa->next;
+	    ipa->log = string_sprintf(" port %d (IPv6 and IPv4)", ipa->port);
+	    (ipa = ipa->next)->log = NULL;
 	    }
 	  else if (ipa->v6_include_v4)
-	    p += sprintf(CS p, " port %d (IPv6 with IPv4)", ipa->port);
+	    ipa->log = string_sprintf(" port %d (IPv6 with IPv4)", ipa->port);
 	  else
-	    p += sprintf(CS p, " port %d (IPv6)", ipa->port);
+	    ipa->log = string_sprintf(" port %d (IPv6)", ipa->port);
 	  }
 	else if (ipa->address[0] == 0)			/* v4 wildcard */
-	  p += sprintf(CS p, " port %d (IPv4)", ipa->port);
+	  ipa->log = string_sprintf(" port %d (IPv4)", ipa->port);
 	else				/* check for previously-seen IP */
 	  {
+	  ip_address_item * i2;
 	  for (i2 = addresses; i2 != ipa; i2 = i2->next)
 	    if (  host_is_tls_on_connect_port(i2->port) == (j > 0)
 	       && Ustrcmp(ipa->address, i2->address) == 0
 	       )
 	      {				/* found; append port to list */
-	      if (p[-1] == '}') p--;
-	      while (isdigit(*--p)) ;
-	      p +=  1 + sprintf(CS p+1, "%s%d,%d}", *p == ',' ? "" : "{",
-		i2->port, ipa->port);
+	      for (p = i2->log; *p; ) p++;	/* end of existing string */
+	      if (*--p == '}') *p = '\0';	/* drop EOL */
+	      while (isdigit(*--p)) ;		/* char before port */
+
+	      i2->log = *p == ':'		/* no list yet? */
+		? string_sprintf("%.*s{%s,%d}",
+		  (int)(p - i2->log + 1), i2->log, p+1, ipa->port)
+		: string_sprintf("%s,%d}", i2->log, ipa->port);
+	      ipa->log = NULL;
 	      break;
 	      }
 	  if (i2 == ipa)		/* first-time IP */
-	    p += sprintf(CS p, " [%s]:%d", ipa->address, ipa->port);
+	    ipa->log = string_sprintf(" [%s]:%d", ipa->address, ipa->port);
 	  }
 	}
       }
+    }
 
-    if (ipa)
+  p = big_buffer;
+  for (int j = 0, i; j < 2; j++)
+    {
+    /* First time round, look for SMTP ports; second time round, look for
+    SMTPS ports. For the first one of each, insert leading text. */
+
+    if (j == 0)
       {
-      memcpy(p, " ...", 5);
-      p += 4;
+      if (smtp_ports > 0)
+	p += sprintf(CS p, "SMTP on");
       }
+    else
+      if (smtps_ports > 0)
+	p += sprintf(CS p, "%sSMTPS on",
+	  smtp_ports == 0 ? "" : " and for ");
+
+    /* Now the information about the port (and sometimes interface) */
+
+    for (i = 0, ipa = addresses; i < 10 && ipa; i++, ipa = ipa->next)
+      if (host_is_tls_on_connect_port(ipa->port) == (j > 0))
+	if (ipa->log)
+	  p += sprintf(CS p, "%s",  ipa->log);
+
+    if (ipa)
+      p += sprintf(CS p, " ...");
     }
 
   log_write(0, LOG_MAIN,
diff --git a/src/src/host.c b/src/src/host.c
index 29c977fe..a3b0977b 100644
--- a/src/src/host.c
+++ b/src/src/host.c
@@ -759,6 +759,7 @@ while ((s = string_nextinlist(&list, &sep, NULL, 0)))
   Ustrcpy(next->address, s);
   next->port = port;
   next->v6_include_v4 = FALSE;
+  next->log = NULL;
 
   if (!yield)
     yield = last = next;
diff --git a/src/src/structs.h b/src/src/structs.h
index 20db0e5f..1e63d752 100644
--- a/src/src/structs.h
+++ b/src/src/structs.h
@@ -444,6 +444,7 @@ typedef struct ip_address_item {
   int    port;
   BOOL   v6_include_v4;            /* Used in the daemon */
   uschar address[46];
+  uschar * log;			   /* portion of "listening on" log line */
 } ip_address_item;
 
 /* Structure for chaining together arbitrary strings. */

commit 55bffb813a410d440f0b9bb89c63d485336a7f43
Author: Jeremy Harris <jgh146exb@wizmail.org>
Date:   Tue Mar 19 15:33:31 2019 +0000

    OpenSSL: Fix aggregation of messages.
    
    Broken-by: a5ffa9b475
    (cherry picked from commit c09dbcfb71f4b9a42cbfd8a20e0be6bfa1b12488)
    (cherry picked from commit 332ebeaf8139b2b75f475880fc14b63c7c45c706)
    (cherry picked from commit 1bd4207a399775cf842607930e76c14ac54327df)
    (cherry picked from commit 412885bdba907588c5ac8ea789e673c3198d381a)

diff --git a/src/src/tls-openssl.c b/src/src/tls-openssl.c
index 8f4cf4d8..cc0ead02 100644
--- a/src/src/tls-openssl.c
+++ b/src/src/tls-openssl.c
@@ -274,6 +274,7 @@ Server:
 typedef struct {
   SSL_CTX *	ctx;
   SSL *		ssl;
+  gstring *	corked;
 } exim_openssl_client_tls_ctx;
 
 static SSL_CTX *server_ctx = NULL;
@@ -2473,6 +2474,7 @@ BOOL require_ocsp = FALSE;
 rc = store_pool;
 store_pool = POOL_PERM;
 exim_client_ctx = store_get(sizeof(exim_openssl_client_tls_ctx));
+exim_client_ctx->corked = NULL;
 store_pool = rc;
 
 #ifdef SUPPORT_DANE
@@ -2908,8 +2910,12 @@ int
 tls_write(void * ct_ctx, const uschar *buff, size_t len, BOOL more)
 {
 int outbytes, error, left;
-SSL * ssl = ct_ctx ? ((exim_openssl_client_tls_ctx *)ct_ctx)->ssl : server_ssl;
-static gstring * corked = NULL;
+SSL * ssl = ct_ctx
+  ? ((exim_openssl_client_tls_ctx *)ct_ctx)->ssl : server_ssl;
+static gstring * server_corked = NULL;
+gstring ** corkedp = ct_ctx
+  ? &((exim_openssl_client_tls_ctx *)ct_ctx)->corked : &server_corked;
+gstring * corked = *corkedp;
 
 DEBUG(D_tls) debug_printf("%s(%p, %lu%s)\n", __FUNCTION__,
   buff, (unsigned long)len, more ? ", more" : "");
@@ -2917,9 +2923,12 @@ DEBUG(D_tls) debug_printf("%s(%p, %lu%s)\n", __FUNCTION__,
 /* Lacking a CORK or MSG_MORE facility (such as GnuTLS has) we copy data when
 "more" is notified.  This hack is only ok if small amounts are involved AND only
 one stream does it, in one context (i.e. no store reset).  Currently it is used
-for the responses to the received SMTP MAIL , RCPT, DATA sequence, only. */
-/*XXX + if PIPE_COMMAND, banner & ehlo-resp for smmtp-on-connect. Suspect there's
-a store reset there. */
+for the responses to the received SMTP MAIL , RCPT, DATA sequence, only.
+We support callouts done by the server process by using a separate client
+context for the stashed information. */
+/* + if PIPE_COMMAND, banner & ehlo-resp for smmtp-on-connect. Suspect there's
+a store reset there, so use POOL_PERM. */
+/* + if CHUNKING, cmds EHLO,MAIL,RCPT(s),BDAT */
 
 if (!ct_ctx && (more || corked))
   {
@@ -2935,10 +2944,13 @@ if (!ct_ctx && (more || corked))
 #endif
 
   if (more)
+    {
+    *corkedp = corked;
     return len;
+    }
   buff = CUS corked->s;
   len = corked->ptr;
-  corked = NULL;
+  *corkedp = NULL;
   }
 
 for (left = len; left > 0;)

commit 93fa5e9d493fded9c6d9bc55b5a3262441147723
Author: Jeremy Harris <jgh146exb@wizmail.org>
Date:   Thu Mar 21 20:01:03 2019 +0000

    Harden plaintext authenticator
    
    Cherry-picked from: f9fc942757
    
    (cherry picked from commit e5b942ae007d0533fbd599c64d550f3a8355b940)
    (cherry picked from commit 7556111f007c98f11adfa27c492d73b775886d9d)
    (cherry picked from commit 3063baa25c0a8103438ee73051e61f82476861b3)

diff --git a/src/src/auths/plaintext.c b/src/src/auths/plaintext.c
index 7a0f7885..fa05b0ad 100644
--- a/src/src/auths/plaintext.c
+++ b/src/src/auths/plaintext.c
@@ -223,11 +223,7 @@ while ((s = string_nextinlist(&text, &sep, big_buffer, big_buffer_size)))
       if (ss[i+1] != '^')
 	ss[i] = 0;
       else
-        {
-        i++;
-        len--;
-        memmove(ss + i, ss + i + 1, len - i);
-        }
+        if (--len > ++i) memmove(ss + i, ss + i + 1, len - i);
 
   /* The first string is attached to the AUTH command; others are sent
   unembellished. */

commit 1845de16b185d52fe82147223bca225a28accd84
Author: Jeremy Harris <jgh146exb@wizmail.org>
Date:   Fri Mar 22 15:00:23 2019 +0000

    Fix "-bP smtp_receive_timeout".  Bug 2384
    
    (cherry picked from commit e6024a5e9e193f559508d05ee401ae8f7f3c25ae)
    (cherry picked from commit 2cf1c24f203b3995cfa4434907cff05917a55c90)
    (cherry picked from commit 9cfb6ebeb68fcefc83e261cff036aaf444d7d4c5)
    (cherry picked from commit 0b558fbc10d6a0dd6337903d3d85dcc161724e8c)

diff --git a/src/src/readconf.c b/src/src/readconf.c
index 5742d10a..10bde557 100644
--- a/src/src/readconf.c
+++ b/src/src/readconf.c
@@ -19,7 +19,7 @@ implementation of the conditional .ifdef etc. */
 
 
 static uschar * syslog_facility_str;
-static void fn_smtp_receive_timeout(const uschar *, const uschar *);
+static void fn_smtp_receive_timeout(const uschar *, const uschar *, unsigned);
 
 /*************************************************
 *           Main configuration options           *
@@ -392,7 +392,8 @@ static int optionlist_config_size = nelem(optionlist_config);
 
 #ifdef MACRO_PREDEF
 
-static void fn_smtp_receive_timeout(const uschar * name, const uschar * str) {/*Dummy*/}
+static void
+fn_smtp_receive_timeout(const uschar * name, const uschar * str, unsigned flags) {/*Dummy*/}
 
 void
 options_main(void)
@@ -559,6 +560,8 @@ static syslog_fac_item syslog_list[] = {
 static int syslog_list_size = sizeof(syslog_list)/sizeof(syslog_fac_item);
 
 
+#define opt_fn_print		BIT(0)
+#define opt_fn_print_label	BIT(1)
 
 
 /*************************************************
@@ -1532,9 +1535,16 @@ return yield;
 *            Custom-handler options              *
 *************************************************/
 static void
-fn_smtp_receive_timeout(const uschar * name, const uschar * str)
+fn_smtp_receive_timeout(const uschar * name, const uschar * str, unsigned flags)
 {
-if (*str == '$')
+if (flags & opt_fn_print)
+  {
+  if (flags & opt_fn_print_label) printf("%s = ", name);
+  printf("%s\n", smtp_receive_timeout_s
+    ? string_printing2(smtp_receive_timeout_s, FALSE)
+    : readconf_printtime(smtp_receive_timeout));
+  }
+else if (*str == '$')
   smtp_receive_timeout_s = string_copy(str);
 else
   {
@@ -2328,7 +2338,7 @@ switch (type)
   case opt_func:
     {
     void (*fn)() = ol->value;
-    fn(name, s);
+    fn(name, s, 0);
     break;
     }
   }
@@ -2670,6 +2680,13 @@ switch(ol->type & opt_mask)
   case opt_bool_set:
     printf("%s%s\n", (*((BOOL *)value))? "" : "no_", name);
     break;
+
+  case opt_func:
+    {
+    void (*fn)() = ol->value;
+    fn(name, NULL, no_labels ? opt_fn_print : opt_fn_print|opt_fn_print_label);
+    break;
+    }
   }
 return TRUE;
 }

commit cf09c7894cd13ff836cf76d6e9f065a45b66f6e7
Author: Jeremy Harris <jgh146exb@wizmail.org>
Date:   Fri Apr 5 13:38:54 2019 +0100

    Fix build with recent LibreSSL, when including DANE.  Bug 2386
    
    (cherry picked from commit c19ab167ac and 1fbf41cdf6
    (cherry picked from commit 0d82437ff97668a34a67b4ba398d1294ec016d3a)
    (cherry picked from commit 09cc73f04332f420e07f4bc8bb2e2466c2460067)
    (cherry picked from commit f627fcf379d9453326672016168e2e73f6c42916)

diff --git a/src/src/dane-openssl.c b/src/src/dane-openssl.c
index f7ccbd76..79f136ea 100644
--- a/src/src/dane-openssl.c
+++ b/src/src/dane-openssl.c
@@ -2,7 +2,7 @@
  *  Author: Viktor Dukhovni
  *  License: THIS CODE IS IN THE PUBLIC DOMAIN.
  *
- * Copyright (c) The Exim Maintainers 2014 - 2018
+ * Copyright (c) The Exim Maintainers 2014 - 2019
  */
 #include <stdio.h>
 #include <string.h>
@@ -25,9 +25,18 @@
 #if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
 # define X509_up_ref(x) CRYPTO_add(&((x)->references), 1, CRYPTO_LOCK_X509)
 #endif
+
+/* LibreSSL 2.9.0 and later - 2.9.0 has removed a number of macros ... */
+#ifdef LIBRESSL_VERSION_NUMBER
+# if LIBRESSL_VERSION_NUMBER >= 0x2090000fL
+#  define EXIM_HAVE_ASN1_MACROS
+# endif
+#endif
+/* OpenSSL */
 #if OPENSSL_VERSION_NUMBER >= 0x10100000L && !defined(LIBRESSL_VERSION_NUMBER)
 # define EXIM_HAVE_ASN1_MACROS
 # define EXIM_OPAQUE_X509
+/* Older OpenSSL and all LibreSSL */
 #else
 # define X509_STORE_CTX_get_verify(ctx)		(ctx)->verify
 # define X509_STORE_CTX_get_verify_cb(ctx)	(ctx)->verify_cb
diff --git a/src/src/tlscert-openssl.c b/src/src/tlscert-openssl.c
index 7e0128ee..3551045c 100644
--- a/src/src/tlscert-openssl.c
+++ b/src/src/tlscert-openssl.c
@@ -2,7 +2,7 @@
 *     Exim - an Internet mail transport agent    *
 *************************************************/
 
-/* Copyright (c) Jeremy Harris 2014 - 2018 */
+/* Copyright (c) Jeremy Harris 2014 - 2019 */
 
 /* This module provides TLS (aka SSL) support for Exim using the OpenSSL
 library. It is #included into the tls.c file when that library is used.
@@ -17,8 +17,14 @@ library. It is #included into the tls.c file when that library is used.
 #include <openssl/rand.h>
 #include <openssl/x509v3.h>
 
-#if OPENSSL_VERSION_NUMBER >= 0x10100000L
-# define EXIM_HAVE_ASN1_MACROS
+#ifdef LIBRESSL_VERSION_NUMBER	/* LibreSSL */
+# if LIBRESSL_VERSION_NUMBER >= 0x2090000fL
+#  define EXIM_HAVE_ASN1_MACROS
+# endif
+#else				/* OpenSSL */
+# if OPENSSL_VERSION_NUMBER >= 0x10100000L
+#  define EXIM_HAVE_ASN1_MACROS
+# endif
 #endif
 
 #if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)

commit dddd8eddd1a995e61b55ab31c35a3c599ec55b9b
Author: Jeremy Harris <jgh146exb@wizmail.org>
Date:   Thu Apr 4 14:33:28 2019 +0100

    SPF: better buld compatibility with OpenBSD
    
    (cherry picked from commit bda76da8a9357f4fc525b5f8b925fae262c28010)
    (cherry picked from commit 804219086fe9afbc1429c309e339524aaaabcec1)
    (cherry picked from commit c26e27d5b81ed5640c00ee87f1d4287fb066dc12)
    (cherry picked from commit 6c2054f65ae6beb2a38c6188c0807417adbb3880)

diff --git a/src/src/lookups/spf.c b/src/src/lookups/spf.c
index b32a73e6..48d6ce3b 100644
--- a/src/src/lookups/spf.c
+++ b/src/src/lookups/spf.c
@@ -25,8 +25,8 @@ static void dummy(int x) { dummy2(x-1); }
 #else
 
 #include "lf_functions.h"
-#ifndef HAVE_NS_TYPE
-#define HAVE_NS_TYPE
+#if !defined(HAVE_NS_TYPE) && defined(NS_INADDRSZ)
+# define HAVE_NS_TYPE
 #endif
 #include <spf2/spf.h>
 #include <spf2/spf_dns_resolv.h>
diff --git a/src/src/spf.h b/src/src/spf.h
index 23ad325f..a0779f87 100644
--- a/src/src/spf.h
+++ b/src/src/spf.h
@@ -11,7 +11,7 @@
 #ifdef SUPPORT_SPF
 
 /* Yes, we do have ns_type. spf.h redefines it if we don't set this. Doh */
-#ifndef HAVE_NS_TYPE
+#if !defined(HAVE_NS_TYPE) && defined(NS_INADDRSZ)
 # define HAVE_NS_TYPE
 #endif
 #include <spf2/spf.h>

commit cbaaae36d45e3b8d1f33dc7dcb2861dc7dac5612
Author: Jeremy Harris <jgh146exb@wizmail.org>
Date:   Thu Apr 25 18:24:33 2019 +0100

    GnuTLS 3.6.7 cipher strings
    (cherry picked from commits d9acfc1ce6, 57eb2f6463, b9c6f63cd5)
    
    WARNING: This changes user-visible and configuration-visible behaviour.
             Read the ChangeLog!
    (cherry picked from commit 656b804e099a4704bd6071241a85bc1e0cc85887)
    (cherry picked from commit bf9375eaa85bfa0dbb973aa03accbe5f21808732)
    (cherry picked from commit d3a0dde57754d2b434957c126e1a22e2094cbbf1)

diff --git a/src/src/tls-gnu.c b/src/src/tls-gnu.c
index de2d70c0..af815d22 100644
--- a/src/src/tls-gnu.c
+++ b/src/src/tls-gnu.c
@@ -67,6 +67,9 @@ require current GnuTLS, then we'll drop support for the ancient libraries).
 #if GNUTLS_VERSION_NUMBER >= 0x030109
 # define SUPPORT_CORK
 #endif
+#if GNUTLS_VERSION_NUMBER >= 0x03010a
+# define SUPPORT_GNUTLS_SESS_DESC
+#endif
 #if GNUTLS_VERSION_NUMBER >= 0x030506 && !defined(DISABLE_OCSP)
 # define SUPPORT_SRV_OCSP_STACK
 #endif
@@ -1487,23 +1490,61 @@ state->peerdn = NULL;
 cipher = gnutls_cipher_get(state->session);
 protocol = gnutls_protocol_get_version(state->session);
 mac = gnutls_mac_get(state->session);
-kx = gnutls_kx_get(state->session);
-
-string_format(cipherbuf, sizeof(cipherbuf),
-    "%s:%s:%d",
-    gnutls_protocol_get_name(protocol),
-    gnutls_cipher_suite_get_name(kx, cipher, mac),
-    (int) gnutls_cipher_get_key_size(cipher) * 8);
-
-/* I don't see a way that spaces could occur, in the current GnuTLS
-code base, but it was a concern in the old code and perhaps older GnuTLS
-releases did return "TLS 1.0"; play it safe, just in case. */
-for (p = cipherbuf; *p != '\0'; ++p)
-  if (isspace(*p))
-    *p = '-';
+kx =
+#ifdef GNUTLS_TLS1_3
+    protocol >= GNUTLS_TLS1_3 ? 0 :
+#endif
+  gnutls_kx_get(state->session);
+
 old_pool = store_pool;
-store_pool = POOL_PERM;
-state->ciphersuite = string_copy(cipherbuf);
+  {
+  store_pool = POOL_PERM;
+
+#ifdef SUPPORT_GNUTLS_SESS_DESC
+    {
+    gstring * g = NULL;
+    uschar * s = US gnutls_session_get_desc(state->session), c;
+
+    /* Nikos M suggests we use this by preference.  It returns like:
+    (TLS1.3)-(ECDHE-SECP256R1)-(RSA-PSS-RSAE-SHA256)-(AES-256-GCM)
+
+    For partial back-compat, put a colon after the TLS version, replace the
+    )-( grouping with __, replace in-group - with _ and append the :keysize. */
+
+    /* debug_printf("peer_status: gnutls_session_get_desc %s\n", s); */
+
+    for (s++; (c = *s) && c != ')'; s++) g = string_catn(g, s, 1);
+    g = string_catn(g, US":", 1);
+    if (*s) s++;		/* now on _ between groups */
+    while ((c = *s))
+      {
+      for (*++s && ++s; (c = *s) && c != ')'; s++) g = string_catn(g, c == '-' ? US"_" : s, 1);
+      /* now on ) closing group */
+      if ((c = *s) && *++s == '-') g = string_catn(g, US"__", 2);
+      /* now on _ between groups */
+      }
+    g = string_catn(g, US":", 1);
+    g = string_cat(g, string_sprintf("%d", (int) gnutls_cipher_get_key_size(cipher) * 8));
+    state->ciphersuite = string_from_gstring(g);
+    }
+#else
+  state->ciphersuite = string_sprintf("%s:%s:%d",
+      gnutls_protocol_get_name(protocol),
+      gnutls_cipher_suite_get_name(kx, cipher, mac),
+      (int) gnutls_cipher_get_key_size(cipher) * 8);
+
+  /* I don't see a way that spaces could occur, in the current GnuTLS
+  code base, but it was a concern in the old code and perhaps older GnuTLS
+  releases did return "TLS 1.0"; play it safe, just in case. */
+
+  for (uschar * p = state->ciphersuite; *p; p++) if (isspace(*p)) *p = '-';
+#endif
+
+/* debug_printf("peer_status: ciphersuite %s\n", state->ciphersuite); */
+
+  state->tlsp->cipher = state->ciphersuite;
+  state->tlsp->bits = gnutls_cipher_get_key_size(cipher) * 8;
+  }
 store_pool = old_pool;
 state->tlsp->cipher = state->ciphersuite;
 

commit 4f75aba203cb7051d757f9d7d927988ec7989735
Author: Jeremy Harris <jgh146exb@wizmail.org>
Date:   Tue May 7 22:55:41 2019 +0100

    GnuTLS: fix $tls_out_ocsp under hosts_request_ocsp
    
    (cherry picked from commit 7a501c874f028f689c44999ab05bb0d39da46941)
    (cherry picked from commit 5e64b73ef7cdaf20b998b3345a588b462fd30bfb)
    (cherry picked from commit 31700e5410af3d27654ff0a32c20d30b1a1e10c3)
    (cherry picked from commit 6712694eae57a7d3544c6f0d8a6c03cd246fdb48)

diff --git a/src/src/tls-gnu.c b/src/src/tls-gnu.c
index af815d22..746eabfd 100644
--- a/src/src/tls-gnu.c
+++ b/src/src/tls-gnu.c
@@ -2491,7 +2491,7 @@ if (!verify_certificate(state, errstr))
   }
 
 #ifndef DISABLE_OCSP
-if (require_ocsp)
+if (request_ocsp)
   {
   DEBUG(D_tls)
     {
@@ -2515,10 +2515,14 @@ if (require_ocsp)
     {
     tlsp->ocsp = OCSP_FAILED;
     tls_error(US"certificate status check failed", NULL, state->host, errstr);
-    return NULL;
+    if (require_ocsp)
+      return FALSE;
+    }
+  else
+    {
+    DEBUG(D_tls) debug_printf("Passed OCSP checking\n");
+    tlsp->ocsp = OCSP_VFIED;
     }
-  DEBUG(D_tls) debug_printf("Passed OCSP checking\n");
-  tlsp->ocsp = OCSP_VFIED;
   }
 #endif
 

commit e27114ab13bdc58af1352a3aa3c294e9a0ed3bfc
Author: Jeremy Harris <jgh146exb@wizmail.org>
Date:   Fri May 10 15:35:58 2019 +0100

    Fix listing a named queue by a non-admin user.  Bug 2398
    
    (cherry picked from commit e5903596a0)
    (cherry picked from commit affc23f0d27bfbca773094146d7e62872ed2895b)
    (cherry picked from commit 772e1c684e79465df71157cdccc57739bb841cae)
    (cherry picked from commit fbf6767e15a0367d3f3a8462bc3a87d96bf7b71a)

diff --git a/src/src/exim.c b/src/src/exim.c
index f6f15f44..83b5ef51 100644
--- a/src/src/exim.c
+++ b/src/src/exim.c
@@ -3187,22 +3187,23 @@ for (i = 1; i < argc; i++)
     /* -q[f][f][l][G<name>]: Run the queue, optionally forced, optionally local
     only, optionally named, optionally starting from a given message id. */
 
-    if (*argrest == 0 &&
-        (i + 1 >= argc || argv[i+1][0] == '-' || mac_ismsgid(argv[i+1])))
-      {
-      queue_interval = 0;
-      if (i+1 < argc && mac_ismsgid(argv[i+1]))
-        start_queue_run_id = argv[++i];
-      if (i+1 < argc && mac_ismsgid(argv[i+1]))
-        stop_queue_run_id = argv[++i];
-      }
+    if (!(list_queue || count_queue))
+      if (*argrest == 0
+	 && (i + 1 >= argc || argv[i+1][0] == '-' || mac_ismsgid(argv[i+1])))
+	{
+	queue_interval = 0;
+	if (i+1 < argc && mac_ismsgid(argv[i+1]))
+	  start_queue_run_id = argv[++i];
+	if (i+1 < argc && mac_ismsgid(argv[i+1]))
+	  stop_queue_run_id = argv[++i];
+	}
 
     /* -q[f][f][l][G<name>/]<n>: Run the queue at regular intervals, optionally
     forced, optionally local only, optionally named. */
 
-    else if ((queue_interval = readconf_readtime(*argrest ? argrest : argv[++i],
-						0, FALSE)) <= 0)
-      exim_fail("exim: bad time value %s: abandoned\n", argv[i]);
+      else if ((queue_interval = readconf_readtime(*argrest ? argrest : argv[++i],
+						  0, FALSE)) <= 0)
+	exim_fail("exim: bad time value %s: abandoned\n", argv[i]);
     break;
 
 

commit 94d64a731f0da6988ca7d130b4dffa00449ff087
Author: Jeremy Harris <jgh146exb@wizmail.org>
Date:   Sun May 19 12:12:36 2019 +0100

    GnuTLS: fix the advertising of acceptable certs by the server.  Bug 2389
    
    (cherry picked from commit 12d95aa62042377fc9f603245a17a43142972447)
    (cherry picked from commit 44893ba5249c6c6d5a0d62a1cc57ba3fbf7185b4)
    (cherry picked from commit 7eb6988c118847820de130c9317f851983e0ba8b)
    (cherry picked from commit 7894bfc6ccf7157dc5d8a11e297fb71968dd2904)

diff --git a/src/src/tls-gnu.c b/src/src/tls-gnu.c
index 746eabfd..867dbbe3 100644
--- a/src/src/tls-gnu.c
+++ b/src/src/tls-gnu.c
@@ -1136,6 +1136,14 @@ else
 #endif
     gnutls_certificate_set_x509_trust_file(state->x509_cred,
       CS state->exp_tls_verify_certificates, GNUTLS_X509_FMT_PEM);
+
+#ifdef SUPPORT_CA_DIR
+  /* Mimic the behaviour with OpenSSL of not advertising a usable-cert list
+  when using the directory-of-certs config model. */
+
+  if ((statbuf.st_mode & S_IFMT) == S_IFDIR)
+    gnutls_certificate_send_x509_rdn_sequence(state->session, 1);
+#endif
   }
 
 if (cert_count < 0)

commit e5b326289c172c290fca5e8f492187aeddce9291
Author: Jeremy Harris <jgh146exb@wizmail.org>
Date:   Tue Jun 4 18:13:21 2019 +0100

    Use dsn_from for success-DSN messages.  Bug 2404
    
    (cherry picked from commit 87abcb247b4444bab5fd0bcb212ddb26d5fd9191)
    (cherry picked from commit 454bab46ae6812e29652d10c390451c962a6f806)
    (cherry picked from commit 9eebb5a0ed51584c18af8b08a27695b806980775)
    (cherry picked from commit 09898a2fe75f7044f9f46bd01dcd0e2f22f61d0d)

diff --git a/src/src/deliver.c b/src/src/deliver.c
index e1799411..4720f596 100644
--- a/src/src/deliver.c
+++ b/src/src/deliver.c
@@ -7365,8 +7365,8 @@ if (addr_senddsn)
     if (errors_reply_to)
       fprintf(f, "Reply-To: %s\n", errors_reply_to);
 
+    moan_write_from(f);
     fprintf(f, "Auto-Submitted: auto-generated\n"
-	"From: Mail Delivery System <Mailer-Daemon@%s>\n"
 	"To: %s\n"
 	"Subject: Delivery Status Notification\n"
 	"Content-Type: multipart/report; report-type=delivery-status; boundary=%s\n"
@@ -7377,7 +7377,7 @@ if (addr_senddsn)
 
 	"This message was created automatically by mail delivery software.\n"
 	" ----- The following addresses had successful delivery notifications -----\n",
-      qualify_domain_sender, sender_address, bound, bound);
+      sender_address, bound, bound);
 
     for (addr_dsntmp = addr_senddsn; addr_dsntmp;
 	 addr_dsntmp = addr_dsntmp->next)

commit 178bafb9f9e6d36fee9d180219eee521a99e162c
Author: Jeremy Harris <jgh146exb@wizmail.org>
Date:   Fri Jun 7 11:54:10 2019 +0100

    Fix detection of 32b platform at build time.  Bug 2405
    
    (cherry picked from commit 26dd3aa007b3b77969610c031f59388e0953bd00)
    (cherry picked from commit da7f749864e0807f796b8fa19573484c92bdc5c2)
    (cherry picked from commit a8e52cc464c132b8c88718af4367a01538d65b5a)
    (cherry picked from commit d508b5ca595a418667a1ae10e6cadf48a901c6f3)

diff --git a/src/src/buildconfig.c b/src/src/buildconfig.c
index 3d404f10..ce01cfb4 100644
--- a/src/src/buildconfig.c
+++ b/src/src/buildconfig.c
@@ -111,6 +111,7 @@ unsigned long test_ulong_t = 0L;
 unsigned int test_uint_t = 0;
 #endif
 long test_long_t = 0;
+long long test_longlong_t = 0;
 int test_int_t = 0;
 FILE *base;
 FILE *new;
@@ -155,15 +156,16 @@ This assumption is known to be OK for the common operating systems. */
 
 fprintf(new, "#ifndef OFF_T_FMT\n");
 if (sizeof(test_off_t) > sizeof(test_long_t))
-  {
   fprintf(new, "# define OFF_T_FMT  \"%%lld\"\n");
-  fprintf(new, "# define LONGLONG_T long long int\n");
-  }
 else
-  {
   fprintf(new, "# define OFF_T_FMT  \"%%ld\"\n");
+fprintf(new, "#endif\n\n");
+
+fprintf(new, "#ifndef LONGLONG_T\n");
+if (sizeof(test_longlong_t) > sizeof(test_long_t))
+  fprintf(new, "# define LONGLONG_T long long int\n");
+else
   fprintf(new, "# define LONGLONG_T long int\n");
-  }
 fprintf(new, "#endif\n\n");
 
 /* Now do the same thing for time_t variables. If the length is greater than

commit ba0277c674485cfdae271e1d75725b9a18db8636
Author: Phil Pennock <pdp@exim.org>
Date:   Wed Jun 5 05:35:28 2019 -0400

    Unbreak heimdal_gssapi auth driver
    
    Commit 251b9eb46 broke heimdal_gssapi by changing the function
    definition in the `.c` without changing the declaration in the `.h`.
    Was part of 4.92.
    
    Make corresponding `.h` change to reflect newer internal API.
    
    (cherry picked from commit 6ee110613402e8562c03b4a11c3ffbdbd47bd153)
    (cherry picked from commit 40fe3ea73eb7524a6143755854633ed8392d39b4)
    (cherry picked from commit 171adf11d72efb4781a3028a849e0ed6e521a4fa)
    (cherry picked from commit 250dc372cfb64dfb21db2e7bd67ed28822aa132d)

diff --git a/src/src/auths/heimdal_gssapi.h b/src/src/auths/heimdal_gssapi.h
index a606a5c2..b682b5ff 100644
--- a/src/src/auths/heimdal_gssapi.h
+++ b/src/src/auths/heimdal_gssapi.h
@@ -32,8 +32,7 @@ extern auth_heimdal_gssapi_options_block auth_heimdal_gssapi_option_defaults;
 
 extern void auth_heimdal_gssapi_init(auth_instance *);
 extern int auth_heimdal_gssapi_server(auth_instance *, uschar *);
-extern int auth_heimdal_gssapi_client(auth_instance *, smtp_inblock *,
-                                smtp_outblock *, int, uschar *, int);
+extern int auth_heimdal_gssapi_client(auth_instance *, void *, int, uschar *, int);
 extern void auth_heimdal_gssapi_version_report(FILE *f);
 
 /* End of heimdal_gssapi.h */

commit 07ce37bca172ccdbacbc3f70b21e108394a3924a
Author: Jeremy Harris <jgh146exb@wizmail.org>
Date:   Wed Jun 26 11:17:52 2019 +0100

    Fix DSN Final-Recipient: field
    
    (cherry picked from commits 436bda2ac0c4 and 98d4eb7a84)
    
    (cherry picked from commit 6b88f51ac13b4fa834796ce12d12c55c95eacc4a)
    (cherry picked from commit ce4d8eca9d3940bb439cdb74a250090fee5538d4)
    (cherry picked from commit f41bc530a8b1a66e811e5c3b4da3df72ecba0e1d)

diff --git a/src/src/deliver.c b/src/src/deliver.c
index 4720f596..53562dd5 100644
--- a/src/src/deliver.c
+++ b/src/src/deliver.c
@@ -5507,6 +5507,25 @@ while ((addr = *anchor))
 
 
 
+/************************************************/
+
+static void
+print_dsn_addr_action(FILE * f, address_item * addr,
+  uschar * action, uschar * status)
+{
+address_item * pa;
+
+if (addr->dsn_orcpt)
+  fprintf(f,"Original-Recipient: %s\n", addr->dsn_orcpt);
+
+for (pa = addr; pa->parent; ) pa = pa->parent;
+fprintf(f, "Action: %s\n"
+    "Final-Recipient: rfc822;%s\n"
+    "Status: %s\n",
+  action, pa->address, status);
+}
+
+
 /*************************************************
 *              Deliver one message               *
 *************************************************/
@@ -7410,10 +7429,7 @@ if (addr_senddsn)
       if (addr_dsntmp->dsn_orcpt)
         fprintf(f,"Original-Recipient: %s\n", addr_dsntmp->dsn_orcpt);
 
-      fprintf(f, "Action: delivered\n"
-	  "Final-Recipient: rfc822;%s\n"
-	  "Status: 2.0.0\n",
-	addr_dsntmp->address);
+      print_dsn_addr_action(f, addr_dsntmp, US"delivered", US"2.0.0");
 
       if (addr_dsntmp->host_used && addr_dsntmp->host_used->name)
         fprintf(f, "Remote-MTA: dns; %s\nDiagnostic-Code: smtp; 250 Ok\n\n",
@@ -7798,10 +7814,9 @@ wording. */
       for (addr = handled_addr; addr; addr = addr->next)
         {
 	host_item * hu;
-        fprintf(fp, "Action: failed\n"
-	    "Final-Recipient: rfc822;%s\n"
-	    "Status: 5.0.0\n",
-	    addr->address);
+
+	print_dsn_addr_action(fp, addr, US"failed", US"5.0.0");
+
         if ((hu = addr->host_used) && hu->name)
 	  {
 	  fprintf(fp, "Remote-MTA: dns; %s\n", hu->name);
@@ -8343,13 +8358,9 @@ else if (addr_defer != (address_item *)(+1))
 
         for ( ; addr_dsndefer; addr_dsndefer = addr_dsndefer->next)
           {
-          if (addr_dsndefer->dsn_orcpt)
-            fprintf(f, "Original-Recipient: %s\n", addr_dsndefer->dsn_orcpt);
 
-          fprintf(f, "Action: delayed\n"
-	      "Final-Recipient: rfc822;%s\n"
-	      "Status: 4.0.0\n",
-	    addr_dsndefer->address);
+	  print_dsn_addr_action(f, addr_dsndefer, US"delayed", US"4.0.0");
+
           if (addr_dsndefer->host_used && addr_dsndefer->host_used->name)
             {
             fprintf(f, "Remote-MTA: dns; %s\n",

commit 7ac90e154be0fa6275bea09e02e3f33f2ecc9362
Author: Jeremy Harris <jgh146exb@wizmail.org>
Date:   Sat Jun 29 19:37:57 2019 +0100

    Fix bounce generation under RFC 3461 request.  Bug 2411
    
    Broken-by: ea97267cea
    (cherry picked from commit df98a6ff2e70887890690ffbf8a8ad583d7d7e38)
    (cherry picked from commit b4a37a77271a8f6efc887d68265eb7867eff6170)
    (cherry picked from commit 145416c70b2e4422f0ff03f402da33a4a4db29e2)
    (cherry picked from commit ee2d305425037fc3bc00e6e44e990a88a92433ab)

diff --git a/src/src/deliver.c b/src/src/deliver.c
index 53562dd5..d4ed8af0 100644
--- a/src/src/deliver.c
+++ b/src/src/deliver.c
@@ -7519,7 +7519,8 @@ while (addr_failed)
   mark the recipient done. */
 
   if (  addr_failed->prop.ignore_error
-     || addr_failed->dsn_flags & (rf_dsnflags & ~rf_notify_failure)
+     ||    addr_failed->dsn_flags & rf_dsnflags
+	&& !(addr_failed->dsn_flags & rf_notify_failure)
      )
     {
     addr = addr_failed;

commit 21c561e744415b491a884bf23a3f18f1d012e629
Author: Jeremy Harris <jgh146exb@wizmail.org>
Date:   Sun Jul 28 14:47:29 2019 +0100

    Fix crash after TLS channel shutdown
    
    (cherry picked from commit bd231acd0f24e4c27c6d6885f48c24360700ec7f)
    (cherry picked from commit 513adf9d59bd8d9515a3c6b9c092a2c376cc6102)
    (cherry picked from commit c8535a954a3ec877083b39088f385ed3174abab7)

diff --git a/src/src/tls-gnu.c b/src/src/tls-gnu.c
index 867dbbe3..8d911d57 100644
--- a/src/src/tls-gnu.c
+++ b/src/src/tls-gnu.c
@@ -2569,8 +2569,9 @@ void
 tls_close(void * ct_ctx, int shutdown)
 {
 exim_gnutls_state_st * state = ct_ctx ? ct_ctx : &state_server;
+tls_support * tlsp = state->tlsp;
 
-if (!state->tlsp || state->tlsp->active.sock < 0) return;  /* TLS was not active */
+if (!tlsp || tlsp->active.sock < 0) return;  /* TLS was not active */
 
 if (shutdown)
   {
@@ -2582,12 +2583,26 @@ if (shutdown)
   ALARM_CLR(0);
   }
 
+if (!ct_ctx)	/* server */
+  {
+  receive_getc =	smtp_getc;
+  receive_getbuf =	smtp_getbuf;
+  receive_get_cache =	smtp_get_cache;
+  receive_ungetc =	smtp_ungetc;
+  receive_feof =	smtp_feof;
+  receive_ferror =	smtp_ferror;
+  receive_smtp_buffered = smtp_buffered;
+  }
+
 gnutls_deinit(state->session);
 gnutls_certificate_free_credentials(state->x509_cred);
 
+tlsp->active.sock = -1;
+tlsp->active.tls_ctx = NULL;
+/* Leave bits, peercert, cipher, peerdn, certificate_verified set, for logging */
+tls_channelbinding_b64 = NULL;
+
 
-state->tlsp->active.sock = -1;
-state->tlsp->active.tls_ctx = NULL;
 if (state->xfer_buffer) store_free(state->xfer_buffer);
 memcpy(state, &exim_gnutls_state_init, sizeof(exim_gnutls_state_init));
 }
@@ -2637,28 +2652,7 @@ if (sigalrm_seen)
 else if (inbytes == 0)
   {
   DEBUG(D_tls) debug_printf("Got TLS_EOF\n");
-
-  receive_getc = smtp_getc;
-  receive_getbuf = smtp_getbuf;
-  receive_get_cache = smtp_get_cache;
-  receive_ungetc = smtp_ungetc;
-  receive_feof = smtp_feof;
-  receive_ferror = smtp_ferror;
-  receive_smtp_buffered = smtp_buffered;
-
-  gnutls_deinit(state->session);
-  gnutls_certificate_free_credentials(state->x509_cred);
-
-  state->session = NULL;
-  state->tlsp->active.sock = -1;
-  state->tlsp->active.tls_ctx = NULL;
-  state->tlsp->bits = 0;
-  state->tlsp->certificate_verified = FALSE;
-  tls_channelbinding_b64 = NULL;
-  state->tlsp->cipher = NULL;
-  state->tlsp->peercert = NULL;
-  state->tlsp->peerdn = NULL;
-
+  tls_close(NULL, TLS_NO_SHUTDOWN);
   return FALSE;
   }
 
diff --git a/src/src/tls-openssl.c b/src/src/tls-openssl.c
index cc0ead02..e751edd9 100644
--- a/src/src/tls-openssl.c
+++ b/src/src/tls-openssl.c
@@ -2727,32 +2727,10 @@ switch(error)
   case SSL_ERROR_ZERO_RETURN:
     DEBUG(D_tls) debug_printf("Got SSL_ERROR_ZERO_RETURN\n");
 
-    receive_getc = smtp_getc;
-    receive_getbuf = smtp_getbuf;
-    receive_get_cache = smtp_get_cache;
-    receive_ungetc = smtp_ungetc;
-    receive_feof = smtp_feof;
-    receive_ferror = smtp_ferror;
-    receive_smtp_buffered = smtp_buffered;
-
     if (SSL_get_shutdown(server_ssl) == SSL_RECEIVED_SHUTDOWN)
 	  SSL_shutdown(server_ssl);
 
-#ifndef DISABLE_OCSP
-    sk_X509_pop_free(server_static_cbinfo->verify_stack, X509_free);
-    server_static_cbinfo->verify_stack = NULL;
-#endif
-    SSL_free(server_ssl);
-    SSL_CTX_free(server_ctx);
-    server_ctx = NULL;
-    server_ssl = NULL;
-    tls_in.active.sock = -1;
-    tls_in.active.tls_ctx = NULL;
-    tls_in.bits = 0;
-    tls_in.cipher = NULL;
-    tls_in.peerdn = NULL;
-    tls_in.sni = NULL;
-
+    tls_close(NULL, TLS_NO_SHUTDOWN);
     return FALSE;
 
   /* Handle genuine errors */
@@ -3040,14 +3018,25 @@ if (shutdown)
     }
   }
 
-#ifndef DISABLE_OCSP
 if (!o_ctx)		/* server side */
   {
+#ifndef DISABLE_OCSP
   sk_X509_pop_free(server_static_cbinfo->verify_stack, X509_free);
   server_static_cbinfo->verify_stack = NULL;
-  }
 #endif
 
+  receive_getc =	smtp_getc;
+  receive_getbuf =	smtp_getbuf;
+  receive_get_cache =	smtp_get_cache;
+  receive_ungetc =	smtp_ungetc;
+  receive_feof =	smtp_feof;
+  receive_ferror =	smtp_ferror;
+  receive_smtp_buffered = smtp_buffered;
+  tls_in.active.tls_ctx = NULL;
+  tls_in.sni = NULL;
+  /* Leave bits, peercert, cipher, peerdn, certificate_verified set, for logging */
+  }
+
 SSL_CTX_free(*ctxp);
 SSL_free(*sslp);
 *ctxp = NULL;

commit 766e8cda1775478d6a98957847df1c4f89973471
Author: Bruce Lee <straightblast426@gmail.com>
Date:   Tue Jul 30 22:43:14 2019 +0100

    Auth: handle socket read errors in Dovecot authenticator
    
    (cherry picked from commit c9f1be94cc304f0343c93b66efa41a747d307fb1)
    (cherry picked from commit 4ba26a040b8765dea7134c883d046418a8b053a1)
    (cherry picked from commit 2ac2eff3c9914a9c77b03db64b31819f361576b9)

diff --git a/src/src/auths/dovecot.c b/src/src/auths/dovecot.c
index b1dde06a..b1c2c6f8 100644
--- a/src/src/auths/dovecot.c
+++ b/src/src/auths/dovecot.c
@@ -212,8 +212,8 @@ for (;;)
   {
   if (socket_buffer_left == 0)
     {
-    socket_buffer_left = read(fd, sbuffer, sizeof(sbuffer));
-    if (socket_buffer_left == 0) { if (count == 0) return NULL; else break; }
+    if ((socket_buffer_left = read(fd, sbuffer, sizeof(sbuffer))) <= 0)
+      if (count == 0) return NULL; else break;
     p = 0;
     }
 

commit a5dd8705075f84dae8d3a7180d7e03c8a9975e17
Author: Jeremy Harris <jgh146exb@wizmail.org>
Date:   Tue Aug 27 17:44:52 2019 +0100

    Fix ${domain:} for a bare local-part input.  Bug 2375
    
    Broken-by: cebd5bd2ab
    (cherry picked from commit c5b0340697326238b0e2afd9d341185077d60d35)
    (cherry picked from commit 92b922fae5bbd5a70da4c5aa2f43a457842c30eb)
    (cherry picked from commit deda0b271ccd27ae76bd69ad1c1d0ef73e20091d)

diff --git a/src/src/expand.c b/src/src/expand.c
index fbb2dfb1..0a8c5fbc 100644
--- a/src/src/expand.c
+++ b/src/src/expand.c
@@ -7151,11 +7151,12 @@ while (*s != 0)
         uschar * t = parse_extract_address(sub, &error, &start, &end, &domain,
           FALSE);
         if (t)
-	  yield = c == EOP_DOMAIN
-	    ? string_cat(yield, t + domain)
-	    : c == EOP_LOCAL_PART && domain > 0
-	    ? string_catn(yield, t, domain - 1 )
-	    : string_cat(yield, t);
+	  if (c != EOP_DOMAIN)
+	    yield = c == EOP_LOCAL_PART && domain > 0
+	      ? string_catn(yield, t, domain - 1)
+	      : string_cat(yield, t);
+	  else if (domain > 0)
+	    yield = string_cat(yield, t + domain);
         continue;
         }
 

commit 4ff72340eedc1e34af715670d2bb52bd91f46438
Author: Heiko Schlittermann (HS12-RIPE) <hs@schlittermann.de>
Date:   Thu Sep 5 14:56:22 2019 +0200

    exim_dbmbuild: handle { '\\', '\0' } sequence.
    
    This fix matches the change introduced for CVE-2019-15846, but
    isn't considered as a security issue, exim_dbmbuild is not designed to
    to run on untrusted data.
    
    Thanks to Thomas Hoger (RedHat) for pointing out.
    
    (cherry picked from commit 66935633816a88460f5222f40dc29d1a4e877978)

diff --git a/src/src/exim_dbmbuild.c b/src/src/exim_dbmbuild.c
index afd5095d..d7e611ab 100644
--- a/src/src/exim_dbmbuild.c
+++ b/src/src/exim_dbmbuild.c
@@ -94,6 +94,7 @@ string_interpret_escape(const uschar **pp)
 int ch;
 const uschar *p = *pp;
 ch = *(++p);
+if (ch == '\0') return *pp;
 if (isdigit(ch) && ch != '8' && ch != '9')
   {
   ch -= '0';

commit 4058f5dff9606ff61e26bf51806590ca7226e2e9
Author: Heiko Schlittermann (HS12-RIPE) <hs@schlittermann.de>
Date:   Fri Sep 6 06:57:11 2019 +0200

    fixup! exim_dbmbuild: handle { '\\', '\0' } sequence.
    
    Credits to Qualys for double checking and reporting.
    
    (cherry picked from commit cdc7f9a9667ecf31d803fc8d1a31b466284360bd)

diff --git a/src/src/exim_dbmbuild.c b/src/src/exim_dbmbuild.c
index d7e611ab..63fd691a 100644
--- a/src/src/exim_dbmbuild.c
+++ b/src/src/exim_dbmbuild.c
@@ -94,7 +94,7 @@ string_interpret_escape(const uschar **pp)
 int ch;
 const uschar *p = *pp;
 ch = *(++p);
-if (ch == '\0') return *pp;
+if (ch == '\0') return **pp;
 if (isdigit(ch) && ch != '8' && ch != '9')
   {
   ch -= '0';

commit c02755406d82d2e012a6ca31713148f867c7c697
Author: Jeremy Harris <jgh146exb@wizmail.org>
Date:   Sat Oct 12 14:12:56 2019 +0100

    Fix errorcheck in smtp transport

diff --git a/src/src/transports/smtp.c b/src/src/transports/smtp.c
index bfd6018d..73c9489d 100644
--- a/src/src/transports/smtp.c
+++ b/src/src/transports/smtp.c
@@ -4290,7 +4290,7 @@ if (sx.completed_addr && sx.ok && sx.send_quit)
 	  /* Set up a pipe for proxying TLS for the new transport process */
 
 	  smtp_peer_options |= OPTION_TLS;
-	  if (sx.ok = (socketpair(AF_UNIX, SOCK_STREAM, 0, pfd) == 0))
+	  if ((sx.ok = socketpair(AF_UNIX, SOCK_STREAM, 0, pfd) == 0))
 	    socket_fd = pfd[1];
 	  else
 	    set_errno(sx.first_addr, errno, US"internal allocation problem",

commit 54a3c57cd134d235e1daec3b6e2dcf3dc1b778ff
Author: Jeremy Harris <jgh146exb@wizmail.org>
Date:   Sat Oct 19 22:25:27 2019 +0100

    CHUNKING: fix all-RCPTs-rejected, non-pipelined.  Bug 2454
    
    (cherry picked from commit c5040dfdb523ce2a14efbdfa0d3eb69d3afef65a)

diff --git a/src/src/transports/smtp.c b/src/src/transports/smtp.c
index 73c9489d..cc37e73f 100644
--- a/src/src/transports/smtp.c
+++ b/src/src/transports/smtp.c
@@ -3656,7 +3656,8 @@ for handling the SMTP dot-handling protocol, flagging to apply to headers as
 well as body. Set the appropriate timeout value to be used for each chunk.
 (Haven't been able to make it work using select() for writing yet.) */
 
-if (!(sx.peer_offered & OPTION_CHUNKING) && !sx.ok)
+if (  !sx.ok
+   && (!(sx.peer_offered & OPTION_CHUNKING) || !pipelining_active))
   {
   /* Save the first address of the next batch. */
   sx.first_addr = sx.next_addr;
