X-Git-Url: https://git.exim.org/exim.git/blobdiff_plain/ef57b25bfa7623c3f8a8e65f927165c4ddc7c43b..HEAD:/src/src/tls.c diff --git a/src/src/tls.c b/src/src/tls.c index 76e72b5f5..a1ae1abd1 100644 --- a/src/src/tls.c +++ b/src/src/tls.c @@ -2,9 +2,10 @@ * Exim - an Internet mail transport agent * *************************************************/ -/* Copyright (c) The Exim Maintainers 2020 - 2022 */ +/* Copyright (c) The Exim Maintainers 2020 - 2024 */ /* Copyright (c) University of Cambridge 1995 - 2018 */ /* See the file NOTICE for conditions of use and distribution. */ +/* SPDX-License-Identifier: GPL-2.0-or-later */ /* 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,11 +26,6 @@ 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 @@ -44,13 +40,16 @@ static void tls_client_resmption_key(tls_support *, smtp_connect_args *, static void tls_per_lib_daemon_init(void); static void tls_per_lib_daemon_tick(void); static unsigned tls_server_creds_init(void); -static void tls_server_creds_invalidate(void); static void tls_client_creds_init(transport_instance *, BOOL); -static void tls_client_creds_invalidate(transport_instance *); static void tls_daemon_creds_reload(void); static BOOL opt_set_and_noexpand(const uschar *); static BOOL opt_unset_or_noexpand(const uschar *); +#if defined(EXIM_HAVE_INOTIFY) || defined(EXIM_HAVE_KEVENT) +static void tls_server_creds_invalidate(void); +static void tls_client_creds_invalidate(transport_instance *); +#endif + /* This module is compiled only when it is specifically requested in the @@ -105,10 +104,14 @@ Returns: TRUE if OK; result may still be NULL after forced failure */ static BOOL -expand_check(const uschar *s, const uschar *name, uschar **result, uschar ** errstr) +expand_check(const uschar * s, const uschar * name, + uschar ** result, uschar ** errstr) { if (!s) + { + f.expand_string_forcedfail = FALSE; *result = NULL; + } else if ( !(*result = expand_string(US s)) /* need to clean up const more */ && !f.expand_string_forcedfail ) @@ -156,7 +159,7 @@ for (unsigned loop = 20; 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), (int)len); + : string_sprintf("%.*s/%.*s", (int)(s - filename), filename, (int)len, buf); s = Ustrrchr(filename, '/'); } if (errno != EINVAL) @@ -324,7 +327,9 @@ tls_client_creds_reload(BOOL watch) for(transport_instance * t = transports; t; t = t->next) if (Ustrcmp(t->driver_name, "smtp") == 0) { +#if defined(EXIM_HAVE_INOTIFY) || defined(EXIM_HAVE_KEVENT) tls_client_creds_invalidate(t); +#endif tls_client_creds_init(t, watch); } } @@ -360,7 +365,11 @@ unsigned lifetime; tls_watch_invalidate(); #endif +#if defined(EXIM_HAVE_INOTIFY) || defined(EXIM_HAVE_KEVENT) tls_server_creds_invalidate(); +#endif + +/* _expire is for a time-limited selfsign server cert */ tls_creds_expire = (lifetime = tls_server_creds_init()) ? time(NULL) + lifetime : 0; @@ -455,6 +464,10 @@ tzset(); /************************************************* * Many functions are package-specific * *************************************************/ +/* Forward decl. */ +static void tls_client_resmption_key(tls_support *, smtp_connect_args *, + smtp_transport_options_block *); + #ifdef USE_GNUTLS # include "tls-gnu.c" @@ -667,21 +680,24 @@ Returns: BOOL tls_is_name_for_cert(const uschar * namelist, void * cert) { -uschar * altnames = tls_cert_subject_altname(cert, US"dns"); -uschar * subjdn; -uschar * certname; +uschar * altnames, * subjdn, * certname, * cmpname; int cmp_sep = 0; -uschar * cmpname; if ((altnames = tls_cert_subject_altname(cert, US"dns"))) { int alt_sep = '\n'; + DEBUG(D_tls|D_lookup) debug_printf_indent("cert has SAN\n"); while ((cmpname = string_nextinlist(&namelist, &cmp_sep, NULL, 0))) { const uschar * an = altnames; + DEBUG(D_tls|D_lookup) debug_printf_indent(" %s in SANs?", cmpname); while ((certname = string_nextinlist(&an, &alt_sep, NULL, 0))) if (is_name_match(cmpname, certname)) + { + DEBUG(D_tls|D_lookup) debug_printf_indent(" yes (matched %s)\n", certname); return TRUE; + } + DEBUG(D_tls|D_lookup) debug_printf_indent(" no (end of SAN list)\n"); } } @@ -693,13 +709,18 @@ else if ((subjdn = tls_cert_subject(cert, NULL))) while ((cmpname = string_nextinlist(&namelist, &cmp_sep, NULL, 0))) { const uschar * sn = subjdn; + DEBUG(D_tls|D_lookup) debug_printf_indent(" %s in SN?", cmpname); while ((certname = string_nextinlist(&sn, &sn_sep, NULL, 0))) if ( *certname++ == 'C' && *certname++ == 'N' && *certname++ == '=' && is_name_match(cmpname, certname) ) + { + DEBUG(D_tls|D_lookup) debug_printf_indent(" yes (matched %s)\n", certname); return TRUE; + } + DEBUG(D_tls|D_lookup) debug_printf_indent(" no (end of CN)\n"); } } return FALSE; @@ -849,6 +870,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*/