]> git.netwichtig.de Git - user/henk/code/exim.git/blobdiff - src/src/deliver.c
Fix post-transport-crash: safeguard for missing spool BUG 1671
[user/henk/code/exim.git] / src / src / deliver.c
index 85a379c1bade7721ec75aa1cc42421f8b6540b6f..b5aa9b9a75d1a211622ca73b0a3b75dc6ad3f9f3 100644 (file)
@@ -2,13 +2,14 @@
 *     Exim - an Internet mail transport agent    *
 *************************************************/
 
-/* Copyright (c) University of Cambridge 1995 - 2014 */
+/* Copyright (c) University of Cambridge 1995 - 2015 */
 /* See the file NOTICE for conditions of use and distribution. */
 
 /* The main code for delivering a message. */
 
 
 #include "exim.h"
+#include <assert.h>
 
 
 /* Data block for keeping track of subprocesses for parallel remote
@@ -676,40 +677,78 @@ while (addr->parent != NULL)
 
 
 
+/*************************************************
+*      Delivery logging support functions        *
+*************************************************/
+
+/* The LOGGING() checks in d_log_interface() are complicated for backwards
+compatibility. When outgoing interface logging was originally added, it was
+conditional on just incoming_interface (which is off by default). The
+outgoing_interface option is on by default to preserve this behaviour, but
+you can enable incoming_interface and disable outgoing_interface to get I=
+fields on incoming lines only.
+
+Arguments:
+  s         The log line buffer
+  sizep     Pointer to the buffer size
+  ptrp      Pointer to current index into buffer
+  addr      The address to be logged
+
+Returns:    New value for s
+*/
+
+static uschar *
+d_log_interface(uschar *s, int *sizep, int *ptrp)
+{
+if (LOGGING(incoming_interface) && LOGGING(outgoing_interface)
+    && sending_ip_address != NULL)
+  {
+  s = string_append(s, sizep, ptrp, 2, US" I=[", sending_ip_address);
+  if (LOGGING(outgoing_port))
+    s = string_append(s, sizep, ptrp, 2, US"]:",
+      string_sprintf("%d", sending_port));
+  else
+    s = string_cat(s, sizep, ptrp, "]", 1);
+  }
+return s;
+}
+
+
 
 static uschar *
-d_hostlog(uschar * s, int * sizep, int * ptrp, address_item * addr)
+d_hostlog(uschar *s, int *sizep, int *ptrp, address_item *addr)
 {
-  s = string_append(s, sizep, ptrp, 5, US" H=", addr->host_used->name,
-    US" [", addr->host_used->address, US"]");
-  if ((log_extra_selector & LX_outgoing_port) != 0)
-    s = string_append(s, sizep, ptrp, 2, US":", string_sprintf("%d",
-      addr->host_used->port));
-  return s;
+s = string_append(s, sizep, ptrp, 5, US" H=", addr->host_used->name,
+  US" [", addr->host_used->address, US"]");
+if (LOGGING(outgoing_port))
+  s = string_append(s, sizep, ptrp, 2, US":", string_sprintf("%d",
+    addr->host_used->port));
+return d_log_interface(s, sizep, ptrp);
 }
 
+
+
 #ifdef SUPPORT_TLS
 static uschar *
 d_tlslog(uschar * s, int * sizep, int * ptrp, address_item * addr)
 {
-  if ((log_extra_selector & LX_tls_cipher) != 0 && addr->cipher != NULL)
-    s = string_append(s, sizep, ptrp, 2, US" X=", addr->cipher);
-  if ((log_extra_selector & LX_tls_certificate_verified) != 0 &&
-       addr->cipher != NULL)
-    s = string_append(s, sizep, ptrp, 2, US" CV=",
-      testflag(addr, af_cert_verified)
-      ?
+if (LOGGING(tls_cipher) && addr->cipher != NULL)
+  s = string_append(s, sizep, ptrp, 2, US" X=", addr->cipher);
+if (LOGGING(tls_certificate_verified) && addr->cipher != NULL)
+  s = string_append(s, sizep, ptrp, 2, US" CV=",
+    testflag(addr, af_cert_verified)
+    ?
 #ifdef EXPERIMENTAL_DANE
-        testflag(addr, af_dane_verified)
-      ? "dane"
-      :
+      testflag(addr, af_dane_verified)
+    ? "dane"
+    :
 #endif
-        "yes"
-      : "no");
-  if ((log_extra_selector & LX_tls_peerdn) != 0 && addr->peerdn != NULL)
-    s = string_append(s, sizep, ptrp, 3, US" DN=\"",
-      string_printing(addr->peerdn), US"\"");
-  return s;
+      "yes"
+    : "no");
+if (LOGGING(tls_peerdn) && addr->peerdn != NULL)
+  s = string_append(s, sizep, ptrp, 3, US" DN=\"",
+    string_printing(addr->peerdn), US"\"");
+return s;
 }
 #endif
 
@@ -808,7 +847,7 @@ pointer to a single host item in their host list, for use by the transport. */
 
 s = reset_point = store_get(size);
 
-log_address = string_log_address(addr, (log_write_selector & L_all_parents) != 0, TRUE);
+log_address = string_log_address(addr, LOGGING(all_parents), TRUE);
 if (msg)
   s = string_append(s, &size, &ptr, 3, host_and_ident(TRUE), US" ", log_address);
 else
@@ -817,12 +856,15 @@ else
   s = string_append(s, &size, &ptr, 2, US"> ", log_address);
   }
 
-if (log_extra_selector & LX_incoming_interface  &&  sending_ip_address)
-  s = string_append(s, &size, &ptr, 3, US" I=[", sending_ip_address, US"]");
-  /* for the port:  string_sprintf("%d", sending_port) */
-
-if ((log_extra_selector & LX_sender_on_delivery) != 0  ||  msg)
-  s = string_append(s, &size, &ptr, 3, US" F=<", sender_address, US">");
+if (LOGGING(sender_on_delivery) || msg)
+  s = string_append(s, &size, &ptr, 3, US" F=<",
+#ifdef EXPERIMENTAL_INTERNATIONAL
+    testflag(addr, af_utf8_downcvt)
+    ? string_address_utf8_to_alabel(sender_address, NULL)
+    :
+#endif
+      sender_address,
+  US">");
 
 #ifdef EXPERIMENTAL_SRS
 if(addr->prop.srs_sender)
@@ -834,8 +876,7 @@ 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
 being run at all. */
 
-if (used_return_path != NULL &&
-      (log_extra_selector & LX_return_path_on_delivery) != 0)
+if (used_return_path != NULL && LOGGING(return_path_on_delivery))
   s = string_append(s, &size, &ptr, 3, US" P=<", used_return_path, US">");
 
 if (msg)
@@ -847,7 +888,7 @@ if (addr->router != NULL)
 
 s = string_append(s, &size, &ptr, 2, US" T=", addr->transport->name);
 
-if ((log_extra_selector & LX_delivery_size) != 0)
+if (LOGGING(delivery_size))
   s = string_append(s, &size, &ptr, 2, US" S=",
     string_sprintf("%d", transport_count));
 
@@ -857,6 +898,7 @@ if (addr->transport->info->local)
   {
   if (addr->host_list)
     s = string_append(s, &size, &ptr, 2, US" H=", addr->host_list->name);
+  s = d_log_interface(s, &size, &ptr);
   if (addr->shadow_message != NULL)
     s = string_cat(s, &size, &ptr, addr->shadow_message,
       Ustrlen(addr->shadow_message));
@@ -894,7 +936,7 @@ else
     if (addr->auth_id)
       {
       s = string_append(s, &size, &ptr, 2, US":", addr->auth_id);
-      if (log_extra_selector & LX_smtp_mailauth  &&  addr->auth_sndr)
+      if (LOGGING(smtp_mailauth) && addr->auth_sndr)
         s = string_append(s, &size, &ptr, 2, US":", addr->auth_sndr);
       }
     }
@@ -907,8 +949,7 @@ else
 
 /* confirmation message (SMTP (host_used) and LMTP (driver_name)) */
 
-if (log_extra_selector & LX_smtp_confirmation &&
-    addr->message &&
+if (LOGGING(smtp_confirmation) && addr->message &&
     (addr->host_used || Ustrcmp(addr->transport->driver_name, "lmtp") == 0))
   {
   unsigned i;
@@ -928,11 +969,11 @@ if (log_extra_selector & LX_smtp_confirmation &&
 
 /* Time on queue and actual time taken to deliver */
 
-if ((log_extra_selector & LX_queue_time) != 0)
+if (LOGGING(queue_time))
   s = string_append(s, &size, &ptr, 2, US" QT=",
     readconf_printtime( (int) ((long)time(NULL) - (long)received_time)) );
 
-if ((log_extra_selector & LX_deliver_time) != 0)
+if (LOGGING(deliver_time))
   s = string_append(s, &size, &ptr, 2, US" DT=",
     readconf_printtime(addr->more_errno));
 
@@ -1163,16 +1204,8 @@ if (result == OK)
   delivery_log(LOG_MAIN, addr, logchar, NULL);
 
 #ifdef SUPPORT_TLS
-  if (tls_out.ourcert)
-    {
-    tls_free_cert(tls_out.ourcert);
-    tls_out.ourcert = NULL;
-    }
-  if (tls_out.peercert)
-    {
-    tls_free_cert(tls_out.peercert);
-    tls_out.peercert = NULL;
-    }
+  tls_free_cert(&tls_out.ourcert);
+  tls_free_cert(&tls_out.peercert);
   tls_out.cipher = NULL;
   tls_out.peerdn = NULL;
   tls_out.ocsp = OCSP_NOT_REQ;
@@ -1231,8 +1264,7 @@ else if (result == DEFER || result == PANIC)
     /* Create the address string for logging. Must not do this earlier, because
     an OK result may be changed to FAIL when a pipe returns text. */
 
-    log_address = string_log_address(addr,
-      (log_write_selector & L_all_parents) != 0, result == OK);
+    log_address = string_log_address(addr, LOGGING(all_parents), result == OK);
 
     s = string_cat(s, &size, &ptr, log_address, Ustrlen(log_address));
 
@@ -1343,18 +1375,16 @@ else
   /* Create the address string for logging. Must not do this earlier, because
   an OK result may be changed to FAIL when a pipe returns text. */
 
-  log_address = string_log_address(addr,
-    (log_write_selector & L_all_parents) != 0, result == OK);
+  log_address = string_log_address(addr, LOGGING(all_parents), result == OK);
 
   s = string_cat(s, &size, &ptr, log_address, Ustrlen(log_address));
 
-  if ((log_extra_selector & LX_sender_on_delivery) != 0)
+  if (LOGGING(sender_on_delivery))
     s = string_append(s, &size, &ptr, 3, US" F=<", sender_address, US">");
 
   /* Return path may not be set if no delivery actually happened */
 
-  if (used_return_path != NULL &&
-      (log_extra_selector & LX_return_path_on_delivery) != 0)
+  if (used_return_path != NULL && LOGGING(return_path_on_delivery))
     s = string_append(s, &size, &ptr, 3, US" P=<", used_return_path, US">");
 
   if (addr->router != NULL)
@@ -3128,15 +3158,17 @@ while (!done)
       break;
 
       case '2':
-      addr->peercert = NULL;
       if (*ptr)
        (void) tls_import_cert(ptr, &addr->peercert);
+      else
+       addr->peercert = NULL;
       break;
 
       case '3':
-      addr->ourcert = NULL;
       if (*ptr)
        (void) tls_import_cert(ptr, &addr->ourcert);
+      else
+       addr->ourcert = NULL;
       break;
 
 # ifndef DISABLE_OCSP
@@ -4448,7 +4480,7 @@ for (delivery_count = 0; addr_remote != NULL; delivery_count++)
       }
 
     /* Local interface address/port */
-    if (log_extra_selector & LX_incoming_interface  &&  sending_ip_address)
+    if (LOGGING(incoming_interface) && sending_ip_address)
       {
       uschar * ptr = big_buffer;
       sprintf(CS ptr, "%.128s", sending_ip_address);
@@ -4808,15 +4840,12 @@ print_address_error(address_item *addr, FILE *f, uschar *t)
 int count = Ustrlen(t);
 uschar *s = testflag(addr, af_pass_message)? addr->message : NULL;
 
-if (s == NULL)
-  {
-  if (addr->user_message != NULL) s = addr->user_message; else return;
-  }
+if (!s && !(s = addr->user_message))
+  return;
 
 fprintf(f, "\n    %s", t);
 
-while (*s != 0)
-  {
+while (*s)
   if (*s == '\\' && s[1] == 'n')
     {
     fprintf(f, "\n    ");
@@ -4833,7 +4862,6 @@ while (*s != 0)
       count = 0;
       }
     }
-  }
 }
 
 
@@ -4845,9 +4873,9 @@ while (*s != 0)
 a bounce or a warning message. It tries to format the message reasonably as
 required by RFC 3461 by adding a space after each newline
 
-we assume that this function is only called if addr->host_used is set and if so
-a useable addr->message is available containing some Exim description with ": \n" 
-ending, followed by the L/SMTP error message.
+it uses the same logic as print_address_error() above. if af_pass_message is true
+and addr->message is set it uses the remote host answer. if not addr->user_message
+is used instead if available.
 
 Arguments:
   addr         the address
@@ -4859,21 +4887,23 @@ Returns:       nothing
 static void
 print_dsn_diagnostic_code(const address_item *addr, FILE *f)
 {
-uschar * s;
-
-/* check host_used, af_pass_message flag and addr->message for safety reasons */
-if (!addr->host_used && testflag(addr, af_pass_message) && addr->message)
-  return;
+uschar *s = testflag(addr, af_pass_message) ? addr->message : NULL;
 
-/* search first ": ". we assume to find the remote-MTA answer there */
-DEBUG(D_deliver)
-  debug_printf("DSN Diagnostic-Code: addr->dsn_message = %s\n", addr->message);
-if (!(s = Ustrstr(addr->message, ": ")))
-  return;                              /* not found, bail out */
+/* af_pass_message and addr->message set ? print remote host answer */
+if (s)
+  {
+  DEBUG(D_deliver)
+    debug_printf("DSN Diagnostic-Code: addr->message = %s\n", addr->message);
 
-fprintf(f, "Diagnostic-Code: smtp; ");
+  /* search first ": ". we assume to find the remote-MTA answer there */
+  if (!(s = Ustrstr(addr->message, ": ")))
+    return;                            /* not found, bail out */
+  s += 2;  /* skip ": " */
+  fprintf(f, "Diagnostic-Code: smtp; ");
+  }
+/* no message available. do nothing */
+else return;
 
-s += 2;  /* skip ": " */
 while (*s)
   if (*s == '\\' && s[1] == 'n')
     {
@@ -5595,8 +5625,15 @@ if (process_recipients != RECIP_IGNORE)
       address_item *new = deliver_make_addr(r->address, FALSE);
       new->prop.errors_address = r->errors_to;
 #ifdef EXPERIMENTAL_INTERNATIONAL
-      new->prop.utf8 = message_smtputf8;
-      DEBUG(D_deliver) if (message_smtputf8) debug_printf("utf8\n");
+      if ((new->prop.utf8_msg = message_smtputf8))
+       {
+       new->prop.utf8_downcvt =       message_utf8_downconvert == 1;
+       new->prop.utf8_downcvt_maybe = message_utf8_downconvert == -1;
+       DEBUG(D_deliver) debug_printf("utf8, downconvert %s\n",
+         new->prop.utf8_downcvt ? "yes"
+         : new->prop.utf8_downcvt_maybe ? "ifneeded"
+         : "no");
+       }
 #endif
 
       if (r->pno >= 0)
@@ -7359,7 +7396,7 @@ if (addr_defer == NULL)
 
   /* Log the end of this message, with queue time if requested. */
 
-  if ((log_extra_selector & LX_queue_time_overall) != 0)
+  if (LOGGING(queue_time_overall))
     log_write(0, LOG_MAIN, "Completed QT=%s",
       readconf_printtime( (int) ((long)time(NULL) - (long)received_time)) );
   else
@@ -7882,7 +7919,7 @@ if (!regex_PRDR) regex_PRDR =
   regex_must_compile(US"\\n250[\\s\\-]PRDR(\\s|\\n|$)", FALSE, TRUE);
 #endif
 
-#ifdef SUPPORT_TLS
+#ifdef EXPERIMENTAL_INTERNATIONAL
 if (!regex_UTF8) regex_UTF8 =
   regex_must_compile(US"\\n250[\\s\\-]SMTPUTF8(\\s|\\n|$)", FALSE, TRUE);
 #endif
@@ -7898,17 +7935,36 @@ if (!regex_IGNOREQUOTA) regex_IGNOREQUOTA =
 uschar *
 deliver_get_sender_address (uschar * id)
 {
+int rc;
+uschar * new_sender_address,
+       * save_sender_address;
+
 if (!spool_open_datafile(id))
   return NULL;
 
+/* Save and restore the global sender_address.  I'm not sure if we should
+not save/restore all the other global variables too, because
+spool_read_header() may change all of them. But OTOH, when this
+deliver_get_sender_address() gets called, the current message is done
+already and nobody needs the globals anymore. (HS12, 2015-08-21) */
+
 sprintf(CS spoolname, "%s-H", id);
-if (spool_read_header(spoolname, TRUE, TRUE) != spool_read_OK)
+save_sender_address = sender_address;
+
+rc = spool_read_header(spoolname, TRUE, TRUE);
+
+new_sender_address = sender_address;
+sender_address = save_sender_address;
+
+if (rc != spool_read_OK)
   return NULL;
 
+assert(new_sender_address);
+
 (void)close(deliver_datafile);
 deliver_datafile = -1;
 
-return sender_address;
+return new_sender_address;
 }
 
 /* vi: aw ai sw=2