[Buzilla 376] Preliminary DKIM support
[exim.git] / src / src / transports / smtp.c
index 509ff1949d589d575814cd0275a49e24d7eb0664..3c09c91816aa6e9aa26d8f4f6989850068dd42d5 100644 (file)
@@ -1,4 +1,4 @@
-/* $Cambridge: exim/src/src/transports/smtp.c,v 1.35 2007/02/06 14:49:13 ph10 Exp $ */
+/* $Cambridge: exim/src/src/transports/smtp.c,v 1.38 2007/09/28 12:21:57 tom Exp $ */
 
 /*************************************************
 *     Exim - an Internet mail transport agent    *
@@ -52,6 +52,20 @@ optionlist smtp_transport_options[] = {
       (void *)offsetof(smtp_transport_options_block, dk_selector) },
   { "dk_strict", opt_stringptr,
       (void *)offsetof(smtp_transport_options_block, dk_strict) },
+#endif
+#ifdef EXPERIMENTAL_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) },
@@ -203,6 +217,14 @@ smtp_transport_options_block smtp_transport_option_defaults = {
   NULL,                /* dk_selector */
   NULL                 /* dk_strict */
   #endif
+  #ifdef EXPERIMENTAL_DKIM
+ ,NULL,                /* dkim_canon */
+  NULL,                /* dkim_domain */
+  NULL,                /* dkim_private_key */
+  NULL,                /* dkim_selector */
+  NULL,                /* dkim_sign_headers */
+  NULL                 /* dkim_strict */
+  #endif
 };
 
 
@@ -789,7 +811,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.
@@ -886,6 +909,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.
@@ -917,7 +945,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,
@@ -1041,6 +1070,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
@@ -1231,14 +1261,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 */
 
@@ -1570,6 +1611,23 @@ if (!ok) ok = TRUE; else
       ob->dk_private_key, ob->dk_domain, ob->dk_selector,
       ob->dk_canon, ob->dk_headers, ob->dk_strict);
   else
+#endif
+#ifdef EXPERIMENTAL_DKIM
+  if ( (ob->dkim_private_key != NULL) && (ob->dkim_domain != NULL) && (ob->dkim_selector != NULL) )
+    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
 #endif
   ok = transport_write_message(addrlist, inblock.sock,
     topt_use_crlf | topt_end_dot | topt_escape_headers |