Update all copyright messages to cover 1995 - 2009. Remove tab from exim_checkaccess.src
[exim.git] / src / src / transports / smtp.c
index 0bc5b533ee77872c801a1fedd738e3bb91d5cbea..fb55ae01bbd7210962e5be0f5ed778faa1329779 100644 (file)
@@ -1,10 +1,10 @@
-/* $Cambridge: exim/src/src/transports/smtp.c,v 1.34 2007/02/06 14:19:00 ph10 Exp $ */
+/* $Cambridge: exim/src/src/transports/smtp.c,v 1.44 2009/11/16 19:56:54 nm4 Exp $ */
 
 /*************************************************
 *     Exim - an Internet mail transport agent    *
 *************************************************/
 
-/* Copyright (c) University of Cambridge 1995 - 2007 */
+/* Copyright (c) University of Cambridge 1995 - 2009 */
 /* See the file NOTICE for conditions of use and distribution. */
 
 #include "../exim.h"
@@ -39,19 +39,19 @@ optionlist smtp_transport_options[] = {
       (void *)offsetof(smtp_transport_options_block, data_timeout) },
   { "delay_after_cutoff", opt_bool,
       (void *)offsetof(smtp_transport_options_block, delay_after_cutoff) },
-#ifdef EXPERIMENTAL_DOMAINKEYS
-  { "dk_canon", opt_stringptr,
-      (void *)offsetof(smtp_transport_options_block, dk_canon) },
-  { "dk_domain", opt_stringptr,
-      (void *)offsetof(smtp_transport_options_block, dk_domain) },
-  { "dk_headers", opt_stringptr,
-      (void *)offsetof(smtp_transport_options_block, dk_headers) },
-  { "dk_private_key", opt_stringptr,
-      (void *)offsetof(smtp_transport_options_block, dk_private_key) },
-  { "dk_selector", opt_stringptr,
-      (void *)offsetof(smtp_transport_options_block, dk_selector) },
-  { "dk_strict", opt_stringptr,
-      (void *)offsetof(smtp_transport_options_block, dk_strict) },
+#ifndef DISABLE_DKIM
+  { "dkim_canon", opt_stringptr,
+      (void *)offsetof(smtp_transport_options_block, dkim_canon) },
+  { "dkim_domain", opt_stringptr,
+      (void *)offsetof(smtp_transport_options_block, dkim_domain) },
+  { "dkim_private_key", opt_stringptr,
+      (void *)offsetof(smtp_transport_options_block, dkim_private_key) },
+  { "dkim_selector", opt_stringptr,
+      (void *)offsetof(smtp_transport_options_block, dkim_selector) },
+  { "dkim_sign_headers", opt_stringptr,
+      (void *)offsetof(smtp_transport_options_block, dkim_sign_headers) },
+  { "dkim_strict", opt_stringptr,
+      (void *)offsetof(smtp_transport_options_block, dkim_strict) },
 #endif
   { "dns_qualify_single",   opt_bool,
       (void *)offsetof(smtp_transport_options_block, dns_qualify_single) },
@@ -63,42 +63,44 @@ optionlist smtp_transport_options[] = {
       (void *)offsetof(smtp_transport_options_block, final_timeout) },
   { "gethostbyname",        opt_bool,
       (void *)offsetof(smtp_transport_options_block, gethostbyname) },
-  #ifdef SUPPORT_TLS
+#ifdef SUPPORT_TLS
   { "gnutls_require_kx",    opt_stringptr,
       (void *)offsetof(smtp_transport_options_block, gnutls_require_kx) },
   { "gnutls_require_mac",   opt_stringptr,
       (void *)offsetof(smtp_transport_options_block, gnutls_require_mac) },
   { "gnutls_require_protocols", opt_stringptr,
       (void *)offsetof(smtp_transport_options_block, gnutls_require_proto) },
-  #endif
+#endif
   { "helo_data",            opt_stringptr,
       (void *)offsetof(smtp_transport_options_block, helo_data) },
   { "hosts",                opt_stringptr,
       (void *)offsetof(smtp_transport_options_block, hosts) },
   { "hosts_avoid_esmtp",    opt_stringptr,
       (void *)offsetof(smtp_transport_options_block, hosts_avoid_esmtp) },
-  #ifdef SUPPORT_TLS
+  { "hosts_avoid_pipelining", opt_stringptr,
+      (void *)offsetof(smtp_transport_options_block, hosts_avoid_pipelining) },
+#ifdef SUPPORT_TLS
   { "hosts_avoid_tls",      opt_stringptr,
       (void *)offsetof(smtp_transport_options_block, hosts_avoid_tls) },
-  #endif
+#endif
   { "hosts_max_try",        opt_int,
       (void *)offsetof(smtp_transport_options_block, hosts_max_try) },
   { "hosts_max_try_hardlimit", opt_int,
       (void *)offsetof(smtp_transport_options_block, hosts_max_try_hardlimit) },
-  #ifdef SUPPORT_TLS
+#ifdef SUPPORT_TLS
   { "hosts_nopass_tls",     opt_stringptr,
       (void *)offsetof(smtp_transport_options_block, hosts_nopass_tls) },
-  #endif
+#endif
   { "hosts_override",       opt_bool,
       (void *)offsetof(smtp_transport_options_block, hosts_override) },
   { "hosts_randomize",      opt_bool,
       (void *)offsetof(smtp_transport_options_block, hosts_randomize) },
   { "hosts_require_auth",   opt_stringptr,
       (void *)offsetof(smtp_transport_options_block, hosts_require_auth) },
-  #ifdef SUPPORT_TLS
+#ifdef SUPPORT_TLS
   { "hosts_require_tls",    opt_stringptr,
       (void *)offsetof(smtp_transport_options_block, hosts_require_tls) },
-  #endif
+#endif
   { "hosts_try_auth",       opt_stringptr,
       (void *)offsetof(smtp_transport_options_block, hosts_try_auth) },
   { "interface",            opt_stringptr,
@@ -121,7 +123,7 @@ optionlist smtp_transport_options[] = {
       (void *)offsetof(smtp_transport_options_block, serialize_hosts) },
   { "size_addition",        opt_int,
       (void *)offsetof(smtp_transport_options_block, size_addition) }
-  #ifdef SUPPORT_TLS
+#ifdef SUPPORT_TLS
  ,{ "tls_certificate",      opt_stringptr,
       (void *)offsetof(smtp_transport_options_block, tls_certificate) },
   { "tls_crl",              opt_stringptr,
@@ -134,7 +136,7 @@ optionlist smtp_transport_options[] = {
       (void *)offsetof(smtp_transport_options_block, tls_tempfail_tryclear) },
   { "tls_verify_certificates", opt_stringptr,
       (void *)offsetof(smtp_transport_options_block, tls_verify_certificates) }
-  #endif
+#endif
 };
 
 /* Size of the options list. An extern variable has to be used so that its
@@ -160,6 +162,7 @@ smtp_transport_options_block smtp_transport_option_defaults = {
   NULL,                /* hosts_require_auth */
   NULL,                /* hosts_require_tls */
   NULL,                /* hosts_avoid_tls */
+  NULL,                /* hosts_avoid_pipelining */
   NULL,                /* hosts_avoid_esmtp */
   NULL,                /* hosts_nopass_tls */
   5*60,                /* command_timeout */
@@ -181,7 +184,7 @@ smtp_transport_options_block smtp_transport_option_defaults = {
   TRUE,                /* keepalive */
   FALSE,               /* lmtp_ignore_quota */
   TRUE                 /* retry_include_ip_address */
-  #ifdef SUPPORT_TLS
+#ifdef SUPPORT_TLS
  ,NULL,                /* tls_certificate */
   NULL,                /* tls_crl */
   NULL,                /* tls_privatekey */
@@ -191,15 +194,15 @@ smtp_transport_options_block smtp_transport_option_defaults = {
   NULL,                /* gnutls_require_proto */
   NULL,                /* tls_verify_certificates */
   TRUE                 /* tls_tempfail_tryclear */
-  #endif
-  #ifdef EXPERIMENTAL_DOMAINKEYS
- ,NULL,                /* dk_canon */
-  NULL,                /* dk_domain */
-  NULL,                /* dk_headers */
-  NULL,                /* dk_private_key */
-  NULL,                /* dk_selector */
-  NULL                 /* dk_strict */
-  #endif
+#endif
+#ifndef DISABLE_DKIM
+ ,NULL,                /* dkim_canon */
+  NULL,                /* dkim_domain */
+  NULL,                /* dkim_private_key */
+  NULL,                /* dkim_selector */
+  NULL,                /* dkim_sign_headers */
+  NULL                 /* dkim_strict */
+#endif
 };
 
 
@@ -786,7 +789,8 @@ return yield;
 
 /* If continue_hostname is not null, we get here only when continuing to
 deliver down an existing channel. The channel was passed as the standard
-input.
+input. TLS is never active on a passed channel; the previous process always
+closes it down before passing the connection on.
 
 Otherwise, we have to make a connection to the remote host, and do the
 initial protocol exchange.
@@ -883,6 +887,11 @@ outblock.ptr = outbuffer;
 outblock.cmd_count = 0;
 outblock.authenticating = FALSE;
 
+/* Reset the parameters of a TLS session. */
+
+tls_cipher = NULL;
+tls_peerdn = NULL;
+
 /* If an authenticated_sender override has been specified for this transport
 instance, expand it. If the expansion is forced to fail, and there was already
 an authenticated_sender for this message, the original value will be used.
@@ -914,7 +923,8 @@ if (continue_hostname == NULL)
   {
   inblock.sock = outblock.sock =
     smtp_connect(host, host_af, port, interface, ob->connect_timeout,
-      ob->keepalive);
+      ob->keepalive);   /* This puts port into host->port */
+
   if (inblock.sock < 0)
     {
     set_errno(addrlist, (errno == ETIMEDOUT)? ERRNO_CONNECTTIMEOUT : errno,
@@ -1038,6 +1048,7 @@ else
   {
   inblock.sock = outblock.sock = fileno(stdin);
   smtp_command = big_buffer;
+  host->port = port;    /* Record the port that was used */
   }
 
 /* If TLS is available on this connection, whether continued or not, attempt to
@@ -1189,9 +1200,12 @@ if (continue_hostname == NULL
       PCRE_EOPT, NULL, 0) >= 0;
 
   /* Note whether the server supports PIPELINING. If hosts_avoid_esmtp matched
-  the current host, esmtp will be false, so PIPELINING can never be used. */
+  the current host, esmtp will be false, so PIPELINING can never be used. If
+  the current host matches hosts_avoid_pipelining, don't do it. */
 
   smtp_use_pipelining = esmtp &&
+    verify_check_this_host(&(ob->hosts_avoid_pipelining), NULL, host->name,
+      host->address, NULL) != OK &&
     pcre_exec(regex_PIPELINING, NULL, CS buffer, Ustrlen(CS buffer), 0,
       PCRE_EOPT, NULL, 0) >= 0;
 
@@ -1225,14 +1239,25 @@ if (continue_hostname == NULL
       DEBUG(D_transport) debug_printf("scanning authentication mechanisms\n");
 
       /* Scan the configured authenticators looking for one which is configured
-      for use as a client and whose name matches an authentication mechanism
-      supported by the server. If one is found, attempt to authenticate by
-      calling its client function. */
+      for use as a client, which is not suppressed by client_condition, and
+      whose name matches an authentication mechanism supported by the server.
+      If one is found, attempt to authenticate by calling its client function.
+      */
 
       for (au = auths; !smtp_authenticated && au != NULL; au = au->next)
         {
         uschar *p = names;
-        if (!au->client) continue;
+        if (!au->client ||
+            (au->client_condition != NULL &&
+             !expand_check_condition(au->client_condition, au->name,
+               US"client authenticator")))
+          {
+          DEBUG(D_transport) debug_printf("skipping %s authenticator: %s\n",
+            au->name,
+            (au->client)? "client_condition is false" :
+                          "not configured as a client");
+          continue;
+          }
 
         /* Loop to scan supported server mechanisms */
 
@@ -1339,6 +1364,7 @@ if (tblock->filter_command != NULL)
   sprintf(CS buffer, "%.50s transport", tblock->name);
   rc = transport_set_up_command(&transport_filter_argv, tblock->filter_command,
     TRUE, DEFER, addrlist, buffer, NULL);
+  transport_filter_timeout = tblock->filter_timeout;
 
   /* On failure, copy the error to all addresses, abandon the SMTP call, and
   yield ERROR. */
@@ -1548,23 +1574,22 @@ if (!ok) ok = TRUE; else
   DEBUG(D_transport|D_v)
     debug_printf("  SMTP>> writing message and terminating \".\"\n");
   transport_count = 0;
-#ifdef EXPERIMENTAL_DOMAINKEYS
-  if ( (ob->dk_private_key != NULL) && (ob->dk_selector != NULL) )
-    ok = dk_transport_write_message(addrlist, inblock.sock,
-      topt_use_crlf | topt_end_dot | topt_escape_headers |
-        (tblock->body_only? topt_no_headers : 0) |
-        (tblock->headers_only? topt_no_body : 0) |
-        (tblock->return_path_add? topt_add_return_path : 0) |
-        (tblock->delivery_date_add? topt_add_delivery_date : 0) |
-        (tblock->envelope_to_add? topt_add_envelope_to : 0),
-      0,            /* No size limit */
-      tblock->add_headers, tblock->remove_headers,
-      US".", US"..",    /* Escaping strings */
-      tblock->rewrite_rules, tblock->rewrite_existflags,
-      ob->dk_private_key, ob->dk_domain, ob->dk_selector,
-      ob->dk_canon, ob->dk_headers, ob->dk_strict);
-  else
-#endif
+#ifndef DISABLE_DKIM
+  ok = dkim_transport_write_message(addrlist, inblock.sock,
+    topt_use_crlf | topt_end_dot | topt_escape_headers |
+      (tblock->body_only? topt_no_headers : 0) |
+      (tblock->headers_only? topt_no_body : 0) |
+      (tblock->return_path_add? topt_add_return_path : 0) |
+      (tblock->delivery_date_add? topt_add_delivery_date : 0) |
+      (tblock->envelope_to_add? topt_add_envelope_to : 0),
+    0,            /* No size limit */
+    tblock->add_headers, tblock->remove_headers,
+    US".", US"..",    /* Escaping strings */
+    tblock->rewrite_rules, tblock->rewrite_existflags,
+    ob->dkim_private_key, ob->dkim_domain, ob->dkim_selector,
+    ob->dkim_canon, ob->dkim_strict, ob->dkim_sign_headers
+    );
+#else
   ok = transport_write_message(addrlist, inblock.sock,
     topt_use_crlf | topt_end_dot | topt_escape_headers |
       (tblock->body_only? topt_no_headers : 0) |
@@ -1576,6 +1601,7 @@ if (!ok) ok = TRUE; else
     tblock->add_headers, tblock->remove_headers,
     US".", US"..",    /* Escaping strings */
     tblock->rewrite_rules, tblock->rewrite_existflags);
+#endif
 
   /* transport_write_message() uses write() because it is called from other
   places to write to non-sockets. This means that under some OS (e.g. Solaris)
@@ -1689,6 +1715,7 @@ if (!ok) ok = TRUE; else
           continue;
           }
         completed_address = TRUE;   /* NOW we can set this flag */
+        conf = string_sprintf("LMTP Successful delivery:%s", string_printing(buffer));
         }
 
       /* SMTP, or success return from LMTP for this address. Pass back the
@@ -2219,6 +2246,15 @@ if (hostlist == NULL || (ob->hosts_override && ob->hosts != NULL))
 
     host_build_hostlist(&hostlist, s, ob->hosts_randomize);
 
+    /* Check that the expansion yielded something useful. */
+    if (hostlist == NULL)
+      {
+      addrlist->message =
+        string_sprintf("%s transport has empty hosts setting", tblock->name);
+      addrlist->transport_return = PANIC;
+      return FALSE;   /* Only top address has status */
+      }
+
     /* If there was no expansion of hosts, save the host list for
     next time. */