Compiler quietening and testcase consistency
[exim.git] / src / src / deliver.c
index 79d431b37307b79fbf24ba6c59d5b926b2a96335..3334ba2cb3ea98418ed4388ce7856580300c3d37 100644 (file)
@@ -2,7 +2,7 @@
 *     Exim - an Internet mail transport agent    *
 *************************************************/
 
-/* Copyright (c) University of Cambridge 1995 - 2009 */
+/* Copyright (c) University of Cambridge 1995 - 2014 */
 /* See the file NOTICE for conditions of use and distribution. */
 
 /* The main code for delivering a message. */
@@ -673,8 +673,36 @@ while (addr->parent != NULL)
 
 
 
+static uschar *
+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;
+}
+
+#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)? "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;
+}
+#endif
+
 /* If msg is NULL this is a delivery log and logchar is used. Otherwise
-this is a nonstandard call; no two-characher delivery flag is written
+this is a nonstandard call; no two-character delivery flag is written
 but sender-host and sender are prefixed and "msg" is inserted in the log line.
 
 Arguments:
@@ -695,6 +723,15 @@ the log line, and reset the store afterwards. Remote deliveries should always
 have a pointer to the host item that succeeded; local deliveries can have a
 pointer to a single host item in their host list, for use by the transport. */
 
+#ifdef EXPERIMENTAL_TPDA
+  tpda_delivery_ip = NULL;     /* presume no successful remote delivery */
+  tpda_delivery_port = 0;
+  tpda_delivery_fqdn = NULL;
+  tpda_delivery_local_part = NULL;
+  tpda_delivery_domain = NULL;
+  tpda_delivery_confirmation = NULL;
+#endif
+
 s = reset_point = store_get(size);
 
 log_address = string_log_address(addr, (log_write_selector & L_all_parents) != 0, TRUE);
@@ -741,7 +778,12 @@ if ((log_extra_selector & LX_delivery_size) != 0)
 if (addr->transport->info->local)
   {
   if (addr->host_list != NULL)
+    {
     s = string_append(s, &size, &ptr, 2, US" H=", addr->host_list->name);
+    #ifdef EXPERIMENTAL_TPDA
+      tpda_delivery_fqdn = addr->host_list->name;
+    #endif
+    }
   if (addr->shadow_message != NULL)
     s = string_cat(s, &size, &ptr, addr->shadow_message,
       Ustrlen(addr->shadow_message));
@@ -753,25 +795,22 @@ else
   {
   if (addr->host_used != NULL)
     {
-    s = string_append(s, &size, &ptr, 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, &size, &ptr, 2, US":", string_sprintf("%d",
-        addr->host_used->port));
+    s = d_hostlog(s, &size, &ptr, addr);
     if (continue_sequence > 1)
       s = string_cat(s, &size, &ptr, US"*", 1);
+
+    #ifdef EXPERIMENTAL_TPDA
+    tpda_delivery_ip =           addr->host_used->address;
+    tpda_delivery_port =         addr->host_used->port;
+    tpda_delivery_fqdn =         addr->host_used->name;
+    tpda_delivery_local_part =   addr->local_part;
+    tpda_delivery_domain =       addr->domain;
+    tpda_delivery_confirmation = addr->message;
+    #endif
     }
 
   #ifdef SUPPORT_TLS
-  if ((log_extra_selector & LX_tls_cipher) != 0 && addr->cipher != NULL)
-    s = string_append(s, &size, &ptr, 2, US" X=", addr->cipher);
-  if ((log_extra_selector & LX_tls_certificate_verified) != 0 &&
-       addr->cipher != NULL)
-    s = string_append(s, &size, &ptr, 2, US" CV=",
-      testflag(addr, af_cert_verified)? "yes":"no");
-  if ((log_extra_selector & LX_tls_peerdn) != 0 && addr->peerdn != NULL)
-    s = string_append(s, &size, &ptr, 3, US" DN=\"",
-      string_printing(addr->peerdn), US"\"");
+  s = d_tlslog(s, &size, &ptr, addr);
   #endif
 
   if (addr->authenticator)
@@ -785,22 +824,30 @@ else
       }
     }
 
-  if ((log_extra_selector & LX_smtp_confirmation) != 0 &&
-      addr->message != NULL)
-    {
-    int i;
-    uschar *p = big_buffer;
-    uschar *ss = addr->message;
-    *p++ = '\"';
-    for (i = 0; i < 100 && ss[i] != 0; i++)
-      {
-      if (ss[i] == '\"' || ss[i] == '\\') *p++ = '\\';
-      *p++ = ss[i];
-      }
-    *p++ = '\"';
-    *p = 0;
-    s = string_append(s, &size, &ptr, 2, US" C=", big_buffer);
-    }
+  #ifdef EXPERIMENTAL_PRDR
+  if (addr->flags & af_prdr_used)
+    s = string_append(s, &size, &ptr, 1, US" PRDR");
+  #endif
+  }
+
+/* confirmation message (SMTP (host_used) and LMTP (driver_name)) */
+
+if ((log_extra_selector & LX_smtp_confirmation) != 0 &&
+    addr->message != NULL &&
+    ((addr->host_used != NULL) || (Ustrcmp(addr->transport->driver_name, "lmtp") == 0)))
+  {
+  int i;
+  uschar *p = big_buffer;
+  uschar *ss = addr->message;
+  *p++ = '\"';
+  for (i = 0; i < 100 && ss[i] != 0; i++)
+    {
+    if (ss[i] == '\"' || ss[i] == '\\') *p++ = '\\';
+    *p++ = ss[i];
+    }
+  *p++ = '\"';
+  *p = 0;
+  s = string_append(s, &size, &ptr, 2, US" C=", big_buffer);
   }
 
 /* Time on queue and actual time taken to deliver */
@@ -822,6 +869,23 @@ store we used to build the line after writing it. */
 
 s[ptr] = 0;
 log_write(0, flags, "%s", s);
+
+#ifdef EXPERIMENTAL_TPDA
+if (addr->transport->tpda_delivery_action)
+  {
+  DEBUG(D_deliver)
+    debug_printf("  TPDA(Delivery): tpda_deliver_action=|%s| tpda_delivery_IP=%s\n",
+      addr->transport->tpda_delivery_action, tpda_delivery_ip);
+
+  router_name =    addr->router->name;
+  transport_name = addr->transport->name;
+  if (!expand_string(addr->transport->tpda_delivery_action) && *expand_string_message)
+    log_write(0, LOG_MAIN|LOG_PANIC, "failed to expand tpda_deliver_action in %s: %s\n",
+      transport_name, expand_string_message);
+  router_name = NULL;
+  transport_name = NULL;
+  }
+#endif
 store_reset(reset_point);
 return;
 }
@@ -900,6 +964,9 @@ if (addr->message != NULL)
   if (((Ustrstr(addr->message, "failed to expand") != NULL) || (Ustrstr(addr->message, "expansion of ") != NULL)) &&
       (Ustrstr(addr->message, "mysql") != NULL ||
        Ustrstr(addr->message, "pgsql") != NULL ||
+#ifdef EXPERIMENTAL_REDIS
+       Ustrstr(addr->message, "redis") != NULL ||
+#endif
        Ustrstr(addr->message, "sqlite") != NULL ||
        Ustrstr(addr->message, "ldap:") != NULL ||
        Ustrstr(addr->message, "ldapdn:") != NULL ||
@@ -990,7 +1057,7 @@ if (addr->return_file >= 0 && addr->return_filename != NULL)
   (void)close(addr->return_file);
   }
 
-/* The sucess case happens only after delivery by a transport. */
+/* The success case happens only after delivery by a transport. */
 
 if (result == OK)
   {
@@ -1006,10 +1073,8 @@ if (result == OK)
   DEBUG(D_deliver) debug_printf("%s delivered\n", addr->address);
 
   if (addr->parent == NULL)
-    {
     deliver_msglog("%s %s: %s%s succeeded\n", now, addr->address,
       driver_name, driver_kind);
-    }
   else
     {
     deliver_msglog("%s %s <%s>: %s%s succeeded\n", now, addr->address,
@@ -1017,7 +1082,35 @@ if (result == OK)
     child_done(addr, now);
     }
 
+  /* Certificates for logging (via TPDA) */
+  #ifdef SUPPORT_TLS
+  tls_out.ourcert = addr->ourcert;
+  addr->ourcert = NULL;
+  tls_out.peercert = addr->peercert;
+  addr->peercert = NULL;
+
+  tls_out.cipher = addr->cipher;
+  tls_out.peerdn = addr->peerdn;
+  tls_out.ocsp = addr->ocsp;
+  #endif
+
   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_out.cipher = NULL;
+  tls_out.peerdn = NULL;
+  tls_out.ocsp = OCSP_NOT_REQ;
+  #endif
   }
 
 
@@ -1188,9 +1281,7 @@ else
 
   if (used_return_path != NULL &&
       (log_extra_selector & LX_return_path_on_delivery) != 0)
-    {
     s = string_append(s, &size, &ptr, 3, US" P=<", used_return_path, US">");
-    }
 
   if (addr->router != NULL)
     s = string_append(s, &size, &ptr, 2, US" R=", addr->router->name);
@@ -1198,8 +1289,11 @@ else
     s = string_append(s, &size, &ptr, 2, US" T=", addr->transport->name);
 
   if (addr->host_used != NULL)
-    s = string_append(s, &size, &ptr, 5, US" H=", addr->host_used->name,
-      US" [", addr->host_used->address, US"]");
+    s = d_hostlog(s, &size, &ptr, addr);
+
+  #ifdef SUPPORT_TLS
+  s = d_tlslog(s, &size, &ptr, addr);
+  #endif
 
   if (addr->basic_errno > 0)
     s = string_append(s, &size, &ptr, 2, US": ",
@@ -1871,6 +1965,9 @@ if ((pid = fork()) == 0)
     set_process_info("delivering %s to %s using %s", message_id,
      addr->local_part, addr->transport->name);
 
+    /* Setting this global in the subprocess means we need never clear it */
+    transport_name = addr->transport->name;
+
     /* If a transport filter has been specified, set up its argument list.
     Any errors will get put into the address, and FALSE yielded. */
 
@@ -2886,30 +2983,65 @@ while (!done)
 
     #ifdef SUPPORT_TLS
     case 'X':
-    if (addr == NULL) goto ADDR_MISMATCH;            /* Below, in 'A' handler */
-    addr->cipher = (*ptr)? string_copy(ptr) : NULL;
-    while (*ptr++);
-    addr->peerdn = (*ptr)? string_copy(ptr) : NULL;
+    if (addr == NULL) goto ADDR_MISMATCH;          /* Below, in 'A' handler */
+    switch (*ptr++)
+      {
+      case '1':
+      addr->cipher = NULL;
+      addr->peerdn = NULL;
+
+      if (*ptr)
+       addr->cipher = string_copy(ptr);
+      while (*ptr++);
+      if (*ptr)
+       addr->peerdn = string_copy(ptr);
+      break;
+
+      case '2':
+      addr->peercert = NULL;
+      if (*ptr)
+       (void) tls_import_cert(ptr, &addr->peercert);
+      break;
+
+      case '3':
+      addr->ourcert = NULL;
+      if (*ptr)
+       (void) tls_import_cert(ptr, &addr->ourcert);
+      break;
+
+      #ifdef EXPERIMENTAL_OCSP
+      case '4':
+      addr->ocsp = OCSP_NOT_REQ;
+      if (*ptr)
+       addr->ocsp = *ptr - '0';
+      break;
+      #endif
+      }
     while (*ptr++);
     break;
     #endif
 
     case 'C':  /* client authenticator information */
     switch (*ptr++)
-    {
-    case '1':
-      addr->authenticator = (*ptr)? string_copy(ptr) : NULL;
-      break;
-    case '2':
-      addr->auth_id = (*ptr)? string_copy(ptr) : NULL;
-      break;
-    case '3':
-      addr->auth_sndr = (*ptr)? string_copy(ptr) : NULL;
-      break;
-    }
+      {
+      case '1':
+       addr->authenticator = (*ptr)? string_copy(ptr) : NULL;
+       break;
+      case '2':
+       addr->auth_id = (*ptr)? string_copy(ptr) : NULL;
+       break;
+      case '3':
+       addr->auth_sndr = (*ptr)? string_copy(ptr) : NULL;
+       break;
+      }
     while (*ptr++);
     break;
 
+#ifdef EXPERIMENTAL_PRDR
+    case 'P':
+      addr->flags |= af_prdr_used; break;
+#endif
+
     case 'A':
     if (addr == NULL)
       {
@@ -3855,8 +3987,10 @@ for (delivery_count = 0; addr_remote != NULL; delivery_count++)
     int fd = pfd[pipe_write];
     host_item *h;
 
-    /* There are weird circumstances in which logging is disabled */
+    /* Setting this global in the subprocess means we need never clear it */
+    transport_name = tp->name;
 
+    /* There are weird circumstances in which logging is disabled */
     disable_logging = tp->disable_logging;
 
     /* Show pids on debug output if parallelism possible */
@@ -3976,19 +4110,51 @@ for (delivery_count = 0; addr_remote != NULL; delivery_count++)
       /* Use an X item only if there's something to send */
 
       #ifdef SUPPORT_TLS
-      if (addr->cipher != NULL)
+      if (addr->cipher)
         {
         ptr = big_buffer;
-        sprintf(CS ptr, "X%.128s", addr->cipher);
+        sprintf(CS ptr, "X1%.128s", addr->cipher);
         while(*ptr++);
-        if (addr->peerdn == NULL) *ptr++ = 0; else
+        if (!addr->peerdn)
+         *ptr++ = 0;
+       else
           {
           sprintf(CS ptr, "%.512s", addr->peerdn);
           while(*ptr++);
           }
+
         rmt_dlv_checked_write(fd, big_buffer, ptr - big_buffer);
         }
-      #endif
+      if (addr->peercert)
+       {
+        ptr = big_buffer;
+       *ptr++ = 'X'; *ptr++ = '2';
+       if (!tls_export_cert(ptr, big_buffer_size-2, addr->peercert))
+         while(*ptr++);
+       else
+         *ptr++ = 0;
+        rmt_dlv_checked_write(fd, big_buffer, ptr - big_buffer);
+       }
+      if (addr->ourcert)
+       {
+        ptr = big_buffer;
+       *ptr++ = 'X'; *ptr++ = '3';
+       if (!tls_export_cert(ptr, big_buffer_size-2, addr->ourcert))
+         while(*ptr++);
+       else
+         *ptr++ = 0;
+        rmt_dlv_checked_write(fd, big_buffer, ptr - big_buffer);
+       }
+      # ifdef EXPERIMENTAL_OCSP
+      if (addr->ocsp > OCSP_NOT_REQ)
+       {
+       ptr = big_buffer;
+       sprintf(CS ptr, "X4%c", addr->ocsp + '0');
+       while(*ptr++);
+        rmt_dlv_checked_write(fd, big_buffer, ptr - big_buffer);
+       }
+      # endif
+      #endif   /*SUPPORT_TLS*/
 
       if (client_authenticator)
         {
@@ -4012,6 +4178,10 @@ for (delivery_count = 0; addr_remote != NULL; delivery_count++)
         rmt_dlv_checked_write(fd, big_buffer, ptr - big_buffer);
        }
 
+      #ifdef EXPERIMENTAL_PRDR
+      if (addr->flags & af_prdr_used) rmt_dlv_checked_write(fd, "P", 1);
+      #endif
+
       /* Retry information: for most success cases this will be null. */
 
       for (r = addr->retries; r != NULL; r = r->next)
@@ -6096,6 +6266,11 @@ if (addr_remote != NULL)
     regex_must_compile(US"\\n250[\\s\\-]STARTTLS(\\s|\\n|$)", FALSE, TRUE);
   #endif
 
+  #ifdef EXPERIMENTAL_PRDR
+  if (regex_PRDR == NULL) regex_PRDR =
+    regex_must_compile(US"\\n250[\\s\\-]PRDR(\\s|\\n|$)", FALSE, TRUE);
+  #endif
+
   /* Now sort the addresses if required, and do the deliveries. The yield of
   do_remote_deliveries is FALSE when mua_wrapper is set and all addresses
   cannot be delivered in one transaction. */
@@ -7098,4 +7273,6 @@ acl_where = ACL_WHERE_UNKNOWN;
 return final_yield;
 }
 
+/* vi: aw ai sw=2
+*/
 /* End of deliver.c */