Documentation: moved the gory details from postconf(5) to
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.
+
+20141010
+
+ Cleanup: make "const char myname[]" declarations static.
+ global/attr_override.c, global/bounce.c, global/dsn_filter.c,
+ global/dynamicmaps.c, global/mkmap_open.c, global/smtputf8.c,
+ smtp/smtp_key.c, smtpd/smtpd_check.c, util/dict_pipe.c,
+ util/dict_union.c, util/mac_expand.c, util/midna.c,
+ util/valid_utf8_hostname.c.
+
+ Documentation: summarize the user-specified "make makefiles"
+ settings at the top of makedefs.out. This file now has so
+ many internal variables that people would get lost.
+
+20141011
+
+ Cleanup: replaced cryptic macros X_SMTP() and SMTP_X() with
+ more descripive names: LMTP_SMTP_SUFFIX() and VAR_LMTP_SMTP().
+ Files: smtp/smtp.c, smtp/smtp.h, smtp/smtp_chat.c,
+ smtp/smtp_connect.c, smtp/smtp_proto.c, smtp/smtp_sasl_glue.c,
+ smtp/smtp_sasl_proto.c, smtp/smtp_tls_policy.c.
+
+ Feature: support to fall back to an unauthenticated TLS
+ security level ("may" or "encrypt) when the Postfix SMTP
+ client cannot establish the preferred authenticated TLS
+ security level ("dane", "dane-only", "fingerprint", "verify",
+ or "secure"). The fall-back levels may be specified globally
+ with the smtp_tls_fallback_level parameter or in per-site
+ TLS policies with the "fallback" attribute. Viktor Dukhovni.
+ Files: mantools/postlink, proto/TLS_README.html,
+ ./proto/postconf.proto, global/mail_params.h, smtp/lmtp_params.c,
+ smtp/smtp.c, smtp/smtp.h, smtp/smtp_connect.c, smtp/smtp_params.c,
+ smtp/smtp_proto.c, smtp/smtp_tls_policy.c, smtp/smtp_trouble.c.
the backwards-compatible default setting is turned on, Postfix may log one of
the following messages:
- * postfix/trivial-rewrite[14777]: using backwards-compatible
- default setting append_dot_mydomain=yes to rewrite
- "localhost" to "localhost.example.com"; please add
- "localhost" to mydestination or other address class
+ * Messages about missing "localhost" in mydestination or other address class:
+
+ postfix/trivial-rewrite[14777]: using backwards-compatible
+ default setting append_dot_mydomain=yes to rewrite
+ "localhost" to "localhost.example.com"; please add
+ "localhost" to mydestination or other address class
If Postfix logs the above message, add "localhost" to mydestination (or
virtual_alias_domains, virtual_mailbox_domains, or relay_domains) and
execute the command "p\bpo\bos\bst\btf\bfi\bix\bx r\bre\bel\blo\boa\bad\bd".
- * postfix/trivial-rewrite[25835]: using backwards-compatible
- default setting append_dot_mydomain=yes to rewrite "foo" to
- "foo.example.com"
+ * Messages about incomplete domains in email addresses:
+
+ postfix/trivial-rewrite[25835]: using backwards-compatible
+ default setting append_dot_mydomain=yes to rewrite "foo" to
+ "foo.example.com"
If Postfix logs the above message for domains different from "localhost",
and the sender cannot be changed to use complete domain names in email
addresses, then the system administrator should make the backwards-
compatible setting "append_dot_mydomain = yes" permanent in main.cf:
- # p\bpo\bos\bst\btc\bco\bon\bnf\bf a\bap\bpp\bpe\ben\bnd\bd_\b_d\bdo\bot\bt_\b_m\bmy\byd\bdo\bom\bma\bai\bin\bn=\b=y\bye\bes\bs
- # p\bpo\bos\bst\btf\bfi\bix\bx r\bre\bel\blo\boa\bad\bd
+ # p\bpo\bos\bst\btc\bco\bon\bnf\bf a\bap\bpp\bpe\ben\bnd\bd_\b_d\bdo\bot\bt_\b_m\bmy\byd\bdo\bom\bma\bai\bin\bn=\b=y\bye\bes\bs
+ # p\bpo\bos\bst\btf\bfi\bix\bx r\bre\bel\blo\boa\bad\bd
U\bUs\bsi\bin\bng\bg b\bba\bac\bck\bkw\bwa\bar\brd\bds\bs-\b-c\bco\bom\bmp\bpa\bat\bti\bib\bbl\ble\be d\bde\bef\bfa\bau\bul\blt\bt s\bse\bet\btt\bti\bin\bng\bg c\bch\bhr\bro\boo\bot\bt=\b=y\by
backwards-compatible default setting is turned on, Postfix may log the
following message while it reads the master.cf file:
-postfix/master[27664]: /etc/postfix/master.cf: line 72: using
- backwards-compatible default setting chroot=y
+ postfix/master[27664]: /etc/postfix/master.cf: line 72: using
+ backwards-compatible default setting chroot=y
If this service should remain chrooted, then the system administrator should
make the backwards-compatible setting "chroot = y" permanent in master.cf. For
example, to update the chroot setting for the "smtp inet" service:
-# p\bpo\bos\bst\btc\bco\bon\bnf\bf -\b-F\bF s\bsm\bmt\btp\bp/\b/i\bin\bne\bet\bt/\b/c\bch\bhr\bro\boo\bot\bt=\b=y\by
-# p\bpo\bos\bst\btf\bfi\bix\bx r\bre\bel\blo\boa\bad\bd
+ # p\bpo\bos\bst\btc\bco\bon\bnf\bf -\b-F\bF s\bsm\bmt\btp\bp/\b/i\bin\bne\bet\bt/\b/c\bch\bhr\bro\boo\bot\bt=\b=y\by
+ # p\bpo\bos\bst\btf\bfi\bix\bx r\bre\bel\blo\boa\bad\bd
U\bUs\bsi\bin\bng\bg b\bba\bac\bck\bkw\bwa\bar\brd\bds\bs-\b-c\bco\bom\bmp\bpa\bat\bti\bib\bbl\ble\be d\bde\bef\bfa\bau\bul\blt\bt s\bse\bet\btt\bti\bin\bng\bg m\bmy\byn\bne\bet\btw\bwo\bor\brk\bks\bs_\b_s\bst\bty\byl\ble\be=\b=s\bsu\bub\bbn\bne\bet\bt
values, and the backwards-compatible default setting is turned on, the Postfix
SMTP server may log one of the following messages:
-postfix/smtpd[17375]: using backwards-compatible default setting
- mynetworks_style=subnet to permit request from client
- "foo.example.com[10.1.1.1]"
+ postfix/smtpd[17375]: using backwards-compatible default setting
+ mynetworks_style=subnet to permit request from client
+ "foo.example.com[10.1.1.1]"
-postfix/postscreen[24982]: using backwards-compatible default
- setting mynetworks_style=subnet to permit request from client
- "10.1.1.1"
+ postfix/postscreen[24982]: using backwards-compatible default
+ setting mynetworks_style=subnet to permit request from client
+ "10.1.1.1"
If the client request should not be rejected, then the system administrator
should make the backwards-compatible setting "mynetworks_style = subnet"
permanent in main.cf:
-# p\bpo\bos\bst\btc\bco\bon\bnf\bf m\bmy\byn\bne\bet\btw\bwo\bor\brk\bks\bs_\b_s\bst\bty\byl\ble\be=\b=s\bsu\bub\bbn\bne\bet\bt
-# p\bpo\bos\bst\btf\bfi\bix\bx r\bre\bel\blo\boa\bad\bd
+ # p\bpo\bos\bst\btc\bco\bon\bnf\bf m\bmy\byn\bne\bet\btw\bwo\bor\brk\bks\bs_\b_s\bst\bty\byl\ble\be=\b=s\bsu\bub\bbn\bne\bet\bt
+ # p\bpo\bos\bst\btf\bfi\bix\bx r\bre\bel\blo\boa\bad\bd
U\bUs\bsi\bin\bng\bg b\bba\bac\bck\bkw\bwa\bar\brd\bds\bs-\b-c\bco\bom\bmp\bpa\bat\bti\bib\bbl\ble\be d\bde\bef\bfa\bau\bul\blt\bt s\bse\bet\btt\bti\bin\bng\bg r\bre\bel\bla\bay\by_\b_d\bdo\bom\bma\bai\bin\bns\bs=\b=$\b$m\bmy\byd\bde\bes\bst\bti\bin\bna\bat\bti\bio\bon\bn
value, and the backwards-compatible default setting is turned on, Postfix may
log one of the following messages.
-Messages about accepting mail for a remote domain:
+ * Messages about accepting mail for a remote domain:
-postfix/smtpd[19052]: using backwards-compatible default setting
- relay_domains=$mydestination to accept mail for domain
- "foo.example.com"
+ postfix/smtpd[19052]: using backwards-compatible default setting
+ relay_domains=$mydestination to accept mail for domain
+ "foo.example.com"
-postfix/smtpd[19052]: using backwards-compatible default setting
- relay_domains=$mydestination to accept mail for address
- "user@foo.example.com"
+ postfix/smtpd[19052]: using backwards-compatible default setting
+ relay_domains=$mydestination to accept mail for address
+ "user@foo.example.com"
-Messages about providing ETRN service for a remote domain:
+ * Messages about providing ETRN service for a remote domain:
-postfix/smtpd[19138]: using backwards-compatible default setting
- relay_domains=$mydestination to flush mail for domain
- "bar.example.com"
+ postfix/smtpd[19138]: using backwards-compatible default setting
+ relay_domains=$mydestination to flush mail for domain
+ "bar.example.com"
-postfix/smtp[13945]: using backwards-compatible default setting
- relay_domains=$mydestination to update fast-flush logfile for
- domain "bar.example.com"
+ postfix/smtp[13945]: using backwards-compatible default setting
+ relay_domains=$mydestination to update fast-flush logfile for
+ domain "bar.example.com"
If Postfix should continue to accept mail for that domain or continue to
provide ETRN service for that domain, then the system administrator should make
the backwards-compatible setting "relay_domains = $mydestination" permanent in
main.cf:
-# p\bpo\bos\bst\btc\bco\bon\bnf\bf r\bre\bel\bla\bay\by_\b_d\bdo\bom\bma\bai\bin\bns\bs=\b=$\b$m\bmy\byd\bde\bes\bst\bti\bin\bna\bat\bti\bio\bon\bn
-# p\bpo\bos\bst\btf\bfi\bix\bx r\bre\bel\blo\boa\bad\bd
+ # p\bpo\bos\bst\btc\bco\bon\bnf\bf r\bre\bel\bla\bay\by_\b_d\bdo\bom\bma\bai\bin\bns\bs=\b=$\b$m\bmy\byd\bde\bes\bst\bti\bin\bna\bat\bti\bio\bon\bn
+ # p\bpo\bos\bst\btf\bfi\bix\bx r\bre\bel\blo\boa\bad\bd
Instead of $mydestination, it may be better to specify an explicit list of
domain names.
backwards-compatible default setting is turned on, Postfix logs a warning each
time an SMTP command uses a non-ASCII address localpart:
-postfix/smtpd[27560]: using backwards-compatible default setting
- smtputf8_enable=no to accept non-ASCII sender address
- "??@example.org" from localhost[127.0.0.1]
+ postfix/smtpd[27560]: using backwards-compatible default setting
+ smtputf8_enable=no to accept non-ASCII sender address
+ "??@example.org" from localhost[127.0.0.1]
-postfix/smtpd[27560]: using backwards-compatible default setting
- smtputf8_enable=no to accept non-ASCII recipient address
- "??@example.com" from localhost[127.0.0.1]
+ postfix/smtpd[27560]: using backwards-compatible default setting
+ smtputf8_enable=no to accept non-ASCII recipient address
+ "??@example.com" from localhost[127.0.0.1]
If the address should not be rejected, and the client cannot be updated to use
SMTPUTF8, then the system administrator should make the backwards-compatible
setting "smtputf8_enable = no" permanent in main.cf:
-# p\bpo\bos\bst\btc\bco\bon\bnf\bf s\bsm\bmt\btp\bpu\but\btf\bf8\b8_\b_e\ben\bna\bab\bbl\ble\be=\b=n\bno\bo
-# p\bpo\bos\bst\btf\bfi\bix\bx r\bre\bel\blo\boa\bad\bd
+ # p\bpo\bos\bst\btc\bco\bon\bnf\bf s\bsm\bmt\btp\bpu\but\btf\bf8\b8_\b_e\ben\bna\bab\bbl\ble\be=\b=n\bno\bo
+ # p\bpo\bos\bst\btf\bfi\bix\bx r\bre\bel\blo\boa\bad\bd
* New backwards-compatibility safety net.
+With NEW Postfix installs, you MUST install a main.cf file with
+the setting "compatibility_level = 2". See conf/main.cf for an
+example.
+
+With UPGRADES of existing Postfix systems, you MUST NOT change the
+main.cf compatibility_level setting (if any).
+
Several Postfix default settings have changed with Postfix 2.12.
To avoid massive breakage, Postfix comes with a safety net that
forces Postfix to keep running with backwards-compatible main.cf
-and master.cf default settings.
-
-With NEW Postfix installs, you should install a main.cf file with
-the setting "compatibility_level = 1". See the stock main.cf file
-in the conf subdirectory.
-
-With existing Postfix UPGRADES, the main.cf compatibility_level
-setting (if any) MUST be left alone, to enable the backwards-compatibility
-safety net as discussed below.
+and master.cf default settings. This safety net depends on the
+main.cf compatibility_level setting (if any). Details are in
+COMPATIBILITY_README.
* New Postfix build system.
(mantools/srctoman - makedefs | nroff -man | less) with information
about build options that are not described in the INSTALL instructions.
-Major changes with snapshot 20141001
+Major changes with snapshot 20141011
====================================
+Support to fall back to an unauthenticated TLS security level ("may"
+or "encrypt) when the Postfix SMTP client cannot establish the
+preferred authenticated TLS security level ("dane", "dane-only",
+"fingerprint", "verify", or "secure"). The fall-back levels may be
+specified globally with the smtp_tls_fallback_level parameter or
+in per-site TLS policies with the "fallback" attribute.
+
+Fallback to unauthenticated TLS is logged, so that downgrade attacks
+are "tamper-evident". Fallback should be used only when testing,
+or temporarily when working around a known problem at a remote site.
+
+Incompatible changes with snapshot 20141008
+===========================================
+
+The default settings have changed for relay_domains (new: empty,
+old: $mydestination) and mynetworks_style (new: host, old: subnet).
+However the backwards-compatibility safety net will prevent these
+changes from taking effect, giving the system administrator the
+option to make an old default setting permanent in main.cf or to
+adopt the new default setting, before turning off backwards
+compatibility. See COMPATIBILITY_README for details.
+
+With this the built-in compatibility level changes from 1 to 2.
+
+Incompatible changes with snapshot 20141001
+===========================================
+
+The default settings have changed for append_dot_mydomain (new: no.
+old: yes), master.cf chroot (new: n, old: y), and smtputf8 (new:
+yes, old: no).
+
A new backwards-compatibility safety net forces Postfix to run with
backwards-compatible main.cf and master.cf default settings after
-an upgrade to a newer but incompatible Postfix version.
+an upgrade to a newer but incompatible Postfix version. See
+COMPATIBILITY_README for details.
While the backwards-compatible default settings are in effect,
Postfix logs what services or what email would be affected by the
See postconf.5.html#compatibility_level for details.
+With this the built-in compatibility level changes from 0 to 1.
+
Major changes with snapshot 20140928
====================================
Update smtputf8_enable in postconf(5)
- use "static const char myname[] ..."
-
Add milter_mumble_macros to the list of per-macro features.
The pickup daemon logs warnings only when the cleanup daemon
depend on these definitions.
Error reporting: see if pcf_check_master_entry() and children
- can return error descriptions instread of terminating with
+ can return error descriptions instead of terminating with
a fatal error.
Make sure that proxy: can handle random:, pipe:, and other
filter should be content_filter. Posted Wed, 10 Sep 2014
09:53:52 -0400 (EDT).
- Clarify that receive_override_options should not be used
- with smtpd_proxy_filter.
+ Clarify that receive_override_options have no effect with
+ smtpd_proxy_filter.
Document the relative order of header_checks, address
rewriting, milters.
- Table-driven case folding and case-insensitive string
- comparison specifically for UTF-8.
+ NOT: Table-driven case folding and case-insensitive string
+ comparison specifically for UTF-8. Use libicu functions
+ instead.
The postfix-mumble@postfix.org list manager sends list mail
with ORCPT=rfc822;postfix-mumble-outgoing. The local
Don't accept AUTH or other features that are not announced
in the EHLO response.
- Per-Milter error action.
-
Suggested at Mailserver conference: Postscreen RDNS-based
reputation (but this makes postscreen performance highly
unpredicable because it introduces a dependency on random
DNS servers).
+ Suggested at Mailserver conference: a way to select a
+ specific field in a table, presumably as the result value.
+ This may be done with a filtermap{i,j,...}: table that propagates
+ only the specified field(s).
+
Discourage the use of "after 220" tests in POSTSCREEN_README
and the documentation of individual parameter settings.
Wietse as the original author, and Lutz Jaenicke's license,
which is wrong.
- Code clarity: replace obscure macro/function names: for
- example SMTP_X(XXX) -> VAR_SMTP(XXX), as the purpose is to
- choose between VAR_SMTP_XXX or VAR_LMTP_XXX; replace
- digestpl() etc. with names that make clear what operation
- is being performed (in this case, update a digest with the
- contents of a buffer with the specified length). Replace r
- with res_opt, ditto for other 1-letter names.
-
We have smtp_host_lookup, smtp_dns_resolver_options, and
now smtp_dns_support_level. Of these, smtp_dns_resolver_options
is orthogonal but the rest has overlap.
#
# The level below is what should be used with new (not upgrade) installs.
#
-compatibility_level = 1
+compatibility_level = 2
# SOFT BOUNCE
#
<ul>
-<li>
+<li> <p> Messages about missing "localhost" in <a href="postconf.5.html#mydestination">mydestination</a> or
+other address class: </p>
+
+<blockquote>
<pre>
postfix/trivial-rewrite[14777]: using backwards-compatible
default setting <a href="postconf.5.html#append_dot_mydomain">append_dot_mydomain</a>=yes to rewrite
"localhost" to "localhost.example.com"; please add
"localhost" to <a href="postconf.5.html#mydestination">mydestination</a> or other address class
</pre>
+</blockquote>
<p> If Postfix logs the above message, add "localhost" to
<a href="postconf.5.html#mydestination">mydestination</a> (or <a href="postconf.5.html#virtual_alias_domains">virtual_alias_domains</a>, <a href="postconf.5.html#virtual_mailbox_domains">virtual_mailbox_domains</a>,
or <a href="postconf.5.html#relay_domains">relay_domains</a>) and execute the command "<b>postfix reload</b>".
-<li>
+<li> <p> Messages about incomplete domains in email addresses: </p>
+
+<blockquote>
<pre>
postfix/trivial-rewrite[25835]: using backwards-compatible
default setting <a href="postconf.5.html#append_dot_mydomain">append_dot_mydomain</a>=yes to rewrite "foo" to
"foo.example.com"
</pre>
+</blockquote>
<p> If Postfix logs the above message for domains different from
"localhost", and the sender cannot be changed to use complete domain
the backwards-compatible setting "<a href="postconf.5.html#append_dot_mydomain">append_dot_mydomain</a> = yes" permanent
in <a href="postconf.5.html">main.cf</a>: </p>
+<blockquote>
<pre>
# <b>postconf <a href="postconf.5.html#append_dot_mydomain">append_dot_mydomain</a>=yes</b>
# <b>postfix reload</b>
</pre>
+</blockquote>
</ul>
is turned on, Postfix may log the following message while it
reads the <a href="master.5.html">master.cf</a> file: </p>
+<blockquote>
<pre>
postfix/master[27664]: /etc/postfix/<a href="master.5.html">master.cf</a>: line 72: using
backwards-compatible default setting chroot=y
</pre>
+</blockquote>
<p> If this service should remain chrooted, then the system
administrator should make the backwards-compatible setting "chroot
= y" permanent in <a href="master.5.html">master.cf</a>. For example, to update the chroot
setting for the "smtp inet" service: </p>
+<blockquote>
<pre>
# <b>postconf -F smtp/inet/chroot=y</b>
# <b>postfix reload</b>
</pre>
+</blockquote>
<h2> <a name="mynetworks_style"> Using backwards-compatible default
setting mynetworks_style=subnet</a> </h2>
default setting is turned on, the Postfix SMTP server may log one
of the following messages: </p>
+<blockquote>
<pre>
postfix/smtpd[17375]: using backwards-compatible default setting
<a href="postconf.5.html#mynetworks_style">mynetworks_style</a>=subnet to permit request from client
"foo.example.com[10.1.1.1]"
</pre>
+</blockquote>
+<blockquote>
<pre>
postfix/postscreen[24982]: using backwards-compatible default
setting <a href="postconf.5.html#mynetworks_style">mynetworks_style</a>=subnet to permit request from client
"10.1.1.1"
</pre>
+</blockquote>
<p> If the client request should not be rejected, then the system
administrator should make the backwards-compatible setting
"<a href="postconf.5.html#mynetworks_style">mynetworks_style</a> = subnet" permanent in <a href="postconf.5.html">main.cf</a>: </p>
+<blockquote>
<pre>
# <b>postconf <a href="postconf.5.html#mynetworks_style">mynetworks_style</a>=subnet</b>
# <b>postfix reload</b>
</pre>
+</blockquote>
<h2><a name="relay_domains"> Using backwards-compatible default
setting relay_domains=$mydestination </a> </h2>
setting is turned on, Postfix may log one of the following messages.
</p>
-<p> Messages about accepting mail for a remote domain:</p>
+<ul>
+
+<li> <p> Messages about accepting mail for a remote domain:</p>
+<blockquote>
<pre>
postfix/smtpd[19052]: using backwards-compatible default setting
<a href="postconf.5.html#relay_domains">relay_domains</a>=$<a href="postconf.5.html#mydestination">mydestination</a> to accept mail for domain
"foo.example.com"
</pre>
+</blockquote>
+<blockquote>
<pre>
postfix/smtpd[19052]: using backwards-compatible default setting
<a href="postconf.5.html#relay_domains">relay_domains</a>=$<a href="postconf.5.html#mydestination">mydestination</a> to accept mail for address
"user@foo.example.com"
</pre>
+</blockquote>
-<p> Messages about providing ETRN service for a remote domain:</p>
+<li> <p> Messages about providing ETRN service for a remote domain:</p>
+<blockquote>
<pre>
postfix/smtpd[19138]: using backwards-compatible default setting
<a href="postconf.5.html#relay_domains">relay_domains</a>=$<a href="postconf.5.html#mydestination">mydestination</a> to flush mail for domain
"bar.example.com"
</pre>
+</blockquote>
+<blockquote>
<pre>
postfix/smtp[13945]: using backwards-compatible default setting
<a href="postconf.5.html#relay_domains">relay_domains</a>=$<a href="postconf.5.html#mydestination">mydestination</a> to update fast-flush logfile for
domain "bar.example.com"
</pre>
+</blockquote>
+
+</ul>
<p> If Postfix should continue to accept mail for that domain or
continue to provide ETRN service for that domain, then the system
administrator should make the backwards-compatible setting
"<a href="postconf.5.html#relay_domains">relay_domains</a> = $<a href="postconf.5.html#mydestination">mydestination</a>" permanent in <a href="postconf.5.html">main.cf</a>: </p>
+<blockquote>
<pre>
# <b>postconf <a href="postconf.5.html#relay_domains">relay_domains</a>=$<a href="postconf.5.html#mydestination">mydestination</a></b>
# <b>postfix reload</b>
</pre>
+</blockquote>
<p> Instead of $<a href="postconf.5.html#mydestination">mydestination</a>, it may be better to specify an
explicit list of domain names. </p>
turned on, Postfix logs a warning each time an SMTP command uses a
non-ASCII address localpart: </p>
+<blockquote>
<pre>
postfix/smtpd[27560]: using backwards-compatible default setting
<a href="postconf.5.html#smtputf8_enable">smtputf8_enable</a>=no to accept non-ASCII sender address
"??@example.org" from localhost[127.0.0.1]
</pre>
+</blockquote>
+<blockquote>
<pre>
postfix/smtpd[27560]: using backwards-compatible default setting
<a href="postconf.5.html#smtputf8_enable">smtputf8_enable</a>=no to accept non-ASCII recipient address
"??@example.com" from localhost[127.0.0.1]
</pre>
+</blockquote>
<p> If the address should not be rejected, and the client cannot
be updated to use SMTPUTF8, then the system administrator should
make the backwards-compatible setting "<a href="postconf.5.html#smtputf8_enable">smtputf8_enable</a> = no" permanent
in <a href="postconf.5.html">main.cf</a>:
+<blockquote>
<pre>
# <b>postconf <a href="postconf.5.html#smtputf8_enable">smtputf8_enable</a>=no</b>
# <b>postfix reload</b>
</pre>
+</blockquote>
</body>
<blockquote>
<pre>
-using backwards-compatible default setting <i>name=value</i> to [accept a specific client request]
+using backwards-compatible default setting <i>name=value</i>
+ to [accept a specific client request]
-using backwards-compatible default setting <i>name=value</i> to [enable specific Postfix behavior]
+using backwards-compatible default setting <i>name=value</i>
+ to [enable specific Postfix behavior]
</pre>
</blockquote>
<blockquote>
<pre>
-warning: To disable backwards compatibility use "postconf <a href="postconf.5.html#compatibility_level">compatibility_level</a>=<i>N</i>" and "postfix reload"
+warning: To disable backwards compatibility use "postconf
+ <a href="postconf.5.html#compatibility_level">compatibility_level</a>=<i>N</i>" and "postfix reload"
</pre>
</blockquote>
# Emit system-dependent Makefile macro definitions to standard output.
+echo "#----------------------------------------------------------------"
+echo "# Start of summary of user-configurable 'make makefiles' options."
+echo "# CCARGS=$CCARGS"
+echo "# AUXLIBS=$AUXLIBS"
+env | grep '^AUXLIBS_' | sed 's/^/# /'
+echo "# dynamicmaps=$dynamicmaps"
+
# Defaults for most sane systems
RANLIB=ranlib
process_input_parameter()
{
+ echo "#" $parm_name=$parm_val
case "$parm_val" in
*MAIL_VERSION*)
cparm_val=`echo "$parm_val" | \
esac
done
+echo "# End of summary of user-configurable 'make makefiles' options."
+echo "#--------------------------------------------------------------"
+
# The following are for non-shared libsasl and libmilter builds.
_AR=$AR
.nf
.na
.ft C
-using backwards-compatible default setting \fIname=value\fR to [accept a specific client request]
+using backwards-compatible default setting \fIname=value\fR
+ to [accept a specific client request]
.sp
-using backwards-compatible default setting \fIname=value\fR to [enable specific Postfix behavior]
+using backwards-compatible default setting \fIname=value\fR
+ to [enable specific Postfix behavior]
.fi
.ad
.ft R
.nf
.na
.ft C
-warning: To disable backwards compatibility use "postconf compatibility_level=\fIN\fR" and "postfix reload"
+warning: To disable backwards compatibility use "postconf
+ compatibility_level=\fIN\fR" and "postfix reload"
.fi
.ad
.ft R
s;\bsmtp_starttls_timeout\b;<a href="postconf.5.html#smtp_starttls_timeout">$&</a>;g;
s;\bsmtp_tls_CAfile\b;<a href="postconf.5.html#smtp_tls_CAfile">$&</a>;g;
s;\bsmtp_tls_CApath\b;<a href="postconf.5.html#smtp_tls_CApath">$&</a>;g;
+ s;\bsmtp_tls_fallback_level\b;<a href="postconf.5.html#smtp_tls_fallback_level">$&</a>;g;
+ s;\blmtp_tls_fallback_level\b;<a href="postconf.5.html#lmtp_tls_fallback_level">$&</a>;g;
s;\bsmtp_tls_cert_file\b;<a href="postconf.5.html#smtp_tls_cert_file">$&</a>;g;
s;\bsmtp_tls_fingerprint_digest\b;<a href="postconf.5.html#smtp_tls_fingerprint_digest">$&</a>;g;
s;\bsmtp_tls_protocols\b;<a href="postconf.5.html#smtp_tls_protocols">$&</a>;g;
<ul>
-<li>
+<li> <p> Messages about missing "localhost" in mydestination or
+other address class: </p>
+
+<blockquote>
<pre>
postfix/trivial-rewrite[14777]: using backwards-compatible
default setting append_dot_mydomain=yes to rewrite
"localhost" to "localhost.example.com"; please add
"localhost" to mydestination or other address class
</pre>
+</blockquote>
<p> If Postfix logs the above message, add "localhost" to
mydestination (or virtual_alias_domains, virtual_mailbox_domains,
or relay_domains) and execute the command "<b>postfix reload</b>".
-<li>
+<li> <p> Messages about incomplete domains in email addresses: </p>
+
+<blockquote>
<pre>
postfix/trivial-rewrite[25835]: using backwards-compatible
default setting append_dot_mydomain=yes to rewrite "foo" to
"foo.example.com"
</pre>
+</blockquote>
<p> If Postfix logs the above message for domains different from
"localhost", and the sender cannot be changed to use complete domain
the backwards-compatible setting "append_dot_mydomain = yes" permanent
in main.cf: </p>
+<blockquote>
<pre>
# <b>postconf append_dot_mydomain=yes</b>
# <b>postfix reload</b>
</pre>
+</blockquote>
</ul>
is turned on, Postfix may log the following message while it
reads the master.cf file: </p>
+<blockquote>
<pre>
postfix/master[27664]: /etc/postfix/master.cf: line 72: using
backwards-compatible default setting chroot=y
</pre>
+</blockquote>
<p> If this service should remain chrooted, then the system
administrator should make the backwards-compatible setting "chroot
= y" permanent in master.cf. For example, to update the chroot
setting for the "smtp inet" service: </p>
+<blockquote>
<pre>
# <b>postconf -F smtp/inet/chroot=y</b>
# <b>postfix reload</b>
</pre>
+</blockquote>
<h2> <a name="mynetworks_style"> Using backwards-compatible default
setting mynetworks_style=subnet</a> </h2>
default setting is turned on, the Postfix SMTP server may log one
of the following messages: </p>
+<blockquote>
<pre>
postfix/smtpd[17375]: using backwards-compatible default setting
mynetworks_style=subnet to permit request from client
"foo.example.com[10.1.1.1]"
</pre>
+</blockquote>
+<blockquote>
<pre>
postfix/postscreen[24982]: using backwards-compatible default
setting mynetworks_style=subnet to permit request from client
"10.1.1.1"
</pre>
+</blockquote>
<p> If the client request should not be rejected, then the system
administrator should make the backwards-compatible setting
"mynetworks_style = subnet" permanent in main.cf: </p>
+<blockquote>
<pre>
# <b>postconf mynetworks_style=subnet</b>
# <b>postfix reload</b>
</pre>
+</blockquote>
<h2><a name="relay_domains"> Using backwards-compatible default
setting relay_domains=$mydestination </a> </h2>
setting is turned on, Postfix may log one of the following messages.
</p>
-<p> Messages about accepting mail for a remote domain:</p>
+<ul>
+
+<li> <p> Messages about accepting mail for a remote domain:</p>
+<blockquote>
<pre>
postfix/smtpd[19052]: using backwards-compatible default setting
relay_domains=$mydestination to accept mail for domain
"foo.example.com"
</pre>
+</blockquote>
+<blockquote>
<pre>
postfix/smtpd[19052]: using backwards-compatible default setting
relay_domains=$mydestination to accept mail for address
"user@foo.example.com"
</pre>
+</blockquote>
-<p> Messages about providing ETRN service for a remote domain:</p>
+<li> <p> Messages about providing ETRN service for a remote domain:</p>
+<blockquote>
<pre>
postfix/smtpd[19138]: using backwards-compatible default setting
relay_domains=$mydestination to flush mail for domain
"bar.example.com"
</pre>
+</blockquote>
+<blockquote>
<pre>
postfix/smtp[13945]: using backwards-compatible default setting
relay_domains=$mydestination to update fast-flush logfile for
domain "bar.example.com"
</pre>
+</blockquote>
+
+</ul>
<p> If Postfix should continue to accept mail for that domain or
continue to provide ETRN service for that domain, then the system
administrator should make the backwards-compatible setting
"relay_domains = $mydestination" permanent in main.cf: </p>
+<blockquote>
<pre>
# <b>postconf relay_domains=$mydestination</b>
# <b>postfix reload</b>
</pre>
+</blockquote>
<p> Instead of $mydestination, it may be better to specify an
explicit list of domain names. </p>
turned on, Postfix logs a warning each time an SMTP command uses a
non-ASCII address localpart: </p>
+<blockquote>
<pre>
postfix/smtpd[27560]: using backwards-compatible default setting
smtputf8_enable=no to accept non-ASCII sender address
"??@example.org" from localhost[127.0.0.1]
</pre>
+</blockquote>
+<blockquote>
<pre>
postfix/smtpd[27560]: using backwards-compatible default setting
smtputf8_enable=no to accept non-ASCII recipient address
"??@example.com" from localhost[127.0.0.1]
</pre>
+</blockquote>
<p> If the address should not be rejected, and the client cannot
be updated to use SMTPUTF8, then the system administrator should
make the backwards-compatible setting "smtputf8_enable = no" permanent
in main.cf:
+<blockquote>
<pre>
# <b>postconf smtputf8_enable=no</b>
# <b>postfix reload</b>
</pre>
+</blockquote>
</body>
<li> <p> The "example.com" destination uses DANE, but if TLSA records
are not present or are unusable, mail is deferred. </p>
-<li> <p> The "example.org" destination uses DANE if possible, but if no TLSA
-records are found opportunistic TLS is used. </p>
+<li> <p> The "example.org" destination uses DANE if possible, but
+uses opportunistic TLS if no TLSA records are found. The
+"fallback" attribute (Postfix ≥ 2.12) overrides the global
+main.cf smtp_tls_fallback_level parameter to employ unauthenticated
+mandatory encryption if DANE authentication fails, after logging a
+warning. </p>
</ul>
<blockquote>
# default_transport = smtp, but some destinations are special:
#
transport_maps = ${indexed}transport
-</pre>
-</blockquote>
-<blockquote>
-<pre>
transport:
example.com dane
example.org dane
-</pre>
-</blockquote>
-<blockquote>
-<pre>
tls_policy:
example.com dane-only
-</pre>
-</blockquote>
+ # Postfix ≥ 2.12, per-destination smtp_tls_fallback_level override
+ example.org dane fallback=encrypt
-<blockquote>
-<pre>
master.cf:
dane unix - - n - - smtp
-o smtp_dns_support_level=dnssec
are obtained for the remote SMTP server, SSLv2 is automatically
disabled (see smtp_tls_mandatory_protocols), and the server certificate
must match the TLSA records. RFC 6698 (DANE) TLS authentication
-and DNSSEC support is available with Postfix 2.11 and later. </dd>
+and DNSSEC support is available with Postfix 2.11 and later.
+The optional "fallback" attribute provides a per-site override of
+the main.cf smtp_tls_fallback_level parameter (Postfix ≥ 2.12).
+</dd>
<dt><b>dane-only</b></dt> <dd><a href="#client_tls_dane">Mandatory DANE TLS</a>.
The TLS policy for the destination is obtained via TLSA records in
obtained for the remote SMTP server, SSLv2 is automatically disabled
(see smtp_tls_mandatory_protocols), and the server certificate must
match the TLSA records. RFC 6698 (DANE) TLS authentication and
-DNSSEC support is available with Postfix 2.11 and later. </dd>
+DNSSEC support is available with Postfix 2.11 and later.
+The optional "fallback" attribute provides a per-site override of
+the main.cf smtp_tls_fallback_level parameter (Postfix ≥ 2.12).
+</dd>
<dt><b>fingerprint</b></dt> <dd><a href="#client_tls_fprint">Certificate
fingerprint verification.</a> Available with Postfix 2.5 and
not checked. Instead, the optional <b>match</b> attribute, or else
the main.cf <b>smtp_tls_fingerprint_cert_match</b> parameter, lists
the server certificate fingerprints or public key fingerprints
-(Postfix 2.9 and later). The
-digest algorithm used to calculate fingerprints is selected by the
-<b>smtp_tls_fingerprint_digest</b> parameter. Multiple fingerprints can
-be combined with a "|" delimiter in a single match attribute, or multiple
-match attributes can be employed. The ":" character is not used as a
-delimiter as it occurs between each pair of fingerprint (hexadecimal)
-digits. </dd>
+(Postfix 2.9 and later). The digest algorithm used to calculate
+fingerprints is selected by the <b>smtp_tls_fingerprint_digest</b>
+parameter. Multiple fingerprints can be combined with a "|" delimiter
+in a single match attribute, or multiple match attributes can be
+employed. The ":" character is not used as a delimiter as it occurs
+between each pair of fingerprint (hexadecimal) digits.
+The optional "fallback" attribute provides a per-site override of
+the main.cf smtp_tls_fallback_level parameter (Postfix ≥ 2.12).
+</dd>
<dt><b>verify</b></dt> <dd><a href="#client_tls_verify">Mandatory
server certificate verification</a>. Mail is delivered only if the
parameter value when no optional "match" attribute is specified).
With Postfix ≥ 2.11 the "tafile" attribute optionally modifies
trust chain verification in the same manner as the
-"smtp_tls_trust_anchor_file" parameter. The "tafile" attribute
-may be specified multiple times to load multiple trust-anchor
-files. </dd>
+"smtp_tls_trust_anchor_file" parameter. The "tafile" attribute may
+be specified multiple times to load multiple trust-anchor files.
+The optional "fallback" attribute provides a per-site override of
+the main.cf smtp_tls_fallback_level parameter (Postfix ≥ 2.12).
+</dd>
<dt><b>secure</b></dt> <dd><a href="#client_tls_secure">Secure certificate
verification.</a> Mail is delivered only if the TLS handshake succeeds,
attribute optionally modifies trust chain verification in the same manner
as the "smtp_tls_trust_anchor_file" parameter. The "tafile" attribute
may be specified multiple times to load multiple trust-anchor
-files. </dd>
+files.
+The optional "fallback" attribute provides a per-site override of
+the main.cf smtp_tls_fallback_level parameter (Postfix ≥ 2.12).
+</dd>
</dl>
smtp_tls_policy_maps = hash:/etc/postfix/tls_policy
# Postfix 2.5 and later
smtp_tls_fingerprint_digest = md5
+
/etc/postfix/tls_policy:
example.edu none
example.mil may
match=3D:95:34:51:24:66:33:B9:D2:40:99:C0:C1:17:0B:D1
# Postfix 2.6 and later
example.info may protocols=!SSLv2 ciphers=medium exclude=3DES
+ # Postfix 2.12 and later override of smtp_tls_fallback_level
+ fallback.example secure fallback=encrypt
</pre>
</blockquote>
<p> This feature is available in Postfix 2.12 and later. </p>
+%PARAM smtp_tls_fallback_level
+
+<p> Optional fallback levels for authenticated TLS levels. Specify
+a white-space or comma-separated list of
+<b>policy_level</b>=<b>fallback_level</b> pairs. The <b>policy_level</b>
+must require authentication (one of dane, dane-only, fingerprint,
+verify, secure). The <b>fallback_level</b> must be "encrypt" or
+"may". When an authenticated connection at some desired policy
+level cannot be established, delivery will proceed at the correponding
+fallback level if possible. A warning will be logged
+indicating the fallback reason. </p>
+
+<p> The TLS <a href="TLS_README.html#client_tls_policy">policy</a> table
+can be used to specify a destination-specific fallback strategy via the
+"fallback" policy attribute. The value of the "fallback" attribute, if
+specified, must be "may", "encrypt" or "none". If not "none", this
+specifies the fallback level for the destination in question. If the
+attribute value is "none", fallback is suppressed for the destination
+even if enabled via a global setting of smtp_tls_fallback_level. </p>
+
+<p> Example: </p>
+
+<blockquote>
+<pre>
+/etc/postfix/main.cf:
+ # When authentication fails, log a warning and deliver anyway
+ # over an unauthenticated TLS connection.
+ #
+ smtp_tls_fallback_level =
+ dane=encrypt,
+ dane-only=encrypt,
+ fingerprint=encrypt,
+ verify=encrypt,
+ secure=encrypt
+ indexed = ${default_database_type}:${config_directory}/
+ smtp_tls_policy_maps = ${indexed}tls-policy
+</pre>
+</blockquote>
+
+<blockquote>
+<pre>
+/etc/postfix/tls-policy:
+ # No fallback for example.com
+ example.com secure fallback=none
+ # For example.net tolerate cleartext fallback
+ example.net dane fallback=may
+</pre>
+</blockquote>
+
+<p> This feature is available in Postfix 2.12 and later. </p>
+
+%PARAM lmtp_tls_fallback_level
+
+<p> The LMTP-specific version of the smtp_tls_fallback_level
+configuration parameter. See there for details. </p>
+
+<p> This feature is available in Postfix 2.12 and later. </p>
+
%PARAM compatibility_level 0
<p> A safety net that causes Postfix to run with backwards-compatible
<blockquote>
<pre>
-using backwards-compatible default setting <i>name=value</i> to [accept a specific client request]
+using backwards-compatible default setting <i>name=value</i>
+ to [accept a specific client request]
<nroffescape .sp>
-using backwards-compatible default setting <i>name=value</i> to [enable specific Postfix behavior]
+using backwards-compatible default setting <i>name=value</i>
+ to [enable specific Postfix behavior]
</pre>
</blockquote>
<blockquote>
<pre>
-warning: To disable backwards compatibility use "postconf compatibility_level=<i>N</i>" and "postfix reload"
+warning: To disable backwards compatibility use "postconf
+ compatibility_level=<i>N</i>" and "postfix reload"
</pre>
</blockquote>
void attr_override(char *cp, const char *sep, const char *parens,...)
{
- const char myname[] = "attr_override";
+ static const char myname[] = "attr_override";
va_list ap;
int idx;
char *nameval;
void bounce_client_init(const char *title, const char *maps)
{
- const char myname[] = "bounce_client_init";
+ static const char myname[] = "bounce_client_init";
if (delivery_status_filter != 0)
msg_panic("%s: duplicate initialization", myname);
DSN_FILTER *dsn_filter_create(const char *title, const char *map_names)
{
- const char myname[] = "dsn_filter_create";
+ static const char myname[] = "dsn_filter_create";
DSN_FILTER *fp;
if (msg_verbose)
DSN *dsn_filter_lookup(DSN_FILTER *fp, DSN *dsn)
{
- const char myname[] = "dsn_filter_lookup";
+ static const char myname[] = "dsn_filter_lookup";
const char *result;
int ndr_dsn = 0;
void dsn_filter_free(DSN_FILTER *fp)
{
- const char myname[] = "dsn_filter_free";
+ static const char myname[] = "dsn_filter_free";
if (msg_verbose)
msg_info("%s: %s", myname, fp->maps->title);
void dymap_init(const char *conf_path, const char *plugin_dir)
{
- const char myname[] = "dymap_init";
+ static const char myname[] = "dymap_init";
SCAN_DIR *dir;
char *conf_path_d;
const char *conf_name;
extern bool var_show_unk_rcpt_table;
/*
- * Compatibility level and migration support. Update postconf(5) and
- * COMPATIBILITY_README when updating the current compatibility level.
+ * Compatibility level and migration support. Update postconf(5),
+ * COMPATIBILITY_README, and conf/main.cf when updating the current
+ * compatibility level.
*/
#define VAR_COMPAT_LEVEL "compatibility_level"
#define DEF_COMPAT_LEVEL 0
#define DEF_LMTP_TLS_LEVEL ""
extern char *var_smtp_tls_level;
+#define VAR_SMTP_TLS_FBACK_LEVEL "smtp_tls_fallback_level"
+#define DEF_SMTP_TLS_FBACK_LEVEL ""
+#define VAR_LMTP_TLS_FBACK_LEVEL "lmtp_tls_fallback_level"
+#define DEF_LMTP_TLS_FBACK_LEVEL ""
+extern char *var_smtp_tls_fback_level;
+
#define VAR_SMTP_TLS_SCERT_VD "smtp_tls_scert_verifydepth"
#define DEF_SMTP_TLS_SCERT_VD 9
#define VAR_LMTP_TLS_SCERT_VD "lmtp_tls_scert_verifydepth"
* Patches change both the patchlevel and the release date. Snapshots have no
* patchlevel; they change the release date only.
*/
-#define MAIL_RELEASE_DATE "20141009"
+#define MAIL_RELEASE_DATE "20141011"
#define MAIL_VERSION_NUMBER "2.12"
#ifdef SNAPSHOT
static void mkmap_open_init(void)
{
- const char myname[] = "mkmap_open_init";
+ static const char myname[] = "mkmap_open_init";
const MKMAP_OPEN_INFO *mp;
if (mkmap_open_hash != 0)
void mkmap_open_register(const char *type, MKMAP_OPEN_FN open_fn)
{
- const char myname[] = "mkmap_open_register";
+ static const char myname[] = "mkmap_open_register";
MKMAP_OPEN_INFO *mp;
HTABLE_INFO *ht;
int smtputf8_autodetect(int class)
{
- const char myname[] = "smtputf8_autodetect";
+ static const char myname[] = "smtputf8_autodetect";
static const NAME_MASK table[] = {
MAIL_SRC_NAME_SENDMAIL, MAIL_SRC_MASK_SENDMAIL,
MAIL_SRC_NAME_SMTPD, MAIL_SRC_MASK_SMTPD,
VAR_LMTP_TLS_ECCERT_FILE, DEF_LMTP_TLS_ECCERT_FILE, &var_smtp_tls_eccert_file, 0, 0,
VAR_LMTP_TLS_ECKEY_FILE, DEF_LMTP_TLS_ECKEY_FILE, &var_smtp_tls_eckey_file, 0, 0,
VAR_LMTP_TLS_LOGLEVEL, DEF_LMTP_TLS_LOGLEVEL, &var_smtp_tls_loglevel, 0, 0,
+ VAR_LMTP_TLS_FBACK_LEVEL, DEF_LMTP_TLS_FBACK_LEVEL, &var_smtp_tls_fback_level, 0, 0,
#endif
VAR_LMTP_SASL_MECHS, DEF_LMTP_SASL_MECHS, &var_smtp_sasl_mechs, 0, 0,
VAR_LMTP_SASL_TYPE, DEF_LMTP_SASL_TYPE, &var_smtp_sasl_type, 1, 0,
/* RFC 6698 trust-anchor digest support in the Postfix TLS library.
/* .IP "\fBtlsmgr_service_name (tlsmgr)\fR"
/* The name of the \fBtlsmgr\fR(8) service entry in master.cf.
+/* .PP
+/* Available in Postfix version 2.12 and later:
+/* .IP "\fBsmtp_tls_fallback_level (empty)\fR"
+/* Optional fallback levels for authenticated TLS levels.
/* OBSOLETE STARTTLS CONTROLS
/* .ad
/* .fi
char *var_smtp_tls_dcert_file;
char *var_smtp_tls_dkey_file;
bool var_smtp_tls_enforce_peername;
+char *var_smtp_tls_fback_level;
char *var_smtp_tls_key_file;
char *var_smtp_tls_loglevel;
bool var_smtp_tls_note_starttls_offer;
smtp_dns_support =
name_code(dns_support, NAME_CODE_FLAG_NONE, var_smtp_dns_support);
if (smtp_dns_support == SMTP_DNS_INVALID)
- msg_fatal("invalid %s: \"%s\"", SMTP_X(DNS_SUPPORT),
+ msg_fatal("invalid %s: \"%s\"", VAR_LMTP_SMTP(DNS_SUPPORT),
var_smtp_dns_support);
var_disable_dns = (smtp_dns_support == SMTP_DNS_DISABLED);
}
smtp_host_lookup_mask = SMTP_HOST_FLAG_NATIVE;
else
smtp_host_lookup_mask =
- name_mask(SMTP_X(HOST_LOOKUP), lookup_masks, var_smtp_host_lookup);
+ name_mask(VAR_LMTP_SMTP(HOST_LOOKUP), lookup_masks,
+ var_smtp_host_lookup);
if (msg_verbose)
msg_info("host name lookup methods: %s",
- str_name_mask(SMTP_X(HOST_LOOKUP), lookup_masks,
+ str_name_mask(VAR_LMTP_SMTP(HOST_LOOKUP), lookup_masks,
smtp_host_lookup_mask));
/*
/*
* Select DNS query flags.
*/
- smtp_dns_res_opt = name_mask(SMTP_X(DNS_RES_OPT), dns_res_opt_masks,
+ smtp_dns_res_opt = name_mask(VAR_LMTP_SMTP(DNS_RES_OPT), dns_res_opt_masks,
var_smtp_dns_res_opt);
}
smtp_sasl_initialize();
#else
msg_warn("%s is true, but SASL support is not compiled in",
- SMTP_X(SASL_ENABLE));
+ VAR_LMTP_SMTP(SASL_ENABLE));
#endif
if (*var_smtp_tls_level != 0)
*/
smtp_tls_ctx =
TLS_CLIENT_INIT(&props,
- log_param = SMTP_X(TLS_LOGLEVEL),
+ log_param = VAR_LMTP_SMTP(TLS_LOGLEVEL),
log_level = var_smtp_tls_loglevel,
verifydepth = var_smtp_tls_scert_vd,
- cache_type = X_SMTP(TLS_MGR_SCACHE),
+ cache_type = LMTP_SMTP_SUFFIX(TLS_MGR_SCACHE),
cert_file = var_smtp_tls_cert_file,
key_file = var_smtp_tls_key_file,
dcert_file = var_smtp_tls_dcert_file,
* EHLO keyword filter.
*/
if (*var_smtp_ehlo_dis_maps)
- smtp_ehlo_dis_maps = maps_create(SMTP_X(EHLO_DIS_MAPS),
+ smtp_ehlo_dis_maps = maps_create(VAR_LMTP_SMTP(EHLO_DIS_MAPS),
var_smtp_ehlo_dis_maps,
DICT_FLAG_LOCK);
* PIX bug workarounds.
*/
if (*var_smtp_pix_bug_maps)
- smtp_pix_bug_maps = maps_create(SMTP_X(PIX_BUG_MAPS),
+ smtp_pix_bug_maps = maps_create(VAR_LMTP_SMTP(PIX_BUG_MAPS),
var_smtp_pix_bug_maps,
DICT_FLAG_LOCK);
ext_prop_mask(VAR_PROP_EXTENSION, var_prop_extension);
if (*var_smtp_generic_maps)
smtp_generic_maps =
- maps_create(SMTP_X(GENERIC_MAPS), var_smtp_generic_maps,
+ maps_create(VAR_LMTP_SMTP(GENERIC_MAPS), var_smtp_generic_maps,
DICT_FLAG_LOCK | DICT_FLAG_FOLD_FIX);
/*
* Header/body checks.
*/
smtp_header_checks = hbc_header_checks_create(
- SMTP_X(HEAD_CHKS), var_smtp_head_chks,
- SMTP_X(MIME_CHKS), var_smtp_mime_chks,
- SMTP_X(NEST_CHKS), var_smtp_nest_chks,
+ VAR_LMTP_SMTP(HEAD_CHKS), var_smtp_head_chks,
+ VAR_LMTP_SMTP(MIME_CHKS), var_smtp_mime_chks,
+ VAR_LMTP_SMTP(NEST_CHKS), var_smtp_nest_chks,
smtp_hbc_callbacks);
smtp_body_checks = hbc_body_checks_create(
- SMTP_X(BODY_CHKS), var_smtp_body_chks,
+ VAR_LMTP_SMTP(BODY_CHKS), var_smtp_body_chks,
smtp_hbc_callbacks);
/*
smtp_addr_pref = name_code(addr_pref_map, NAME_CODE_FLAG_NONE,
var_smtp_addr_pref);
if (smtp_addr_pref < 0)
- msg_fatal("bad %s value: %s", SMTP_X(ADDR_PREF), var_smtp_addr_pref);
+ msg_fatal("bad %s value: %s", VAR_LMTP_SMTP(ADDR_PREF),
+ var_smtp_addr_pref);
}
}
typedef struct SMTP_TLS_POLICY {
int level; /* TLS enforcement level */
+ int policy_level; /* TLS desired policy level */
+ int fallback_level; /* TLS fallback level */
char *protocols; /* Acceptable SSL protocols */
char *grade; /* Cipher grade: "export", ... */
VSTRING *exclusions; /* Excluded SSL ciphers */
SMTP_TLS_POLICY *_tls_policy_dummy_tmp = (t); \
smtp_tls_policy_init(_tls_policy_dummy_tmp, (DSN_BUF *) 0); \
_tls_policy_dummy_tmp->level = TLS_LEV_NONE; \
+ _tls_policy_dummy_tmp->policy_level = TLS_LEV_NONE; \
} while (0)
/* This macro is not part of the module external interface. */
#define smtp_tls_policy_init(t, w) do { \
SMTP_TLS_POLICY *_tls_policy_init_tmp = (t); \
+ _tls_policy_init_tmp->fallback_level = TLS_LEV_NOTFOUND; \
_tls_policy_init_tmp->protocols = 0; \
_tls_policy_init_tmp->grade = 0; \
_tls_policy_init_tmp->exclusions = 0; \
char *tls_nexthop; /* Nexthop domain for cert checks */
int tls_retry_plain; /* Try plain when TLS handshake fails */
SMTP_TLS_POLICY *tls; /* TEMPORARY */
+ int tls_level; /* Actual tls level */
#endif
SMTP_STATE *state; /* back link */
#define PLAINTEXT_FALLBACK_OK_AFTER_STARTTLS_FAILURE \
(session->tls_context == 0 \
- && session->tls->level == TLS_LEV_MAY \
+ && (session->tls->level == TLS_LEV_MAY \
+ || session->tls->fallback_level == TLS_LEV_MAY) \
&& PREACTIVE_DELAY >= var_min_backoff_time \
&& !HAVE_SASL_CREDENTIALS)
#define PLAINTEXT_FALLBACK_OK_AFTER_TLS_SESSION_FAILURE \
(session->tls_context != 0 \
&& SMTP_RCPT_LEFT(state) > SMTP_RCPT_MARK_COUNT(state) \
- && session->tls->level == TLS_LEV_MAY \
+ && (session->tls->level == TLS_LEV_MAY \
+ || session->tls->fallback_level == TLS_LEV_MAY) \
&& PREACTIVE_DELAY >= var_min_backoff_time \
&& !HAVE_SASL_CREDENTIALS)
#define RETRY_AS_PLAINTEXT do { \
session->tls_retry_plain = 1; \
state->misc_flags &= ~SMTP_MISC_FLAG_FINAL_SERVER; \
+ (void) smtp_tls_trouble(state, session->tls_context ? \
+ STARTTLS_SESSION_FALLBACK : \
+ STARTTLS_HANDSHAKE_FALLBACK); \
} while (0)
+#define STARTTLS_FEATURE_FALLBACK 1 /* No STARTTLS feature */
+#define STARTTLS_COMMAND_FALLBACK 2 /* Refused STARTTLS command */
+#define STARTTLS_HANDSHAKE_FALLBACK 3 /* Handshake failed */
+#define STARTTLS_VERIFY_FALLBACK 4 /* Peer verification failed */
+#define STARTTLS_SESSION_FALLBACK 5 /* Data transfer failed */
+
/*
* smtp_chat.c
*/
const char *,...);
extern int smtp_stream_except(SMTP_STATE *, int, const char *);
+#ifdef USE_TLS
+extern int smtp_tls_trouble(SMTP_STATE *, int);
+
+#endif
+
/*
* smtp_unalias.c
*/
extern int smtp_mode;
-#define SMTP_X(x) (smtp_mode ? VAR_SMTP_##x : VAR_LMTP_##x)
-#define X_SMTP(x) (smtp_mode ? x##_SMTP : x##_LMTP)
+#define VAR_LMTP_SMTP(x) (smtp_mode ? VAR_SMTP_##x : VAR_LMTP_##x)
+#define LMTP_SMTP_SUFFIX(x) (smtp_mode ? x##_SMTP : x##_LMTP)
/* LICENSE
/* .ad
msg_warn("to prevent loss of mail, turn off command pipelining "
"for %s with the %s parameter",
STR(session->iterator->addr),
- SMTP_X(EHLO_DIS_MAPS));
+ VAR_LMTP_SMTP(EHLO_DIS_MAPS));
}
}
#include <smtp_addr.h>
#include <smtp_reuse.h>
+ /*
+ * XXX All TLS security level info belongs in session->tls. It should not
+ * pollute the session structure and consequently pollute internal APIs that
+ * don't need access to the session structure. However session->tls is a
+ * pointer into the cache and must therefore not be modified.
+ */
+#ifdef USE_TLS
+#define TLS_SESS_INIT(session, state) do { \
+ session->tls_level = state->tls->level; /* XXX Pre fallback */ \
+ session->tls = state->tls; /* TEMPORARY */ \
+ } while (0)
+#endif
+
/*
* Forward declaration.
*/
#ifdef HAS_IPV6
if (sa->sa_family == AF_INET6) {
bind_addr = var_smtp_bind_addr6;
- bind_var = SMTP_X(BIND_ADDR6);
+ bind_var = VAR_LMTP_SMTP(BIND_ADDR6);
} else
#endif
if (sa->sa_family == AF_INET) {
bind_addr = var_smtp_bind_addr;
- bind_var = SMTP_X(BIND_ADDR);
+ bind_var = VAR_LMTP_SMTP(BIND_ADDR);
} else
bind_var = bind_addr = "";
if (*bind_addr) {
if ((state->session = session) != 0) {
session->state = state;
#ifdef USE_TLS
- session->tls = state->tls; /* TEMPORARY */
+ TLS_SESS_INIT(session, state); /* TEMPORARY */
session->tls_nexthop = var_myhostname; /* for TLS_LEV_SECURE */
if (session->tls->level == TLS_LEV_MAY) {
msg_warn("%s: opportunistic TLS encryption is not appropriate "
&& *addr_list == 0)
state->misc_flags |= SMTP_MISC_FLAG_FINAL_SERVER;
#ifdef USE_TLS
- session->tls = state->tls; /* TEMPORARY */
+ TLS_SESS_INIT(session, state); /* TEMPORARY */
#endif
smtp_xfer(state);
smtp_cleanup_session(state);
&& next == 0)
state->misc_flags |= SMTP_MISC_FLAG_FINAL_SERVER;
#ifdef USE_TLS
- session->tls = state->tls; /* TEMPORARY */
+ TLS_SESS_INIT(session, state); /* TEMPORARY */
#endif
smtp_xfer(state);
smtp_cleanup_session(state);
if ((state->session = session) != 0) {
session->state = state;
#ifdef USE_TLS
- session->tls = state->tls; /* TEMPORARY */
+ TLS_SESS_INIT(session, state); /* TEMPORARY */
/* XXX: EAI: Convert to A-label here or in TLS library */
session->tls_nexthop = domain; /* for TLS_LEV_SECURE */
#endif
char *smtp_key_prefix(VSTRING *buffer, const char *delim_na,
SMTP_ITERATOR *iter, int flags)
{
- const char myname[] = "smtp_key_prefix";
+ static const char myname[] = "smtp_key_prefix";
SMTP_STATE *state = iter->parent; /* private member */
/*
VAR_SMTP_TLS_ECCERT_FILE, DEF_SMTP_TLS_ECCERT_FILE, &var_smtp_tls_eccert_file, 0, 0,
VAR_SMTP_TLS_ECKEY_FILE, DEF_SMTP_TLS_ECKEY_FILE, &var_smtp_tls_eckey_file, 0, 0,
VAR_SMTP_TLS_LOGLEVEL, DEF_SMTP_TLS_LOGLEVEL, &var_smtp_tls_loglevel, 0, 0,
+ VAR_SMTP_TLS_FBACK_LEVEL, DEF_SMTP_TLS_FBACK_LEVEL, &var_smtp_tls_fback_level, 0, 0,
#endif
VAR_SMTP_SASL_MECHS, DEF_SMTP_SASL_MECHS, &var_smtp_sasl_mechs, 0, 0,
VAR_SMTP_SASL_TYPE, DEF_SMTP_SASL_TYPE, &var_smtp_sasl_type, 1, 0,
/*
* If the policy table specifies a bogus TLS security level, fail
* now.
+ *
+ * XXX: This should be caught in smtp_connect before we even make a
+ * connection to the host. Change to msg_panic()?
*/
#ifdef USE_TLS
if (session->tls->level == TLS_LEV_INVALID)
&& (pix_bug_words =
maps_find(smtp_pix_bug_maps,
STR(iter->addr), 0)) != 0) {
- pix_bug_source = SMTP_X(PIX_BUG_MAPS);
+ pix_bug_source = VAR_LMTP_SMTP(PIX_BUG_MAPS);
} else {
pix_bug_words = var_smtp_pix_bug_words;
- pix_bug_source = SMTP_X(PIX_BUG_WORDS);
+ pix_bug_source = VAR_LMTP_SMTP(PIX_BUG_WORDS);
}
if (*pix_bug_words) {
pix_bug_mask = name_mask_opt(pix_bug_source, pix_bug_table,
* although support for it was announced in the EHLO response.
*/
session->features &= ~SMTP_FEATURE_STARTTLS;
- if (TLS_REQUIRED(session->tls->level))
+ if (smtp_tls_trouble(state, STARTTLS_COMMAND_FALLBACK))
return (smtp_site_fail(state, STR(iter->host), resp,
"TLS is required, but host %s refused to start TLS: %s",
session->namaddr,
translit(resp->str, "\n", " ")));
/* Else try to continue in plain-text mode. */
- }
+ } else {
- /*
- * Give up if we must use TLS but can't for various reasons.
- *
- * 200412 Be sure to provide the default clause at the bottom of this
- * block. When TLS is required we must never, ever, end up in
- * plain-text mode.
- */
- if (TLS_REQUIRED(session->tls->level)) {
- if (!(session->features & SMTP_FEATURE_STARTTLS)) {
- return (smtp_site_fail(state, DSN_BY_LOCAL_MTA,
- SMTP_RESP_FAKE(&fake, "4.7.4"),
+ /*
+ * Give up if we must use TLS but can't for various reasons.
+ *
+ * 200412 Be sure to provide the default clause at the bottom of
+ * this block. When TLS is required we must never, ever, end up
+ * in plain-text mode.
+ */
+ if (smtp_tls_trouble(state, STARTTLS_FEATURE_FALLBACK)) {
+ if (!(session->features & SMTP_FEATURE_STARTTLS)) {
+ return (smtp_site_fail(state, DSN_BY_LOCAL_MTA,
+ SMTP_RESP_FAKE(&fake, "4.7.4"),
"TLS is required, but was not offered by host %s",
- session->namaddr));
- } else if (smtp_tls_ctx == 0) {
- return (smtp_site_fail(state, DSN_BY_LOCAL_MTA,
- SMTP_RESP_FAKE(&fake, "4.7.5"),
+ session->namaddr));
+ } else if (smtp_tls_ctx == 0) {
+ return (smtp_site_fail(state, DSN_BY_LOCAL_MTA,
+ SMTP_RESP_FAKE(&fake, "4.7.5"),
"TLS is required, but our TLS engine is unavailable"));
- } else {
- msg_warn("%s: TLS is required but unavailable, don't know why",
- myname);
- return (smtp_site_fail(state, DSN_BY_LOCAL_MTA,
- SMTP_RESP_FAKE(&fake, "4.7.0"),
+ } else {
+ msg_warn("%s: TLS is required but unavailable, don't know why",
+ myname);
+ return (smtp_site_fail(state, DSN_BY_LOCAL_MTA,
+ SMTP_RESP_FAKE(&fake, "4.7.0"),
"TLS is required, but unavailable"));
+ }
}
}
}
TLS_CLIENT_START_PROPS tls_props;
VSTRING *serverid;
SMTP_RESP fake;
+ int tls_level;
/*
* Turn off SMTP connection caching. When the TLS handshake succeeds, we
* resulting TLScontext. It is now up to the application to abort the TLS
* connection if it chooses.
*
+ * Consequently, the TLS library need not and does not distinguish between
+ * the "dane" and "dane-only" security levels. By the time we have TLSA
+ * records in hand, both behave identically modulo application-level
+ * fallback. We collapse these now equivalent security levels.
+ *
* XXX When tls_client_start() fails then we don't know what state the SMTP
* connection is in, so we give up on this connection even if we are not
* required to use TLS.
* Large parameter lists are error-prone, so we emulate a language feature
* that C does not have natively: named parameter lists.
*/
+ if ((tls_level = session->tls->level) == TLS_LEV_DANE_ONLY)
+ tls_level = TLS_LEV_DANE;
session->tls_context =
TLS_CLIENT_START(&tls_props,
ctx = smtp_tls_ctx,
stream = session->stream,
timeout = var_smtp_starttls_tmout,
- tls_level = session->tls->level,
+ tls_level = tls_level,
nexthop = session->tls_nexthop,
host = STR(iter->host),
namaddr = session->namaddrport,
* result, abort the delivery here. We have a usable TLS session with the
* server, so no need to disable I/O, ... we can even be polite and send
* "QUIT".
- *
- * See src/tls/tls_level.c and src/tls/tls.h. Levels above "encrypt" require
- * matching. Levels >= "dane" require CA or DNSSEC trust.
- *
- * When DANE TLSA records specify an end-entity certificate, the trust and
- * match bits always coincide, but it is fine to report the wrong
- * end-entity certificate as untrusted rather than unmatched.
*/
- if (TLS_MUST_TRUST(session->tls->level))
- if (!TLS_CERT_IS_TRUSTED(session->tls_context))
+ if (TLS_MUST_TRUST(session->tls_level)
+ && !TLS_CERT_IS_TRUSTED(session->tls_context)) {
+ if (smtp_tls_trouble(state, STARTTLS_VERIFY_FALLBACK))
return (smtp_site_fail(state, DSN_BY_LOCAL_MTA,
SMTP_RESP_FAKE(&fake, "4.7.5"),
"Server certificate not trusted"));
- if (TLS_MUST_MATCH(session->tls->level))
- if (!TLS_CERT_IS_MATCHED(session->tls_context))
+ } else if (TLS_MUST_MATCH(session->tls_level)
+ && !TLS_CERT_IS_MATCHED(session->tls_context)) {
+ /* Peer certificate not matched as it should be */
+ if (smtp_tls_trouble(state, STARTTLS_VERIFY_FALLBACK))
return (smtp_site_fail(state, DSN_BY_LOCAL_MTA,
SMTP_RESP_FAKE(&fake, "4.7.5"),
"Server certificate not verified"));
-
+ }
/* At this point there must not be any pending plaintext. */
vstream_fpurge(session->stream, VSTREAM_PURGE_BOTH);
}
/*
- * Request SMTPUTF8 when the remote SMTP server supports
- * SMTPUTF8 and the sender requested SMTPUTF8 support.
+ * Request SMTPUTF8 when the remote SMTP server supports SMTPUTF8
+ * and the sender requested SMTPUTF8 support.
*
* If the sender requested SMTPUTF8 but the remote SMTP server does
* not support SMTPUTF8, then we have already determined earlier
"unexpected server message");
msg_warn("server %s violates %s policy",
session->namaddr,
- SMTP_X(TLS_BLK_EARLY_MAIL_REPLY));
+ VAR_LMTP_SMTP(TLS_BLK_EARLY_MAIL_REPLY));
mail_from_rejected = 1;
}
#endif
msg_panic("smtp_sasl_initialize: repeated call");
if (*var_smtp_sasl_passwd == 0)
msg_fatal("specify a password table via the `%s' configuration parameter",
- SMTP_X(SASL_PASSWD));
+ VAR_LMTP_SMTP(SASL_PASSWD));
/*
* Open the per-host password table and initialize the SASL library. Use
var_smtp_sasl_auth_cache_time);
#else
msg_warn("not compiled with TLS support -- "
- "ignoring the %s setting", SMTP_X(SASL_AUTH_CACHE_NAME));
+ "ignoring the %s setting", VAR_LMTP_SMTP(SASL_AUTH_CACHE_NAME));
#endif
}
}
/* Session reuse is disabled. */
} else {
#ifndef USE_TLS
- smtp_sasl_start(session, SMTP_X(SASL_OPTS), var_smtp_sasl_opts);
+ smtp_sasl_start(session, VAR_LMTP_SMTP(SASL_OPTS), var_smtp_sasl_opts);
#else
if (session->tls_context == 0)
- smtp_sasl_start(session, SMTP_X(SASL_OPTS), var_smtp_sasl_opts);
+ smtp_sasl_start(session, VAR_LMTP_SMTP(SASL_OPTS),
+ var_smtp_sasl_opts);
else if (TLS_CERT_IS_MATCHED(session->tls_context))
- smtp_sasl_start(session, SMTP_X(SASL_TLSV_OPTS),
+ smtp_sasl_start(session, VAR_LMTP_SMTP(SASL_TLSV_OPTS),
var_smtp_sasl_tlsv_opts);
else
- smtp_sasl_start(session, SMTP_X(SASL_TLS_OPTS),
+ smtp_sasl_start(session, VAR_LMTP_SMTP(SASL_TLS_OPTS),
var_smtp_sasl_tls_opts);
#endif
if (smtp_sasl_authenticate(session, why) <= 0) {
void smtp_tls_list_init(void)
{
if (*var_smtp_tls_policy) {
- tls_policy = maps_create(SMTP_X(TLS_POLICY), var_smtp_tls_policy,
+ tls_policy = maps_create(VAR_LMTP_SMTP(TLS_POLICY), var_smtp_tls_policy,
DICT_FLAG_LOCK | DICT_FLAG_FOLD_FIX);
if (*var_smtp_tls_per_site)
msg_warn("%s ignored when %s is not empty.",
- SMTP_X(TLS_PER_SITE), SMTP_X(TLS_POLICY));
+ VAR_LMTP_SMTP(TLS_PER_SITE), VAR_LMTP_SMTP(TLS_POLICY));
return;
}
if (*var_smtp_tls_per_site) {
- tls_per_site = maps_create(SMTP_X(TLS_PER_SITE), var_smtp_tls_per_site,
+ tls_per_site = maps_create(VAR_LMTP_SMTP(TLS_PER_SITE),
+ var_smtp_tls_per_site,
DICT_FLAG_LOCK | DICT_FLAG_FOLD_FIX);
}
}
}
#define MARK_INVALID(why, levelp) do { \
- dsb_simple((why), "4.7.5", "client TLS configuration problem"); \
+ dsb_simple((why), "4.7.0", "client TLS configuration problem"); \
*(levelp) = TLS_LEV_INVALID; } while (0)
/* tls_site_lookup - look up per-site TLS security level */
}
continue;
}
+ /* Only one instance per policy. */
+ if (!strcasecmp(name, "fallback")) {
+ int l;
+
+ if (!TLS_MUST_MATCH(*site_level)) {
+ msg_warn("%s: attribute \"%s\" invalid at security level"
+ " \"%s\"", WHERE, name, policy_name(*site_level));
+ continue;
+ }
+ if (tls->fallback_level != TLS_LEV_NOTFOUND) {
+ msg_warn("%s: attribute \"%s\" is specified multiple times",
+ WHERE, name);
+ continue;
+ }
+ if (*val == 0) {
+ msg_warn("%s: attribute \"%s\" has empty value", WHERE, name);
+ continue;
+ }
+ switch (l = tls_level_lookup(val)) {
+ case TLS_LEV_NONE:
+ case TLS_LEV_MAY:
+ case TLS_LEV_ENCRYPT:
+ tls->fallback_level = l;
+ break;
+ default:
+ msg_warn("%s: attribute \"%s\" invalid fallback level: \"%s\"",
+ WHERE, name, val);
+ break;
+ }
+ continue;
+ }
msg_warn("%s: invalid attribute name: \"%s\"", WHERE, name);
INVALID_RETURN(tls->why, site_level);
}
break;
case TLS_LEV_DANE:
+ case TLS_LEV_DANE_ONLY:
case TLS_LEV_FPRINT:
case TLS_LEV_VERIFY:
case TLS_LEV_SECURE:
ADD_EXCLUDE(tls->exclusions, also_exclude);
}
+static int global_fallback(SMTP_TLS_POLICY *tls)
+{
+ static int l = TLS_LEV_NOTFOUND;
+ const char *lname = str_tls_level(tls->level);
+ const char *err;
+ char *saved;
+ char *fback;
+ char *tok;
+ char *name;
+ char *val;
+
+ /*
+ * Silently ignore any spurious fallback setting for unauthenticated TLS.
+ */
+ if (!*var_smtp_tls_fback_level || tls->level <= TLS_LEV_ENCRYPT)
+ return l;
+
+ saved = fback = mystrdup(var_smtp_tls_fback_level);
+ while ((tok = mystrtok(&fback, "\t\n\r ,")) != 0) {
+ if ((err = split_nameval(tok, &name, &val)) != 0) {
+ msg_warn("malformed %s: \"%s\": %s", VAR_LMTP_SMTP(TLS_FBACK_LEVEL),
+ saved, err);
+ l = TLS_LEV_NOTFOUND;
+ break;
+ }
+ if (strcmp(name, lname) == 0) {
+ switch (l = tls_level_lookup(val)) {
+ case TLS_LEV_MAY:
+ case TLS_LEV_ENCRYPT:
+ break;
+ default:
+ msg_warn("%s: bad fallback mapping: %s=%s",
+ VAR_LMTP_SMTP(TLS_FBACK_LEVEL), name, val);
+ l = TLS_LEV_NOTFOUND;
+ break;
+ }
+ break;
+ }
+ }
+ myfree(saved);
+ return (l);
+}
+
/* policy_create - create SMTP TLS policy cache object (ctable call-back) */
static void *policy_create(const char *unused_key, void *context)
return ((void *) tls);
}
+ /*
+ * Save level as policy level (may be downgraded by early fallback, and
+ * compute fallback level if not specified per-site. If site fallback
+ * level is "none", replace with "notfound", otherwise if no site
+ * fallback level, use the global value.
+ */
+ tls->policy_level = tls->level;
+ if (tls->fallback_level == TLS_LEV_NONE)
+ tls->fallback_level = TLS_LEV_NOTFOUND;
+ else if (tls->fallback_level == TLS_LEV_NOTFOUND
+ && (tls->fallback_level = global_fallback(tls)) == TLS_LEV_INVALID)
+ tls->fallback_level = TLS_LEV_NOTFOUND;
+
/*
* DANE initialization may change the security level to something else,
* so do this early, so that we use the right level below. Note that
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)
#define NONDANE_CONFIG 0 /* Administrator's fault */
#define NONDANE_DEST 1 /* Remote server's fault */
#define DANE_UNUSABLE 2 /* Remote server's fault */
+#define TLSA_LOOKUP_ERR 3 /* DNS lookup failed */
-static void PRINTFLIKE(4, 5) dane_incompat(SMTP_TLS_POLICY *tls,
- SMTP_ITERATOR *iter,
+static void PRINTFLIKE(3, 4) dane_incompat(SMTP_TLS_POLICY *tls,
int errtype,
const char *fmt,...)
{
va_list ap;
va_start(ap, fmt);
- if (tls->level == TLS_LEV_DANE) {
- tls->level = (errtype == DANE_UNUSABLE) ? TLS_LEV_ENCRYPT : TLS_LEV_MAY;
+
+ /*
+ * TLSA lookup errors are potential downgrade attacks, since they can
+ * hide the presence of usable TLSA RRs, we must fail or fallback, not
+ * downgrade to encryption-only or opportunistic TLS as with unusable or
+ * absent TLSA records.
+ */
+ if (tls->level == TLS_LEV_DANE && errtype != TLSA_LOOKUP_ERR) {
+ if (errtype == DANE_UNUSABLE) {
+
+ /*
+ * When TLSA are present, but none are usable, "dane" clients are
+ * expected to perform mandatory unauthenticated TLS. If the
+ * "dane" the fallback level is "may", we enable fallback to
+ * cleartext (with the appropriate warnings).
+ */
+ tls->level = TLS_LEV_ENCRYPT;
+ if (tls->fallback_level != TLS_LEV_MAY)
+ tls->fallback_level = TLS_LEV_NOTFOUND;
+ } else {
+ tls->level = TLS_LEV_MAY;
+ tls->fallback_level = TLS_LEV_NOTFOUND;
+ }
if (errtype == NONDANE_CONFIG)
vmsg_warn(fmt, ap);
else if (msg_verbose)
vmsg_info(fmt, ap);
- } else { /* dane-only */
- if (errtype == NONDANE_CONFIG) {
- vmsg_warn(fmt, ap);
+ } else {
+ vmsg_warn(fmt, ap);
+ if (errtype == NONDANE_CONFIG
+ || tls->fallback_level == TLS_LEV_NOTFOUND)
MARK_INVALID(tls->why, &tls->level);
- } else {
- tls->level = TLS_LEV_INVALID;
- vdsb_simple(tls->why, "4.7.5", fmt, ap);
- }
+ else
+ tls->level = tls->fallback_level;
}
va_end(ap);
}
return;
}
if (!tls_dane_avail()) {
- dane_incompat(tls, iter, NONDANE_CONFIG,
+ dane_incompat(tls, NONDANE_CONFIG,
"%s: %s configured, but no requisite library support",
STR(iter->dest), policy_name(tls->level));
return;
}
if (!(smtp_host_lookup_mask & SMTP_HOST_FLAG_DNS)
|| smtp_dns_support != SMTP_DNS_DNSSEC) {
- dane_incompat(tls, iter, NONDANE_CONFIG,
+ dane_incompat(tls, NONDANE_CONFIG,
"%s: %s configured with dnssec lookups disabled",
STR(iter->dest), policy_name(tls->level));
return;
* key material.
*/
if (smtp_mode && var_ign_mx_lookup_err) {
- dane_incompat(tls, iter, NONDANE_CONFIG,
+ dane_incompat(tls, NONDANE_CONFIG,
"%s: %s configured with MX lookup errors ignored",
STR(iter->dest), policy_name(tls->level));
return;
* to certificate name checks, ...
*/
if (smtp_dns_res_opt & (RES_DEFNAMES | RES_DNSRCH)) {
- dane_incompat(tls, iter, NONDANE_CONFIG,
+ dane_incompat(tls, NONDANE_CONFIG,
"%s: dns resolver options incompatible with %s TLS",
STR(iter->dest), policy_name(tls->level));
return;
}
/* When the MX name is present and insecure, DANE does not apply. */
if (iter->mx && !iter->mx->dnssec_valid) {
- dane_incompat(tls, iter, NONDANE_DEST, "non DNSSEC destination");
+ dane_incompat(tls, NONDANE_DEST, "%s: non-DNSSEC destination",
+ STR(iter->dest));
return;
}
- /* When TLSA lookups fail, we defer the message */
+
+ /*
+ * When TLSA lookups fail, as with dane-only, we fall back or defer the
+ * message, the level will be set to either the fallback level or
+ * "invalid".
+ */
if ((dane = tls_dane_resolve(iter->port, "tcp", iter->rr,
var_smtp_tls_force_tlsa)) == 0) {
- tls->level = TLS_LEV_INVALID;
- dsb_simple(tls->why, "4.7.5", "TLSA lookup error for %s:%u",
- STR(iter->host), ntohs(iter->port));
+ dane_incompat(tls, TLSA_LOOKUP_ERR,
+ "%s:%u: DANE TLSA lookup error",
+ STR(iter->host), ntohs(iter->port));
return;
}
if (tls_dane_notfound(dane)) {
- dane_incompat(tls, iter, NONDANE_DEST, "no TLSA records found");
+ dane_incompat(tls, NONDANE_DEST,
+ "%s:%u: no DANE TLSA records found",
+ STR(iter->host), ntohs(iter->port));
tls_dane_free(dane);
return;
}
-
- /*
- * Some TLSA records found, but none usable, per
- *
- * https://tools.ietf.org/html/draft-ietf-dane-srv-02#section-4
- *
- * we MUST use TLS, and SHALL use full PKIX certificate checks. The latter
- * would be unwise for SMTP: no human present to "click ok" and risk of
- * non-delivery in most cases exceeds risk of interception.
- *
- * We also have a form of Goedel's incompleteness theorem in play: any list
- * of public root CA certs is either incomplete or inconsistent (for any
- * given verifier some of the CAs are surely not trustworthy).
+ /*-
+ * Some TLSA records found, but none usable, per:
+ *
+ * https://tools.ietf.org/html/draft-ietf-dane-smtp-with-dane
+ *
+ * we MUST use TLS.
*/
if (tls_dane_unusable(dane)) {
- dane_incompat(tls, iter, DANE_UNUSABLE, "TLSA records unusable");
+ dane_incompat(tls, DANE_UNUSABLE,
+ "%s:%u: all DANE TLSA records unusable",
+ STR(iter->host), ntohs(iter->port));
tls_dane_free(dane);
return;
}
} else if (!TLS_DANE_HASEE(dane))
msg_panic("empty DANE match list");
tls->dane = dane;
- tls->level = TLS_LEV_DANE;
return;
}
/* SMTP_STATE *state;
/* int exception;
/* const char *description;
+/*
+/* int smtp_tls_trouble(state, protocol_stage)
+/* SMTP_STATE *state;
+/* int protocol_stage;
/* DESCRIPTION
/* This module handles all non-fatal errors that can happen while
/* attempting to deliver mail via SMTP, and implements the policy
/* The session is marked as "do not cache".
/* The result is non-zero.
/*
+/* smtp_tls_trouble() handles failure to establish a TLS connection or
+/* else failure to authenticate the peer. The protocol_stage argument
+/* indicates what TLS problem was detected. The return value is 0 when
+/* TLS is not required or a fallback strategy allows delivery to continue.
+/* When a non-zero value is returned delivery must not continue via the
+/* current SMTP server. All relevant warnings are logged.
+/*
/* Arguments:
/* .IP state
/* SMTP client state per delivery request.
*/
return (smtp_bulk_fail(state, SMTP_THROTTLE));
}
+
+#ifdef USE_TLS
+
+/* smtp_tls_trouble - Fail or fall back when TLS state is not satisfactory. */
+
+int smtp_tls_trouble(SMTP_STATE *state, int protocol_stage)
+{
+ SMTP_SESSION *session = state->session;
+ SMTP_TLS_POLICY *tls = session->tls;
+
+ /* Handle non-recoverable cases */
+ switch (protocol_stage) {
+ case STARTTLS_VERIFY_FALLBACK:
+ if (tls->fallback_level == TLS_LEV_NOTFOUND)
+ return (-1);
+ break;
+ case STARTTLS_FEATURE_FALLBACK:
+ /* No recovery when skipping STARTTLS due to local problems */
+ if (session->features & SMTP_FEATURE_STARTTLS)
+ return (-1);
+ /* FALLTHROUGH */
+ case STARTTLS_COMMAND_FALLBACK:
+ case STARTTLS_HANDSHAKE_FALLBACK:
+ case STARTTLS_SESSION_FALLBACK:
+ if (TLS_REQUIRED(session->tls_level)
+ && tls->fallback_level != TLS_LEV_MAY)
+ return (-1);
+ break;
+ default:
+ msg_panic("Unexpected TLS failure stage: %d", protocol_stage);
+ }
+
+ /* Log appropriate warning and perform fallback */
+ switch (protocol_stage) {
+ case STARTTLS_FEATURE_FALLBACK:
+ if (session->tls_level > TLS_LEV_MAY)
+ msg_warn("%s: cleartext fallback, host did not offer STARTTLS",
+ session->namaddrport);
+ break;
+
+ case STARTTLS_COMMAND_FALLBACK:
+ if (session->tls_level > TLS_LEV_MAY)
+ msg_warn("%s: cleartext fallback, host refused to start TLS",
+ session->namaddrport);
+ break;
+
+ case STARTTLS_HANDSHAKE_FALLBACK:
+ if (session->tls_level > TLS_LEV_MAY)
+ msg_warn("%s: cleartext fallback, TLS handshake failed",
+ session->namaddrport);
+ break;
+
+ case STARTTLS_SESSION_FALLBACK:
+ msg_warn("%s: cleartext fallback, post-handshake TLS failure",
+ session->namaddrport);
+ break;
+
+ case STARTTLS_VERIFY_FALLBACK:
+ msg_warn("%s: fallback to unauthenticated TLS: %s",
+ session->namaddrport,
+ TLS_CERT_IS_TRUSTED(session->tls_context) ?
+ "Server certificate failed verification" :
+ "Server certificate not trusted");
+ break;
+ }
+
+ session->tls_level = tls->fallback_level;
+ return (0);
+}
+
+#endif
static void policy_client_register(const char *name)
{
- const char myname[] = "policy_client_register";
+ static const char myname[] = "policy_client_register";
SMTPD_POLICY_CLNT *policy_client;
char *saved_name = 0;
const char *policy_name = 0;
static const char *dict_pipe_lookup(DICT *dict, const char *query)
{
- const char myname[] = "dict_pipe_lookup";
+ static const char myname[] = "dict_pipe_lookup";
DICT_PIPE *dict_pipe = (DICT_PIPE *) dict;
DICT *map;
char **cpp;
DICT *dict_pipe_open(const char *name, int open_flags, int dict_flags)
{
- const char myname[] = "dict_pipe_open";
+ static const char myname[] = "dict_pipe_open";
DICT_PIPE *dict_pipe;
char *saved_name = 0;
char *dict_type_name;
static const char *dict_union_lookup(DICT *dict, const char *query)
{
- const char myname[] = "dict_union_lookup";
+ static const char myname[] = "dict_union_lookup";
DICT_UNION *dict_union = (DICT_UNION *) dict;
DICT *map;
char **cpp;
DICT *dict_union_open(const char *name, int open_flags, int dict_flags)
{
- const char myname[] = "dict_union_open";
+ static const char myname[] = "dict_union_open";
DICT_UNION *dict_union;
char *saved_name = 0;
char *dict_type_name;
static int mac_expand_callback(int type, VSTRING *buf, char *ptr)
{
- const char myname[] = "mac_expand_callback";
+ static const char myname[] = "mac_expand_callback";
MAC_EXP_CONTEXT *mc = (MAC_EXP_CONTEXT *) ptr;
int lookup_mode;
const char *lookup;
static void *midna_utf8_to_ascii_create(const char *name, void *unused_context)
{
- const char myname[] = "midna_utf8_to_ascii_create";
+ static const char myname[] = "midna_utf8_to_ascii_create";
char buf[1024]; /* XXX */
UErrorCode error = U_ZERO_ERROR;
UIDNAInfo info = UIDNA_INFO_INITIALIZER;
static void *midna_ascii_to_utf8_create(const char *name, void *unused_context)
{
- const char myname[] = "midna_ascii_to_utf8_create";
+ static const char myname[] = "midna_ascii_to_utf8_create";
char buf[1024]; /* XXX */
UErrorCode error = U_ZERO_ERROR;
UIDNAInfo info = UIDNA_INFO_INITIALIZER;
int valid_utf8_hostname(int enable_utf8, const char *name, int gripe)
{
- const char myname[] = "valid_utf8_hostname";
+ static const char myname[] = "valid_utf8_hostname";
const char *aname;
int ret;