Add tls_verify_hosts and tls_try_verify_hosts to smtp transport
[exim.git] / src / src / transports / smtp.c
index b18720cc02ccf625f49ae880d5809c028bec7e06..938844799f731d50016a4ff504e6f362f02db208 100644 (file)
@@ -2,7 +2,7 @@
 *     Exim - an Internet mail transport agent    *
 *************************************************/
 
-/* Copyright (c) University of Cambridge 1995 - 2012 */
+/* Copyright (c) University of Cambridge 1995 - 2013 */
 /* See the file NOTICE for conditions of use and distribution. */
 
 #include "../exim.h"
@@ -153,8 +153,16 @@ optionlist smtp_transport_options[] = {
       (void *)offsetof(smtp_transport_options_block, tls_sni) },
   { "tls_tempfail_tryclear", opt_bool,
       (void *)offsetof(smtp_transport_options_block, tls_tempfail_tryclear) },
+  { "tls_try_verify_hosts", opt_stringptr,
+      (void *)offsetof(smtp_transport_options_block, tls_try_verify_hosts) },
   { "tls_verify_certificates", opt_stringptr,
-      (void *)offsetof(smtp_transport_options_block, tls_verify_certificates) }
+      (void *)offsetof(smtp_transport_options_block, tls_verify_certificates) },
+  { "tls_verify_hosts",     opt_stringptr,
+      (void *)offsetof(smtp_transport_options_block, tls_verify_hosts) }
+#endif
+#ifdef EXPERIMENTAL_TPDA
+ ,{ "tpda_host_defer_action", opt_stringptr,
+      (void *)offsetof(smtp_transport_options_block, tpda_host_defer_action) },
 #endif
 };
 
@@ -223,7 +231,9 @@ smtp_transport_options_block smtp_transport_option_defaults = {
   NULL,                /* tls_verify_certificates */
   EXIM_CLIENT_DH_DEFAULT_MIN_BITS,
                        /* tls_dh_min_bits */
-  TRUE                 /* tls_tempfail_tryclear */
+  TRUE,                /* tls_tempfail_tryclear */
+  NULL,                /* tls_verify_hosts */
+  NULL                 /* tls_try_verify_hosts */
 #endif
 #ifndef DISABLE_DKIM
  ,NULL,                /* dkim_canon */
@@ -233,6 +243,9 @@ smtp_transport_options_block smtp_transport_option_defaults = {
   NULL,                /* dkim_sign_headers */
   NULL                 /* dkim_strict */
 #endif
+#ifdef EXPERIMENTAL_TPDA
+ ,NULL                 /* tpda_host_defer_action */
+#endif
 };
 
 
@@ -577,6 +590,59 @@ else
 
 
 
+#ifdef EXPERIMENTAL_TPDA
+/*************************************************
+*   Post-defer action                            *
+*************************************************/
+
+/* This expands an arbitrary per-transport string.
+   It might, for example, be used to write to the database log.
+
+Arguments:
+  ob                    transport options block
+  addr                  the address item containing error information
+  host                  the current host
+
+Returns:   nothing
+*/
+
+static void
+tpda_deferred(smtp_transport_options_block *ob, address_item *addr, host_item *host)
+{
+uschar *action = ob->tpda_host_defer_action;
+if (!action)
+       return;
+
+tpda_delivery_ip =         string_copy(host->address);
+tpda_delivery_port =       (host->port == PORT_NONE)? 25 : host->port;
+tpda_delivery_fqdn =       string_copy(host->name);
+tpda_delivery_local_part = string_copy(addr->local_part);
+tpda_delivery_domain =     string_copy(addr->domain);
+tpda_defer_errno =         addr->basic_errno;
+
+tpda_defer_errstr = addr->message
+  ? addr->basic_errno > 0
+    ? string_sprintf("%s: %s", addr->message, strerror(addr->basic_errno))
+    : string_copy(addr->message)
+  : addr->basic_errno > 0
+    ? string_copy(strerror(addr->basic_errno))
+    : NULL;
+
+DEBUG(D_transport)
+  debug_printf("  TPDA(host defer): tpda_host_defer_action=|%s| tpda_delivery_IP=%s\n",
+    action, tpda_delivery_ip);
+
+router_name =    addr->router->name;
+transport_name = addr->transport->name;
+if (!expand_string(action) && *expand_string_message)
+  log_write(0, LOG_MAIN|LOG_PANIC, "failed to expand tpda_defer_action in %s: %s\n",
+    transport_name, expand_string_message);
+router_name = transport_name = NULL;
+}
+#endif
+
+
+
 /*************************************************
 *           Synchronize SMTP responses           *
 *************************************************/
@@ -1386,7 +1452,9 @@ if (tls_offered && !suppress_tls &&
       ob->hosts_require_ocsp,
 #endif
       ob->tls_dh_min_bits,
-      ob->command_timeout);
+      ob->command_timeout,
+      ob->tls_verify_hosts,
+      ob->tls_try_verify_hosts);
 
     /* 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
@@ -1912,7 +1980,12 @@ if (!ok) ok = TRUE; else
 
     /* Set up confirmation if needed - applies only to SMTP */
 
-    if ((log_extra_selector & LX_smtp_confirmation) != 0 && !lmtp)
+    if (
+        #ifndef EXPERIMENTAL_TPDA
+          (log_extra_selector & LX_smtp_confirmation) != 0 &&
+        #endif
+          !lmtp
+       )
       {
       uschar *s = string_printing(buffer);
       conf = (s == buffer)? (uschar *)string_copy(s) : s;
@@ -3051,6 +3124,11 @@ for (cutoff_retry = 0; expired &&
                          first_addr->basic_errno != ERRNO_TLSFAILURE)
         write_logs(first_addr, host);
 
+      #ifdef EXPERIMENTAL_TPDA
+      if (rc == DEFER)
+        tpda_deferred(ob, first_addr, host);
+      #endif
+
       /* If STARTTLS was accepted, but there was a failure in setting up the
       TLS session (usually a certificate screwup), and the host is not in
       hosts_require_tls, and tls_tempfail_tryclear is true, try again, with
@@ -3073,6 +3151,10 @@ for (cutoff_retry = 0; expired &&
           expanded_hosts != NULL, &message_defer, TRUE);
         if (rc == DEFER && first_addr->basic_errno != ERRNO_AUTHFAIL)
           write_logs(first_addr, host);
+        #ifdef EXPERIMENTAL_TPDA
+        if (rc == DEFER)
+          tpda_deferred(ob, first_addr, host);
+        #endif
         }
       #endif
       }