diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/src/exipick.src | 6 | ||||
-rw-r--r-- | src/src/functions.h | 2 | ||||
-rw-r--r-- | src/src/globals.c | 3 | ||||
-rw-r--r-- | src/src/local_scan.h | 2 | ||||
-rw-r--r-- | src/src/macros.h | 3 | ||||
-rw-r--r-- | src/src/receive.c | 5 | ||||
-rw-r--r-- | src/src/smtp_in.c | 5 | ||||
-rw-r--r-- | src/src/string.c | 2 | ||||
-rw-r--r-- | src/src/tls-gnu.c | 6 | ||||
-rw-r--r-- | src/src/tls-openssl.c | 37 | ||||
-rw-r--r-- | src/src/transports/smtp.c | 10 | ||||
-rw-r--r-- | src/src/transports/smtp.h | 1 |
12 files changed, 66 insertions, 16 deletions
diff --git a/src/src/exipick.src b/src/src/exipick.src index 811092dc1..ed3b66154 100644 --- a/src/src/exipick.src +++ b/src/src/exipick.src @@ -955,6 +955,8 @@ sub _parse_header { $self->{_vars}{tls_cipher} = $arg; } elsif ($tag eq '-tls_peerdn') { $self->{_vars}{tls_peerdn} = $arg; + } elsif ($tag eq '-tls_sni') { + $self->{_vars}{tls_sni} = $arg; } elsif ($tag eq '-host_address') { $self->{_vars}{sender_host_port} = $self->_get_host_and_port(\$arg); $self->{_vars}{sender_host_address} = $arg; @@ -1793,6 +1795,10 @@ The cipher suite that was negotiated for encrypted SMTP connections. The value of the Distinguished Name of the certificate if Exim is configured to request one +=item S . $tls_sni + +The value of the Server Name Indication TLS extension sent by a client, if one was sent. + =item N + $warning_count The number of delay warnings which have been sent for this message. diff --git a/src/src/functions.h b/src/src/functions.h index f1af42ee5..220235235 100644 --- a/src/src/functions.h +++ b/src/src/functions.h @@ -23,7 +23,7 @@ extern uschar *init_perl(uschar *); #ifdef SUPPORT_TLS extern int tls_client_start(int, host_item *, address_item *, uschar *, uschar *, uschar *, uschar *, uschar *, uschar *, uschar *, - uschar *, uschar *, int); + uschar *, uschar *, uschar *, int); extern void tls_close(BOOL); extern int tls_feof(void); extern int tls_ferror(void); diff --git a/src/src/globals.c b/src/src/globals.c index 7985cd3f0..f11c7c2db 100644 --- a/src/src/globals.c +++ b/src/src/globals.c @@ -697,7 +697,7 @@ uschar *log_file_path = US LOG_FILE_PATH /* Those log options with L_xxx identifiers have values less than 0x800000 and are the ones that get put into log_write_selector. They can be used in calls to log_write() to test for the bit. The options with LX_xxx identifiers have -values greater than 0x80000000 and are put int log_extra_selector (without the +values greater than 0x80000000 and are put into log_extra_selector (without the top bit). They are never used in calls to log_write(), but are tested independently. This separation became necessary when the number of log selectors was getting close to filling a 32-bit word. */ @@ -746,6 +746,7 @@ bit_table log_options[] = { { US"tls_certificate_verified", LX_tls_certificate_verified }, { US"tls_cipher", LX_tls_cipher }, { US"tls_peerdn", LX_tls_peerdn }, + { US"tls_sni", LX_tls_sni }, { US"unknown_in_list", LX_unknown_in_list } }; diff --git a/src/src/local_scan.h b/src/src/local_scan.h index 25b194407..aedfc9f92 100644 --- a/src/src/local_scan.h +++ b/src/src/local_scan.h @@ -186,7 +186,7 @@ extern uschar *rfc2047_decode(uschar *, BOOL, uschar *, int, int *, uschar **); extern int smtp_fflush(void); extern void smtp_printf(const char *, ...) PRINTF_FUNCTION(1,2); extern void smtp_vprintf(const char *, va_list); -extern uschar *string_copy(uschar *); +extern uschar *string_copy(const uschar *); extern uschar *string_copyn(uschar *, int); extern uschar *string_sprintf(const char *, ...) PRINTF_FUNCTION(1,2); diff --git a/src/src/macros.h b/src/src/macros.h index c1c4cc33f..9b41226e5 100644 --- a/src/src/macros.h +++ b/src/src/macros.h @@ -407,7 +407,8 @@ set all the bits in a multi-word selector. */ #define LX_tls_certificate_verified 0x80100000 #define LX_tls_cipher 0x80200000 #define LX_tls_peerdn 0x80400000 -#define LX_unknown_in_list 0x80800000 +#define LX_tls_sni 0x80800000 +#define LX_unknown_in_list 0x81000000 #define L_default (L_connection_reject | \ L_delay_delivery | \ diff --git a/src/src/receive.c b/src/src/receive.c index 71052657c..aaaf64ce6 100644 --- a/src/src/receive.c +++ b/src/src/receive.c @@ -3488,6 +3488,11 @@ if ((log_extra_selector & LX_tls_certificate_verified) != 0 && if ((log_extra_selector & LX_tls_peerdn) != 0 && tls_peerdn != NULL) s = string_append(s, &size, &sptr, 3, US" DN=\"", string_printing(tls_peerdn), US"\""); +#ifndef USE_GNUTLS +if ((log_extra_selector & LX_tls_sni) != 0 && tls_sni != NULL) + s = string_append(s, &size, &sptr, 3, US" SNI=\"", + string_printing(tls_sni), US"\""); +#endif #endif if (sender_host_authenticated != NULL) diff --git a/src/src/smtp_in.c b/src/src/smtp_in.c index 23bc5315e..d1c10f00f 100644 --- a/src/src/smtp_in.c +++ b/src/src/smtp_in.c @@ -841,6 +841,11 @@ if ((log_extra_selector & LX_tls_certificate_verified) != 0 && if ((log_extra_selector & LX_tls_peerdn) != 0 && tls_peerdn != NULL) s = string_append(s, &size, &ptr, 3, US" DN=\"", string_printing(tls_peerdn), US"\""); +#ifndef USE_GNUTLS +if ((log_extra_selector & LX_tls_sni) != 0 && tls_sni != NULL) + s = string_append(s, &size, &ptr, 3, US" SNI=\"", + string_printing(tls_sni), US"\""); +#endif #endif sep = (smtp_connection_had[SMTP_HBUFF_SIZE-1] != SCH_NONE)? diff --git a/src/src/string.c b/src/src/string.c index 0a321ee1f..3fea7c048 100644 --- a/src/src/string.c +++ b/src/src/string.c @@ -415,7 +415,7 @@ Returns: copy of string in new store */ uschar * -string_copy(uschar *s) +string_copy(const uschar *s) { int len = Ustrlen(s) + 1; uschar *ss = store_get(len); diff --git a/src/src/tls-gnu.c b/src/src/tls-gnu.c index 2f952e47b..7e87dded0 100644 --- a/src/src/tls-gnu.c +++ b/src/src/tls-gnu.c @@ -1055,6 +1055,7 @@ Arguments: dhparam DH parameter file certificate certificate file privatekey private key file + sni TLS SNI to send to remote host verify_certs file for certificate verify verify_crl CRL for verify require_ciphers list of allowed ciphers or NULL @@ -1069,8 +1070,9 @@ Returns: OK/DEFER/FAIL (because using common functions), int tls_client_start(int fd, host_item *host, address_item *addr, uschar *dhparam, - uschar *certificate, uschar *privatekey, uschar *verify_certs, - uschar *verify_crl, uschar *require_ciphers, uschar *require_mac, + uschar *certificate, uschar *privatekey, uschar *sni ARG_UNUSED, + uschar *verify_certs, uschar *verify_crl, + uschar *require_ciphers, uschar *require_mac, uschar *require_kx, uschar *require_proto, int timeout) { const gnutls_datum *server_certs; diff --git a/src/src/tls-openssl.c b/src/src/tls-openssl.c index 8cc2457e5..e609670ee 100644 --- a/src/src/tls-openssl.c +++ b/src/src/tls-openssl.c @@ -385,15 +385,18 @@ tls_servername_cb(SSL *s, int *ad ARG_UNUSED, void *arg) const char *servername = SSL_get_servername(s, TLSEXT_NAMETYPE_host_name); const tls_ext_ctx_cb *cbinfo = (tls_ext_ctx_cb *) arg; int rc; +int old_pool = store_pool; if (!servername) return SSL_TLSEXT_ERR_OK; -DEBUG(D_tls) debug_printf("TLS SNI: %s%s\n", servername, +DEBUG(D_tls) debug_printf("Received TLS SNI \"%s\"%s\n", servername, reexpand_tls_files_for_sni ? "" : " (unused for certificate selection)"); /* Make the extension value available for expansion */ -tls_sni = servername; +store_pool = POOL_PERM; +tls_sni = string_copy(US servername); +store_pool = old_pool; if (!reexpand_tls_files_for_sni) return SSL_TLSEXT_ERR_OK; @@ -550,10 +553,13 @@ if (rc != OK) return rc; /* If we need to handle SNI, do so */ #if OPENSSL_VERSION_NUMBER >= 0x0090806fL && !defined(OPENSSL_NO_TLSEXT) -/* We always do this, so that $tls_sni is available even if not used in -tls_certificate */ -SSL_CTX_set_tlsext_servername_callback(ctx, tls_servername_cb); -SSL_CTX_set_tlsext_servername_arg(ctx, cbinfo); +if (host == NULL) + { + /* We always do this, so that $tls_sni is available even if not used in + tls_certificate */ + SSL_CTX_set_tlsext_servername_callback(ctx, tls_servername_cb); + SSL_CTX_set_tlsext_servername_arg(ctx, cbinfo); + } #endif /* Set up the RSA callback */ @@ -944,6 +950,7 @@ Argument: dhparam DH parameter file certificate certificate file privatekey private key file + sni TLS SNI to send to remote host verify_certs file for certificate verify crl file containing CRL require_ciphers list of allowed ciphers @@ -961,7 +968,8 @@ Returns: OK on success int tls_client_start(int fd, host_item *host, address_item *addr, uschar *dhparam, - uschar *certificate, uschar *privatekey, uschar *verify_certs, uschar *crl, + uschar *certificate, uschar *privatekey, uschar *sni, + uschar *verify_certs, uschar *crl, uschar *require_ciphers, uschar *require_mac, uschar *require_kx, uschar *require_proto, int timeout) { @@ -1000,6 +1008,19 @@ SSL_set_session_id_context(ssl, sid_ctx, Ustrlen(sid_ctx)); SSL_set_fd(ssl, fd); SSL_set_connect_state(ssl); +if (sni) + { + if (!expand_check(sni, US"tls_sni", &tls_sni)) + return FAIL; + if (!Ustrlen(tls_sni)) + tls_sni = NULL; + else + { + DEBUG(D_tls) debug_printf("Setting TLS SNI \"%s\"\n", tls_sni); + SSL_set_tlsext_host_name(ssl, tls_sni); + } + } + /* There doesn't seem to be a built-in timeout on connection. */ DEBUG(D_tls) debug_printf("Calling SSL_connect\n"); @@ -1078,8 +1099,10 @@ if (ssl_xfer_buffer_lwm >= ssl_xfer_buffer_hwm) SSL_free(ssl); ssl = NULL; tls_active = -1; + tls_bits = 0; tls_cipher = NULL; tls_peerdn = NULL; + tls_sni = NULL; return smtp_getc(); } diff --git a/src/src/transports/smtp.c b/src/src/transports/smtp.c index c571d874c..b1fedd2d4 100644 --- a/src/src/transports/smtp.c +++ b/src/src/transports/smtp.c @@ -128,8 +128,10 @@ optionlist smtp_transport_options[] = { (void *)offsetof(smtp_transport_options_block, tls_crl) }, { "tls_privatekey", opt_stringptr, (void *)offsetof(smtp_transport_options_block, tls_privatekey) }, - { "tls_require_ciphers", opt_stringptr, + { "tls_require_ciphers", opt_stringptr, (void *)offsetof(smtp_transport_options_block, tls_require_ciphers) }, + { "tls_sni", opt_stringptr, + (void *)offsetof(smtp_transport_options_block, tls_sni) }, { "tls_tempfail_tryclear", opt_bool, (void *)offsetof(smtp_transport_options_block, tls_tempfail_tryclear) }, { "tls_verify_certificates", opt_stringptr, @@ -191,7 +193,8 @@ smtp_transport_options_block smtp_transport_option_defaults = { NULL, /* gnutls_require_mac */ NULL, /* gnutls_require_proto */ NULL, /* tls_verify_certificates */ - TRUE /* tls_tempfail_tryclear */ + TRUE, /* tls_tempfail_tryclear */ + NULL /* tls_sni */ #endif #ifndef DISABLE_DKIM ,NULL, /* dkim_canon */ @@ -889,8 +892,10 @@ outblock.authenticating = FALSE; /* Reset the parameters of a TLS session. */ +tls_bits = 0; tls_cipher = NULL; tls_peerdn = NULL; +tls_sni = 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 @@ -1122,6 +1127,7 @@ if (tls_offered && !suppress_tls && NULL, /* No DH param */ ob->tls_certificate, ob->tls_privatekey, + ob->tls_sni, ob->tls_verify_certificates, ob->tls_crl, ob->tls_require_ciphers, diff --git a/src/src/transports/smtp.h b/src/src/transports/smtp.h index a2ea4ff0a..605be4800 100644 --- a/src/src/transports/smtp.h +++ b/src/src/transports/smtp.h @@ -54,6 +54,7 @@ typedef struct { uschar *gnutls_require_proto; uschar *tls_verify_certificates; BOOL tls_tempfail_tryclear; + uschar *tls_sni; #endif #ifndef DISABLE_DKIM uschar *dkim_domain; |