SPDX: license tags (mostly by guesswork)
[exim.git] / src / src / tls.c
index c497ac307c1782c4155cd6135ea219331bea6e75..9e20b5bca977fae7525b13e6c93bc973f426fd8c 100644 (file)
@@ -2,9 +2,10 @@
 *     Exim - an Internet mail transport agent    *
 *************************************************/
 
+/* Copyright (c) The Exim Maintainers 2020 - 2022 */
 /* Copyright (c) University of Cambridge 1995 - 2018 */
-/* Copyright (c) The Exim Maintainers 2020 */
 /* See the file NOTICE for conditions of use and distribution. */
+/* SPDX-License-Identifier: GPL-2.0-only */
 
 /* This module provides TLS (aka SSL) support for Exim. The code for OpenSSL is
 based on a patch that was originally contributed by Steve Haslam. It was
@@ -25,6 +26,11 @@ functions from the OpenSSL or GNU TLS libraries. */
 #endif
 
 
+/* Forward decl. */
+static void tls_client_resmption_key(tls_support *, smtp_connect_args *,
+  smtp_transport_options_block *);
+
+
 #if defined(MACRO_PREDEF) && !defined(DISABLE_TLS)
 # include "macro_predef.h"
 # ifdef USE_GNUTLS
@@ -138,15 +144,29 @@ static BOOL
 tls_set_one_watch(const uschar * filename)
 # ifdef EXIM_HAVE_INOTIFY
 {
+uschar buf[PATH_MAX];
+ssize_t len;
 uschar * s;
 
 if (Ustrcmp(filename, "system,cache") == 0) return TRUE;
-
 if (!(s = Ustrrchr(filename, '/'))) return FALSE;
+
+for (unsigned loop = 20;
+     (len = readlink(CCS filename, CS buf, sizeof(buf))) >= 0; )
+  {                                            /* a symlink */
+  if (--loop == 0) { errno = ELOOP; return FALSE; }
+  filename = buf[0] == '/'
+    ? string_copyn(buf, (unsigned)len) /* mem released by tls_set_watch */
+    : string_sprintf("%.*s/%.*s", (int)(s - filename), filename, (int)len, buf);
+  s = Ustrrchr(filename, '/');
+  }
+if (errno != EINVAL)
+  return FALSE;                                        /* other error */
+
+/* not a symlink */
 s = string_copyn(filename, s - filename);      /* mem released by tls_set_watch */
-DEBUG(D_tls) debug_printf("watch dir '%s'\n", s);
 
-/*XXX unclear what effect symlinked files will have for inotify */
+DEBUG(D_tls) debug_printf("watch dir '%s'\n", s);
 
 if (inotify_add_watch(tls_watch_fd, CCS s,
       IN_ONESHOT | IN_CLOSE_WRITE | IN_DELETE | IN_DELETE_SELF
@@ -185,8 +205,8 @@ for (;;)
     {
     if ((fd1 = open(CCS filename, O_RDONLY | O_NOFOLLOW)) < 0)
       { s = US"open file"; goto bad; }
-    DEBUG(D_tls) debug_printf("watch file '%s'\n", filename);
-    EV_SET(&kev[++kev_used],
+    DEBUG(D_tls) debug_printf("watch file '%s':\t%d\n", filename, fd1);
+    EV_SET(&kev[kev_used++],
        (uintptr_t)fd1,
        EVFILT_VNODE,
        EV_ADD | EV_ENABLE | EV_ONESHOT,
@@ -196,8 +216,8 @@ for (;;)
        NULL);
     cnt++;
     }
-  DEBUG(D_tls) debug_printf("watch dir  '%s'\n", s);
-  EV_SET(&kev[++kev_used],
+  DEBUG(D_tls) debug_printf("watch dir  '%s':\t%d\n", s, fd2);
+  EV_SET(&kev[kev_used++],
        (uintptr_t)fd2,
        EVFILT_VNODE,
        EV_ADD | EV_ENABLE | EV_ONESHOT,
@@ -209,7 +229,7 @@ for (;;)
 
   if (!(S_ISLNK(sb.st_mode))) break;
 
-  t = store_get(1024, FALSE);
+  t = store_get(1024, GET_UNTAINTED);
   Ustrncpy(t, s, 1022);
   j = Ustrlen(s);
   t[j++] = '/';
@@ -320,6 +340,7 @@ if (tls_watch_fd < 0) return;
 /* Close the files we had open for kevent */
 for (int i = 0; i < kev_used; i++)
   {
+  DEBUG(D_tls) debug_printf("closing watch fd: %d\n", (int) kev[i].ident);
   (void) close((int) kev[i].ident);
   kev[i].ident = (uintptr_t)-1;
   }
@@ -341,6 +362,8 @@ tls_watch_invalidate();
 #endif
 
 tls_server_creds_invalidate();
+
+/* _expire is for a time-limited selfsign server cert */
 tls_creds_expire = (lifetime = tls_server_creds_init())
   ? time(NULL) + lifetime : 0;
 
@@ -790,6 +813,45 @@ return status == 0;
 
 
 
+static void
+tls_client_resmption_key(tls_support * tlsp, smtp_connect_args * conn_args,
+  smtp_transport_options_block * ob)
+{
+#ifndef DISABLE_TLS_RESUME
+hctx * h = &tlsp->resume_hctx;
+blob b;
+gstring * g;
+
+DEBUG(D_tls) if (conn_args->host_lbserver)
+  debug_printf("TLS: lbserver '%s'\n", conn_args->host_lbserver);
+
+# ifdef EXIM_HAVE_SHA2
+exim_sha_init(h, HASH_SHA2_256);
+# else
+exim_sha_init(h, HASH_SHA1);
+# endif
+exim_sha_update_string(h, conn_args->host_lbserver);
+# ifdef SUPPORT_DANE
+if (conn_args->dane)
+  exim_sha_update(h,  CUS &conn_args->tlsa_dnsa, sizeof(dns_answer));
+# endif
+exim_sha_update_string(h, conn_args->host->address);
+exim_sha_update(h,   CUS &conn_args->host->port, sizeof(conn_args->host->port));
+exim_sha_update_string(h, conn_args->sending_ip_address);
+exim_sha_update_string(h, openssl_options);
+exim_sha_update_string(h, ob->tls_require_ciphers);
+exim_sha_update_string(h, tlsp->sni);
+# ifdef EXIM_HAVE_ALPN
+exim_sha_update_string(h, ob->tls_alpn);
+# endif
+exim_sha_finish(h, &b);
+for (g = string_get(b.len*2+1); b.len-- > 0; )
+  g = string_fmt_append(g, "%02x", *b.data++);
+tlsp->resume_index = string_from_gstring(g);
+DEBUG(D_tls) debug_printf("TLS: resume session index %s\n", tlsp->resume_index);
+#endif
+}
+
 #endif /*!DISABLE_TLS*/
 #endif /*!MACRO_PREDEF*/