SPDX: license tags (mostly by guesswork)
[exim.git] / src / src / deliver.c
index 2ced28e9a70baa44a3cc0d69e640e7825c04eb95..719fa9d93f52687bd7e8c8e061b2c6dba38a2d44 100644 (file)
@@ -2,9 +2,10 @@
 *     Exim - an Internet mail transport agent    *
 *************************************************/
 
+/* Copyright (c) The Exim Maintainers 2020 - 2022 */
 /* Copyright (c) University of Cambridge 1995 - 2018 */
-/* Copyright (c) The Exim Maintainers 2020 - 2021 */
 /* See the file NOTICE for conditions of use and distribution. */
+/* SPDX-License-Identifier: GPL-2.0-only */
 
 /* The main code for delivering a message. */
 
@@ -146,7 +147,7 @@ Returns:      a pointer to an initialized address_item
 address_item *
 deliver_make_addr(uschar *address, BOOL copy)
 {
-address_item *addr = store_get(sizeof(address_item), FALSE);
+address_item * addr = store_get(sizeof(address_item), GET_UNTAINTED);
 *addr = address_defaults;
 if (copy) address = string_copy(address);
 addr->address = address;
@@ -953,9 +954,22 @@ router_name = transport_name = NULL;
 
 
 /*************************************************
-*        Generate local prt for logging          *
+*        Generate local part for logging         *
 *************************************************/
 
+static uschar *
+string_get_lpart_sub(const address_item * addr, uschar * s)
+{
+#ifdef SUPPORT_I18N
+if (testflag(addr, af_utf8_downcvt))
+  {
+  uschar * t = string_localpart_utf8_to_alabel(s, NULL);
+  return t ? t : s;    /* t is NULL on a failed conversion */
+  }
+#endif
+return s;
+}
+
 /* This function is a subroutine for use in string_log_address() below.
 
 Arguments:
@@ -970,32 +984,13 @@ string_get_localpart(address_item * addr, gstring * yield)
 {
 uschar * s;
 
-s = addr->prefix;
-if (testflag(addr, af_include_affixes) && s)
-  {
-#ifdef SUPPORT_I18N
-  if (testflag(addr, af_utf8_downcvt))
-    s = string_localpart_utf8_to_alabel(s, NULL);
-#endif
-  yield = string_cat(yield, s);
-  }
+if (testflag(addr, af_include_affixes) && (s = addr->prefix))
+  yield = string_cat(yield, string_get_lpart_sub(addr, s));
 
-s = addr->local_part;
-#ifdef SUPPORT_I18N
-if (testflag(addr, af_utf8_downcvt))
-  s = string_localpart_utf8_to_alabel(s, NULL);
-#endif
-yield = string_cat(yield, s);
+yield = string_cat(yield, string_get_lpart_sub(addr, addr->local_part));
 
-s = addr->suffix;
-if (testflag(addr, af_include_affixes) && s)
-  {
-#ifdef SUPPORT_I18N
-  if (testflag(addr, af_utf8_downcvt))
-    s = string_localpart_utf8_to_alabel(s, NULL);
-#endif
-  yield = string_cat(yield, s);
-  }
+if (testflag(addr, af_include_affixes) && (s = addr->suffix))
+  yield = string_cat(yield, string_get_lpart_sub(addr, s));
 
 return yield;
 }
@@ -1148,7 +1143,7 @@ pointer to a single host item in their host list, for use by the transport. */
 #endif
 
 reset_point = store_mark();
-g = string_get_tainted(256, TRUE);     /* addrs will be tainted, so avoid copy */
+g = string_get_tainted(256, GET_TAINTED);      /* addrs will be tainted, so avoid copy */
 
 if (msg)
   g = string_append(g, 2, host_and_ident(TRUE), US" ");
@@ -1172,11 +1167,6 @@ if (LOGGING(sender_on_delivery) || msg)
 if (*queue_name)
   g = string_append(g, 2, US" Q=", queue_name);
 
-#ifdef EXPERIMENTAL_SRS_ALT
-if(addr->prop.srs_sender)
-  g = string_append(g, 3, US" SRS=<", addr->prop.srs_sender, US">");
-#endif
-
 /* You might think that the return path must always be set for a successful
 delivery; indeed, I did for some time, until this statement crashed. The case
 when it is not set is for a delivery to /dev/null which is optimised by not
@@ -2160,10 +2150,6 @@ has its own return path setting, expand it and replace the existing value. */
 
 if(addr->prop.errors_address)
   return_path = addr->prop.errors_address;
-#ifdef EXPERIMENTAL_SRS_ALT
-else if (addr->prop.srs_sender)
-  return_path = addr->prop.srs_sender;
-#endif
 else
   return_path = sender_address;
 
@@ -2385,27 +2371,29 @@ if ((pid = exim_fork(US"delivery-local")) == 0)
     {
     BOOL ok = TRUE;
     set_process_info("delivering %s to %s using %s", message_id,
-     addr->local_part, addr->transport->name);
+     addr->local_part, tp->name);
 
-    /* Setting this global in the subprocess means we need never clear it */
+    /* Setting these globals in the subprocess means we need never clear them */
     transport_name = addr->transport->name;
+    driver_srcfile = tp->srcfile;
+    driver_srcline = tp->srcline;
 
     /* If a transport filter has been specified, set up its argument list.
     Any errors will get put into the address, and FALSE yielded. */
 
-    if (addr->transport->filter_command)
+    if (tp->filter_command)
       {
       ok = transport_set_up_command(&transport_filter_argv,
-        addr->transport->filter_command,
-        TRUE, PANIC, addr, US"transport filter", NULL);
-      transport_filter_timeout = addr->transport->filter_timeout;
+        tp->filter_command,
+        TRUE, PANIC, addr, FALSE, US"transport filter", NULL);
+      transport_filter_timeout = tp->filter_timeout;
       }
     else transport_filter_argv = NULL;
 
     if (ok)
       {
-      debug_print_string(addr->transport->debug_string);
-      replicate = !(addr->transport->info->code)(addr->transport, addr);
+      debug_print_string(tp->debug_string);
+      replicate = !(tp->info->code)(addr->transport, addr);
       }
     }
 
@@ -3058,7 +3046,7 @@ while (addr_local)
     else for (addr2 = addr; addr2; addr2 = addr2->next)
       if (addr2->transport_return == OK)
        {
-       addr3 = store_get(sizeof(address_item), FALSE);
+       addr3 = store_get(sizeof(address_item), GET_UNTAINTED);
        *addr3 = *addr2;
        addr3->next = NULL;
        addr3->shadow_message = US &addr2->shadow_message;
@@ -3453,7 +3441,7 @@ while (!done)
 
       if (!r || !(*ptr & rf_delete))
        {
-       r = store_get(sizeof(retry_item), FALSE);
+       r = store_get(sizeof(retry_item), GET_UNTAINTED);
        r->next = addr->retries;
        addr->retries = r;
        r->flags = *ptr++;
@@ -3644,7 +3632,7 @@ while (!done)
 
          if (*ptr)
            {
-           h = store_get(sizeof(host_item), FALSE);
+           h = store_get(sizeof(host_item), GET_UNTAINTED);
            h->name = string_copy(ptr);
            while (*ptr++);
            h->address = string_copy(ptr);
@@ -4222,10 +4210,10 @@ set up, do so. */
 
 if (!parlist)
   {
-  parlist = store_get(remote_max_parallel * sizeof(pardata), FALSE);
+  parlist = store_get(remote_max_parallel * sizeof(pardata), GET_UNTAINTED);
   for (poffset = 0; poffset < remote_max_parallel; poffset++)
     parlist[poffset].pid = 0;
-  parpoll = store_get(remote_max_parallel * sizeof(struct pollfd), FALSE);
+  parpoll = store_get(remote_max_parallel * sizeof(struct pollfd), GET_UNTAINTED);
   }
 
 /* Now loop for each remote delivery */
@@ -4453,10 +4441,6 @@ nonmatch domains
 
   if(addr->prop.errors_address)
     return_path = addr->prop.errors_address;
-#ifdef EXPERIMENTAL_SRS_ALT
-  else if(addr->prop.srs_sender)
-    return_path = addr->prop.srs_sender;
-#endif
   else
     return_path = sender_address;
 
@@ -4677,8 +4661,10 @@ all pipes, so I do not see a reason to use non-blocking IO here
     int fd = pfd[pipe_write];
     host_item *h;
 
-    /* Setting this global in the subprocess means we need never clear it */
-    transport_name = tp->name;
+    /* Setting these globals in the subprocess means we need never clear them */
+    transport_name = addr->transport->name;
+    driver_srcfile = tp->srcfile;
+    driver_srcline = tp->srcline;
 
     /* There are weird circumstances in which logging is disabled */
     f.disable_logging = tp->disable_logging;
@@ -5124,7 +5110,7 @@ where they are locally interpreted. [The new draft "821" is more explicit on
 this, Jan 1999.] We know the syntax is valid, so this can be done by simply
 removing quoting backslashes and any unquoted doublequotes. */
 
-t = addr->cc_local_part = store_get(len+1, is_tainted(address));
+t = addr->cc_local_part = store_get(len+1, address);
 while(len-- > 0)
   {
   int c = *address++;
@@ -5167,7 +5153,7 @@ if (percent_hack_domains)
 
   if (new_address)
     {
-    address_item *new_parent = store_get(sizeof(address_item), FALSE);
+    address_item * new_parent = store_get(sizeof(address_item), GET_UNTAINTED);
     *new_parent = *addr;
     addr->parent = new_parent;
     new_parent->child_count = 1;
@@ -5361,10 +5347,10 @@ Returns:       nothing
 */
 
 static void
-print_address_error(address_item *addr, FILE *f, uschar *t)
+print_address_error(address_item * addr, FILE * f, const uschar * t)
 {
 int count = Ustrlen(t);
-uschar *s = testflag(addr, af_pass_message) ? addr->message : NULL;
+uschar * s = testflag(addr, af_pass_message) ? addr->message : NULL;
 
 if (!s && !(s = addr->user_message))
   return;
@@ -5558,11 +5544,10 @@ FILE * fp = NULL;
 if (!s || !*s)
   log_write(0, LOG_MAIN|LOG_PANIC,
     "Failed to expand %s: '%s'\n", varname, filename);
-else if (*s != '/')
-  log_write(0, LOG_MAIN|LOG_PANIC, "%s is not absolute after expansion: '%s'\n",
-    varname, s);
-else if (is_tainted2(s, LOG_MAIN|LOG_PANIC, "Tainted %s after expansion: '%s'\n", varname, s))
-  ;
+else if (*s != '/' || is_tainted(s))
+  log_write(0, LOG_MAIN|LOG_PANIC,
+    "%s is not %s after expansion: '%s'\n",
+    varname, *s == '/' ? "untainted" : "absolute", s);
 else if (!(fp = Ufopen(s, "rb")))
   log_write(0, LOG_MAIN|LOG_PANIC, "Failed to open %s for %s "
     "message texts: %s", s, reason, strerror(errno));
@@ -5905,7 +5890,7 @@ if (message_logs)
     return continue_closedown();   /* yields DELIVER_NOT_ATTEMPTED */
     }
 
-  /* Make a C stream out of it. */
+  /* Make a stdio stream out of it. */
 
   if (!(message_log = fdopen(fd, "a")))
     {
@@ -6172,10 +6157,9 @@ else if (system_filter && process_recipients != RECIP_FAIL_TIMEOUT)
           if (!tmp)
             p->message = string_sprintf("failed to expand \"%s\" as a "
               "system filter transport name", tpname);
-          { uschar *m;
-         if ((m = is_tainted2(tmp, 0, "Tainted values '%s' " "for transport '%s' as a system filter", tmp, tpname)))
-            p->message = m;
-          }
+         if (is_tainted(tmp))
+            p->message = string_sprintf("attempt to used tainted value '%s' for"
+             "transport '%s' as a system filter", tmp, tpname);
           tpname = tmp;
           }
         else
@@ -6433,10 +6417,8 @@ while (addr_new)           /* Loop until all addresses dealt with */
   while (addr_new)
     {
     int rc;
-    uschar *p;
-    tree_node *tnode;
-    dbdata_retry *domain_retry_record;
-    dbdata_retry *address_retry_record;
+    tree_node * tnode;
+    dbdata_retry * domain_retry_record, * address_retry_record;
 
     addr = addr_new;
     addr_new = addr->next;
@@ -6569,7 +6551,7 @@ while (addr_new)           /* Loop until all addresses dealt with */
       if (Ustrcmp(addr->address, "/dev/null") == 0)
         {
        transport_instance * save_t = addr->transport;
-       transport_instance * t = store_get(sizeof(*t), is_tainted(save_t));
+       transport_instance * t = store_get(sizeof(*t), save_t);
        *t = *save_t;
        t->name = US"**bypassed**";
        addr->transport = t;
@@ -6653,8 +6635,7 @@ while (addr_new)           /* Loop until all addresses dealt with */
     /* Ensure that the domain in the unique field is lower cased, because
     domains are always handled caselessly. */
 
-    p = Ustrrchr(addr->unique, '@');
-    while (*p != 0) { *p = tolower(*p); p++; }
+    for (uschar * p = Ustrrchr(addr->unique, '@'); *p; p++) *p = tolower(*p);
 
     DEBUG(D_deliver|D_route) debug_printf("unique = %s\n", addr->unique);
 
@@ -7223,7 +7204,7 @@ local and remote LMTP deliveries. */
 
 if (!regex_IGNOREQUOTA)
   regex_IGNOREQUOTA =
-    regex_must_compile(US"\\n250[\\s\\-]IGNOREQUOTA(\\s|\\n|$)", FALSE, TRUE);
+    regex_must_compile(US"\\n250[\\s\\-]IGNOREQUOTA(\\s|\\n|$)", MCS_NOFLAGS, TRUE);
 
 /* Handle local deliveries */
 
@@ -7404,7 +7385,7 @@ for (address_item * a = addr_succeed; a; a = a->next)
     {
     /* copy and relink address_item and send report with all of them at once later */
     address_item * addr_next = addr_senddsn;
-    addr_senddsn = store_get(sizeof(address_item), FALSE);
+    addr_senddsn = store_get(sizeof(address_item), GET_UNTAINTED);
     *addr_senddsn = *a;
     addr_senddsn->next = addr_next;
     }
@@ -8623,7 +8604,7 @@ if (cutthrough.cctx.sock >= 0 && cutthrough.callout_hold_only)
     if (pid == 0)      /* child: will fork again to totally disconnect */
       {
       smtp_proxy_tls(cutthrough.cctx.tls_ctx, big_buffer, big_buffer_size,
-                     pfd, 5*60);
+                     pfd, 5*60, cutthrough.host.name);
       /* does not return */
       }