From 5c187bc356bc40e654434ef116f8444a01b3f9cc Mon Sep 17 00:00:00 2001 From: Wietse Venema Date: Sun, 18 Jan 2015 00:00:00 -0500 Subject: [PATCH] postfix-2.12-20150118 --- postfix/HISTORY | 110 ++++++++------- postfix/README_FILES/COMPATIBILITY_README | 4 +- postfix/WISHLIST | 6 + postfix/html/COMPATIBILITY_README.html | 4 +- postfix/proto/COMPATIBILITY_README.html | 4 +- postfix/src/global/mail_version.h | 2 +- postfix/src/posttls-finger/posttls-finger.c | 147 ++++++++++++-------- postfix/src/smtp/smtp_tls_policy.c | 5 +- postfix/src/smtpd/smtpd.c | 18 +++ postfix/src/tls/tls.h | 2 + postfix/src/tls/tls_client.c | 10 +- postfix/src/tls/tls_fprint.c | 2 +- 12 files changed, 194 insertions(+), 120 deletions(-) diff --git a/postfix/HISTORY b/postfix/HISTORY index 318c8c754..950281132 100644 --- a/postfix/HISTORY +++ b/postfix/HISTORY @@ -11196,7 +11196,7 @@ Apologies for any names omitted. in the anvil server, TLS request rate error message in the smtp server, and documentation, but no changes in code. Files: anvil/anvil.c, smtpd/smtpd.c. - + 20051013 Horror: some systems have basename() and dirname() and some @@ -19583,8 +19583,8 @@ Apologies for any names omitted. smtp/smtp.h, smtp/smtp_rcpt.c. Logging: the TLS client logged that an "Untrusted" TLS - connection was established instead of "Anonymous". - Viktor Dukhovni. File: tls/tls_client.c. + connection was established instead of "Anonymous". Viktor + Dukhovni. File: tls/tls_client.c. Documentation: new self-signed certificate example and updated private CA example. File: proto/TLS_README.html. @@ -19662,7 +19662,7 @@ Apologies for any names omitted. 20140323 Feature: initial merge of Debian-style dynamic linking. - Viktor Dukhovni. + Viktor Dukhovni. 20140406 @@ -19755,8 +19755,8 @@ Apologies for any names omitted. 20140508 Cleanup: dynamicmaps.cf is now installed into $daemon_directory - because the file is shared among Postfix instances just like - postfix-files and other files. Files: conf/dynamicmaps.cf, + because the file is shared among Postfix instances just + like postfix-files and other files. Files: conf/dynamicmaps.cf, Makefile.in, conf/postfix-files. Cleanup: INSTALL is now plain ASCII instead of README format, @@ -19807,11 +19807,11 @@ Apologies for any names omitted. Support for "make shared=yes" and "make dynamicmaps=yes". New plugin_directory parameter for the location of the dynamicmaps.cf file and for plugins with a relative pathname. - See RELEASE_NOTES and INSTALL for details. Files: - postfix.c, mail_params.[hc], dynamicmaps.c, mail_dict.c, - makedefs, postfix-files, dynamicmaps.cf, Makefile.in, - util/Makefile.in, global/Makefile.in, postlink, postconf.proto. - INSTALL.html, RELEASE_NOTES. + See RELEASE_NOTES and INSTALL for details. Files: postfix.c, + mail_params.[hc], dynamicmaps.c, mail_dict.c, makedefs, + postfix-files, dynamicmaps.cf, Makefile.in, util/Makefile.in, + global/Makefile.in, postlink, postconf.proto. INSTALL.html, + RELEASE_NOTES. 20140523 @@ -20243,9 +20243,9 @@ Apologies for any names omitted. Cleanup: change extract_addr() API to indicate that an address is parsed in SMTPUTF8 context. File: smtpd/smtpd.c. - Cleanup: shared-library build fixes. Viktor Dukhovni. - Files: makedefs, dns/Makefile.in, global/Makefile.in, - master/Makefile.in, tls/Makefile.in, util/Makefile.in. + Cleanup: shared-library build fixes. Viktor Dukhovni. Files: + makedefs, dns/Makefile.in, global/Makefile.in, master/Makefile.in, + tls/Makefile.in, util/Makefile.in. First general release with SMTPUTF8 support; see RELEASE_NOTES for an initial writeup. The last pre-SMTPUTF8 release is @@ -20317,8 +20317,8 @@ Apologies for any names omitted. 20140731 - Feature: the Postfix SMTP server now logs at the end of - a session how many times each SMTP command was successfully + Feature: the Postfix SMTP server now logs at the end of a + session how many times each SMTP command was successfully invoked, followed by the total number of invocations if it is different. File: smtpd/smtpd.c. @@ -20431,7 +20431,7 @@ Apologies for any names omitted. Cleanup: dict_db and dict_lmdb global settings. Files: global/mail_params.c, util/dict_open.c. - + Feature: unionmap, based on contribution by Roel van Meer. Files: mantools/postlink, postconf/postconf.c (manpage), proto/DATABASE_README.html, util/dict_open.c, util/dict_union.[hc]. @@ -20461,9 +20461,9 @@ Apologies for any names omitted. 20140927 - Cleanup: specify { name = value } in per-Milter settings, to support - space around the "=" or comma/space within the value. Files: - global/attr_over.[hc]. + Cleanup: specify { name = value } in per-Milter settings, + to support space around the "=" or comma/space within the + value. Files: global/attr_over.[hc]. Cleanup: "postconf -n" now only shows config_directory when an override is in effect (environment, -c or -o). @@ -20504,15 +20504,14 @@ Apologies for any names omitted. Cleanup: force LANG=C to prevent groff from outputting non-ASCII cruft into the HTML-ized manpages. Files: - html/Makefile.in, proto/Makefile.in, many HTML output - files. + html/Makefile.in, proto/Makefile.in, many HTML output files. 20140929 Cleanup: the table-driven code for per-Milter and per-policy - overrides now updates arbitrary variables, so that it can also - be used for, say, TLS policies. Files: global/attr_override.[hc], - smtpd/smtpd_check.c, milter/milter.c. + overrides now updates arbitrary variables, so that it can + also be used for, say, TLS policies. Files: + global/attr_override.[hc], smtpd/smtpd_check.c, milter/milter.c. Documentation: support for "{ argument with whitespace }" in master(5) and pipe(8). Files: proto/master, src/pipe/pipe.c. @@ -20524,12 +20523,12 @@ Apologies for any names omitted. 20141001 - Safety: backwards-compatibility safety net that forces Postfix - to run with backwards-compatible default settings after an - upgrade to a newer Postfix version. Postfix logs all uses - of those backwards-compatible default settings so that the - system administator can determine whether or not some - backwards-compatible default settings need to be made + Safety: backwards-compatibility safety net that forces + Postfix to run with backwards-compatible default settings + after an upgrade to a newer Postfix version. Postfix logs + all uses of those backwards-compatible default settings so + that the system administator can determine whether or not + some backwards-compatible default settings need to be made permanent in main.cf or master.cf. All this is controlled with a new compatibility_level parameter, default value 0. Files: global/mail_params.[hc], trivial-rewrite/rewrite.c, @@ -20556,9 +20555,9 @@ Apologies for any names omitted. 20141003 - Workaround: kludge for multiple paragraphs of text in indented - paragraphs. Files: mantools/postconf2html, mantools/postconf2man, - proto/Makefile.in, proto/postconf.proto + Workaround: kludge for multiple paragraphs of text in + indented paragraphs. Files: mantools/postconf2html, + mantools/postconf2man, proto/Makefile.in, proto/postconf.proto 20141005 @@ -20605,8 +20604,9 @@ Apologies for any names omitted. a new COMPATIBILITY_README document. Files: proto/postconf.proto, proto/COMPATIBILITY_README.html html/index.html. - Documentation: update the conf/main.cf compatibility_level setting - for new Postfix installs, and updated a reminder in mail_params.h. + Documentation: update the conf/main.cf compatibility_level + setting for new Postfix installs, and updated a reminder + in mail_params.h. 20141010 @@ -20898,7 +20898,7 @@ Apologies for any names omitted. about that later. Files: smtpd/smtpd_check.c, smtp/smtp_addr.c, dns/dns.h, dns/dns_lookup.c. - Cleanup: eliminate TLS state duplication from state->tls + Cleanup: eliminate TLS state duplication from state->tls to session->tls. Viktor Dukhovni. Files: src/smtp/smtp.h, src/smtp/smtp_connect.c, src/smtp/smtp_proto.c, src/smtp/smtp_reuse.c, src/smtp/smtp_session.c. @@ -21011,8 +21011,8 @@ Apologies for any names omitted. 20141208 - Bugfix (introduced: 20141207): in new #ifdef, && should be ||. - File: smtpd.c. + Bugfix (introduced: 20141207): in new #ifdef, && should be + ||. File: smtpd.c. 20141210 @@ -21180,7 +21180,7 @@ Apologies for any names omitted. Cleanup: instead of making up new names, use a consistent CA_ prefix for macros that implement compile-time argument - typechecks for non-protocol attribute-value APIs. This + typechecks for non-protocol attribute-value APIs. This transformation and its verification are mechanical. Bugfix (introduced: Postfix 1.1, but latent before 2.12): @@ -21204,11 +21204,11 @@ Apologies for any names omitted. 20141228 - Cleanup: the IDNA conversion routines now accept both - ASCII and UTF8 inputs. The functions als verify that - either their result is a valid ASCII domain name or that - it converts into a valid ASCII domain name. Files: - util/midna.c, util/midna_test.in, util/midna_test.ref. + Cleanup: the IDNA conversion routines now accept both ASCII + and UTF8 inputs. The functions als verify that either their + result is a valid ASCII domain name or that it converts + into a valid ASCII domain name. Files: util/midna.c, + util/midna_test.in, util/midna_test.ref. 20141230 @@ -21238,9 +21238,10 @@ Apologies for any names omitted. byte values, and UTF-8 case folding. As recommended at http://www.w3.org/International/wiki/Case_folding for caseless string comparison, this uses the en_US locale to - avoid surprises. The implementatin handles - the entire RFC 3629 Unicode range (code points U+0000..U+10FFFF - including surrogates) and is chroot(2) safe. Files: casefold.c, stringops.h. + avoid surprises. The implementatin handles the entire RFC + 3629 Unicode range (code points U+0000..U+10FFFF including + surrogates) and is chroot(2) safe. Files: casefold.c, + stringops.h. Infrastructure: revised the midna_domain_to_ascii and midna_domain_to_utf8 domain name conversion functions after @@ -21412,3 +21413,16 @@ Apologies for any names omitted. Cleanup: missing " in \%s\" in postscreen(8) fatal error messages. Iain Hibbert. File: postconf/postconf_master.c. + +20150118 + + Bugfix (introduced: 20140731): when a connection timed out + before any command was received, the Postfix SMTP server + "disconnect from" logging would show the content of the + last SMTP server response (421 4.4.2 $myhostname error: + timeout exceeded) instead of per-command statistics, because + there were no statistics to report. The Postfix SMTP server + now always logs the total number of commands (commands=x/y) + even when the client did not send any. This helps logfile + analyzers to recognize sessions without commands. File: + smtpd/smtpd.c. diff --git a/postfix/README_FILES/COMPATIBILITY_README b/postfix/README_FILES/COMPATIBILITY_README index f3978c15b..223597d86 100644 --- a/postfix/README_FILES/COMPATIBILITY_README +++ b/postfix/README_FILES/COMPATIBILITY_README @@ -151,9 +151,11 @@ provide ETRN service for that domain, then the system administrator should make the backwards-compatible setting "relay_domains = $mydestination" permanent in main.cf: - # ppoossttccoonnff rreellaayy__ddoommaaiinnss==$$mmyyddeessttiinnaattiioonn + # ppoossttccoonnff ''rreellaayy__ddoommaaiinnss==$$mmyyddeessttiinnaattiioonn'' # ppoossttffiixx rreellooaadd +Note: quotes are required as indicated above. + Instead of $mydestination, it may be better to specify an explicit list of domain names. diff --git a/postfix/WISHLIST b/postfix/WISHLIST index b83e5f0f3..9262c9904 100644 --- a/postfix/WISHLIST +++ b/postfix/WISHLIST @@ -8,6 +8,12 @@ Wish list: Things to do after the stable release: + postconf -P: emit '{ name = value }' when editing/adding a + parameter whose new value contains whitespace. + + In release-notes add commands=x/y logging to the command + statistics. + UTF8 DNS[BW]L domain name. Consolidate maps flags in mail_params.h instead of having diff --git a/postfix/html/COMPATIBILITY_README.html b/postfix/html/COMPATIBILITY_README.html index 4c0cfdb8a..87519dd5a 100644 --- a/postfix/html/COMPATIBILITY_README.html +++ b/postfix/html/COMPATIBILITY_README.html @@ -253,11 +253,13 @@ administrator should make the backwards-compatible setting
-# postconf relay_domains=$mydestination
+# postconf 'relay_domains=$mydestination'
 # postfix reload
 
+

Note: quotes are required as indicated above.

+

Instead of $mydestination, it may be better to specify an explicit list of domain names.

diff --git a/postfix/proto/COMPATIBILITY_README.html b/postfix/proto/COMPATIBILITY_README.html index c90321481..6b4b9b57b 100644 --- a/postfix/proto/COMPATIBILITY_README.html +++ b/postfix/proto/COMPATIBILITY_README.html @@ -253,11 +253,13 @@ administrator should make the backwards-compatible setting
-# postconf relay_domains=$mydestination
+# postconf 'relay_domains=$mydestination'
 # postfix reload
 
+

Note: quotes are required as indicated above.

+

Instead of $mydestination, it may be better to specify an explicit list of domain names.

diff --git a/postfix/src/global/mail_version.h b/postfix/src/global/mail_version.h index 14f2f9bb1..8205d448d 100644 --- a/postfix/src/global/mail_version.h +++ b/postfix/src/global/mail_version.h @@ -20,7 +20,7 @@ * Patches change both the patchlevel and the release date. Snapshots have no * patchlevel; they change the release date only. */ -#define MAIL_RELEASE_DATE "20150117" +#define MAIL_RELEASE_DATE "20150118" #define MAIL_VERSION_NUMBER "2.12" #ifdef SNAPSHOT diff --git a/postfix/src/posttls-finger/posttls-finger.c b/postfix/src/posttls-finger/posttls-finger.c index 8be46e40b..81680f176 100644 --- a/postfix/src/posttls-finger/posttls-finger.c +++ b/postfix/src/posttls-finger/posttls-finger.c @@ -228,6 +228,12 @@ /* .IP "\fB-v\fR" /* Enable verose Postfix logging. Specify more than once to increase /* the level of verbose logging. +/* .IP "\fB-w\fR" +/* Enable outgoing TLS wrapper mode, or SMTPS support. This is typically +/* provided on port 465 by servers that are compatible with the ad-hoc +/* SMTP in SSL protocol, rather than the standard STARTTLS protocol. +/* The destination \fIdomain\fR:\fIport\fR should of course provide such +/* a service. /* .IP "[\fBinet:\fR]\fIdomain\fR[:\fIport\fR]" /* Connect via TCP to domain \fIdomain\fR, port \fIport\fR. The default /* port is \fBsmtp\fR (or 24 with LMTP). With SMTP an MX lookup is @@ -421,6 +427,7 @@ typedef struct STATE { VSTRING *buffer; /* Response buffer */ VSTREAM *stream; /* Open connection */ int level; /* TLS security level */ + int wrapper_mode; /* SMTPS support */ #ifdef USE_TLS char *mdalg; /* fingerprint digest algorithm */ char *CAfile; /* Trusted public CAs */ @@ -547,6 +554,33 @@ static char *exception_text(int except) } } +/* greeting - read server's 220 greeting */ + +static int greeting(STATE *state) +{ + VSTREAM *stream = state->stream; + int except; + RESPONSE *resp; + + /* + * Prepare for disaster. + */ + smtp_stream_setup(stream, conn_tmout, 1); + if ((except = vstream_setjmp(stream)) != 0) { + msg_info("%s while reading server greeting", exception_text(except)); + return (1); + } + + /* + * Read and parse the server's SMTP greeting banner. + */ + if (((resp = response(state, 1))->code / 100) != 2) { + msg_info("SMTP service not available: %d %s", resp->code, resp->str); + return (1); + } + return (0); +} + /* ehlo - send EHLO/LHLO */ static RESPONSE *ehlo(STATE *state) @@ -647,26 +681,27 @@ static int starttls(STATE *state) VSTREAM *stream = state->stream; TLS_CLIENT_START_PROPS tls_props; - /* SMTP stream with deadline timeouts */ - smtp_stream_setup(stream, smtp_tmout, 1); - if ((except = vstream_setjmp(stream)) != 0) { - msg_fatal("%s while sending STARTTLS", exception_text(except)); - return (1); + if (state->wrapper_mode == 0) { + /* SMTP stream with deadline timeouts */ + smtp_stream_setup(stream, smtp_tmout, 1); + if ((except = vstream_setjmp(stream)) != 0) { + msg_fatal("%s while sending STARTTLS", exception_text(except)); + return (1); + } + command(state, state->pass == 1, "STARTTLS"); + + resp = response(state, state->pass == 1); + if (resp->code / 100 != 2) { + msg_info("STARTTLS rejected: %d %s", resp->code, resp->str); + return (1); + } + + /* + * Discard any plain-text data that may be piggybacked after the + * server's 220 STARTTLS reply. Should we abort the session instead? + */ + vstream_fpurge(stream, VSTREAM_PURGE_READ); } - command(state, state->pass == 1, "STARTTLS"); - - resp = response(state, state->pass == 1); - if (resp->code / 100 != 2) { - msg_info("STARTTLS rejected: %d %s", resp->code, resp->str); - return (1); - } - - /* - * Discard any plain-text data that may be piggybacked after the server's - * 220 STARTTLS reply. Should we abort the session instead? - */ - vstream_fpurge(stream, VSTREAM_PURGE_READ); - #define ADD_EXCLUDE(vstr, str) \ do { \ if (*(str)) \ @@ -718,6 +753,9 @@ static int starttls(STATE *state) state->stream = 0; return (1); } + if (state->wrapper_mode && greeting(state) != 0) + return (1); + if (state->pass == 1) { ehlo(state); if (!TLS_CERT_IS_PRESENT(state->tls_context)) @@ -743,42 +781,27 @@ static int doproto(STATE *state) int except; int n; char *lines; - char *words; + char *words = 0; char *word; - /* - * Prepare for disaster. - */ - smtp_stream_setup(stream, conn_tmout, 1); - if ((except = vstream_setjmp(stream)) != 0) - msg_fatal("%s while reading server greeting", exception_text(except)); + if (!state->wrapper_mode) { + if (greeting(state) != 0) + return (1); + if ((resp = ehlo(state)) == 0) + return (1); - /* - * Read and parse the server's SMTP greeting banner. - */ - if (((resp = response(state, 1))->code / 100) != 2) { - msg_info("SMTP service not available: %d %s", resp->code, resp->str); - return (1); - } - - /* - * Send the standard greeting with our hostname - */ - if ((resp = ehlo(state)) == 0) - return (1); - - lines = resp->str; - for (n = 0; (words = mystrtok(&lines, "\n")) != 0; ++n) { - if ((word = mystrtok(&words, " \t=")) != 0) { - if (n == 0) - state->helo = mystrdup(word); - if (strcasecmp(word, "STARTTLS") == 0) - break; + lines = resp->str; + for (n = 0; (words = mystrtok(&lines, "\n")) != 0; ++n) { + if ((word = mystrtok(&words, " \t=")) != 0) { + if (n == 0) + state->helo = mystrdup(word); + if (strcasecmp(word, "STARTTLS") == 0) + break; + } } } - #ifdef USE_TLS - if (words && state->tls_ctx) + if ((state->wrapper_mode || words) && state->tls_ctx) if (starttls(state)) return (1); #endif @@ -793,7 +816,6 @@ static int doproto(STATE *state) } command(state, 1, "QUIT"); (void) response(state, 1); - return (0); } @@ -1191,7 +1213,7 @@ static int dane_host_level(STATE *state, DNS_RR *addr) int level = state->level; #ifdef USE_TLS - if (level == TLS_LEV_DANE) { + if (TLS_DANE_BASED(level)) { if (state->mx == 0 || state->mx->dnssec_valid) { if (state->log_mask & (TLS_LOG_CERTMATCH | TLS_LOG_VERBOSE)) tls_dane_verbose(1); @@ -1214,7 +1236,8 @@ static int dane_host_level(STATE *state, DNS_RR *addr) HNAME(addr), ntohs(state->port)); level = TLS_LEV_INVALID; } else if (tls_dane_notfound(state->ddane) - || tls_dane_unusable(state->ddane)) { + || tls_dane_unusable(state->ddane) + || level == TLS_LEV_DANE_ONLY) { if (msg_verbose) msg_info("no %sTLSA records found, " "resorting to \"secure\"", @@ -1223,7 +1246,7 @@ static int dane_host_level(STATE *state, DNS_RR *addr) level = TLS_LEV_SECURE; } else if (!TLS_DANE_HASTA(state->ddane) && !TLS_DANE_HASEE(state->ddane)) { - msg_panic("empty DANE match list"); + msg_panic("DANE activated with no TLSA records to match"); } else { if (state->match) argv_free(state->match); @@ -1531,7 +1554,7 @@ static void usage(void) #ifdef USE_TLS fprintf(stderr, "usage: %s %s \\\n\t%s \\\n\t%s \\\n\t%s" " destination [match ...]\n", var_procname, - "[-acCfSv] [-t conn_tmout] [-T cmd_tmout] [-L logopts]", + "[-acCfSvw] [-t conn_tmout] [-T cmd_tmout] [-L logopts]", "[-h host_lookup] [-l level] [-d mdalg] [-g grade] [-p protocols]", "[-A tafile] [-F CAfile.pem] [-P CApath/] [-m count] [-r delay]", "[-o name=value]"); @@ -1594,6 +1617,7 @@ static void parse_options(STATE *state, int argc, char *argv[]) state->pass = 1; state->reconnect = -1; state->max_reconnect = 5; + state->wrapper_mode = 0; #ifdef USE_TLS state->protocols = mystrdup("!SSLv2"); state->grade = mystrdup("medium"); @@ -1603,7 +1627,7 @@ static void parse_options(STATE *state, int argc, char *argv[]) #define OPTS "a:ch:o:St:T:v" #ifdef USE_TLS -#define TLSOPTS "A:Cd:fF:g:l:L:m:p:P:r:" +#define TLSOPTS "A:Cd:fF:g:l:L:m:p:P:r:w" state->mdalg = mystrdup("sha1"); state->CApath = mystrdup(""); @@ -1692,6 +1716,9 @@ static void parse_options(STATE *state, int argc, char *argv[]) case 'r': state->reconnect = atoi(optarg); break; + case 'w': + state->wrapper_mode = 1; + break; #endif } } @@ -1725,10 +1752,9 @@ static void parse_options(STATE *state, int argc, char *argv[]) state->level = tls_level_lookup(state->options.level); switch (state->level) { - case TLS_LEV_DANE_ONLY: - state->level = TLS_LEV_DANE; - break; case TLS_LEV_NONE: + if (state->wrapper_mode) + msg_fatal("SSL wrapper mode requires that TLS not be disabled"); return; case TLS_LEV_INVALID: msg_fatal("Invalid TLS level \"%s\"", state->options.level); @@ -1741,8 +1767,8 @@ static void parse_options(STATE *state, int argc, char *argv[]) * required for DANE support. */ tls_init(state); - if (state->level == TLS_LEV_DANE && !tls_dane_avail()) { - msg_warn("The \"dane\" TLS security level is not available"); + if (TLS_DANE_BASED(state->level) && !tls_dane_avail()) { + msg_warn("DANE TLS support is not available, resorting to \"secure\""); state->level = TLS_LEV_SECURE; } state->tls_bio = 0; @@ -1780,6 +1806,7 @@ static void parse_match(STATE *state, int argc, char *argv[]) state->mdalg, *argv++, ""); break; case TLS_LEV_DANE: + case TLS_LEV_DANE_ONLY: state->match = argv_alloc(2); argv_add(state->match, "nexthop", "hostname", ARGV_END); break; diff --git a/postfix/src/smtp/smtp_tls_policy.c b/postfix/src/smtp/smtp_tls_policy.c index 22b76ab49..deb7e04db 100644 --- a/postfix/src/smtp/smtp_tls_policy.c +++ b/postfix/src/smtp/smtp_tls_policy.c @@ -437,6 +437,7 @@ static void set_cipher_grade(SMTP_TLS_POLICY *tls) break; case TLS_LEV_DANE: + case TLS_LEV_DANE_ONLY: case TLS_LEV_FPRINT: case TLS_LEV_VERIFY: case TLS_LEV_SECURE: @@ -534,7 +535,7 @@ static void *policy_create(const char *unused_key, void *context) * "dane-only" changes to "dane" once we obtain the requisite TLSA * records. */ - if (tls->level == TLS_LEV_DANE || tls->level == TLS_LEV_DANE_ONLY) + if (TLS_DANE_BASED(tls->level)) dane_init(tls, iter); if (tls->level == TLS_LEV_INVALID) return ((void *) tls); @@ -563,6 +564,7 @@ static void *policy_create(const char *unused_key, void *context) case TLS_LEV_MAY: case TLS_LEV_ENCRYPT: case TLS_LEV_DANE: + case TLS_LEV_DANE_ONLY: break; case TLS_LEV_FPRINT: if (tls->dane == 0) @@ -844,7 +846,6 @@ static void dane_init(SMTP_TLS_POLICY *tls, SMTP_ITERATOR *iter) } else if (!TLS_DANE_HASEE(dane)) msg_panic("empty DANE match list"); tls->dane = dane; - tls->level = TLS_LEV_DANE; return; } diff --git a/postfix/src/smtpd/smtpd.c b/postfix/src/smtpd/smtpd.c index 566bc3b2f..ad58afacb 100644 --- a/postfix/src/smtpd/smtpd.c +++ b/postfix/src/smtpd/smtpd.c @@ -5132,7 +5132,13 @@ static void smtpd_proto(SMTPD_STATE *state) static char *smtpd_format_cmd_stats(VSTRING *buf) { SMTPD_CMD *cmdp; + int all_success = 0; + int all_total = 0; + /* + * Log the statistics. Note that this loop produces no output when no + * command was received. We address that after the loop. + */ VSTRING_RESET(buf); for (cmdp = smtpd_cmd_table; /* see below */ ; cmdp++) { if (cmdp->total_count > 0) { @@ -5141,10 +5147,22 @@ static char *smtpd_format_cmd_stats(VSTRING *buf) cmdp->success_count); if (cmdp->success_count != cmdp->total_count) vstring_sprintf_append(buf, "/%d", cmdp->total_count); + all_success += cmdp->success_count; + all_total += cmdp->total_count; } if (cmdp->name == 0) break; } + + /* + * Log total numbers, so that logfile analyzers will see something even + * if the above loop produced no output. When no commands were received + * log "0/0" to simplify the identification of abnormal sessions: any + * statistics with [0-9]/ indicate that there was a problem. + */ + vstring_sprintf_append(buf, " commands=%d", all_success); + if (all_success != all_total || all_total == 0) + vstring_sprintf_append(buf, "/%d", all_total); return (lowercase(STR(buf))); } diff --git a/postfix/src/tls/tls.h b/postfix/src/tls/tls.h index 9e5f3dc8b..16e49c58b 100644 --- a/postfix/src/tls/tls.h +++ b/postfix/src/tls/tls.h @@ -53,6 +53,8 @@ #define TLS_MUST_MATCH(l) ((l) > TLS_LEV_ENCRYPT) #define TLS_MUST_TRUST(l) ((l) >= TLS_LEV_DANE) #define TLS_MUST_PKIX(l) ((l) >= TLS_LEV_VERIFY) +#define TLS_OPPORTUNISTIC(l) ((l) == TLS_LEV_MAY || (l) == TLS_LEV_DANE) +#define TLS_DANE_BASED(l) ((l) == TLS_LEV_DANE || (l) == TLS_LEV_DANE_ONLY) extern const NAME_CODE tls_level_table[]; diff --git a/postfix/src/tls/tls_client.c b/postfix/src/tls/tls_client.c index 8211e2602..fc3d607ca 100644 --- a/postfix/src/tls/tls_client.c +++ b/postfix/src/tls/tls_client.c @@ -827,10 +827,10 @@ TLS_SESS_STATE *tls_client_start(const TLS_CLIENT_START_PROPS *props) /* * When certificate verification is required, log trust chain validation * errors even when disabled by default for opportunistic sessions. For - * "dane" this only applies when using trust-anchor associations. + * DANE this only applies when using trust-anchor associations. */ if (TLS_MUST_TRUST(props->tls_level) - && (props->tls_level != TLS_LEV_DANE || TLS_DANE_HASTA(props->dane))) + && (!TLS_DANE_BASED(props->tls_level) || TLS_DANE_HASTA(props->dane))) log_mask |= TLS_LOG_UNTRUSTED; if (log_mask & TLS_LOG_VERBOSE) @@ -849,8 +849,8 @@ TLS_SESS_STATE *tls_client_start(const TLS_CLIENT_START_PROPS *props) props->namaddr, props->protocols); return (0); } - /* The DANE level requires SSLv3 or later, not SSLv2. */ - if (props->tls_level == TLS_LEV_DANE) + /* DANE requires SSLv3 or later, not SSLv2. */ + if (TLS_DANE_BASED(props->tls_level)) protomask |= TLS_PROTOCOL_SSLv2; /* @@ -945,7 +945,7 @@ TLS_SESS_STATE *tls_client_start(const TLS_CLIENT_START_PROPS *props) } } #ifdef TLSEXT_MAXLEN_host_name - if (props->tls_level == TLS_LEV_DANE + if (TLS_DANE_BASED(props->tls_level) && strlen(props->host) <= TLSEXT_MAXLEN_host_name) { /* diff --git a/postfix/src/tls/tls_fprint.c b/postfix/src/tls/tls_fprint.c index abd5ff7d4..a03e3cc1e 100644 --- a/postfix/src/tls/tls_fprint.c +++ b/postfix/src/tls/tls_fprint.c @@ -227,7 +227,7 @@ char *tls_serverid_digest(const TLS_CLIENT_START_PROPS *props, long protomask, #if 0 digest_dane(props->dane, ee); /* See above */ #endif - digest_string(props->tls_level == TLS_LEV_DANE ? props->host : ""); + digest_string(TLS_DANE_BASED(props->tls_level) ? props->host : ""); } checkok(EVP_DigestFinal_ex(mdctx, md_buf, &md_len)); EVP_MD_CTX_destroy(mdctx);