From: Wietse Venema Date: Sat, 17 Nov 2018 05:00:00 +0000 (-0500) Subject: postfix-3.4-20181117-nonprod X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=refs%2Fheads%2F20181117-nonprod;p=thirdparty%2Fpostfix.git postfix-3.4-20181117-nonprod --- diff --git a/postfix/.indent.pro b/postfix/.indent.pro index 8f3031c89..b57603810 100644 --- a/postfix/.indent.pro +++ b/postfix/.indent.pro @@ -336,7 +336,6 @@ -TSTATE -TSTRING_LIST -TSTRING_TABLE --TSUMMARY_CLASS -TSYS_EXITS_DETAIL -TTLSMGR_SCACHE -TTLSP_STATE @@ -348,7 +347,6 @@ -TTLS_PKEYS -TTLS_PRNG_SEED_INFO -TTLS_PRNG_SRC --TTLS_ROLE -TTLS_SCACHE -TTLS_SCACHE_ENTRY -TTLS_SERVER_INIT_PROPS diff --git a/postfix/HISTORY b/postfix/HISTORY index 0ed7db882..feb8ea0d6 100644 --- a/postfix/HISTORY +++ b/postfix/HISTORY @@ -23794,3 +23794,13 @@ Apologies for any names omitted. 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. + +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. diff --git a/postfix/makedefs b/postfix/makedefs index c3efa42c6..049848e8b 100644 --- a/postfix/makedefs +++ b/postfix/makedefs @@ -880,7 +880,7 @@ CCARGS="$CCARGS -DSNAPSHOT" # Non-production: needs thorough testing, or major changes are still # needed before the code stabilizes. -#CCARGS="$CCARGS -DNONPROD" +CCARGS="$CCARGS -DNONPROD" # Workaround: prepend Postfix include files before other include files. CCARGS="-I. -I../../include $CCARGS" diff --git a/postfix/src/smtp/smtp.h b/postfix/src/smtp/smtp.h index 778a3d524..623633e14 100644 --- a/postfix/src/smtp/smtp.h +++ b/postfix/src/smtp/smtp.h @@ -229,6 +229,7 @@ typedef struct SMTP_STATE { #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. diff --git a/postfix/src/smtp/smtp_proto.c b/postfix/src/smtp/smtp_proto.c index 0169f1716..7f9a3a8cf 100644 --- a/postfix/src/smtp/smtp_proto.c +++ b/postfix/src/smtp/smtp_proto.c @@ -1018,6 +1018,11 @@ static int smtp_start_tls(SMTP_STATE *state) * 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 */ diff --git a/postfix/src/smtp/smtp_session.c b/postfix/src/smtp/smtp_session.c index 2b4ce8675..7ae9afd0c 100644 --- a/postfix/src/smtp/smtp_session.c +++ b/postfix/src/smtp/smtp_session.c @@ -113,11 +113,28 @@ #include #include +/* TLS Library. */ + +#include + /* 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, @@ -183,7 +200,8 @@ void smtp_session_free(SMTP_SESSION *session) 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, @@ -220,6 +238,7 @@ int smtp_session_passivate(SMTP_SESSION *session, VSTRING *dest_prop, VSTRING *endp_prop) { SMTP_ITERATOR *iter = session->iterator; + VSTREAM *mp; int fd; /* @@ -228,55 +247,61 @@ int smtp_session_passivate(SMTP_SESSION *session, VSTRING *dest_prop, * 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 @@ -297,50 +322,52 @@ SMTP_SESSION *smtp_session_activate(int fd, SMTP_ITERATOR *iter, 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 @@ -355,36 +382,25 @@ SMTP_SESSION *smtp_session_activate(int fd, SMTP_ITERATOR *iter, * 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. @@ -393,7 +409,9 @@ SMTP_SESSION *smtp_session_activate(int fd, SMTP_ITERATOR *iter, 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; @@ -401,20 +419,15 @@ SMTP_SESSION *smtp_session_activate(int fd, SMTP_ITERATOR *iter, 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); diff --git a/postfix/src/util/vstream.c b/postfix/src/util/vstream.c index 674e79604..7af288271 100644 --- a/postfix/src/util/vstream.c +++ b/postfix/src/util/vstream.c @@ -1714,7 +1714,7 @@ VSTREAM *vstream_memreopen(VSTREAM *stream, VSTRING *string, int flags) 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;