Fix CVE-2019-10149
[exim.git] / src / src / deliver.c
index a7f561c9c355fe6b4cb20d0b05b251c4b3d14aa2..45cc0723f9203a5bf55aecb06ad6736cc173f387 100644 (file)
@@ -2,7 +2,7 @@
 *     Exim - an Internet mail transport agent    *
 *************************************************/
 
-/* Copyright (c) University of Cambridge 1995 - 2017 */
+/* Copyright (c) University of Cambridge 1995 - 2018 */
 /* See the file NOTICE for conditions of use and distribution. */
 
 /* The main code for delivering a message. */
@@ -817,7 +817,7 @@ if (LOGGING(tls_certificate_verified) && addr->cipher)
   s = string_append(s, 2, US" CV=",
     testflag(addr, af_cert_verified)
     ?
-#ifdef EXPERIMENTAL_DANE
+#ifdef SUPPORT_DANE
       testflag(addr, af_dane_verified)
     ? "dane"
     :
@@ -1030,10 +1030,8 @@ else
   and all parents are not being included, don't add on the top address. First
   of all, do a caseless comparison; if this succeeds, do a caseful comparison
   on the local parts. */
-  /*XXX dodgy coding.  the string at "cmp" might not be nul-terminated if
-  we had to extend the allocation! */
 
-  g->s[g->ptr] = '\0';
+  string_from_gstring(g);      /* ensure nul-terminated */
   if (  strcmpic(cmp, topaddr->address) == 0
      && Ustrncmp(cmp, topaddr->address, Ustrchr(cmp, '@') - cmp) == 0
      && !addr->onetime_parent
@@ -1089,7 +1087,7 @@ if ((diff->tv_usec -= then->tv_usec) < 0)
 
 
 
-static uschar *
+uschar *
 string_timediff(struct timeval * diff)
 {
 static uschar buf[sizeof("0.000s")];
@@ -1621,7 +1619,7 @@ if (result == OK)
   tls_out.cipher = addr->cipher;
   tls_out.peerdn = addr->peerdn;
   tls_out.ocsp = addr->ocsp;
-# ifdef EXPERIMENTAL_DANE
+# ifdef SUPPORT_DANE
   tls_out.dane_verified = testflag(addr, af_dane_verified);
 # endif
 #endif
@@ -1634,7 +1632,7 @@ if (result == OK)
   tls_out.cipher = NULL;
   tls_out.peerdn = NULL;
   tls_out.ocsp = OCSP_NOT_REQ;
-# ifdef EXPERIMENTAL_DANE
+# ifdef SUPPORT_DANE
   tls_out.dane_verified = FALSE;
 # endif
 #endif
@@ -4787,7 +4785,7 @@ all pipes, so I do not see a reason to use non-blocking IO here
 
       /* The certificate verification status goes into the flags */
       if (tls_out.certificate_verified) setflag(addr, af_cert_verified);
-#ifdef EXPERIMENTAL_DANE
+#ifdef SUPPORT_DANE
       if (tls_out.dane_verified)        setflag(addr, af_dane_verified);
 #endif
 
@@ -4990,7 +4988,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");
@@ -5557,7 +5555,8 @@ message size. This use of strcpy() is OK because the length id is checked when
 it is obtained from a command line (the -M or -q options), and otherwise it is
 known to be a valid message id. */
 
-Ustrcpy(message_id, id);
+if (id != message_id)
+  Ustrcpy(message_id, id);
 deliver_force = forced;
 return_count = 0;
 message_size = 0;
@@ -6152,7 +6151,7 @@ if (process_recipients != RECIP_IGNORE)
       new->dsn_flags = r->dsn_flags & rf_dsnflags;
       new->dsn_orcpt = r->orcpt;
       DEBUG(D_deliver) debug_printf("DSN: set orcpt: %s  flags: %d\n",
-       new->dsn_orcpt, new->dsn_flags);
+       new->dsn_orcpt ? new->dsn_orcpt : US"", new->dsn_flags);
 
       switch (process_recipients)
         {
@@ -6228,17 +6227,23 @@ if (process_recipients != RECIP_IGNORE)
        {
        uschar * save_local =  deliver_localpart;
        const uschar * save_domain = deliver_domain;
+       uschar * addr = new->address, * errmsg = NULL;
+       int start, end, dom;
 
-       deliver_localpart = expand_string(
-                     string_sprintf("${local_part:%s}", new->address));
-       deliver_domain =    expand_string(
-                     string_sprintf("${domain:%s}", new->address));
+       if (!parse_extract_address(addr, &errmsg, &start, &end, &dom, TRUE))
+         log_write(0, LOG_MAIN|LOG_PANIC,
+                "failed to parse address '%.100s': %s\n", addr, errmsg);
+       else
+         {
+         deliver_localpart =
+           string_copyn(addr+start, dom ? (dom-1) - start : end - start);
+         deliver_domain = dom ? CUS string_copyn(addr+dom, end - dom) : CUS"";
 
-       (void) event_raise(event_action,
-                     US"msg:fail:internal", new->message);
+         event_raise(event_action, US"msg:fail:internal", new->message);
 
-       deliver_localpart = save_local;
-       deliver_domain =    save_domain;
+         deliver_localpart = save_local;
+         deliver_domain = save_domain;
+         }
        }
 #endif
       }
@@ -7221,11 +7226,12 @@ for (addr_dsntmp = addr_succeed; addr_dsntmp; addr_dsntmp = addr_dsntmp->next)
       "DSN: envid: %s  ret: %d\n"
       "DSN: Final recipient: %s\n"
       "DSN: Remote SMTP server supports DSN: %d\n",
-      addr_dsntmp->router->name,
+      addr_dsntmp->router ? addr_dsntmp->router->name : US"(unknown)",
       addr_dsntmp->address,
       sender_address,
-      addr_dsntmp->dsn_orcpt, addr_dsntmp->dsn_flags,
-      dsn_envid, dsn_ret,
+      addr_dsntmp->dsn_orcpt ? addr_dsntmp->dsn_orcpt : US"NULL",
+      addr_dsntmp->dsn_flags,
+      dsn_envid ? dsn_envid : US"NULL", dsn_ret,
       addr_dsntmp->address,
       addr_dsntmp->dsn_aware
       );
@@ -7934,8 +7940,7 @@ if (!addr_defer)
   /* Log the end of this message, with queue time if requested. */
 
   if (LOGGING(queue_time_overall))
-    log_write(0, LOG_MAIN, "Completed QT=%s",
-      string_timesince(&received_time));
+    log_write(0, LOG_MAIN, "Completed QT=%s", string_timesince(&received_time));
   else
     log_write(0, LOG_MAIN, "Completed");
 
@@ -8551,8 +8556,11 @@ if (cutthrough.fd >= 0 && cutthrough.callout_hold_only)
       goto fail;
 
     else if (pid == 0)         /* child: fork again to totally disconnect */
+      {
+      if (running_in_test_harness) millisleep(100); /* let parent debug out */
       /* does not return */
       smtp_proxy_tls(big_buffer, big_buffer_size, pfd, 5*60);
+      }
 
     DEBUG(D_transport) debug_printf("proxy-proc inter-pid %d\n", pid);
     close(pfd[0]);