SNI for ${readsocket }
authorJeremy Harris <jgh146exb@wizmail.org>
Mon, 13 Mar 2023 00:43:01 +0000 (00:43 +0000)
committerJeremy Harris <jgh146exb@wizmail.org>
Mon, 13 Mar 2023 15:41:09 +0000 (15:41 +0000)
doc/doc-docbook/spec.xfpt
doc/doc-txt/NewStuff
src/src/functions.h
src/src/lookups/readsock.c
src/src/tls.c
test/confs/1149
test/log/1149
test/scripts/1100-Basic-TLS/1149
test/stdout/1149

index 0ba62ce5e471c846d0f19409a9c79b3859e9f636..bdc0eb30eed9ddf6301736720acbfb913b289373 100644 (file)
@@ -10495,6 +10495,11 @@ Defines whether or not a write-shutdown is done on the connection after
 sending the request. Values are &"yes"& (the default) or &"no"&
 (preferred, eg. by some webservers).
 
+.next
+&*sni*&
+Controls the use of Server Name Identification on the connection.
+Any nonempty value will be the SNI sent; TLS will be forced.
+
 .next
 &*tls*&
 Controls the use of TLS on the connection.
index d12246e03a90fb6e796339626372145172f4eb3c..84db8ea589bf5bf94d588cf3d57471adc31729b0 100644 (file)
@@ -29,6 +29,8 @@ Version 4.97
 
  10. A commandline option to print just the message IDs of the queue
 
+ 11. An option for the ${readsocket } expansion to set an SNI for TLS.
+
 Version 4.96
 ------------
 
index 5fbb426eca7517ca2fc91e9dc3707ea05b533301..896122a69386f6264744ea33f09a6c9141882d1c 100644 (file)
@@ -54,6 +54,8 @@ extern uschar * tls_cert_fprt_sha256(void *);
 extern void    tls_clean_env(void);
 extern BOOL    tls_client_start(client_conn_ctx *, smtp_connect_args *,
                  void *, tls_support *, uschar **);
+extern BOOL    tls_client_adjunct_start(host_item *, client_conn_ctx *,
+                 const uschar *, uschar **);
 extern void    tls_client_creds_reload(BOOL);
 
 extern void    tls_close(void *, int);
index b1ea42c7f234a504426360c067f2cee0334c1781..a3f87108a1cf31bfcada38b5a04fd31b06ae1b3a 100644 (file)
@@ -13,7 +13,7 @@
 
 static int
 internal_readsock_open(client_conn_ctx * cctx, const uschar * sspec,
-  int timeout, BOOL do_tls, uschar ** errmsg)
+  int timeout, uschar * do_tls, uschar ** errmsg)
 {
 const uschar * server_name;
 host_item host;
@@ -116,27 +116,8 @@ else
 
 #ifndef DISABLE_TLS
 if (do_tls)
-  {
-  union sockaddr_46 interface_sock;
-  EXIM_SOCKLEN_T size = sizeof(interface_sock);
-  smtp_connect_args conn_args = {.host = &host };
-  tls_support tls_dummy = { .sni = NULL };
-  uschar * errstr;
-
-  if (getsockname(cctx->sock, (struct sockaddr *) &interface_sock, &size) == 0)
-    conn_args.sending_ip_address = host_ntoa(-1, &interface_sock, NULL, NULL);
-  else
-    {
-    *errmsg = string_sprintf("getsockname failed: %s", strerror(errno));
+  if (!tls_client_adjunct_start(&host, cctx, do_tls, errmsg))
     goto bad;
-    }
-
-  if (!tls_client_start(cctx, &conn_args, NULL, &tls_dummy, &errstr))
-    {
-    *errmsg = string_sprintf("TLS connect failed: %s", errstr);
-    goto bad;
-    }
-  }
 #endif
 
 DEBUG(D_expand|D_lookup) debug_printf_indent("  connected to socket %s\n", sspec);
@@ -187,8 +168,8 @@ client_conn_ctx * cctx = handle;
 int sep = ',';
 struct {
        BOOL do_shutdown:1;
-       BOOL do_tls:1;
        BOOL cache:1;
+       uschar * do_tls;        /* NULL, empty-string, or SNI */
 } lf = {.do_shutdown = TRUE};
 uschar * eol = NULL;
 int timeout = 5;
@@ -207,8 +188,10 @@ if (opts) for (uschar * s; s = string_nextinlist(&opts, &sep, NULL, 0); )
   else if (Ustrncmp(s, "shutdown=", 9) == 0)
     lf.do_shutdown = Ustrcmp(s + 9, "no") != 0;
 #ifndef DISABLE_TLS
-  else if (Ustrncmp(s, "tls=", 4) == 0 && Ustrcmp(s + 4, US"no") != 0)
-    lf.do_tls = TRUE;
+  else if (Ustrncmp(s, "tls=", 4) == 0 && Ustrcmp(s + 4, US"no") != 0 && !lf.do_tls)
+    lf.do_tls = US"";
+  else if (Ustrncmp(s, "sni=", 4) == 0)
+    lf.do_tls = s + 4;
 #endif
   else if (Ustrncmp(s, "eol=", 4) == 0)
     eol = string_unprinting(s + 4);
index ba7c2de38c318f5a2a203c6727c7b0b487df253c..825313a9a25de7f25792fab31deb8ecabda96941 100644 (file)
@@ -852,6 +852,57 @@ DEBUG(D_tls) debug_printf("TLS: resume session index %s\n", tlsp->resume_index);
 #endif
 }
 
+
+
+/* Start TLS as a client for an ajunct connection, eg. readsocket
+Return boolean success.
+*/
+
+BOOL
+tls_client_adjunct_start(host_item * host, client_conn_ctx * cctx,
+  const uschar * sni, uschar ** errmsg)
+{
+union sockaddr_46 interface_sock;
+EXIM_SOCKLEN_T size = sizeof(interface_sock);
+smtp_connect_args conn_args = {.host = host };
+tls_support tls_dummy = { .sni = NULL };
+uschar * errstr;
+
+if (getsockname(cctx->sock, (struct sockaddr *) &interface_sock, &size) == 0)
+  conn_args.sending_ip_address = host_ntoa(-1, &interface_sock, NULL, NULL);
+else
+  {
+  *errmsg = string_sprintf("getsockname failed: %s", strerror(errno));
+  return FALSE;
+  }
+
+/* To handle SNI we need to emulate more of a real transport because the
+base tls code assumes that is where the SNI string lives. */
+
+if (*sni)
+  {
+  transport_instance * tb;
+  smtp_transport_options_block * ob;
+
+  conn_args.tblock = tb = store_get(sizeof(*tb), GET_UNTAINTED);
+  memset(tb, 0, sizeof(*tb));
+
+  tb->options_block = ob = store_get(sizeof(*ob), GET_UNTAINTED);
+  memcpy(ob, &smtp_transport_option_defaults, sizeof(*ob));
+
+  ob->tls_sni = sni;
+  }
+
+if (!tls_client_start(cctx, &conn_args, NULL, &tls_dummy, &errstr))
+  {
+  *errmsg = string_sprintf("TLS connect failed: %s", errstr);
+  return FALSE;
+  }
+return TRUE;
+}
+
+
+
 #endif /*!DISABLE_TLS*/
 #endif /*!MACRO_PREDEF*/
 
index 7377531095d98a04975a53f33375db88d92becb0..dfe5b33cbf9890f7ec51e293f033741ac103ed96 100644 (file)
@@ -13,4 +13,6 @@ tls_advertise_hosts = *
 tls_certificate = DIR/aux-fixed/cert1
 tls_privatekey = DIR/aux-fixed/cert1
 
+acl_smtp_helo = accept logwrite = HELO <$sender_helo_name> SNI <$tls_in_sni>
+
 # End
index bc6ac7f77df8121f4272115800ad08a700054441..efcef1b23a625a3f72fb2e52f9e1c010b8ef2352 100644 (file)
@@ -1,3 +1,4 @@
 
 ******** SERVER ********
 1999-03-02 09:44:33 exim x.yz daemon started: pid=p1234, no queue runs, listening for SMTPS on port PORT_D
+1999-03-02 09:44:33 HELO <tester> SNI <fubar>
index 501a9c9da3db3dbcaaa4c73638737ac13428dff2..29702b049bceff19ff9af35c0c69042abb1c7c81 100644 (file)
@@ -8,6 +8,7 @@ exim -DSERVER=server -tls-on-connect -bd -oX PORT_D
 millisleep 500
 exim -be
 1 >>${readsocket{inet:thisloop:PORT_D}{QUIT\n}{2s:tls=yes}}<<
+2 >>${readsocket{inet:thisloop:PORT_D}{EHLO tester\n}{1s:tls=yes:sni=fubar}}<<
 ****
 millisleep 500
 #
index a3eab5117ac4a69ddce1e3691d8532aad1e5dddd..c67e31cfe3f2e551a653af331ded74fb85b5feff 100644 (file)
@@ -1,4 +1,5 @@
 > 1 >>220 myhost.test.ex ESMTP Exim x.yz Tue, 2 Mar 1999 09:44:33 +0000\r
 221 myhost.test.ex closing connection\r
 <<
+> Failed: socket read timed out
 >