dbdata_callout_cache_address new_address_record;
host_item *host;
time_t callout_start_time;
-#ifdef SUPPORT_I18N
-BOOL utf8_offered = FALSE;
-#endif
+uschar peer_offered = 0;
new_domain_record.result = ccache_unknown;
new_domain_record.postmaster_result = ccache_unknown;
uschar inbuffer[4096];
uschar outbuffer[1024];
uschar responsebuffer[4096];
+ uschar * size_str;
clearflag(addr, af_verify_pmfail); /* postmaster callout flag */
clearflag(addr, af_verify_nsfail); /* null sender callout flag */
if (host->dnssec == DS_YES)
{
- if( ( dane_required
- || verify_check_given_host(&ob->hosts_try_dane, host) == OK
- )
- && (rc = tlsa_lookup(host, &tlsa_dnsa, dane_required, &dane)) != OK
+ if( dane_required
+ || verify_check_given_host(&ob->hosts_try_dane, host) == OK
)
- return rc;
+ {
+ if ((rc = tlsa_lookup(host, &tlsa_dnsa, dane_required)) != OK)
+ return rc;
+ dane = TRUE;
+ }
}
else if (dane_required)
{
#ifdef SUPPORT_TLS
if (smtps && tls_out.active < 0) /* ssl-on-connect, first pass */
{
- tls_offered = TRUE;
+ peer_offered &= ~PEER_OFFERED_TLS;
ob->tls_tempfail_tryclear = FALSE;
}
else /* all other cases */
goto RESPONSE_FAILED;
}
#ifdef SUPPORT_TLS
- tls_offered = FALSE;
+ peer_offered &= ~PEER_OFFERED_TLS;
#endif
esmtp = FALSE;
goto esmtp_retry; /* fallback to HELO */
}
/* Set tls_offered if the response to EHLO specifies support for STARTTLS. */
-#ifdef SUPPORT_TLS
- if (esmtp && !suppress_tls && tls_out.active < 0)
- {
- if (regex_STARTTLS == NULL) regex_STARTTLS =
- regex_must_compile(US"\\n250[\\s\\-]STARTTLS(\\s|\\n|$)", FALSE, TRUE);
- tls_offered = pcre_exec(regex_STARTTLS, NULL, CS responsebuffer,
- Ustrlen(responsebuffer), 0, PCRE_EOPT, NULL, 0) >= 0;
- }
- else
- tls_offered = FALSE;
+ peer_offered = esmtp
+ ? ehlo_response(responsebuffer, sizeof(responsebuffer),
+ (!suppress_tls && tls_out.active < 0 ? PEER_OFFERED_TLS : 0)
+ | 0 /* no IGNQ */
+ | 0 /* no PRDR */
+#ifdef SUPPORT_I18N
+ | (addr->prop.utf8_msg && !addr->prop.utf8_downcvt
+ ? PEER_OFFERED_UTF8 : 0)
#endif
+ | 0 /* no DSN */
+ | 0 /* no PIPE */
+
+ /* only care about SIZE if we have size from inbound */
+ | (message_size > 0 && ob->size_addition >= 0
+ ? PEER_OFFERED_SIZE : 0)
+ )
+ : 0;
}
+ size_str = peer_offered & PEER_OFFERED_SIZE
+ ? string_sprintf(" SIZE=%d", message_size + ob->size_addition) : US"";
+
+#ifdef SUPPORT_TLS
+ tls_offered = !!(peer_offered & PEER_OFFERED_TLS);
+#endif
+
/* If TLS is available on this connection attempt to
start up a TLS session, unless the host is in hosts_avoid_tls. If successful,
send another EHLO - the server may give a different answer in secure mode. We
for error analysis. */
#ifdef SUPPORT_TLS
- if ( tls_offered
+ if ( peer_offered & PEER_OFFERED_TLS
&& verify_check_given_host(&ob->hosts_avoid_tls, host) != OK
&& verify_check_given_host(&ob->hosts_verify_avoid_tls, host) != OK
)
if (!smtps && !smtp_read_response(&inblock, buffer2, sizeof(buffer2), '2',
ob->command_timeout))
{
- if (errno != 0 || buffer2[0] == 0 ||
- (buffer2[0] == '4' && !ob->tls_tempfail_tryclear))
+ if ( errno != 0
+ || buffer2[0] == 0
+ || buffer2[0] == '4' && !ob->tls_tempfail_tryclear
+ )
{
Ustrncpy(responsebuffer, buffer2, sizeof(responsebuffer));
done= FALSE;
(void) event_raise(addr->transport->event_action,
US"tcp:close", NULL);
# endif
-# ifdef EXPERIMENTAL_DANE
- if (dane)
- {
- if (!dane_required)
- {
- log_write(0, LOG_MAIN, "DANE attempt failed;"
- " trying CA-root TLS to %s [%s] (not in hosts_require_dane)",
- host->name, host->address);
- dane = FALSE;
- goto tls_negotiate;
- }
- }
- else
-# endif
- if ( ob->tls_tempfail_tryclear
- && !smtps
- && verify_check_given_host(&ob->hosts_require_tls, host) != OK
- )
+ if ( ob->tls_tempfail_tryclear
+ && !smtps
+ && verify_check_given_host(&ob->hosts_require_tls, host) != OK
+ )
{
log_write(0, LOG_MAIN, "TLS session failure:"
" delivering unencrypted to %s [%s] (not in hosts_require_tls)",
log_write(0, LOG_MAIN,
"H=%s [%s]: a TLS session is required for this host, but %s",
host->name, host->address,
- tls_offered ? "an attempt to start TLS failed"
- : "the server did not offer TLS support");
+ peer_offered & PEER_OFFERED_TLS
+ ? "an attempt to start TLS failed"
+ : "the server did not offer TLS support");
done= FALSE;
goto TLS_FAILED;
}
done = TRUE; /* so far so good; have response to HELO */
- /*XXX the EHLO response would be analyzed here for IGNOREQUOTA, SIZE, PIPELINING */
-
/* For now, transport_filter by cutthrough-delivery is not supported */
/* Need proper integration with the proper transport mechanism. */
if (cutthrough.delivery)
#ifdef SUPPORT_I18N
else if ( addr->prop.utf8_msg
&& !addr->prop.utf8_downcvt
- && !( esmtp
- && ( regex_UTF8
- || ( (regex_UTF8 = regex_must_compile(
- US"\\n250[\\s\\-]SMTPUTF8(\\s|\\n|$)", FALSE, TRUE)),
- TRUE
- ) )
- && ( (utf8_offered = pcre_exec(regex_UTF8, NULL,
- CS responsebuffer, Ustrlen(responsebuffer),
- 0, PCRE_EOPT, NULL, 0) >= 0)
- || addr->prop.utf8_downcvt_maybe
- ) ) )
+ && !(peer_offered & PEER_OFFERED_UTF8)
+ )
{
HDEBUG(D_acl|D_v) debug_printf("utf8 required but not offered\n");
errno = ERRNO_UTF8_FWD;
done = FALSE;
}
else if ( addr->prop.utf8_msg
- && (addr->prop.utf8_downcvt || !utf8_offered)
+ && (addr->prop.utf8_downcvt || !(peer_offered & PEER_OFFERED_UTF8))
&& (setflag(addr, af_utf8_downcvt),
from_address = string_address_utf8_to_alabel(from_address,
&addr->message),
(smtp_write_command(&outblock, FALSE,
#ifdef SUPPORT_I18N
addr->prop.utf8_msg && !addr->prop.utf8_downcvt
- ? "MAIL FROM:<%s>%s SMTPUTF8\r\n"
+ ? "MAIL FROM:<%s>%s%s SMTPUTF8\r\n"
:
#endif
- "MAIL FROM:<%s>%s\r\n",
- from_address, responsebuffer) >= 0)
+ "MAIL FROM:<%s>%s%s\r\n",
+ from_address, responsebuffer, size_str) >= 0)
) &&
smtp_read_response(&inblock, responsebuffer, sizeof(responsebuffer),
/* Flip the legacy TLS-related variables over to the outbound set in case
they're used in the context of a transport used by verification. Reset them
-at exit from this routine. */
+at exit from this routine (so no returns allowed from here on). */
tls_modify_variables(&tls_out);
save_sender = sender_address;
+/* Observability variable for router/transport use */
+
+verify_mode = is_recipient ? US"R" : US"S";
+
/* Update the address structure with the possibly qualified and rewritten
address. Set it up as the starting address on the chain of new addresses. */
full_info is set, and this can only be set locally. Remote enquiries just get
information about the top level address, not anything that it generated. */
-while (addr_new != NULL)
+while (addr_new)
{
int rc;
address_item *addr = addr_new;
/* Just in case some router parameter refers to it. */
- return_path = (addr->prop.errors_address != NULL)?
- addr->prop.errors_address : sender_address;
+ return_path = addr->prop.errors_address
+ ? addr->prop.errors_address : sender_address;
/* Split the address into domain and local part, handling the %-hack if
necessary, and then route it. While routing a sender address, set
$sender_address to <> because that is what it will be if we were trying to
send a bounce to the sender. */
- if (routed != NULL) *routed = FALSE;
+ if (routed) *routed = FALSE;
if ((rc = deliver_split_address(addr)) == OK)
{
if (!is_recipient) sender_address = null_sender;
if (rc == OK)
{
- if (routed != NULL) *routed = TRUE;
+ if (routed) *routed = TRUE;
if (callout > 0)
{
- host_item *host_list = addr->host_list;
transport_instance * tp;
+ host_item * host_list = addr->host_list;
/* Make up some data for use in the case where there is no remote
transport. */
transport is configured to override the router's hosts, we must build a
host list of the transport's hosts, and find the IP addresses */
- if (tf.hosts != NULL && (host_list == NULL || tf.hosts_override))
+ if (tf.hosts && (!host_list || tf.hosts_override))
{
uschar *s;
const uschar *save_deliver_domain = deliver_domain;
deliver_domain = save_deliver_domain;
deliver_localpart = save_deliver_localpart;
- if (s == NULL)
+ if (!s)
{
log_write(0, LOG_MAIN|LOG_PANIC, "failed to expand list of hosts "
"\"%s\" in %s transport for callout: %s", tf.hosts,
if (tf.qualify_single) flags |= HOST_FIND_QUALIFY_SINGLE;
if (tf.search_parents) flags |= HOST_FIND_SEARCH_PARENTS;
- for (host = host_list; host != NULL; host = nexthost)
+ for (host = host_list; host; host = nexthost)
{
nexthost = host->next;
if (tf.gethostbyname ||
/* Can only do a callout if we have at least one host! If the callout
fails, it will have set ${sender,recipient}_verify_failure. */
- if (host_list != NULL)
+ if (host_list)
{
HDEBUG(D_verify) debug_printf("Attempting full verification using callout\n");
if (host_checking && !host_checking_callout)
#ifdef SUPPORT_TLS
deliver_set_expansions(addr);
#endif
- verify_mode = is_recipient ? US"R" : US"S";
rc = do_callout(addr, host_list, &tf, callout, callout_overall,
callout_connect, options, se_mailfrom, pm_mailfrom);
- verify_mode = NULL;
}
}
else
if (rc == FAIL)
{
allok = FALSE;
- if (f != NULL)
+ if (f)
{
address_item *p = addr->parent;
respond_printf(f, "%s%s %s", ko_prefix,
- full_info? addr->address : address,
- address_test_mode? "is undeliverable" : "failed to verify");
+ full_info ? addr->address : address,
+ address_test_mode ? "is undeliverable" : "failed to verify");
if (!expn && admin_user)
{
if (addr->basic_errno > 0)
respond_printf(f, ": %s", strerror(addr->basic_errno));
- if (addr->message != NULL)
+ if (addr->message)
respond_printf(f, ": %s", addr->message);
}
/* Show parents iff doing full info */
- if (full_info) while (p != NULL)
+ if (full_info) while (p)
{
respond_printf(f, "%s\n <-- %s", cr, p->address);
p = p->parent;
cancel_cutthrough_connection("routing hard fail");
if (!full_info)
- {
+ {
yield = copy_error(vaddr, addr, FAIL);
goto out;
- }
- else yield = FAIL;
+ }
+ yield = FAIL;
}
/* Soft failure */
else if (rc == DEFER)
{
allok = FALSE;
- if (f != NULL)
+ if (f)
{
address_item *p = addr->parent;
respond_printf(f, "%s%s cannot be resolved at this time", ko_prefix,
{
if (addr->basic_errno > 0)
respond_printf(f, ": %s", strerror(addr->basic_errno));
- if (addr->message != NULL)
+ if (addr->message)
respond_printf(f, ": %s", addr->message);
else if (addr->basic_errno <= 0)
respond_printf(f, ": unknown error");
/* Show parents iff doing full info */
- if (full_info) while (p != NULL)
+ if (full_info) while (p)
{
respond_printf(f, "%s\n <-- %s", cr, p->address);
p = p->parent;
yield = copy_error(vaddr, addr, DEFER);
goto out;
}
- else if (yield == OK) yield = DEFER;
+ if (yield == OK) yield = DEFER;
}
/* If we are handling EXPN, we do not want to continue to route beyond
else if (expn)
{
uschar *ok_prefix = US"250-";
- if (addr_new == NULL)
- {
- if (addr_local == NULL && addr_remote == NULL)
+
+ if (!addr_new)
+ if (!addr_local && !addr_remote)
respond_printf(f, "250 mail to <%s> is discarded\r\n", address);
else
respond_printf(f, "250 <%s>\r\n", address);
- }
- else while (addr_new != NULL)
+
+ else do
{
address_item *addr2 = addr_new;
addr_new = addr2->next;
- if (addr_new == NULL) ok_prefix = US"250 ";
+ if (!addr_new) ok_prefix = US"250 ";
respond_printf(f, "%s<%s>\r\n", ok_prefix, addr2->address);
- }
+ } while (addr_new);
yield = OK;
goto out;
}
just a single new address as a special case, and continues on to verify the
generated address. */
- if (!full_info && /* Stop if short info wanted AND */
- (((addr_new == NULL || /* No new address OR */
- addr_new->next != NULL || /* More than one new address OR */
- testflag(addr_new, af_pfr))) /* New address is pfr */
- || /* OR */
- (addr_new != NULL && /* At least one new address AND */
- success_on_redirect))) /* success_on_redirect is set */
+ if ( !full_info /* Stop if short info wanted AND */
+ && ( ( !addr_new /* No new address OR */
+ || addr_new->next /* More than one new address OR */
+ || testflag(addr_new, af_pfr) /* New address is pfr */
+ )
+ || /* OR */
+ ( addr_new /* At least one new address AND */
+ && success_on_redirect /* success_on_redirect is set */
+ ) )
+ )
{
- if (f != NULL) fprintf(f, "%s %s\n", address,
- address_test_mode? "is deliverable" : "verified");
+ if (f) fprintf(f, "%s %s\n",
+ address, address_test_mode ? "is deliverable" : "verified");
/* If we have carried on to verify a child address, we want the value
of $address_data to be that of the child */
or autoreplies, and there were no errors or deferments, the message is to be
discarded, usually because of the use of :blackhole: in an alias file. */
-if (allok && addr_local == NULL && addr_remote == NULL)
+if (allok && !addr_local && !addr_remote)
{
fprintf(f, "mail to %s is discarded\n", address);
goto out;
the -bv or -bt case). */
out:
+verify_mode = NULL;
tls_modify_variables(&tls_in);
return yield;