X-Git-Url: https://git.exim.org/exim.git/blobdiff_plain/fcc8e04755fd6f211fd636e6c077ac41963ab0b9..e51c7be22dfccad376659a1a46cee93c9979bbf7:/src/src/transports/smtp.c diff --git a/src/src/transports/smtp.c b/src/src/transports/smtp.c index 25cc5490a..c175d2ffe 100644 --- a/src/src/transports/smtp.c +++ b/src/src/transports/smtp.c @@ -2,7 +2,7 @@ * Exim - an Internet mail transport agent * *************************************************/ -/* Copyright (c) University of Cambridge 1995 - 2012 */ +/* Copyright (c) University of Cambridge 1995 - 2014 */ /* See the file NOTICE for conditions of use and distribution. */ #include "../exim.h" @@ -55,6 +55,10 @@ optionlist smtp_transport_options[] = { (void *)offsetof(smtp_transport_options_block, dns_qualify_single) }, { "dns_search_parents", opt_bool, (void *)offsetof(smtp_transport_options_block, dns_search_parents) }, + { "dnssec_request_domains", opt_stringptr, + (void *)offsetof(smtp_transport_options_block, dnssec_request_domains) }, + { "dnssec_require_domains", opt_stringptr, + (void *)offsetof(smtp_transport_options_block, dnssec_require_domains) }, { "dscp", opt_stringptr, (void *)offsetof(smtp_transport_options_block, dscp) }, { "fallback_hosts", opt_stringptr, @@ -98,6 +102,10 @@ optionlist smtp_transport_options[] = { (void *)offsetof(smtp_transport_options_block, hosts_override) }, { "hosts_randomize", opt_bool, (void *)offsetof(smtp_transport_options_block, hosts_randomize) }, +#if defined(SUPPORT_TLS) && defined(EXPERIMENTAL_OCSP) + { "hosts_request_ocsp", opt_stringptr, + (void *)offsetof(smtp_transport_options_block, hosts_request_ocsp) }, +#endif { "hosts_require_auth", opt_stringptr, (void *)offsetof(smtp_transport_options_block, hosts_require_auth) }, #ifdef SUPPORT_TLS @@ -110,7 +118,7 @@ optionlist smtp_transport_options[] = { #endif { "hosts_try_auth", opt_stringptr, (void *)offsetof(smtp_transport_options_block, hosts_try_auth) }, -#ifdef EXPERIMENTAL_PRDR +#ifndef DISABLE_PRDR { "hosts_try_prdr", opt_stringptr, (void *)offsetof(smtp_transport_options_block, hosts_try_prdr) }, #endif @@ -153,8 +161,20 @@ optionlist smtp_transport_options[] = { (void *)offsetof(smtp_transport_options_block, tls_sni) }, { "tls_tempfail_tryclear", opt_bool, (void *)offsetof(smtp_transport_options_block, tls_tempfail_tryclear) }, + { "tls_try_verify_hosts", opt_stringptr, + (void *)offsetof(smtp_transport_options_block, tls_try_verify_hosts) }, +#ifdef EXPERIMENTAL_CERTNAMES + { "tls_verify_cert_hostnames", opt_stringptr, + (void *)offsetof(smtp_transport_options_block,tls_verify_cert_hostnames)}, +#endif { "tls_verify_certificates", opt_stringptr, - (void *)offsetof(smtp_transport_options_block, tls_verify_certificates) } + (void *)offsetof(smtp_transport_options_block, tls_verify_certificates) }, + { "tls_verify_hosts", opt_stringptr, + (void *)offsetof(smtp_transport_options_block, tls_verify_hosts) } +#endif +#ifdef EXPERIMENTAL_TPDA + ,{ "tpda_host_defer_action", opt_stringptr, + (void *)offsetof(smtp_transport_options_block, tpda_host_defer_action) }, #endif }; @@ -180,10 +200,11 @@ smtp_transport_options_block smtp_transport_option_defaults = { NULL, /* serialize_hosts */ NULL, /* hosts_try_auth */ NULL, /* hosts_require_auth */ -#ifdef EXPERIMENTAL_PRDR +#ifndef DISABLE_PRDR NULL, /* hosts_try_prdr */ #endif #ifdef EXPERIMENTAL_OCSP + US"*", /* hosts_request_ocsp */ NULL, /* hosts_require_ocsp */ #endif NULL, /* hosts_require_tls */ @@ -205,6 +226,8 @@ smtp_transport_options_block smtp_transport_option_defaults = { FALSE, /* gethostbyname */ TRUE, /* dns_qualify_single */ FALSE, /* dns_search_parents */ + NULL, /* dnssec_request_domains */ + NULL, /* dnssec_require_domains */ TRUE, /* delay_after_cutoff */ FALSE, /* hosts_override */ FALSE, /* hosts_randomize */ @@ -223,7 +246,12 @@ smtp_transport_options_block smtp_transport_option_defaults = { NULL, /* tls_verify_certificates */ EXIM_CLIENT_DH_DEFAULT_MIN_BITS, /* tls_dh_min_bits */ - TRUE /* tls_tempfail_tryclear */ + TRUE, /* tls_tempfail_tryclear */ + NULL, /* tls_verify_hosts */ + NULL /* tls_try_verify_hosts */ +# ifdef EXPERIMENTAL_CERTNAMES + ,NULL /* tls_verify_cert_hostnames */ +# endif #endif #ifndef DISABLE_DKIM ,NULL, /* dkim_canon */ @@ -233,6 +261,9 @@ smtp_transport_options_block smtp_transport_option_defaults = { NULL, /* dkim_sign_headers */ NULL /* dkim_strict */ #endif +#ifdef EXPERIMENTAL_TPDA + ,NULL /* tpda_host_defer_action */ +#endif }; @@ -577,6 +608,59 @@ else +#ifdef EXPERIMENTAL_TPDA +/************************************************* +* Post-defer action * +*************************************************/ + +/* This expands an arbitrary per-transport string. + It might, for example, be used to write to the database log. + +Arguments: + ob transport options block + addr the address item containing error information + host the current host + +Returns: nothing +*/ + +static void +tpda_deferred(smtp_transport_options_block *ob, address_item *addr, host_item *host) +{ +uschar *action = ob->tpda_host_defer_action; +if (!action) + return; + +tpda_delivery_ip = string_copy(host->address); +tpda_delivery_port = (host->port == PORT_NONE)? 25 : host->port; +tpda_delivery_fqdn = string_copy(host->name); +tpda_delivery_local_part = string_copy(addr->local_part); +tpda_delivery_domain = string_copy(addr->domain); +tpda_defer_errno = addr->basic_errno; + +tpda_defer_errstr = addr->message + ? addr->basic_errno > 0 + ? string_sprintf("%s: %s", addr->message, strerror(addr->basic_errno)) + : string_copy(addr->message) + : addr->basic_errno > 0 + ? string_copy(US strerror(addr->basic_errno)) + : NULL; + +DEBUG(D_transport) + debug_printf(" TPDA(host defer): tpda_host_defer_action=|%s| tpda_delivery_IP=%s\n", + action, tpda_delivery_ip); + +router_name = addr->router->name; +transport_name = addr->transport->name; +if (!expand_string(action) && *expand_string_message) + log_write(0, LOG_MAIN|LOG_PANIC, "failed to expand tpda_defer_action in %s: %s\n", + transport_name, expand_string_message); +router_name = transport_name = NULL; +} +#endif + + + /************************************************* * Synchronize SMTP responses * *************************************************/ @@ -976,7 +1060,7 @@ smtp_auth(uschar *buffer, unsigned bufsize, address_item *addrlist, host_item *h FALSE); return DEFER; } - + return OK; } @@ -1108,7 +1192,7 @@ BOOL completed_address = FALSE; BOOL esmtp = TRUE; BOOL pending_MAIL; BOOL pass_message = FALSE; -#ifdef EXPERIMENTAL_PRDR +#ifndef DISABLE_PRDR BOOL prdr_offered = FALSE; BOOL prdr_active; #endif @@ -1147,25 +1231,27 @@ outblock.authenticating = FALSE; /* Reset the parameters of a TLS session. */ -tls_in.bits = 0; -tls_in.cipher = NULL; /* for back-compatible behaviour */ -tls_in.peerdn = NULL; -#if defined(SUPPORT_TLS) && !defined(USE_GNUTLS) -tls_in.sni = NULL; -#endif - tls_out.bits = 0; tls_out.cipher = NULL; /* the one we may use for this transport */ +tls_out.ourcert = NULL; +tls_out.peercert = NULL; tls_out.peerdn = NULL; #if defined(SUPPORT_TLS) && !defined(USE_GNUTLS) tls_out.sni = NULL; #endif +tls_out.ocsp = OCSP_NOT_REQ; + +/* Flip the legacy TLS-related variables over to the outbound set in case +they're used in the context of the transport. Don't bother resetting +afterward as we're in a subprocess. */ + +tls_modify_variables(&tls_out); #ifndef SUPPORT_TLS if (smtps) { - set_errno(addrlist, 0, US"TLS support not available", DEFER, FALSE); - return ERROR; + set_errno(addrlist, 0, US"TLS support not available", DEFER, FALSE); + return ERROR; } #endif @@ -1307,7 +1393,7 @@ goto SEND_QUIT; PCRE_EOPT, NULL, 0) >= 0; #endif - #ifdef EXPERIMENTAL_PRDR + #ifndef DISABLE_PRDR prdr_offered = esmtp && (pcre_exec(regex_PRDR, NULL, CS buffer, Ustrlen(buffer), 0, PCRE_EOPT, NULL, 0) >= 0) && @@ -1373,20 +1459,7 @@ if (tls_offered && !suppress_tls && else TLS_NEGOTIATE: { - int rc = tls_client_start(inblock.sock, - host, - addrlist, - ob->tls_certificate, - ob->tls_privatekey, - ob->tls_sni, - ob->tls_verify_certificates, - ob->tls_crl, - ob->tls_require_ciphers, -#ifdef EXPERIMENTAL_OCSP - ob->hosts_require_ocsp, -#endif - ob->tls_dh_min_bits, - ob->command_timeout); + int rc = tls_client_start(inblock.sock, host, addrlist, ob); /* 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 @@ -1407,7 +1480,10 @@ if (tls_offered && !suppress_tls && if (addr->transport_return == PENDING_DEFER) { addr->cipher = tls_out.cipher; + addr->ourcert = tls_out.ourcert; + addr->peercert = tls_out.peercert; addr->peerdn = tls_out.peerdn; + addr->ocsp = tls_out.ocsp; } } } @@ -1516,7 +1592,7 @@ if (continue_hostname == NULL DEBUG(D_transport) debug_printf("%susing PIPELINING\n", smtp_use_pipelining? "" : "not "); -#ifdef EXPERIMENTAL_PRDR +#ifndef DISABLE_PRDR prdr_offered = esmtp && pcre_exec(regex_PRDR, NULL, CS buffer, Ustrlen(CS buffer), 0, PCRE_EOPT, NULL, 0) >= 0 && @@ -1604,7 +1680,7 @@ if (smtp_use_size) while (*p) p++; } -#ifdef EXPERIMENTAL_PRDR +#ifndef DISABLE_PRDR prdr_active = FALSE; if (prdr_offered) { @@ -1840,7 +1916,7 @@ if (!ok) ok = TRUE; else smtp_command = US"end of data"; -#ifdef EXPERIMENTAL_PRDR +#ifndef DISABLE_PRDR /* For PRDR we optionally get a partial-responses warning * followed by the individual responses, before going on with * the overall response. If we don't get the warning then deal @@ -1912,7 +1988,12 @@ if (!ok) ok = TRUE; else /* Set up confirmation if needed - applies only to SMTP */ - if ((log_extra_selector & LX_smtp_confirmation) != 0 && !lmtp) + if ( + #ifndef EXPERIMENTAL_TPDA + (log_extra_selector & LX_smtp_confirmation) != 0 && + #endif + !lmtp + ) { uschar *s = string_printing(buffer); conf = (s == buffer)? (uschar *)string_copy(s) : s; @@ -1930,7 +2011,7 @@ if (!ok) ok = TRUE; else address. For temporary errors, add a retry item for the address so that it doesn't get tried again too soon. */ -#ifdef EXPERIMENTAL_PRDR +#ifndef DISABLE_PRDR if (lmtp || prdr_active) #else if (lmtp) @@ -1941,7 +2022,7 @@ if (!ok) ok = TRUE; else { if (errno != 0 || buffer[0] == 0) goto RESPONSE_FAILED; addr->message = string_sprintf( -#ifdef EXPERIMENTAL_PRDR +#ifndef DISABLE_PRDR "%s error after %s: %s", prdr_active ? "PRDR":"LMTP", #else "LMTP error after %s: %s", @@ -1955,7 +2036,7 @@ if (!ok) ok = TRUE; else errno = ERRNO_DATA4XX; addr->more_errno |= ((buffer[1] - '0')*10 + buffer[2] - '0') << 8; addr->transport_return = DEFER; -#ifdef EXPERIMENTAL_PRDR +#ifndef DISABLE_PRDR if (!prdr_active) #endif retry_add_item(addr, addr->address_retry_key, 0); @@ -1978,12 +2059,12 @@ if (!ok) ok = TRUE; else addr->host_used = thost; addr->special_action = flag; addr->message = conf; -#ifdef EXPERIMENTAL_PRDR +#ifndef DISABLE_PRDR if (prdr_active) addr->flags |= af_prdr_used; #endif flag = '-'; -#ifdef EXPERIMENTAL_PRDR +#ifndef DISABLE_PRDR if (!prdr_active) #endif { @@ -1991,12 +2072,12 @@ if (!ok) ok = TRUE; else the transport name. See lots of comments in deliver.c about the reasons for the complications when homonyms are involved. Just carry on after write error, as it may prove possible to update the spool file later. */ - + if (testflag(addr, af_homonym)) sprintf(CS buffer, "%.500s/%s\n", addr->unique + 3, tblock->name); else sprintf(CS buffer, "%.500s\n", addr->unique); - + DEBUG(D_deliver) debug_printf("journalling %s", buffer); len = Ustrlen(CS buffer); if (write(journal_fd, buffer, len) != len) @@ -2005,7 +2086,7 @@ if (!ok) ok = TRUE; else } } -#ifdef EXPERIMENTAL_PRDR +#ifndef DISABLE_PRDR if (prdr_active) { /* PRDR - get the final, overall response. For any non-success @@ -2033,7 +2114,7 @@ if (!ok) ok = TRUE; else sprintf(CS buffer, "%.500s/%s\n", addr->unique + 3, tblock->name); else sprintf(CS buffer, "%.500s\n", addr->unique); - + DEBUG(D_deliver) debug_printf("journalling(PRDR) %s", buffer); len = Ustrlen(CS buffer); if (write(journal_fd, buffer, len) != len) @@ -2339,8 +2420,6 @@ tls_close(FALSE, TRUE); #endif /* Close the socket, and return the appropriate value, first setting -continue_transport and continue_hostname NULL to prevent any other addresses -that may include the host from trying to re-use a continuation socket. This works because the NULL setting is passed back to the calling process, and remote_max_parallel is forced to 1 when delivering over an existing connection, @@ -2441,7 +2520,10 @@ for (addr = addrlist; addr != NULL; addr = addr->next) addr->message = NULL; #ifdef SUPPORT_TLS addr->cipher = NULL; + addr->ourcert = NULL; + addr->peercert = NULL; addr->peerdn = NULL; + addr->ocsp = OCSP_NOT_REQ; #endif } return first_addr; @@ -2744,6 +2826,7 @@ for (cutoff_retry = 0; expired && rc = host_find_byname(host, NULL, flags, &canonical_name, TRUE); else rc = host_find_bydns(host, NULL, flags, NULL, NULL, NULL, + ob->dnssec_request_domains, ob->dnssec_require_domains, &canonical_name, NULL); /* Update the host (and any additional blocks, resulting from @@ -2843,6 +2926,9 @@ for (cutoff_retry = 0; expired && deliver_host = host->name; deliver_host_address = host->address; + lookup_dnssec_authenticated = host->dnssec == DS_YES ? US"yes" + : host->dnssec == DS_NO ? US"no" + : US""; /* Set up a string for adding to the retry key if the port number is not the standard SMTP port. A host may have its own port setting that overrides @@ -3051,6 +3137,11 @@ for (cutoff_retry = 0; expired && first_addr->basic_errno != ERRNO_TLSFAILURE) write_logs(first_addr, host); + #ifdef EXPERIMENTAL_TPDA + if (rc == DEFER) + tpda_deferred(ob, first_addr, host); + #endif + /* If STARTTLS was accepted, but there was a failure in setting up the TLS session (usually a certificate screwup), and the host is not in hosts_require_tls, and tls_tempfail_tryclear is true, try again, with @@ -3073,6 +3164,10 @@ for (cutoff_retry = 0; expired && expanded_hosts != NULL, &message_defer, TRUE); if (rc == DEFER && first_addr->basic_errno != ERRNO_AUTHFAIL) write_logs(first_addr, host); + #ifdef EXPERIMENTAL_TPDA + if (rc == DEFER) + tpda_deferred(ob, first_addr, host); + #endif } #endif } @@ -3347,4 +3442,6 @@ DEBUG(D_transport) debug_printf("Leaving %s transport\n", tblock->name); return TRUE; /* Each address has its status */ } +/* vi: aw ai sw=2 +*/ /* End of transport/smtp.c */