X-Git-Url: https://git.exim.org/exim.git/blobdiff_plain/74954688e4f61475b2451b2cb22045ab8e7f0150..0509be3542344cf27658df9935d930cb2d2b9560:/src/src/transports/smtp.c diff --git a/src/src/transports/smtp.c b/src/src/transports/smtp.c index 6d3492295..addbf0ed8 100644 --- a/src/src/transports/smtp.c +++ b/src/src/transports/smtp.c @@ -19,6 +19,11 @@ before the lower case letters). Some live in the transport_instance block so as to be publicly visible; these are flagged with opt_public. */ optionlist smtp_transport_options[] = { + { "*expand_multi_domain", opt_stringptr | opt_hidden | opt_public, + (void *)offsetof(transport_instance, expand_multi_domain) }, + { "*expand_retry_include_ip_address", opt_stringptr | opt_hidden, + (void *)(offsetof(smtp_transport_options_block, expand_retry_include_ip_address)) }, + { "address_retry_include_sender", opt_bool, (void *)offsetof(smtp_transport_options_block, address_retry_include_sender) }, { "allow_localhost", opt_bool, @@ -142,13 +147,13 @@ optionlist smtp_transport_options[] = { (void *)offsetof(smtp_transport_options_block, lmtp_ignore_quota) }, { "max_rcpt", opt_int | opt_public, (void *)offsetof(transport_instance, max_addresses) }, - { "multi_domain", opt_bool | opt_public, + { "multi_domain", opt_expand_bool | opt_public, (void *)offsetof(transport_instance, multi_domain) }, { "port", opt_stringptr, (void *)offsetof(smtp_transport_options_block, port) }, { "protocol", opt_stringptr, (void *)offsetof(smtp_transport_options_block, protocol) }, - { "retry_include_ip_address", opt_bool, + { "retry_include_ip_address", opt_expand_bool, (void *)offsetof(smtp_transport_options_block, retry_include_ip_address) }, { "serialize_hosts", opt_stringptr, (void *)offsetof(smtp_transport_options_block, serialize_hosts) }, @@ -171,10 +176,8 @@ optionlist smtp_transport_options[] = { (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) }, { "tls_verify_hosts", opt_stringptr, @@ -209,7 +212,7 @@ smtp_transport_options_block smtp_transport_option_defaults = { NULL, /* hosts_require_dane */ #endif #ifndef DISABLE_PRDR - NULL, /* hosts_try_prdr */ + US"*", /* hosts_try_prdr */ #endif #ifndef DISABLE_OCSP US"*", /* hosts_request_ocsp (except under DANE; tls_client_start()) */ @@ -241,6 +244,7 @@ smtp_transport_options_block smtp_transport_option_defaults = { FALSE, /* hosts_randomize */ TRUE, /* keepalive */ FALSE, /* lmtp_ignore_quota */ + NULL, /* expand_retry_include_ip_address */ TRUE /* retry_include_ip_address */ #ifdef SUPPORT_TLS ,NULL, /* tls_certificate */ @@ -251,15 +255,13 @@ smtp_transport_options_block smtp_transport_option_defaults = { NULL, /* gnutls_require_mac */ NULL, /* gnutls_require_proto */ NULL, /* tls_sni */ - NULL, /* tls_verify_certificates */ + US"system", /* tls_verify_certificates */ EXIM_CLIENT_DH_DEFAULT_MIN_BITS, /* tls_dh_min_bits */ TRUE, /* tls_tempfail_tryclear */ NULL, /* tls_verify_hosts */ - NULL /* tls_try_verify_hosts */ -# ifdef EXPERIMENTAL_CERTNAMES - ,NULL /* tls_verify_cert_hostnames */ -# endif + US"*", /* tls_try_verify_hosts */ + US"*" /* tls_verify_cert_hostnames */ #endif #ifndef DISABLE_DKIM ,NULL, /* dkim_canon */ @@ -277,7 +279,7 @@ smtp_transport_options_block smtp_transport_option_defaults = { static int rf_list[] = {rf_notify_never, rf_notify_success, rf_notify_failure, rf_notify_delay }; -static uschar *rf_names[] = { "NEVER", "SUCCESS", "FAILURE", "DELAY" }; +static uschar *rf_names[] = { US"NEVER", US"SUCCESS", US"FAILURE", US"DELAY" }; #endif @@ -640,7 +642,7 @@ msglog_line(host_item * host, uschar * message) -#ifdef EXPERIMENTAL_TPDA +#ifdef EXPERIMENTAL_EVENT /************************************************* * Post-defer action * *************************************************/ @@ -656,9 +658,9 @@ Returns: nothing */ static void -tpda_deferred(address_item *addr, host_item *host) +deferred_event_raise(address_item *addr, host_item *host) { -uschar * action = addr->transport->tpda_event_action; +uschar * action = addr->transport->event_action; uschar * save_domain; uschar * save_local; @@ -670,15 +672,15 @@ save_local = deliver_localpart; /*XXX would ip & port already be set up? */ deliver_host_address = string_copy(host->address); -deliver_host_port = (host->port == PORT_NONE)? 25 : host->port; -tpda_defer_errno = addr->basic_errno; +deliver_host_port = host->port == PORT_NONE ? 25 : host->port; +event_defer_errno = addr->basic_errno; router_name = addr->router->name; transport_name = addr->transport->name; deliver_domain = addr->domain; deliver_localpart = addr->local_part; -(void) tpda_raise_event(action, US"msg:host:defer", +(void) event_raise(action, US"msg:host:defer", addr->message ? addr->basic_errno > 0 ? string_sprintf("%s: %s", addr->message, strerror(addr->basic_errno)) @@ -970,8 +972,7 @@ uschar *fail_reason = US"server did not advertise AUTH support"; smtp_authenticated = FALSE; client_authenticator = client_authenticated_id = client_authenticated_sender = NULL; -require_auth = verify_check_this_host(&(ob->hosts_require_auth), NULL, - host->name, host->address, NULL); +require_auth = verify_check_given_host(&ob->hosts_require_auth, host); if (is_esmtp && !regex_AUTH) regex_AUTH = regex_must_compile(US"\\n250[\\s\\-]AUTH\\s+([\\-\\w\\s]+)(?:\\n|$)", @@ -986,8 +987,7 @@ if (is_esmtp && regex_match_and_setup(regex_AUTH, buffer, 0, -1)) regex match above. */ if (require_auth == OK || - verify_check_this_host(&(ob->hosts_try_auth), NULL, host->name, - host->address, NULL) == OK) + verify_check_given_host(&ob->hosts_try_auth, host) == OK) { auth_instance *au; fail_reason = US"no common mechanisms were found"; @@ -1356,8 +1356,8 @@ if (continue_hostname == NULL) inblock.sock = outblock.sock = smtp_connect(host, host_af, port, interface, ob->connect_timeout, ob->keepalive, ob->dscp -#ifdef EXPERIMENTAL_TPDA - , tblock->tpda_event_action +#ifdef EXPERIMENTAL_EVENT + , tblock->event_action #endif ); @@ -1375,14 +1375,12 @@ if (continue_hostname == NULL) tls_out.dane_verified = FALSE; tls_out.tlsa_usage = 0; - dane_required = verify_check_this_host(&ob->hosts_require_dane, NULL, - host->name, host->address, NULL) == OK; + dane_required = verify_check_given_host(&ob->hosts_require_dane, host) == OK; if (host->dnssec == DS_YES) { if( dane_required - || verify_check_this_host(&ob->hosts_try_dane, NULL, - host->name, host->address, NULL) == OK + || verify_check_given_host(&ob->hosts_try_dane, host) == OK ) if ((rc = tlsa_lookup(host, &tlsa_dnsa, dane_required, &dane)) != OK) return rc; @@ -1413,15 +1411,21 @@ if (continue_hostname == NULL) if (!smtp_read_response(&inblock, buffer, sizeof(buffer), '2', ob->command_timeout)) goto RESPONSE_FAILED; -#ifdef EXPERIMENTAL_TPDA - if (tpda_raise_event(tblock->tpda_event_action, US"smtp:connect", buffer) - == DEFER) +#ifdef EXPERIMENTAL_EVENT + { + uschar * s; + lookup_dnssec_authenticated = host->dnssec==DS_YES ? US"yes" + : host->dnssec==DS_NO ? US"no" : NULL; + s = event_raise(tblock->event_action, US"smtp:connect", buffer); + if (s) { - uschar *message = US"deferred by smtp:connect event expansion"; - set_errno(addrlist, 0, message, DEFER, FALSE, NULL); + set_errno(addrlist, 0, + string_sprintf("deferred by smtp:connect event expansion: %s", s), + DEFER, FALSE, NULL); yield = DEFER; goto SEND_QUIT; } + } #endif /* Now check if the helo_data expansion went well, and sign off cleanly if @@ -1472,8 +1476,7 @@ goto SEND_QUIT; mailers use upper case for some reason (the RFC is quite clear about case independence) so, for peace of mind, I gave in. */ - esmtp = verify_check_this_host(&(ob->hosts_avoid_esmtp), NULL, - host->name, host->address, NULL) != OK; + esmtp = verify_check_given_host(&ob->hosts_avoid_esmtp, host) != OK; /* Alas; be careful, since this goto is not an error-out, so conceivably we might set data between here and the target which we assume to exist @@ -1531,11 +1534,10 @@ goto SEND_QUIT; #endif #ifndef DISABLE_PRDR - prdr_offered = esmtp && - (pcre_exec(regex_PRDR, NULL, CS buffer, Ustrlen(buffer), 0, - PCRE_EOPT, NULL, 0) >= 0) && - (verify_check_this_host(&(ob->hosts_try_prdr), NULL, host->name, - host->address, NULL) == OK); + prdr_offered = esmtp + && pcre_exec(regex_PRDR, NULL, CS buffer, Ustrlen(buffer), 0, + PCRE_EOPT, NULL, 0) >= 0 + && verify_check_given_host(&ob->hosts_try_prdr, host) == OK; if (prdr_offered) {DEBUG(D_transport) debug_printf("PRDR usable\n");} @@ -1565,9 +1567,9 @@ the client not be required to use TLS. If the response is bad, copy the buffer for error analysis. */ #ifdef SUPPORT_TLS -if (tls_offered && !suppress_tls && - verify_check_this_host(&(ob->hosts_avoid_tls), NULL, host->name, - host->address, NULL) != OK) +if ( tls_offered + && !suppress_tls + && verify_check_given_host(&ob->hosts_avoid_tls, host) != OK) { uschar buffer2[4096]; if (smtp_write_command(&outblock, FALSE, "STARTTLS\r\n") < 0) @@ -1685,8 +1687,7 @@ else if ( # ifdef EXPERIMENTAL_DANE dane || # endif - verify_check_this_host(&(ob->hosts_require_tls), NULL, host->name, - host->address, NULL) == OK + verify_check_given_host(&ob->hosts_require_tls, host) == OK ) { save_errno = ERRNO_TLSREQUIRED; @@ -1726,21 +1727,19 @@ if (continue_hostname == NULL the current host, esmtp will be false, so PIPELINING can never be used. If the current host matches hosts_avoid_pipelining, don't do it. */ - smtp_use_pipelining = esmtp && - verify_check_this_host(&(ob->hosts_avoid_pipelining), NULL, host->name, - host->address, NULL) != OK && - pcre_exec(regex_PIPELINING, NULL, CS buffer, Ustrlen(CS buffer), 0, - PCRE_EOPT, NULL, 0) >= 0; + smtp_use_pipelining = esmtp + && verify_check_given_host(&ob->hosts_avoid_pipelining, host) != OK + && pcre_exec(regex_PIPELINING, NULL, CS buffer, Ustrlen(CS buffer), 0, + PCRE_EOPT, NULL, 0) >= 0; DEBUG(D_transport) debug_printf("%susing PIPELINING\n", smtp_use_pipelining? "" : "not "); #ifndef DISABLE_PRDR - prdr_offered = esmtp && - pcre_exec(regex_PRDR, NULL, CS buffer, Ustrlen(CS buffer), 0, - PCRE_EOPT, NULL, 0) >= 0 && - verify_check_this_host(&(ob->hosts_try_prdr), NULL, host->name, - host->address, NULL) == OK; + prdr_offered = esmtp + && pcre_exec(regex_PRDR, NULL, CS buffer, Ustrlen(CS buffer), 0, + PCRE_EOPT, NULL, 0) >= 0 + && verify_check_given_host(&ob->hosts_try_prdr, host) == OK; if (prdr_offered) {DEBUG(D_transport) debug_printf("PRDR usable\n");} @@ -1865,12 +1864,12 @@ if ((smtp_use_dsn) && (dsn_all_lasthop == FALSE)) { if (dsn_ret == dsn_ret_hdrs) { - strcpy(p, " RET=HDRS"); + Ustrcpy(p, " RET=HDRS"); while (*p) p++; } else if (dsn_ret == dsn_ret_full) { - strcpy(p, " RET=FULL"); + Ustrcpy(p, " RET=FULL"); while (*p) p++; } if (dsn_envid != NULL) @@ -1967,14 +1966,14 @@ for (addr = first_addr; { int i; BOOL first = TRUE; - strcpy(p, " NOTIFY="); + Ustrcpy(p, " NOTIFY="); while (*p) p++; for (i = 0; i < 4; i++) if ((addr->dsn_flags & rf_list[i]) != 0) { if (!first) *p++ = ','; first = FALSE; - strcpy(p, rf_names[i]); + Ustrcpy(p, rf_names[i]); while (*p) p++; } } @@ -2218,7 +2217,7 @@ if (!ok) ok = TRUE; else /* Set up confirmation if needed - applies only to SMTP */ if ( -#ifndef EXPERIMENTAL_TPDA +#ifndef EXPERIMENTAL_EVENT (log_extra_selector & LX_smtp_confirmation) != 0 && #endif !lmtp @@ -2540,15 +2539,15 @@ DEBUG(D_transport) if (completed_address && ok && send_quit) { BOOL more; - if (first_addr != NULL || continue_more || - ( - (tls_out.active < 0 || - verify_check_this_host(&(ob->hosts_nopass_tls), NULL, host->name, - host->address, NULL) != OK) + if ( first_addr != NULL + || continue_more + || ( ( tls_out.active < 0 + || verify_check_given_host(&ob->hosts_nopass_tls, host) != OK + ) && transport_check_waiting(tblock->name, host->name, tblock->connection_max_messages, new_message_id, &more) - )) + ) ) { uschar *msg; BOOL pass_message; @@ -2659,8 +2658,8 @@ case continue_more won't get set. */ (void)close(inblock.sock); -#ifdef EXPERIMENTAL_TPDA -(void) tpda_raise_event(tblock->tpda_event_action, US"tcp:close", NULL); +#ifdef EXPERIMENTAL_EVENT +(void) event_raise(tblock->event_action, US"tcp:close", NULL); #endif continue_transport = NULL; @@ -3188,14 +3187,20 @@ for (cutoff_retry = 0; expired && if (cutoff_retry == 0) { + BOOL incl_ip; /* Ensure the status of the address is set by checking retry data if - necessary. There maybe host-specific retry data (applicable to all + necessary. There may be host-specific retry data (applicable to all messages) and also data for retries of a specific message at this host. If either of these retry records are actually read, the keys used are returned to save recomputing them later. */ + if (exp_bool(addrlist, US"transport", tblock->name, D_transport, + US"retry_include_ip_address", ob->retry_include_ip_address, + ob->expand_retry_include_ip_address, &incl_ip) != OK) + continue; /* with next host */ + host_is_expired = retry_check_address(addrlist->domain, host, pistring, - ob->retry_include_ip_address, &retry_host_key, &retry_message_key); + incl_ip, &retry_host_key, &retry_message_key); DEBUG(D_transport) debug_printf("%s [%s]%s status = %s\n", host->name, (host->address == NULL)? US"" : host->address, pistring, @@ -3258,8 +3263,7 @@ for (cutoff_retry = 0; expired && sending the message down a pre-existing connection. */ if (!continuing && - verify_check_this_host(&(ob->serialize_hosts), NULL, host->name, - host->address, NULL) == OK) + verify_check_given_host(&ob->serialize_hosts, host) == OK) { serialize_key = string_sprintf("host-serialize-%s", host->name); if (!enq_start(serialize_key)) @@ -3370,9 +3374,9 @@ for (cutoff_retry = 0; expired && first_addr->basic_errno != ERRNO_TLSFAILURE) write_logs(first_addr, host); -#ifdef EXPERIMENTAL_TPDA +#ifdef EXPERIMENTAL_EVENT if (rc == DEFER) - tpda_deferred(first_addr, host); + deferred_event_raise(first_addr, host); #endif /* If STARTTLS was accepted, but there was a failure in setting up the @@ -3388,8 +3392,7 @@ for (cutoff_retry = 0; expired && if ( rc == DEFER && first_addr->basic_errno == ERRNO_TLSFAILURE && ob->tls_tempfail_tryclear - && verify_check_this_host(&(ob->hosts_require_tls), NULL, host->name, - host->address, NULL) != OK + && verify_check_given_host(&ob->hosts_require_tls, host) != OK ) { log_write(0, LOG_MAIN, "TLS session failure: delivering unencrypted " @@ -3399,9 +3402,9 @@ 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 +# ifdef EXPERIMENTAL_EVENT if (rc == DEFER) - tpda_deferred(first_addr, host); + deferred_event_raise(first_addr, host); # endif } #endif /*SUPPORT_TLS*/ @@ -3433,7 +3436,13 @@ for (cutoff_retry = 0; expired && int delete_flag = (rc != DEFER)? rf_delete : 0; if (retry_host_key == NULL) { - retry_host_key = ob->retry_include_ip_address? + BOOL incl_ip; + if (exp_bool(addrlist, US"transport", tblock->name, D_transport, + US"retry_include_ip_address", ob->retry_include_ip_address, + ob->expand_retry_include_ip_address, &incl_ip) != OK) + incl_ip = TRUE; /* error; use most-specific retry record */ + + retry_host_key = incl_ip ? string_sprintf("T:%S:%s%s", host->name, host->address, pistring) : string_sprintf("T:%S%s", host->name, pistring); } @@ -3475,7 +3484,13 @@ for (cutoff_retry = 0; expired && int delete_flag = message_defer? 0 : rf_delete; if (retry_message_key == NULL) { - retry_message_key = ob->retry_include_ip_address? + BOOL incl_ip; + if (exp_bool(addrlist, US"transport", tblock->name, D_transport, + US"retry_include_ip_address", ob->retry_include_ip_address, + ob->expand_retry_include_ip_address, &incl_ip) != OK) + incl_ip = TRUE; /* error; use most-specific retry record */ + + retry_message_key = incl_ip ? string_sprintf("T:%S:%s%s:%s", host->name, host->address, pistring, message_id) : string_sprintf("T:%S%s:%s", host->name, pistring, message_id);