[exim-dev] TLS on connect for remote_smtp transport [PATCH]

Startseite
Nachricht löschen
Nachricht beantworten
Autor: Arnold Metselaar
Datum:  
To: exim-dev
Betreff: [exim-dev] TLS on connect for remote_smtp transport [PATCH]
Hi all,

Currently exim supports tls_on_connect for incoming connections, but
not for outgoing e-mail. Some mail servers, such as gmail require
tls_on_connect.

The patch attached adds an option "tls_on_connect" of type boolean
to the remote_smtp transport with default false. If the option is
set to true TLS negotiation is started before waiting for the
initial OK reply, and issuing STARTTLS later and retrying in clear
text are both suppressed.

I have tested these changes with debian exim4 4.69-11, and I have
verified that this patch leaves exim in a compilable state.

Can someone please review my patch?
Should I also contribute patches for the documentation?
Is this the right way to contribute patches to exim?

Kind regards,
Arnold Metselaar

Index: src/transports/smtp.c
===================================================================
RCS file: /repo/exim/exim-src/src/transports/smtp.c,v
retrieving revision 1.42
diff -u -p -r1.42 smtp.c
--- src/transports/smtp.c    10 Jun 2009 07:34:05 -0000    1.42
+++ src/transports/smtp.c    22 Aug 2009 10:56:14 -0000
@@ -128,6 +128,8 @@ optionlist smtp_transport_options[] = {
       (void *)offsetof(smtp_transport_options_block, tls_certificate) },
   { "tls_crl",              opt_stringptr,
       (void *)offsetof(smtp_transport_options_block, tls_crl) },
+  { "tls_on_connect",       opt_bool,
+      (void *)offsetof(smtp_transport_options_block, tls_on_connect) },
   { "tls_privatekey",       opt_stringptr,
       (void *)offsetof(smtp_transport_options_block, tls_privatekey) },
   { "tls_require_ciphers",   opt_stringptr,
@@ -185,7 +187,8 @@ smtp_transport_options_block smtp_transp
   FALSE,               /* lmtp_ignore_quota */
   TRUE                 /* retry_include_ip_address */
 #ifdef SUPPORT_TLS
- ,NULL,                /* tls_certificate */
+  ,FALSE,              /* tls_on_connect */
+  NULL,                /* tls_certificate */
   NULL,                /* tls_crl */
   NULL,                /* tls_privatekey */
   NULL,                /* tls_require_ciphers */
@@ -931,7 +934,50 @@ if (continue_hostname == NULL)
       NULL, DEFER, FALSE);
     return DEFER;
     }
+    
+#ifdef SUPPORT_TLS 
+  /* If the remote host expects tls on connect we start tls directly and skip to REDO_EHLO. */
+  if (ob->tls_on_connect)
+    {
+    int rc = tls_client_start(inblock.sock,
+      host,
+      addrlist,
+      NULL,                    /* No DH param */
+      ob->tls_certificate,
+      ob->tls_privatekey,
+      ob->tls_verify_certificates,
+      ob->tls_crl,
+      ob->tls_require_ciphers,
+      ob->gnutls_require_mac,
+      ob->gnutls_require_kx,
+      ob->gnutls_require_proto,
+      ob->command_timeout);


+    /* 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
+    it for this host. */
+
+    if (rc != OK)
+      {
+      save_errno = ERRNO_TLSFAILURE;
+      message = US"failure while setting up TLS session on connect";
+      send_quit = FALSE;
+      goto TLS_FAILED;
+      }
+
+    /* TLS session is set up. */
+
+    for (addr = addrlist; addr != NULL; addr = addr->next)
+      {
+      if (addr->transport_return == PENDING_DEFER)
+        {
+        addr->cipher = tls_cipher;
+        addr->peerdn = tls_peerdn;
+        }
+      }
+    }
+
+#endif
   /* Expand the greeting message while waiting for the initial response. (Makes
   sense if helo_data contains ${lookup dnsdb ...} stuff). The expansion is
   delayed till here so that $sending_interface and $sending_port are set. */
@@ -1031,7 +1077,7 @@ goto SEND_QUIT;
   /* Set tls_offered if the response to EHLO specifies support for STARTTLS. */


   #ifdef SUPPORT_TLS
-  tls_offered = esmtp &&
+  tls_offered = esmtp && !ob->tls_on_connect &&
     pcre_exec(regex_STARTTLS, NULL, CS buffer, Ustrlen(buffer), 0,
       PCRE_EOPT, NULL, 0) >= 0;
   #endif
@@ -1133,7 +1179,7 @@ another process, and so we won't have ex
 expand it here. $sending_ip_address and $sending_port are set up right at the
 start of the Exim process (in exim.c). */


-if (tls_active >= 0)
+if ( (tls_active >= 0) && (!ob->tls_on_connect) )
   {
   if (helo_data == NULL)
     {
@@ -2758,7 +2804,7 @@ for (cutoff_retry = 0; expired &&


       #ifdef SUPPORT_TLS
       if (rc == DEFER && first_addr->basic_errno == ERRNO_TLSFAILURE &&
-           ob->tls_tempfail_tryclear &&
+           ob->tls_tempfail_tryclear && !ob->tls_on_connect &&
            verify_check_this_host(&(ob->hosts_require_tls), NULL, host->name,
              host->address, NULL) != OK)
         {
Index: src/transports/smtp.h
===================================================================
RCS file: /repo/exim/exim-src/src/transports/smtp.h,v
retrieving revision 1.15
diff -u -p -r1.15 smtp.h
--- src/transports/smtp.h    10 Jun 2009 07:34:05 -0000    1.15
+++ src/transports/smtp.h    22 Aug 2009 10:56:14 -0000
@@ -47,6 +47,7 @@ typedef struct {
   BOOL    lmtp_ignore_quota;
   BOOL    retry_include_ip_address;
   #ifdef SUPPORT_TLS
+  BOOL    tls_on_connect;
   uschar *tls_certificate;
   uschar *tls_crl;
   uschar *tls_privatekey;