* 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"
(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,
(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
#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
(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) },
{ "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
};
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 */
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 */
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 */
#endif
#ifndef DISABLE_DKIM
,NULL, /* dkim_canon */
NULL, /* dkim_sign_headers */
NULL /* dkim_strict */
#endif
+#ifdef EXPERIMENTAL_TPDA
+ ,NULL /* tpda_host_defer_action */
+#endif
};
+#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 *
*************************************************/
FALSE);
return DEFER;
}
-
+
return OK;
}
BOOL esmtp = TRUE;
BOOL pending_MAIL;
BOOL pass_message = FALSE;
-#ifdef EXPERIMENTAL_PRDR
+#ifndef DISABLE_PRDR
BOOL prdr_offered = FALSE;
BOOL prdr_active;
#endif
/* 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
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) &&
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
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;
}
}
}
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 &&
while (*p) p++;
}
-#ifdef EXPERIMENTAL_PRDR
+#ifndef DISABLE_PRDR
prdr_active = FALSE;
if (prdr_offered)
{
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
/* 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;
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)
{
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",
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);
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
{
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)
}
}
-#ifdef EXPERIMENTAL_PRDR
+#ifndef DISABLE_PRDR
if (prdr_active)
{
/* PRDR - get the final, overall response. For any non-success
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)
#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,
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;
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
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
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
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
}
return TRUE; /* Each address has its status */
}
+/* vi: aw ai sw=2
+*/
/* End of transport/smtp.c */