-TSTATE
-TSTRING_LIST
-TSTRING_TABLE
--TSUMMARY_CLASS
-TSYS_EXITS_DETAIL
-TTLSMGR_SCACHE
-TTLSP_STATE
-TTLS_SESS_STATE
-TTLS_TICKET_KEY
-TTLS_TLSA
+-TTLS_USAGE
-TTLS_VINFO
-TTLScontext_t
-TTOK822
postmap/postmap.c.
Cleanup: don't use ssize_t for boolean result. File:
- global/smtp_stream.c. Memory leak: the Berkeley DB client
- leaked a small amount of memory asfter failing to open a
- table. File: util/dict_db.c.
+ global/smtp_stream.c.
Cleanup: memory leak caused by missing dbenv->close() call
after failing to open a Berkeley DB table. File: util/dict_db.c.
tls/tls_proxy_context_print.c, tls/tls_proxy_context_scan.c,
tls/tls_client.c, tls/tls_server.c, smtpd/smtpd.c,
posttls-finger/posttls-finger.c.
+
+ Cleanup: vstream_memopen() flags handling. File:
+ util/vstream.c.
+
+ Cleanup: the SMTP client now uses 'attr_print_plain'
+ serialization and 'attr_scan_plain' deserialization for
+ connection cache lookup keys, which now contain a serialized
+ version of the TLS context. File: smtp/smtp_session.c.
+
+20181117
+
+ The Postfix SMTP client now logs whether an SMTP-over-TLS
+ connection is newly established ("TLS connection established")
+ or whether the connection is reused ("TLS connection reused").
+ Files: smtp/smtp.h, smtp/smtp_proto.c, smtp/smtp_session.c.
+
+20181118
+
+ Cleanup, no behavior change: updated comments concerning
+ connection reuse, and updated some identifiers to reflect
+ current reality. Files: smtp_reuse.c, smtp_key.c, smtp_proto.c,
+ smtp_tls_policy.c, smtp.h, smtp_connect.c.
+
* TLS_README: TLS Encryption and authentication
* FORWARD_SECRECY_README: TLS Forward Secrecy
* IPV6_README: IP Version 6 Support
- * IPV6_README: IP Version 6 Support
* SMTPUTF8_README: SMTPUTF8 Support
* COMPATIBILITY_README: Backwards-Compatibility Safety Net
* INSTALL: Installation from source code
(No client certificate requested)
TLS 1.3 examples. Some of the new attributes may not appear when not
- applicable or not available in an older versions of the OpenSSL library.
+ applicable or not available in older versions of the OpenSSL library.
Received: from localhost (localhost [127.0.0.1])
(using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256
</blockquote>
<p> TLS 1.3 examples. Some of the new attributes may not appear when not
-applicable or not available in an older versions of the OpenSSL library. </p>
+applicable or not available in older versions of the OpenSSL library. </p>
<blockquote>
<pre>
<li> <a href="IPV6_README.html"> IP Version 6 Support </a>
-<li> <a href="IPV6_README.html"> IP Version 6 Support </a>
-
<li> <a href="SMTPUTF8_README.html"> SMTPUTF8 Support </a>
<li> <a href="COMPATIBILITY_README.html"> Backwards-Compatibility Safety Net</a>
</blockquote>
<p> TLS 1.3 examples. Some of the new attributes may not appear when not
-applicable or not available in an older versions of the OpenSSL library. </p>
+applicable or not available in older versions of the OpenSSL library. </p>
<blockquote>
<pre>
* Patches change both the patchlevel and the release date. Snapshots have no
* patchlevel; they change the release date only.
*/
-#define MAIL_RELEASE_DATE "20181117"
+#define MAIL_RELEASE_DATE "20181118"
#define MAIL_VERSION_NUMBER "3.4"
#ifdef SNAPSHOT
} SMTP_STATE;
/*
- * TODO: use the new SMTP_ITER name space.
+ * Primitives to enable/disable/test connection caching and reuse based on
+ * the delivery request next-hop destination (i.e. not smtp_fallback_relay).
+ *
+ * Connection cache lookup by the request next-hop destination allows a reuse
+ * request to skip over bad hosts, and may result in a connection to a
+ * fall-back relay. Once we have found a 'good' host for a request next-hop,
+ * clear the request next-hop destination, to avoid caching less-preferred
+ * connections under that same request next-hop.
*/
-#define SET_NEXTHOP_STATE(state, nexthop) { \
+#define SET_SCACHE_REQUEST_NEXTHOP(state, nexthop) do { \
vstring_strcpy((state)->iterator->request_nexthop, nexthop); \
- }
+ } while (0)
-#define FREE_NEXTHOP_STATE(state) { \
+#define CLEAR_SCACHE_REQUEST_NEXTHOP(state) do { \
STR((state)->iterator->request_nexthop)[0] = 0; \
- }
+ } while (0)
-#define HAVE_NEXTHOP_STATE(state) (STR((state)->iterator->request_nexthop)[0] != 0)
+#define HAVE_SCACHE_REQUEST_NEXTHOP(state) \
+ (STR((state)->iterator->request_nexthop)[0] != 0)
/*
#define SMTP_FEATURE_EARLY_TLS_MAIL_REPLY (1<<19) /* CVE-2009-3555 */
#define SMTP_FEATURE_XFORWARD_IDENT (1<<20)
#define SMTP_FEATURE_SMTPUTF8 (1<<21) /* RFC 6531 */
+#define SMTP_FEATURE_FROM_PROXY (1<<22) /* proxied connection */
/*
* Features that passivate under the endpoint.
#define SMTP_KEY_FLAG_SERVICE (1<<0) /* service name */
#define SMTP_KEY_FLAG_SENDER (1<<1) /* sender address */
#define SMTP_KEY_FLAG_REQ_NEXTHOP (1<<2) /* request nexthop */
-#define SMTP_KEY_FLAG_NEXTHOP (1<<3) /* current nexthop */
+#define SMTP_KEY_FLAG_CUR_NEXTHOP (1<<3) /* current nexthop */
#define SMTP_KEY_FLAG_HOSTNAME (1<<4) /* remote host name */
#define SMTP_KEY_FLAG_ADDR (1<<5) /* remote address */
#define SMTP_KEY_FLAG_PORT (1<<6) /* remote port */
#define SMTP_KEY_MASK_ALL \
(SMTP_KEY_FLAG_SERVICE | SMTP_KEY_FLAG_SENDER | \
SMTP_KEY_FLAG_REQ_NEXTHOP | \
- SMTP_KEY_FLAG_NEXTHOP | SMTP_KEY_FLAG_HOSTNAME | \
+ SMTP_KEY_FLAG_CUR_NEXTHOP | SMTP_KEY_FLAG_HOSTNAME | \
SMTP_KEY_FLAG_ADDR | SMTP_KEY_FLAG_PORT | SMTP_KEY_FLAG_TLS_LEVEL)
/*
((var_smtp_sender_auth && *var_smtp_sasl_passwd) ? \
SMTP_KEY_FLAG_SENDER : 0)
-#define COND_SASL_SMTP_KEY_FLAG_NEXTHOP \
- (*var_smtp_sasl_passwd ? SMTP_KEY_FLAG_NEXTHOP : 0)
+#define COND_SASL_SMTP_KEY_FLAG_CUR_NEXTHOP \
+ (*var_smtp_sasl_passwd ? SMTP_KEY_FLAG_CUR_NEXTHOP : 0)
#ifdef USE_TLS
-#define COND_TLS_SMTP_KEY_FLAG_NEXTHOP \
- (TLS_MUST_MATCH(state->tls->level) ? SMTP_KEY_FLAG_NEXTHOP : 0)
+#define COND_TLS_SMTP_KEY_FLAG_CUR_NEXTHOP \
+ (TLS_MUST_MATCH(state->tls->level) ? SMTP_KEY_FLAG_CUR_NEXTHOP : 0)
#else
-#define COND_TLS_SMTP_KEY_FLAG_NEXTHOP \
+#define COND_TLS_SMTP_KEY_FLAG_CUR_NEXTHOP \
(0)
#endif
(*var_smtp_sasl_passwd ? SMTP_KEY_FLAG_HOSTNAME : 0)
/*
- * Connection-cache destination lookup key. The SENDER attribute is a proxy
- * for sender-dependent SASL credentials (or absence thereof), and prevents
- * false connection sharing when different SASL credentials may be required
- * for different deliveries to the same domain and port. The SERVICE
+ * Connection-cache destination lookup key, based on the delivery request
+ * nexthop. The SENDER attribute is a proxy for sender-dependent SASL
+ * credentials (or absence thereof), and prevents false connection sharing
+ * when different SASL credentials may be required for different deliveries
+ * to the same domain and port. Likewise, the delivery request nexthop
+ * (REQ_NEXTHOP) prevents false sharing of TLS identities (the destination
+ * key links only to appropriate endpoint lookup keys). The SERVICE
* attribute is a proxy for all request-independent configuration details.
*/
#define SMTP_KEY_MASK_SCACHE_DEST_LABEL \
| SMTP_KEY_FLAG_REQ_NEXTHOP)
/*
- * Connection-cache endpoint lookup key. The SENDER, NEXTHOP, and HOSTNAME
- * attributes are proxies for SASL credentials (or absence thereof), and
- * prevent false connection sharing when different SASL credentials may be
- * required for different deliveries to the same IP address and port.
+ * Connection-cache endpoint lookup key. The SENDER, CUR_NEXTHOP, HOSTNAME,
+ * PORT and TLS_LEVEL attributes are proxies for SASL credentials and TLS
+ * authentication (or absence thereof), and prevent false connection sharing
+ * when different SASL credentials or TLS identities may be required for
+ * different deliveries to the same IP address and port. The SERVICE
+ * attribute is a proxy for all request-independent configuration details.
*/
#define SMTP_KEY_MASK_SCACHE_ENDP_LABEL \
(SMTP_KEY_FLAG_SERVICE | COND_SASL_SMTP_KEY_FLAG_SENDER \
- | COND_SASL_SMTP_KEY_FLAG_NEXTHOP | COND_SASL_SMTP_KEY_FLAG_HOSTNAME \
- | COND_TLS_SMTP_KEY_FLAG_NEXTHOP | SMTP_KEY_FLAG_ADDR | \
+ | COND_SASL_SMTP_KEY_FLAG_CUR_NEXTHOP \
+ | COND_SASL_SMTP_KEY_FLAG_HOSTNAME \
+ | COND_TLS_SMTP_KEY_FLAG_CUR_NEXTHOP | SMTP_KEY_FLAG_ADDR | \
SMTP_KEY_FLAG_PORT | SMTP_KEY_FLAG_TLS_LEVEL)
/*
/* 111 8th Avenue
/* New York, NY 10011, USA
/*
-/* Wietse Venema
-/* Google, Inc.
-/* 111 8th Avenue
-/* New York, NY 10011, USA
-/*
/* TLS support originally by:
/* Lutz Jaenicke
/* BTU Cottbus
state->session = 0;
/*
- * If this session was good, reset the logical next-hop state, so that we
- * won't cache connections to alternate servers under the logical
- * next-hop destination. Otherwise we could end up skipping over the
- * available and more preferred servers.
+ * If this session was good, reset the logical next-hop destination, so
+ * that we won't cache connections to less-preferred servers under the
+ * logical next-hop destination. Otherwise we could end up skipping over
+ * the available and more-preferred servers.
*/
- if (HAVE_NEXTHOP_STATE(state) && !throttled)
- FREE_NEXTHOP_STATE(state);
+ if (HAVE_SCACHE_REQUEST_NEXTHOP(state) && !throttled)
+ CLEAR_SCACHE_REQUEST_NEXTHOP(state);
/*
* Clean up the lists with todo and dropped recipients.
#endif
SMTP_ITER_SAVE_DEST(state->iterator);
if (*addr_list && SMTP_RCPT_LEFT(state) > 0
- && HAVE_NEXTHOP_STATE(state)
+ && HAVE_SCACHE_REQUEST_NEXTHOP(state)
&& (session = smtp_reuse_nexthop(state, SMTP_KEY_MASK_SCACHE_DEST_LABEL)) != 0) {
session_count = 1;
smtp_update_addr_list(addr_list, STR(iter->addr), session_count);
if (addr_list && (state->misc_flags & SMTP_MISC_FLAG_FIRST_NEXTHOP)) {
smtp_cache_policy(state, domain);
if (state->misc_flags & SMTP_MISC_FLAG_CONN_CACHE_MASK)
- SET_NEXTHOP_STATE(state, dest);
+ SET_SCACHE_REQUEST_NEXTHOP(state, dest);
}
/*
/*
* Cleanup.
*/
- if (HAVE_NEXTHOP_STATE(state))
- FREE_NEXTHOP_STATE(state);
+ if (HAVE_SCACHE_REQUEST_NEXTHOP(state))
+ CLEAR_SCACHE_REQUEST_NEXTHOP(state);
argv_free(sites);
}
/* .IP SMTP_KEY_FLAG_REQ_NEXTHOP
/* The request nexthop destination. This is a proxy for
/* destination-dependent, but host-independent context.
-/* .IP SMTP_KEY_FLAG_NEXTHOP
+/* .IP SMTP_KEY_FLAG_CUR_NEXTHOP
/* The current iterator's nexthop destination (request nexthop
/* or fallback nexthop, including optional [] and :port). This
/* is the form that users specify in a SASL or TLS lookup
*/
if (flags & SMTP_KEY_FLAG_REQ_NEXTHOP)
smtp_key_append_str(buffer, STR(iter->request_nexthop), delim_na);
- if (flags & SMTP_KEY_FLAG_NEXTHOP)
+ if (flags & SMTP_KEY_FLAG_CUR_NEXTHOP)
smtp_key_append_str(buffer, STR(iter->dest), delim_na);
/*
*/
serverid = vstring_alloc(10);
smtp_key_prefix(serverid, "&", state->iterator, SMTP_KEY_FLAG_SERVICE
- | SMTP_KEY_FLAG_NEXTHOP /* With port */
+ | SMTP_KEY_FLAG_CUR_NEXTHOP /* With port */
| SMTP_KEY_FLAG_HOSTNAME
| SMTP_KEY_FLAG_ADDR);
* context attributes.
*/
session->tls_context = tls_proxy_context_receive(session->stream);
+ if (session->tls_context) {
+ session->features |= SMTP_FEATURE_FROM_PROXY;
+ tls_log_summary(TLS_ROLE_CLIENT, TLS_USAGE_NEW,
+ session->tls_context);
+ }
}
} else { /* state->tls->conn_reuse */
/* This module implements the SMTP client specific interface to
/* the generic session cache infrastructure.
/*
-/* A cached connection is closed when the TLS policy requires
-/* that TLS is enabled.
+/* The caller needs to include additional state in _key_flags
+/* to avoid false sharing of SASL-authenticated or TLS-authenticated
+/* sessions.
/*
/* smtp_save_session() stores the current session under the
-/* next-hop logical destination (if available) and under the
-/* remote server address. The SMTP_SESSION object is destroyed.
+/* delivery request next-hop logical destination (if applicable)
+/* and under the remote server address. The SMTP_SESSION object
+/* is destroyed.
/*
-/* smtp_reuse_nexthop() looks up a cached session by its logical
-/* destination, and verifies that the session is still alive.
-/* The restored session information includes the "best MX" bit
-/* and overrides the iterator dest, host and addr fields.
-/* The result is null in case of failure.
+/* smtp_reuse_nexthop() looks up a cached session by its
+/* delivery request next-hop destination, and verifies that
+/* the session is still alive. The restored session information
+/* includes the "best MX" bit and overrides the iterator dest,
+/* host and addr fields. The result is null in case of failure.
/*
/* smtp_reuse_addr() looks up a cached session by its server
/* address, and verifies that the session is still alive.
/* The restored session information does not include the "best
/* MX" bit, and does not override the iterator dest, host and
-/* addr fields.
-/* This function is a NOOP for TLS levels stronger than "encrypt",
-/* because stronger levels require certificate checks,
-/* The result is null in case of failure.
+/* addr fields. The result is null in case of failure.
/*
/* Arguments:
/* .IP state
int fd;
/*
- * Encode the next-hop logical destination, if available. Reuse storage
- * that is also used for cache lookup queries.
+ * Encode the delivery request next-hop destination, if applicable. Reuse
+ * storage that is also used for cache lookup queries.
+ *
+ * HAVE_SCACHE_REQUEST_NEXTHOP() controls whether or not to reuse or cache a
+ * connection by its delivery request next-hop destination. The idea is
+ * 1) to allow a reuse request to skip over bad hosts, and 2) to avoid
+ * caching a less-preferred connection when a more-preferred connection
+ * was possible.
*/
- if (HAVE_NEXTHOP_STATE(state))
+ if (HAVE_SCACHE_REQUEST_NEXTHOP(state))
smtp_key_prefix(state->dest_label, SMTP_REUSE_KEY_DELIM_NA,
state->iterator, name_key_flags);
state->session = 0;
/*
- * Save the session under the next-hop name, if available.
+ * Save the session under the delivery request next-hop name, if
+ * applicable.
*
* XXX The logical to physical binding can be kept for as long as the DNS
* allows us to (but that could result in the caching of lots of unused
* bindings). The session should be idle for no more than 30 seconds or
* so.
*/
- if (HAVE_NEXTHOP_STATE(state))
- scache_save_dest(smtp_scache, var_smtp_cache_conn, STR(state->dest_label),
- STR(state->dest_prop), STR(state->endp_label));
+ if (HAVE_SCACHE_REQUEST_NEXTHOP(state))
+ scache_save_dest(smtp_scache, var_smtp_cache_conn,
+ STR(state->dest_label), STR(state->dest_prop),
+ STR(state->endp_label));
/*
* Save every good session under its physical endpoint address.
SMTP_ITERATOR *iter = state->iterator;
SMTP_SESSION *session;
- /*
- * Obsolete.
- */
-#ifdef notdef
- if (state->tls->level > TLS_LEV_NONE)
- msg_panic("%s: unexpected plain-text cached session to %s",
- myname, label);
-#endif
-
/*
* Re-activate the SMTP_SESSION object.
*/
SMTP_SESSION *session;
int fd;
- /*
- * Obsolete: the TLS level and nexthop are part of the connection cache
- * key. TODO(tlsproxy) is the port included in the nexthop?
- */
-#ifdef notdef
- if (state->tls->level > TLS_LEV_NONE)
- return (0);
-#endif
-
/*
* Look up the session by its logical name.
*/
int fd;
/*
- * Allow address-based reuse only for security levels that don't require
- * certificate checks. Not to be confused with a similar constraint in
- * the destination label smtp_key pattern, which conditionally includes
- * the nexthop to prevent the reuse of an authenticated connection to the
- * same MX hostname and the same IP address, but for a different nexthop
- * destination (just in case we start to send SNI with the nexthop, and
- * forget to update connection cache lookup key patterns).
+ * Address-based reuse is safe for security levels that require TLS
+ * certificate checks, as long as the current nexhop is included in the
+ * cache lookup key (COND_TLS_SMTP_KEY_FLAG_CUR_NEXTHOP). This is
+ * sufficient to prevent the reuse of a TLS-authenticated connection to
+ * the same MX hostname, IP address, and port, but for a different
+ * current nexthop destination with a different TLS policy.
*/
-#ifdef USE_TLS
- if (TLS_MUST_MATCH(state->tls->level))
- return (0);
-#endif
/*
* Look up the session by its IP address. This means that we have no
#include <debug_peer.h>
#include <mail_params.h>
+/* TLS Library. */
+
+#include <tls_proxy.h>
+
/* Application-specific. */
#include "smtp.h"
#include "smtp_sasl.h"
+ /*
+ * Local, because these are meaningful only for code in this file.
+ */
+#define SESS_ATTR_DEST "destination"
+#define SESS_ATTR_HOST "host_name"
+#define SESS_ATTR_ADDR "host_addr"
+#define SESS_ATTR_DEST_FEATURES "destination_features"
+
+#define SESS_ATTR_TLS_LEVEL "tls_level"
+#define SESS_ATTR_REUSE_COUNT "reuse_count"
+#define SESS_ATTR_ENDP_FEATURES "endpoint_features"
+#define SESS_ATTR_EXPIRE_TIME "expire_time"
+
/* smtp_session_alloc - allocate and initialize SMTP_SESSION structure */
SMTP_SESSION *smtp_session_alloc(VSTREAM *stream, SMTP_ITERATOR *iter,
vstream_fflush(session->stream);
}
if (session->tls_context) {
- if (session->state->tls->conn_reuse)
+ if (session->features &
+ (SMTP_FEATURE_FROM_CACHE | SMTP_FEATURE_FROM_PROXY))
tls_proxy_context_free(session->tls_context);
else
tls_client_stop(smtp_tls_ctx, session->stream,
VSTRING *endp_prop)
{
SMTP_ITERATOR *iter = session->iterator;
+ VSTREAM *mp;
int fd;
/*
* destination (this information is needed for loop handling in
* smtp_proto()).
*
- * XXX It would be nice to have a VSTRING to VSTREAM adapter so that we can
- * serialize the properties with attr_print() instead of using ad-hoc,
- * non-reusable, code and hard-coded format strings.
- *
- * TODO(tlsproxy): save TLS_SESS_STATE information so that we can restore
- * TLS session properties.
- *
* TODO: save SASL username and password information so that we can
* correctly save a reused authenticated connection.
*
- * Note: the TLS level field is always present.
+ * These memory writes should never fail.
*/
- vstring_sprintf(dest_prop, "%s\n%s\n%s\n%u\n%u",
- STR(iter->dest), STR(iter->host), STR(iter->addr),
-#ifdef USE_TLS
- iter->parent->tls->level,
-#else
- 0,
-#endif
- session->features & SMTP_FEATURE_DESTINATION_MASK);
+ if ((mp = vstream_memopen(dest_prop, O_WRONLY)) == 0
+ || attr_print_plain(mp, ATTR_FLAG_NONE,
+ SEND_ATTR_STR(SESS_ATTR_DEST, STR(iter->dest)),
+ SEND_ATTR_STR(SESS_ATTR_HOST, STR(iter->host)),
+ SEND_ATTR_STR(SESS_ATTR_ADDR, STR(iter->addr)),
+ SEND_ATTR_INT(SESS_ATTR_DEST_FEATURES,
+ session->features & SMTP_FEATURE_DESTINATION_MASK),
+ ATTR_TYPE_END) != 0
+ || vstream_fclose(mp) != 0)
+ msg_fatal("smtp_session_passivate: can't save dest properties: %m");
/*
* Encode the physical endpoint properties: all the session properties
* except for "session from cache", "best MX", or "RSET failure".
+ * Plus the TLS level, reuse count, and connection expiration time.
*
- * XXX It would be nice to have a VSTRING to VSTREAM adapter so that we can
- * serialize the properties with attr_print() instead of using obscure
- * hard-coded format strings.
+ * XXX Should also record how many non-delivering mail transactions there
+ * were during this session, and perhaps other statistics, so that we
+ * don't reuse a session too much.
*
- * XXX Should also record an absolute time when a session must be closed,
- * how many non-delivering mail transactions there were during this
- * session, and perhaps other statistics, so that we don't reuse a
- * session too much.
+ * TODO: passivate SASL username and password information so that we can
+ * correctly save a reused authenticated connection.
*
- * XXX Be sure to use unsigned types in the format string. Sign characters
- * would be rejected by the alldig() test on the reading end.
+ * These memory writes should never fail.
*/
- vstring_sprintf(endp_prop, "%u\n%u\n%lu",
- session->reuse_count,
- session->features & SMTP_FEATURE_ENDPOINT_MASK,
- (long) session->expire_time);
+ if ((mp = vstream_memopen(endp_prop, O_WRONLY)) == 0
+ || attr_print_plain(mp, ATTR_FLAG_NONE,
+ SEND_ATTR_INT(SESS_ATTR_TLS_LEVEL,
+ session->state->tls->level),
+ SEND_ATTR_INT(SESS_ATTR_REUSE_COUNT,
+ session->reuse_count),
+ SEND_ATTR_INT(SESS_ATTR_ENDP_FEATURES,
+ session->features & SMTP_FEATURE_ENDPOINT_MASK),
+ SEND_ATTR_LONG(SESS_ATTR_EXPIRE_TIME,
+ (long) session->expire_time),
+ ATTR_TYPE_END) != 0
/*
- * Append the passivated SASL attributes.
+ * Append the passivated TLS context. These memory writes should never
+ * fail.
*/
-#ifdef notdef
- if (smtp_sasl_enable)
- smtp_sasl_passivate(endp_prop, session);
+#ifdef USE_TLS
+ || (session->tls_context
+ && attr_print_plain(mp, ATTR_FLAG_NONE,
+ SEND_ATTR_FUNC(tls_proxy_context_print,
+ (void *) session->tls_context),
+ ATTR_TYPE_END) != 0)
#endif
+ || vstream_fclose(mp) != 0)
+ msg_fatal("smtp_session_passivate: cannot save TLS context: %m");
/*
* Salvage the underlying file descriptor, and destroy the session
VSTRING *endp_prop)
{
const char *myname = "smtp_session_activate";
+ VSTREAM *mp;
SMTP_SESSION *session;
- char *dest_props;
- char *endp_props;
- const char *prop;
- const char *dest;
- const char *host;
- const char *addr;
- unsigned features; /* server features */
- time_t expire_time; /* session re-use expiration time */
- unsigned reuse_count; /* # times reused */
+ int endp_features; /* server features */
+ int dest_features; /* server features */
+ long expire_time; /* session re-use expiration time */
+ int reuse_count; /* # times reused */
+ TLS_SESS_STATE *tls_context = 0;
#ifdef USE_TLS
SMTP_TLS_POLICY *tls = iter->parent->tls;
#endif
+#define SMTP_SESSION_ACTIVATE_ERR_RETURN() do { \
+ if (tls_context) \
+ tls_proxy_context_free(tls_context); \
+ return (0); \
+ } while (0)
+
/*
- * XXX it would be nice to have a VSTRING to VSTREAM adapter so that we
- * can de-serialize the properties with attr_scan(), instead of using
- * ad-hoc, non-reusable code.
- *
- * XXX As a preliminary solution we use mystrtok(), but that function is not
- * suitable for zero-length fields.
+ * Sanity check: if TLS is required, the cached properties must contain a
+ * TLS context.
*/
- endp_props = STR(endp_prop);
- if ((prop = mystrtok(&endp_props, "\n")) == 0 || !alldig(prop)) {
- msg_warn("%s: bad cached session reuse count property", myname);
- return (0);
- }
- reuse_count = atoi(prop);
- if ((prop = mystrtok(&endp_props, "\n")) == 0 || !alldig(prop)) {
- msg_warn("%s: bad cached session features property", myname);
- return (0);
- }
- features = atoi(prop);
- if ((prop = mystrtok(&endp_props, "\n")) == 0 || !alldig(prop)) {
- msg_warn("%s: bad cached session expiration time property", myname);
- return (0);
- }
-#ifdef MISSING_STRTOUL
- expire_time = strtol(prop, 0, 10);
-#else
- expire_time = strtoul(prop, 0, 10);
+ if ((mp = vstream_memopen(endp_prop, O_RDONLY)) == 0
+ || attr_scan_plain(mp, ATTR_FLAG_NONE,
+ RECV_ATTR_INT(SESS_ATTR_TLS_LEVEL,
+ &tls->level),
+ RECV_ATTR_INT(SESS_ATTR_REUSE_COUNT,
+ &reuse_count),
+ RECV_ATTR_INT(SESS_ATTR_ENDP_FEATURES,
+ &endp_features),
+ RECV_ATTR_LONG(SESS_ATTR_EXPIRE_TIME,
+ &expire_time),
+ ATTR_TYPE_END) != 4
+#ifdef USE_TLS
+ || ((tls->level > TLS_LEV_MAY
+ || (tls->level == TLS_LEV_MAY && vstream_peek(mp) > 0))
+ && attr_scan_plain(mp, ATTR_FLAG_NONE,
+ RECV_ATTR_FUNC(tls_proxy_context_scan,
+ (void *) &tls_context),
+ ATTR_TYPE_END) != 1)
#endif
+ || vstream_fclose(mp) != 0) {
+ msg_warn("smtp_session_activate: bad cached endp properties");
+ SMTP_SESSION_ACTIVATE_ERR_RETURN();
+ }
/*
* Clobber the iterator's current nexthop, host and address fields with
* correctly save a reused authenticated connection.
*/
if (dest_prop && VSTRING_LEN(dest_prop)) {
- dest_props = STR(dest_prop);
- if ((dest = mystrtok(&dest_props, "\n")) == 0) {
- msg_warn("%s: missing cached session destination property", myname);
- return (0);
- }
- if ((host = mystrtok(&dest_props, "\n")) == 0) {
- msg_warn("%s: missing cached session hostname property", myname);
- return (0);
- }
- if ((addr = mystrtok(&dest_props, "\n")) == 0) {
- msg_warn("%s: missing cached session address property", myname);
- return (0);
- }
- /* Note: the TLS level field is always present. */
- if ((prop = mystrtok(&dest_props, "\n")) == 0 || !alldig(prop)) {
- msg_warn("%s: bad cached destination TLS level property", myname);
- return (0);
+ if ((mp = vstream_memopen(dest_prop, O_RDONLY)) == 0
+ || attr_scan_plain(mp, ATTR_FLAG_NONE,
+ RECV_ATTR_STR(SESS_ATTR_DEST, iter->dest),
+ RECV_ATTR_STR(SESS_ATTR_HOST, iter->host),
+ RECV_ATTR_STR(SESS_ATTR_ADDR, iter->addr),
+ RECV_ATTR_INT(SESS_ATTR_DEST_FEATURES,
+ &dest_features),
+ ATTR_TYPE_END) != 4
+ || vstream_fclose(mp) != 0) {
+ msg_warn("smtp_session_passivate: bad cached dest properties");
+ SMTP_SESSION_ACTIVATE_ERR_RETURN();
}
+ } else {
+ dest_features = 0;
+ }
#ifdef USE_TLS
- tls->level = atoi(prop);
- if (msg_verbose)
- msg_info("%s: tls_level=%d", myname, tls->level);
+ if (msg_verbose)
+ msg_info("%s: tls_level=%d", myname, tls->level);
#endif
- if ((prop = mystrtok(&dest_props, "\n")) == 0 || !alldig(prop)) {
- msg_warn("%s: bad cached destination features property", myname);
- return (0);
- }
- features |= atoi(prop);
- SMTP_ITER_CLOBBER(iter, dest, host, addr);
- }
/*
* Allright, bundle up what we have sofar.
session = smtp_session_alloc(vstream_fdopen(fd, O_RDWR), iter,
(time_t) 0, NO_FLAGS);
- session->features = (features | SMTP_FEATURE_FROM_CACHE);
+ session->features =
+ (endp_features | dest_features | SMTP_FEATURE_FROM_CACHE);
+ session->tls_context = tls_context;
CACHE_THIS_SESSION_UNTIL(expire_time);
session->reuse_count = ++reuse_count;
msg_info("%s: dest=%s host=%s addr=%s port=%u features=0x%x, "
"ttl=%ld, reuse=%d",
myname, STR(iter->dest), STR(iter->host),
- STR(iter->addr), ntohs(iter->port), features,
+ STR(iter->addr), ntohs(iter->port),
+ endp_features | dest_features,
(long) (expire_time - time((time_t *) 0)),
reuse_count);
- /*
- * Re-activate the SASL attributes.
- */
-#ifdef notdef
- if (smtp_sasl_enable && smtp_sasl_activate(session, endp_props) < 0) {
- vstream_fdclose(session->stream);
- session->stream = 0;
- smtp_session_free(session);
- return (0);
- }
+#if USE_TLS
+ if (tls_context)
+ tls_log_summary(TLS_ROLE_CLIENT, TLS_USAGE_USED,
+ session->tls_context);
#endif
return (session);
* values that also appear in other cache and table search keys.
*/
key = vstring_alloc(100);
- smtp_key_prefix(key, ":", iter, SMTP_KEY_FLAG_NEXTHOP
+ smtp_key_prefix(key, ":", iter, SMTP_KEY_FLAG_CUR_NEXTHOP
| SMTP_KEY_FLAG_HOSTNAME
| SMTP_KEY_FLAG_PORT);
ctable_newcontext(policy_cache, (void *) iter);
#endif
/*-
- * Backwards compatibility with OpenSSL < 1.1.1a (or some later version).
+ * Backwards compatibility with OpenSSL < 1.1.1a.
*
- * The client-only interface SSL_get_server_tmp_key() is slated to be made to
- * work on both client and server, and renamed to SSL_get_peer_tmp_key(), with
- * the original name left behind as an alias. We use the new name when
- * available.
+ * In OpenSSL 1.1.1a the client-only interface SSL_get_server_tmp_key() was
+ * updated to work on both the client and the server, and was renamed to
+ * SSL_get_peer_tmp_key(), with the original name left behind as an alias. We
+ * use the new name when available.
*/
#if OPENSSL_VERSION_NUMBER < 0x1010101fUL
#undef SSL_get_signature_nid
/*
* TLS role, presently for logging.
*/
-typedef enum { TLS_ROLE_CLIENT, TLS_ROLE_SERVER, } TLS_ROLE;
+typedef enum {
+ TLS_ROLE_CLIENT, TLS_ROLE_SERVER,
+} TLS_ROLE;
-typedef enum { TLS_USAGE_NEW, TLS_USAGE_USED, } TLS_USAGE;
+typedef enum {
+ TLS_USAGE_NEW, TLS_USAGE_USED,
+} TLS_USAGE;
/*
* Names of valid tlsmgr(8) session caches.
&& !TLS_NEVER_SECURED(props->tls_level))
TLScontext->peer_status |= TLS_CERT_FLAG_SECURED;
+ /*
+ * With the handshake done, extract TLS 1.3 signature metadata.
+ */
tls_get_signature_params(TLScontext);
if (TLScontext->log_mask & TLS_LOG_SUMMARY)
/* TLS_USAGE usage;
/* TLS_SESS_STATE *TLScontext;
/*
+/* const char *tls_compile_version(void)
+/*
+/* const char *tls_run_version(void)
+/*
+/* const char **tls_pkey_algorithms(void)
+/*
/* .SH Internal functions
/* .nf
/* .na
/*
/* int tls_validate_digest(dgst)
/* const char *dgst;
-/*
-/* const char *tls_compile_version(void)
-/*
-/* const char *tls_run_version(void)
-/*
-/* const char **tls_pkey_algorithms(void)
/* DESCRIPTION
/* This module implements public and internal routines that
/* support the TLS client and server.
/* connections, or TLS_ROLE_SERVER for incoming server connections,
/* and the "usage" must be TLS_USAGE_NEW or TLS_USAGE_USED.
/*
+/* tls_compile_version() returns a text string description of
+/* the compile-time TLS library.
+/*
+/* tls_run_version() is just tls_compile_version() but with the runtime
+/* version instead of the compile-time version.
+/*
+/* tls_pkey_algorithms() returns a pointer to null-terminated
+/* array of string constants with the names of the supported
+/* public-key algorithms.
+/*
/* tls_alloc_app_context() creates an application context that
/* holds the SSL context for the application and related cached state.
/*
/*
/* tls_validate_digest() returns non-zero if the named digest
/* is usable and zero otherwise.
-/*
-/* tls_compile_version() returns a text string description of
-/* the compile-time TLS library.
-/*
-/* tls_run_version() is just tls_compile_version() but with the runtime
-/* version instead of the compile-time version.
-/*
-/* tls_pkey_algorithms() returns a pointer to null-terminated
-/* array of string constants with the names of the supported
-/* public-key algorithms.
/* LICENSE
/* .ad
/* .fi
stream->write_fn = 0;
stream->vstring = string;
memcpy(&stream->buf, &stream->vstring->vbuf, sizeof(stream->buf));
- stream->buf.flags |= (flags | VSTREAM_FLAG_MEMORY);
+ stream->buf.flags |= VSTREAM_FLAG_MEMORY;
switch (VSTREAM_ACC_MASK(flags)) {
case O_RDONLY:
stream->buf.flags |= VSTREAM_FLAG_READ;