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,
(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) },
(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,
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()) */
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 */
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 */
#endif
};
-#ifdef EXPERIMENTAL_DSN
/* some DSN flags for use later */
static int rf_list[] = {rf_notify_never, rf_notify_success,
rf_notify_failure, rf_notify_delay };
static uschar *rf_names[] = { US"NEVER", US"SUCCESS", US"FAILURE", US"DELAY" };
-#endif
orvalue = RTEF_CTOUT;
}
for (addr = addrlist; addr != NULL; addr = addr->next)
- {
- if (addr->transport_return < PENDING) continue;
- addr->basic_errno = errno_value;
- addr->more_errno |= orvalue;
- if (msg != NULL)
+ if (addr->transport_return >= PENDING)
{
- addr->message = msg;
- if (pass_message) setflag(addr, af_pass_message);
+ addr->basic_errno = errno_value;
+ addr->more_errno |= orvalue;
+ if (msg != NULL)
+ {
+ addr->message = msg;
+ if (pass_message) setflag(addr, af_pass_message);
+ }
+ addr->transport_return = rc;
+ if (host)
+ addr->host_used = host;
}
- addr->transport_return = rc;
- if (host)
- addr->host_used = host;
- }
}
else if (errno == ETIMEDOUT)
{
- int save_errno = errno;
uschar *message = string_sprintf("SMTP timeout after RCPT TO:<%s>",
transport_rcpt_address(addr, include_affixes));
- set_errno(addrlist, save_errno, message, DEFER, FALSE, NULL);
+ set_errno(addrlist, ETIMEDOUT, message, DEFER, FALSE, NULL);
retry_add_item(addr, addr->address_retry_key, 0);
update_waiting = FALSE;
return -1;
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|$)",
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";
/* Internal problem, message in buffer. */
case ERROR:
- set_errno(addrlist, 0, string_copy(buffer), DEFER, FALSE, NULL);
+ set_errno(addrlist, ERRNO_AUTHPROB, string_copy(buffer),
+ DEFER, FALSE, NULL);
return ERROR;
}
{
uschar *message = string_sprintf("failed to expand "
"authenticated_sender: %s", expand_string_message);
- set_errno(addrlist, 0, message, DEFER, FALSE, NULL);
+ set_errno(addrlist, ERRNO_EXPANDFAIL, message, DEFER, FALSE, NULL);
return TRUE;
}
}
BOOL prdr_offered = FALSE;
BOOL prdr_active;
#endif
-#ifdef EXPERIMENTAL_DSN
BOOL dsn_all_lasthop = TRUE;
-#endif
#if defined(SUPPORT_TLS) && defined(EXPERIMENTAL_DANE)
BOOL dane = FALSE;
dns_answer tlsa_dnsa;
#ifndef SUPPORT_TLS
if (smtps)
{
- set_errno(addrlist, 0, US"TLS support not available", DEFER, FALSE, NULL);
+ set_errno(addrlist, ERRNO_TLSFAILURE, US"TLS support not available",
+ DEFER, FALSE, NULL);
return ERROR;
}
#endif
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;
s = event_raise(tblock->event_action, US"smtp:connect", buffer);
if (s)
{
- set_errno(addrlist, 0,
+ set_errno(addrlist, ERRNO_EXPANDFAIL,
string_sprintf("deferred by smtp:connect event expansion: %s", s),
DEFER, FALSE, NULL);
yield = DEFER;
{
uschar *message = string_sprintf("failed to expand helo_data: %s",
expand_string_message);
- set_errno(addrlist, 0, message, DEFER, FALSE, NULL);
+ set_errno(addrlist, ERRNO_EXPANDFAIL, message, DEFER, FALSE, NULL);
yield = DEFER;
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
#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");}
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)
{
uschar *message = string_sprintf("failed to expand helo_data: %s",
expand_string_message);
- set_errno(addrlist, 0, message, DEFER, FALSE, NULL);
+ set_errno(addrlist, ERRNO_EXPANDFAIL, message, DEFER, FALSE, NULL);
yield = DEFER;
goto SEND_QUIT;
}
# 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;
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");}
#endif
-#ifdef EXPERIMENTAL_DSN
/* Note if the server supports DSN */
smtp_use_dsn = esmtp && pcre_exec(regex_DSN, NULL, CS buffer, (int)Ustrlen(CS buffer), 0,
PCRE_EOPT, NULL, 0) >= 0;
DEBUG(D_transport) debug_printf("use_dsn=%d\n", smtp_use_dsn);
-#endif
/* Note if the response to EHLO specifies support for the AUTH extension.
If it has, check that this host is one we want to authenticate to, and do
}
#endif
-#ifdef EXPERIMENTAL_DSN
/* check if all addresses have lasthop flag */
/* do not send RET and ENVID if true */
dsn_all_lasthop = TRUE;
while (*p) p++;
}
}
-#endif
/* 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
int count;
BOOL no_flush;
-#ifdef EXPERIMENTAL_DSN
addr->dsn_aware = smtp_use_dsn ? dsn_support_yes : dsn_support_no;
-#endif
if (addr->transport_return != PENDING_DEFER) continue;
address_count++;
no_flush = smtp_use_pipelining && (!mua_wrapper || addr->next != NULL);
-#ifdef EXPERIMENTAL_DSN
/* Add any DSN flags to the rcpt command and add to the sent string */
p = buffer;
while (*p) p++;
}
}
-#endif
-
/* Now send the RCPT command, and process outstanding responses when
necessary. After a timeout on RCPT, we just end the function, leaving the
yield as OK, because this error can often mean that there is a problem with
just one address, so we don't want to delay the host. */
-#ifdef EXPERIMENTAL_DSN
count = smtp_write_command(&outblock, no_flush, "RCPT TO:<%s>%s%s\r\n",
transport_rcpt_address(addr, tblock->rcpt_include_affixes), igquotstr, buffer);
-#else
- count = smtp_write_command(&outblock, no_flush, "RCPT TO:<%s>%s\r\n",
- transport_rcpt_address(addr, tblock->rcpt_include_affixes), igquotstr);
-#endif
if (count < 0) goto SEND_FAILED;
if (count > 0)
if (mua_wrapper)
{
address_item *badaddr;
- for (badaddr = first_addr; badaddr != NULL; badaddr = badaddr->next)
- {
- if (badaddr->transport_return != PENDING_OK) break;
- }
- if (badaddr != NULL)
- {
- set_errno(addrlist, 0, badaddr->message, FAIL,
- testflag(badaddr, af_pass_message), NULL);
- ok = FALSE;
- }
+ for (badaddr = first_addr; badaddr; badaddr = badaddr->next)
+ if (badaddr->transport_return != PENDING_OK)
+ {
+ /*XXX could we find a better errno than 0 here? */
+ set_errno(addrlist, 0, badaddr->message, FAIL,
+ testflag(badaddr, af_pass_message), NULL);
+ ok = FALSE;
+ break;
+ }
}
/* If ok is TRUE, we know we have got at least one good recipient, and must now
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;
address_item *first_addr = NULL;
address_item *addr;
for (addr = addrlist; addr != NULL; addr = addr->next)
- {
- if (addr->transport_return != DEFER) continue;
- if (first_addr == NULL) first_addr = addr;
- addr->transport_return = PENDING_DEFER;
- addr->basic_errno = 0;
- addr->more_errno = (host->mx >= 0)? 'M' : 'A';
- addr->message = NULL;
+ if (addr->transport_return == DEFER)
+ {
+ if (first_addr == NULL) first_addr = addr;
+ addr->transport_return = PENDING_DEFER;
+ addr->basic_errno = 0;
+ addr->more_errno = (host->mx >= 0)? 'M' : 'A';
+ addr->message = NULL;
#ifdef SUPPORT_TLS
- addr->cipher = NULL;
- addr->ourcert = NULL;
- addr->peercert = NULL;
- addr->peerdn = NULL;
- addr->ocsp = OCSP_NOT_REQ;
+ addr->cipher = NULL;
+ addr->ourcert = NULL;
+ addr->peercert = NULL;
+ addr->peerdn = NULL;
+ addr->ocsp = OCSP_NOT_REQ;
#endif
- }
+ }
return first_addr;
}
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,
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))
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 "
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);
}
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);