]> git.ipfire.org Git - thirdparty/postfix.git/commitdiff
postfix-3.10-20240902-nonprod
authorWietse Z Venema <wietse@porcupine.org>
Mon, 2 Sep 2024 05:00:00 +0000 (00:00 -0500)
committerViktor Dukhovni <ietf-dane@dukhovni.org>
Wed, 4 Sep 2024 13:42:06 +0000 (23:42 +1000)
67 files changed:
postfix/.indent.pro
postfix/HISTORY
postfix/README_FILES/AAAREADME
postfix/README_FILES/SASL_README
postfix/README_FILES/TLSRPT_README [new file with mode: 0644]
postfix/conf/postfix-files
postfix/html/SASL_README.html
postfix/html/TLSRPT_README.html [new file with mode: 0644]
postfix/html/access.5.html
postfix/html/header_checks.5.html
postfix/html/index.html
postfix/html/lmtp.8.html
postfix/html/postconf.5.html
postfix/html/smtp.8.html
postfix/makedefs
postfix/man/man5/access.5
postfix/man/man5/header_checks.5
postfix/man/man5/postconf.5
postfix/man/man8/smtp.8
postfix/mantools/postlink
postfix/proto/Makefile.in
postfix/proto/TLSRPT_README.html [new file with mode: 0644]
postfix/proto/postconf.proto
postfix/proto/stop
postfix/proto/stop.double-cc
postfix/proto/stop.double-proto-html
postfix/proto/stop.spell-cc
postfix/proto/stop.spell-proto-html
postfix/src/dns/dns.h
postfix/src/dns/dns_rr.c
postfix/src/dns/dns_rr_test.c
postfix/src/global/mail_params.h
postfix/src/posttls-finger/posttls-finger.c
postfix/src/smtp/Makefile.in
postfix/src/smtp/lmtp_params.c
postfix/src/smtp/smtp.c
postfix/src/smtp/smtp.h
postfix/src/smtp/smtp_connect.c
postfix/src/smtp/smtp_params.c
postfix/src/smtp/smtp_proto.c
postfix/src/smtp/smtp_state.c
postfix/src/smtp/smtp_tls_policy.c
postfix/src/smtp/smtp_tlsrpt.c [new file with mode: 0644]
postfix/src/tls/Makefile.in
postfix/src/tls/tls.h
postfix/src/tls/tls_client.c
postfix/src/tls/tls_dane.c
postfix/src/tls/tls_misc.c
postfix/src/tls/tls_proxy.h
postfix/src/tls/tls_proxy_client_print.c
postfix/src/tls/tls_proxy_client_scan.c
postfix/src/tls/tls_proxy_context_print.c
postfix/src/tls/tls_proxy_context_scan.c
postfix/src/tls/tls_server.c
postfix/src/tls/tls_verify.c
postfix/src/tls/tlsrpt_wrapper.c [new file with mode: 0644]
postfix/src/tls/tlsrpt_wrapper.h [new file with mode: 0644]
postfix/src/tlsproxy/Makefile.in
postfix/src/tlsproxy/tlsproxy.c
postfix/src/util/Makefile.in
postfix/src/util/argv.c
postfix/src/util/argv.h
postfix/src/util/hex_code.c
postfix/src/util/hex_code.h
postfix/src/util/mystrerror.c [new file with mode: 0644]
postfix/src/util/stringops.h
postfix/src/util/vbuf_print.c

index 8ee03dbe70d2992b1a03b756ed67d62e4f81fe1a..99ab2e36f0d46f4b98323cb73bccba7d84cd4198 100644 (file)
 -TTLS_PRNG_SEED_INFO
 -TTLS_PRNG_SRC
 -TTLS_ROLE
+-TTLSRPT_WRAPPER
 -TTLS_SCACHE
 -TTLS_SCACHE_ENTRY
 -TTLS_SERVER_INIT_PROPS
index 4be10b6608795fa4ca4e7ecf166774ed69e0fa5a..d0f4791f75ffb0cdc4570abcabf6bb1647c4255e 100644 (file)
@@ -28200,3 +28200,24 @@ Apologies for any names omitted.
        matches the envelope sender (MAIL FROM) address. File:
        proto/postconf.proto.
 
+
+20240730 
+
+       Infrastructure: added argv_addv() function to append an
+       array of strings. File: util/argv.c.
+
+20240809
+
+       Infrastructure: added a dns_rr_detach() function to extract
+       one DNS record from a list. Files: dns/dns_rr.c, dns_rr_test.c.
+
+20240816
+
+       Infrastructure: factored out strerror() wrapper that reports
+       "Application error" instead of "Success" when errno == 0.
+       Files: util/mystrerror.c, util/vbuf_print.c.
+
+20240822
+
+       Infrastructure: added "append to buffer" option to the
+       hex_encode_opt() function. Files: util/hex_encode.[hc];
index 94d552ece498af240de410ab1e8c210a22139f46..f8f2fb7dc4413f4b64407dece13a92c7458e8090 100644 (file)
@@ -10,6 +10,7 @@ G\bGe\ben\bne\ber\bra\bal\bl c\bco\bon\bnf\bfi\big\bgu\bur\bra\bat\bti\bio\bon\bn
   * VIRTUAL_README: Virtual domain hosting
   * SASL_README: SASL Authentication
   * TLS_README: TLS Encryption and authentication
+  * TLSRPT_README: TLSRPT notification
   * FORWARD_SECRECY_README: TLS Forward Secrecy
   * IPV6_README: IP Version 6 Support
   * SMTPUTF8_README: SMTPUTF8 Support
index 617212e5c673df14e4c6bbce0317b6eb8854a3b3..83c0b297ffce6753bb8b9e63a7fa1905511ab976 100644 (file)
@@ -185,9 +185,12 @@ You can read more about the following topics:
     cyrus_sasl_config_path and/or the distribution-specific documentation to
     determine the expected location.
 
-  * Some Debian-based Postfix distributions ignore the "cyrus_sasl_config_path"
-    parameter setting, and force Postfix to open the file /etc/postfix/sasl/
-    smtpd.conf.
+  * Some Debian-based Postfix distributions patch Postfix to hardcode a non-
+    default search path, making it impossible to set an alternate search path
+    via the "cyrus_sasl_config_path" parameter. This is likely to be the case
+    when the distribution documents a Postfix-specific path (e.g. /etc/postfix/
+    sasl/) that is different from the default value of "cyrus_sasl_config_path"
+    (which then is likely to be empty).
 
     N\bNo\bot\bte\be
 
diff --git a/postfix/README_FILES/TLSRPT_README b/postfix/README_FILES/TLSRPT_README
new file mode 100644 (file)
index 0000000..7b8af47
--- /dev/null
@@ -0,0 +1,177 @@
+P\bPo\bos\bst\btf\bfi\bix\bx T\bTL\bLS\bSR\bRP\bPT\bT H\bHo\bow\bwt\bto\bo
+
+-------------------------------------------------------------------------------
+
+T\bTO\bOC\bC
+
+  * Introduction
+  * Building Postfix with TLSRPT support
+  * Using TLSRPT
+  * MTA-STS Support via smtp_tls_policy_maps
+  * Limitations
+  * Credits
+
+I\bIn\bnt\btr\bro\bod\bdu\buc\bct\bti\bio\bon\bn
+
+The TLSRPT protocol is defined in RFC 8460. With this, an email receiving
+domain can publish a policy in DNS to request daily summary reports for
+successful and failed TLS connections to that domain. Support for TLSRPT was
+added in Postfix 3.10.
+
+When Postfix TLSRPT support is enabled (with "smtp_tlsrpt_enable = yes"), the
+Postfix SMTP and TLS clients engines will generate "success" and "failure"
+events, and will pass those events to a TLSRPT client library and report
+generator that are maintained by sys4. The Postfix implementation supports both
+DANE (Postfix built-in) and MTA-STS (through an smtp_tls_policy_maps plug-in).
+
+The high-level diagram shows how Postfix events are reported to domains that
+publish a TLSRPT policy.
+
+    Postfix SMTP and   --> TLSRPT client --> TLSRPT report --> Email or HTTP
+    TLS client engines     library           generator         summary
+
+The Postfix smtp(8) client process implements the SMTP client engine. With
+"smtp_tls_connection_reuse = no", the smtp(8) client process also implements
+the TLS client engine. With "smtp_tls_connection_reuse = yes", the smtp(8)
+client process delegates TLS processing to a Postfix tlsproxy(8) process.
+Either way, Postfix will generate the exact same TLSRPT events.
+
+B\bBu\bui\bil\bld\bdi\bin\bng\bg P\bPo\bos\bst\btf\bfi\bix\bx w\bwi\bit\bth\bh T\bTL\bLS\bSR\bRP\bPT\bT s\bsu\bup\bpp\bpo\bor\brt\bt
+
+These instructions assume that you build Postfix from source code as described
+in the INSTALL document. Some modification may be required if you build Postfix
+from a vendor-specific source package.
+
+The Postfix TLSRPT client builds on a TLSRPT client library whose source code
+can be obtained from:
+
+    https://github.com/sys4/tlsrpt
+
+The library is typically installed as a header file in /usr/local/include/
+tlsrpt.h and an object library in /usr/local/lib/libtlsrpt.a or /usr/local/lib/
+libtlsrpt.so. The actual pathnames will depend on OS platform conventions.
+
+In order to build Postfix with TLSRPT support, you will need to add compiler
+options -\b-D\bDU\bUS\bSE\bE_\b_T\bTL\bLS\bSR\bRP\bPT\bT (to build with TLSRPT support), and -\b-I\bI (with the directory
+containing the tlsrpt.h header file), and you will need to add linker options
+to link with the TLSRPT client library, for example:
+
+    make -f Makefile.init makefiles \
+      "CCARGS=-DUSE_TLSRPT -I/usr/local/include" \
+      "AUXLIBS=-L/usr/local/lib -ltlsrpt"
+
+Then, just run 'make'.
+
+    Note: if your build command line already has CCARGS or AUXLIBS options,
+    then simply append the above options to the existing CCARGS or AUXLIBS
+    values.
+
+U\bUs\bsi\bin\bng\bg T\bTL\bLS\bSR\bRP\bPT\bT
+
+After installing Postfix TLSRPT support, you can enable TLSRPT support in
+main.cf like this:
+
+    smtp_tlsrpt_enable = yes
+    smtp_tlsrpt_socket_name = /path/to/socket
+
+The smtp_tlsrpt_socket_name parameter specifies an absolute pathname, or a
+pathname that is relative to $queue_directory.
+
+A good socket location would be under $queue_directory/run/tlsrpt or
+$queue_directory/var/run/tlsrpt. These can then be configured in Postfix as a
+relative pathname (run/tlsrpt/tlsrpt.sock or var/run/tlsrpt/tlsrpt.sock) so
+that the same name will work with and without Postfix chroot support. Do not
+specify a location under directory that is already used by Postfix programs.
+Only Postfix programs should create sockets there.
+
+M\bMT\bTA\bA-\b-S\bST\bTS\bS S\bSu\bup\bpp\bpo\bor\brt\bt v\bvi\bia\ba s\bsm\bmt\btp\bp_\b_t\btl\bls\bs_\b_p\bpo\bol\bli\bic\bcy\by_\b_m\bma\bap\bps\bs
+
+Postfix supports MTA-STS though an smtp_tls_policy_maps policy plugin. Postfix
+TLSRPT support expects a response with the usual security level and matching
+requirements, plus any applicable name=value attributes described below.
+Specify { name = value } when a value may contain whitespace.
+
+    Note 1: Postfix 3.10 and later will accept these attributes in an MTA-STS
+    response even if TLSRPT support is disabled (at build time or run time),
+    but it will not use most attributes except ttl and policy_failure.
+
+    Note 2: It is an error to specify these attributes for a non-STS policy.
+
+The examples in the table apply to the MTA-STS policy example given in https://
+datatracker.ietf.org/doc/html/rfc8460#section-4.5.
+
+  * policy_type=type
+
+    Specify sts or no-policy-found.
+
+  * policy_domain=name
+
+    The domain that the MTA-STS policy applies to.
+
+  * policy_ttl=time
+
+    How long (in seconds) a Postfix SMTP client process will cache the MTA-STS
+    plugin response.
+
+  * { policy_string = value }
+
+    Specify one policy_string instance for each MTA-STS policy feature,
+    enclosed inside "{" and "}" to protect whitespace in attribute values.
+
+    Example:
+
+        { policy_string = version: STSv1 }, { policy_string = mode: testing },
+        ...
+
+    This form ignores whitespace after the opening "{", around the "=", and
+    before the closing "}".
+
+  * mx_host_pattern=pattern
+
+    Specify one mx_host_pattern instance for each "mx:" feature in the MTA-STS
+    policy.
+
+    Example:
+
+        mx_host_pattern=mx1.example.com, mx_host_pattern=mx2.example.com, ...
+
+  * policy_failure=type
+
+    If specified, forces MTA-STS policy enforcement to fail with the indicated
+    error, even if a server certificate would satisfy conventional PKI
+    constraints.
+
+    Valid errors are sts-policy-fetch-error, sts-policy-invalid, sts-webpki-
+    invalid, or the less informative validation-failure.
+
+    Example:
+
+        policy_failure=sts-webpki-invalid
+
+L\bLi\bim\bmi\bit\bta\bat\bti\bio\bon\bns\bs
+
+The following limitations exist primarily because some errors may be reported
+by a Postfix smtp(8) client process, and some errors by a Postfix tlsproxy(8)
+process. It is too difficult to propagate TLSRPT client library state between
+processes.
+
+The Postfix TLSRPT client reports one final status (either 'success' or
+'failure') for each MTA that it is able to connect to. It cannot report a final
+status 'success' with some recoverable 'failure'. Specifically:
+
+  * The Postfix TLSRPT client can report either successful TLS policy
+    compliance, or an unrecoverable failure that prevents TLS policy compliance
+    (examples: all TLSA records are unusable, or some PKI error during
+    certificate verification).
+
+  * The Postfix TLSRPT client must not be used to report a potentially
+    recoverable failure such as a non-parsable TLSA record, because some other
+    TLSA record for the same host may still allow successful TLS policy
+    compliance.
+
+C\bCr\bre\bed\bdi\bit\bts\bs
+
+  * The TLSRPT client library and report generator are implemented and
+    maintained by sys4 (sys4.de).
+  * Wietse Venema implemented the integration with Postfix.
+
index 5a939822bcc959bd085fc5a348bc6e1fc6fd1fd4..2467af478b120348d6827e5f94c408fcb10552bc 100644 (file)
@@ -330,6 +330,7 @@ $readme_directory/STANDARD_CONFIGURATION_README:f:root:-:644
 $readme_directory/STRESS_README:f:root:-:644
 $readme_directory/TLS_LEGACY_README:f:root:-:644
 $readme_directory/TLS_README:f:root:-:644
+$readme_directory/TLSRPT_README:f:root:-:644
 $readme_directory/TUNING_README:f:root:-:644
 $readme_directory/ULTRIX_README:f:root:-:644
 $readme_directory/UUCP_README:f:root:-:644
@@ -392,6 +393,7 @@ $html_directory/STANDARD_CONFIGURATION_README.html:f:root:-:644
 $html_directory/STRESS_README.html:f:root:-:644
 $html_directory/TLS_LEGACY_README.html:f:root:-:644
 $html_directory/TLS_README.html:f:root:-:644
+$html_directory/TLSRPT_README.html:f:root:-:644
 $html_directory/TUNING_README.html:f:root:-:644
 $html_directory/ULTRIX_README.html:f:root:-:644:o
 $html_directory/UUCP_README.html:f:root:-:644
index f02208e6ef942fafa5b294553dbecd2b804f3de7..c95ac8c84537ffe0cfc3ff04def021c4a396c51b 100644 (file)
@@ -281,9 +281,13 @@ configuration file in <code>/etc/postfix/sasl/</code>,
 <a href="postconf.5.html#cyrus_sasl_config_path">cyrus_sasl_config_path</a></code> and/or the distribution-specific
 documentation to determine the expected location. </p> </li>
 
-<li> <p> Some Debian-based Postfix distributions ignore the
-"<a href="postconf.5.html#cyrus_sasl_config_path">cyrus_sasl_config_path</a>" parameter setting, and force Postfix to
-open the file <code>/etc/postfix/sasl/smtpd.conf</code>. </p> </li>
+<li> <p> Some Debian-based Postfix distributions patch Postfix to
+hardcode a non-default search path, making it impossible to set an
+alternate search path via the "<a href="postconf.5.html#cyrus_sasl_config_path">cyrus_sasl_config_path</a>" parameter.  This
+is likely to be the case when the distribution documents a
+Postfix-specific path (e.g. <code>/etc/postfix/sasl/</code>) that is
+different from the default value of "<a href="postconf.5.html#cyrus_sasl_config_path">cyrus_sasl_config_path</a>" (which
+then is likely to be empty). </p> </li>
 
 </ul>
 
diff --git a/postfix/html/TLSRPT_README.html b/postfix/html/TLSRPT_README.html
new file mode 100644 (file)
index 0000000..1b15391
--- /dev/null
@@ -0,0 +1,276 @@
+<!doctype html public "-//W3C//DTD HTML 4.01 Transitional//EN"
+  "http://www.w3.org/TR/html4/loose.dtd">
+
+<html>
+
+<head>
+
+<title>Postfix TLSRPT notification Howto</title>
+
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<link rel='stylesheet' type='text/css' href='postfix-doc.css'>
+
+</head>
+
+<body>
+
+<h1><img src="postfix-logo.jpg" width="203" height="98" ALT="">Postfix TLSRPT Howto</h1>
+
+<hr>
+
+<h2> TOC </h2>
+
+<ul>
+
+<li> <a href="#intro"> Introduction </a> </li>
+<li> <a href="#building"> Building Postfix with TLSRPT support </a>
+<li> <a href="#using"> Using TLSRPT </a> </li>
+<li> <a href="#mta-sts"> MTA-STS Support via smtp_tls_policy_maps </a> </li>
+<li> <a href="#limitations"> Limitations </a></li>
+<li> <a href="#credits"> Credits </a> </li>
+
+</ul>
+
+<h2> <a name="intro"> Introduction </a> </h2>
+
+<p> The TLSRPT protocol is defined in <a href="https://tools.ietf.org/html/rfc8460">RFC 8460</a>. With this, an email
+receiving domain can publish a policy in DNS to request daily summary
+reports for successful and failed TLS connections to that domain.
+Support for TLSRPT was added in Postfix 3.10. </p>
+
+<p> When Postfix TLSRPT support is enabled (with "<a href="postconf.5.html#smtp_tlsrpt_enable">smtp_tlsrpt_enable</a>
+= yes"), the Postfix SMTP and TLS clients engines will generate
+"success" and "failure" events, and will pass those events to a
+TLSRPT client library and report generator that are maintained by
+sys4. The Postfix implementation supports both DANE (Postfix built-in)
+and MTA-STS (through an <a href="postconf.5.html#smtp_tls_policy_maps">smtp_tls_policy_maps</a> plug-in). </p>
+
+<p> The high-level diagram shows how Postfix events are reported
+to domains that publish a TLSRPT policy.
+
+<blockquote>
+
+<table>
+
+<tr> <td bgcolor="#f0f0ff"> Postfix SMTP and<br> TLS client engines
+</td> <td> <tt> --&gt; </tt> </td>
+
+<td bgcolor="#f0f0ff"> TLSRPT client library </td> <td> <tt> --&gt;
+</tt> </td>
+
+<td bgcolor="#f0f0ff"> TLSRPT report generator </td> <td> <tt>
+--&gt; </tt> </td>
+
+<td bgcolor="#f0f0ff"> Email or HTTP summary </td> </tr>
+
+</table>
+
+</blockquote>
+
+<p> The Postfix <a href="smtp.8.html">smtp(8)</a> client process implements the SMTP client
+engine.  With "<a href="postconf.5.html#smtp_tls_connection_reuse">smtp_tls_connection_reuse</a> = no", the <a href="smtp.8.html">smtp(8)</a> client
+process also implements the TLS client engine. With
+"<a href="postconf.5.html#smtp_tls_connection_reuse">smtp_tls_connection_reuse</a> = yes", the <a href="smtp.8.html">smtp(8)</a> client process
+delegates TLS processing to a Postfix <a href="tlsproxy.8.html">tlsproxy(8)</a> process. Either
+way, Postfix will generate the exact same TLSRPT events. </p>
+
+<h2> <a name="building"> Building Postfix with TLSRPT support </a>
+</h2>
+
+<p> These instructions assume that you build Postfix from source
+code as described in the <a href="INSTALL.html">INSTALL</a> document. Some modification may
+be required if you build Postfix from a vendor-specific source
+package. </p>
+
+<p> The Postfix TLSRPT client builds on a TLSRPT client library
+whose source code can be obtained from: </p>
+
+<blockquote>
+ <p> <a href="https://github.com/sys4/tlsrpt">https://github.com/sys4/tlsrpt</a> </p>
+</blockquote>
+
+<p> The library is typically installed as a header file in
+/usr/local/include/tlsrpt.h and an object library in
+/usr/local/lib/libtlsrpt.a or /usr/local/lib/libtlsrpt.so. The
+actual pathnames will depend on OS platform conventions. </p>
+
+<p> In order to build Postfix with TLSRPT support, you will need
+to add compiler options <b>-DUSE_TLSRPT</b> (to build with TLSRPT
+support), and <b>-I</b> (with the directory containing the tlsrpt.h
+header file), and you will need to add linker options to link with
+the TLSRPT client library, for example: </p>
+
+<blockquote>
+<pre>
+make -f Makefile.init makefiles \
+  "CCARGS=-DUSE_TLSRPT -I/usr/local/include" \
+  "AUXLIBS=-L/usr/local/lib -ltlsrpt"
+</pre>
+</blockquote>
+
+<p> Then, just run 'make'. </p>
+
+<blockquote>
+
+<p> Note: if your build command line already has CCARGS or AUXLIBS
+options, then simply append the above options to the existing CCARGS
+or AUXLIBS values. </p>
+
+</blockquote>
+
+<h2> <a name="using"> Using TLSRPT </a> </h2>
+
+<p> After installing Postfix TLSRPT support, you can enable TLSRPT
+support in <a href="postconf.5.html">main.cf</a> like this: </p>
+
+<blockquote>
+<pre>
+<a href="postconf.5.html#smtp_tlsrpt_enable">smtp_tlsrpt_enable</a> = yes
+<a href="postconf.5.html#smtp_tlsrpt_socket_name">smtp_tlsrpt_socket_name</a> = /path/to/socket
+</pre>
+</blockquote>
+
+<p> The <a href="postconf.5.html#smtp_tlsrpt_socket_name">smtp_tlsrpt_socket_name</a> parameter specifies an absolute
+pathname, or a pathname that is relative to $<a href="postconf.5.html#queue_directory">queue_directory</a>. </p>
+
+<p> A good socket location would be under $<a href="postconf.5.html#queue_directory">queue_directory</a>/run/tlsrpt
+or $<a href="postconf.5.html#queue_directory">queue_directory</a>/var/run/tlsrpt. These can then be configured
+in Postfix as a relative pathname (run/tlsrpt/tlsrpt.sock or
+var/run/tlsrpt/tlsrpt.sock) so that the same name will work with
+and without Postfix chroot support. Do not specify a location under
+directory that is already used by Postfix programs. Only Postfix
+programs should create sockets there. </p>
+
+<h2> <a name="mta-sts"> MTA-STS Support via smtp_tls_policy_maps
+</a></h2>
+
+<p> Postfix supports MTA-STS though an <a href="postconf.5.html#smtp_tls_policy_maps">smtp_tls_policy_maps</a> policy
+plugin. Postfix TLSRPT support expects a response with the usual
+security level and matching requirements, plus any applicable
+name=value attributes described below. Specify { name = value }
+when a value may contain whitespace. </p>
+
+<blockquote>
+
+<p> Note 1: Postfix 3.10 and later will accept these attributes in
+an MTA-STS response even if TLSRPT support is disabled (at build
+time or run time), but it will not use most attributes except
+<tt>ttl</tt> and <tt>policy_failure</tt>.  </p>
+
+<p> Note 2: It is an error to specify these attributes for a non-STS
+policy. </p>
+
+</blockquote>
+
+<p> The examples in the table apply to the MTA-STS policy example
+given in <a href="https://datatracker.ietf.org/doc/html/rfc8460#section-4.5">https://datatracker.ietf.org/doc/html/rfc8460#section-4.5</a>.
+<p>
+
+<ul>
+
+<li> <p> <tt> policy_type=<i>type</i> </tt>
+
+<p> Specify <tt>sts</tt> or <tt>no-policy-found</tt>. </p> </li>
+
+<li> <p> <tt> policy_domain=<i>name</i> </tt> </p>
+
+<p> The domain that the MTA-STS policy applies to. </p> </li>
+
+<li> <p> <tt> policy_ttl=<i>time</i> </tt> </p>
+
+<p> How long (in seconds) a Postfix SMTP client process will cache
+the MTA-STS plugin response.  </p> </li>
+
+<li> <p> <tt> { policy_string = <i>value</i> } </tt> </p>
+
+<p> Specify one <tt>policy_string</tt> instance for each MTA-STS
+policy feature, enclosed inside "{" and "}" to protect whitespace
+in attribute values. </p>
+
+<p> Example: </p>
+
+<blockquote>
+<pre>
+{ policy_string = version: STSv1 }, { policy_string = mode: testing }, ...
+</pre> 
+</blockquote> 
+
+<p> This form ignores whitespace after the opening "{", around the "=",
+and before the closing "}".</p> </li>
+
+<li> <p> <tt> mx_host_pattern=<i>pattern</i> </tt> </p>
+
+<p> Specify one <tt>mx_host_pattern</tt> instance for each "mx:" feature
+in the MTA-STS policy. </p>
+
+<p> Example: </p>
+
+<blockquote>
+<pre>
+mx_host_pattern=mx1.example.com, mx_host_pattern=mx2.example.com, ...
+</pre>
+</blockquote>
+</li>
+
+<li> <p> <tt> policy_failure=<i>type</i> </tt> </p>
+
+<p> If specified, forces MTA-STS policy enforcement to fail with
+the indicated error, even if a server certificate would satisfy
+conventional PKI constraints. </p>
+
+<p> Valid errors are <tt>sts-policy-fetch-error, sts-policy-invalid</tt>,
+<tt>sts-webpki-invalid</tt>, or the less informative
+<tt>validation-failure</tt>. </p>
+
+<p> Example: </p>
+
+<blockquote>
+<pre>
+policy_failure=sts-webpki-invalid
+</pre>
+</blockquote>
+</li>
+
+</ul>
+
+<h2> <a name="limitations"> Limitations </a></h2>
+
+<p> The following limitations exist primarily because some errors
+may be reported by a Postfix <a href="smtp.8.html">smtp(8)</a> client process, and some errors
+by a Postfix <a href="tlsproxy.8.html">tlsproxy(8)</a> process. It is too difficult to propagate
+TLSRPT client library state between processes.</p>
+
+<p> The Postfix TLSRPT client reports one final status (either
+'success' or 'failure') for each MTA that it is able to connect to.
+It cannot report a final status 'success' with some recoverable
+'failure'. Specifically: </p>
+
+<ul>
+
+<li> <p> The Postfix TLSRPT client can report either successful TLS
+policy compliance, or an unrecoverable failure that prevents TLS
+policy compliance (examples: all TLSA records are unusable, or some
+PKI error during certificate verification). <p> </li>
+
+<li> <p> The Postfix TLSRPT client must not be used to report a
+potentially recoverable failure such as a non-parsable TLSA record,
+because some other TLSA record for the same host may still allow
+successful TLS policy compliance. </p> </li>
+
+</ul>
+
+<h2> <a name="credits"> Credits </a> </h2>
+
+<ul>
+
+<li> The TLSRPT client library and report generator are implemented
+and maintained by sys4 (sys4.de). </li>
+
+<li> Wietse Venema implemented the integration with Postfix.
+</li>
+
+</ul>
+
+</body>
+
+</html>
index 4d9cc2b0a111095177ae0a8ca2c8113e80f99e9a..427eacf74463cef5843d42766c2c456c4331dbd3 100644 (file)
@@ -320,13 +320,9 @@ ACCESS(5)                                                            ACCESS(5)
               address instead of the intended recipient(s).  When multiple <b>RE-</b>
               <b>DIRECT</b> actions fire, only the last one takes effect.
 
-              Note  1:  this action overrides the FILTER action, and currently
+              Note:  this  action  overrides  the FILTER action, and currently
               overrides all recipients of the message.
 
-              Note 2: a REDIRECT address is subject to  canonicalization  (add
-              missing  domain)  but NOT subject to canonical, masquerade, bcc,
-              or virtual alias mapping.
-
               This feature is available in Postfix 2.1 and later.
 
        <b>INFO</b> <i>optional text...</i>
index 579437f5e0b3deaaed9d0eefaaa5ecd556c908a6..c1c8b17cc1b6aecdfa047d8dc4441adc026bd3a8 100644 (file)
@@ -312,14 +312,10 @@ HEADER_CHECKS(5)                                              HEADER_CHECKS(5)
               will  be  sent  to the specified address instead of the intended
               recipient(s).
 
-              Note 1: this action overrides the <b>FILTER</b> action, and affects all
+              Note: this action overrides the <b>FILTER</b> action, and  affects  all
               recipients  of  the  message. If multiple <b>REDIRECT</b> actions fire,
               only the last one is executed.
 
-              Note 2: a REDIRECT address is subject to  canonicalization  (add
-              missing  domain)  but NOT subject to canonical, masquerade, bcc,
-              or virtual alias mapping.
-
               This feature is available in Postfix 2.1 and later.
 
               This feature is not supported with smtp header/body checks.
index a7da6cb510c7e57854b419a0069103ea407e8da6..5fa7a69cd926e33de81054848ab088fbc08a9154 100644 (file)
@@ -43,6 +43,8 @@ configuration examples </a>
 
 <li> <a href="TLS_README.html"> TLS Encryption and authentication </a>
 
+<li> <a href="TLSRPT_README.html"> TLSRPT notification </a>
+
 <li> <a href="FORWARD_SECRECY_README.html"> TLS Forward Secrecy </a>
 
 <li> <a href="IPV6_README.html"> IP Version 6 Support </a>
index 4cc187c75174313bead975256ac969be83787590..dbf71d264c765c9ea55d750e7f2cb689de37aad3 100644 (file)
@@ -746,41 +746,48 @@ SMTP,(LMTP)                                                        SMTP,(LMTP)
               Request  that remote SMTP servers send an <a href="https://tools.ietf.org/html/rfc7250">RFC7250</a> raw public key
               instead of an X.509 certificate.
 
+       <b><a href="postconf.5.html#smtp_tlsrpt_enable">smtp_tlsrpt_enable</a> (no)</b>
+              Enable support for <a href="https://tools.ietf.org/html/rfc8460">RFC 8460</a> TLSRPT notifications.
+
+       <b><a href="postconf.5.html#smtp_tlsrpt_socket_name">smtp_tlsrpt_socket_name</a> (empty)</b>
+              The pathname of a UNIX-domain datagram socket that is managed by
+              a local TLSRPT reporting service.
+
 <b>OBSOLETE STARTTLS CONTROLS</b>
-       The following configuration parameters  exist  for  compatibility  with
-       Postfix  versions  before  2.3.  Support for these will be removed in a
+       The  following  configuration  parameters  exist for compatibility with
+       Postfix versions before 2.3. Support for these will  be  removed  in  a
        future release.
 
        <b><a href="postconf.5.html#smtp_use_tls">smtp_use_tls</a> (no)</b>
-              Opportunistic mode: use TLS when a remote SMTP server  announces
+              Opportunistic  mode: use TLS when a remote SMTP server announces
               STARTTLS support, otherwise send the mail in the clear.
 
        <b><a href="postconf.5.html#smtp_enforce_tls">smtp_enforce_tls</a> (no)</b>
-              Enforcement  mode:  require  that  remote  SMTP  servers use TLS
+              Enforcement mode: require  that  remote  SMTP  servers  use  TLS
               encryption, and never send mail in the clear.
 
        <b><a href="postconf.5.html#smtp_tls_enforce_peername">smtp_tls_enforce_peername</a> (yes)</b>
-              With mandatory TLS encryption,  require  that  the  remote  SMTP
-              server  hostname  matches  the  information  in  the remote SMTP
+              With  mandatory  TLS  encryption,  require  that the remote SMTP
+              server hostname matches  the  information  in  the  remote  SMTP
               server certificate.
 
        <b><a href="postconf.5.html#smtp_tls_per_site">smtp_tls_per_site</a> (empty)</b>
-              Optional lookup tables with the Postfix SMTP  client  TLS  usage
-              policy  by  next-hop destination and by remote SMTP server host-
+              Optional  lookup  tables  with the Postfix SMTP client TLS usage
+              policy by next-hop destination and by remote SMTP  server  host-
               name.
 
        <b><a href="postconf.5.html#smtp_tls_cipherlist">smtp_tls_cipherlist</a> (empty)</b>
-              Obsolete Postfix &lt; 2.3 control for the Postfix SMTP  client  TLS
+              Obsolete  Postfix  &lt; 2.3 control for the Postfix SMTP client TLS
               cipher list.
 
 <b>RESOURCE AND RATE CONTROLS</b>
        <b><a href="postconf.5.html#smtp_connect_timeout">smtp_connect_timeout</a> (30s)</b>
-              The  Postfix SMTP client time limit for completing a TCP connec-
+              The Postfix SMTP client time limit for completing a TCP  connec-
               tion, or zero (use the operating system built-in time limit).
 
        <b><a href="postconf.5.html#smtp_helo_timeout">smtp_helo_timeout</a> (300s)</b>
-              The Postfix SMTP client time limit for sending the HELO or  EHLO
-              command,  and  for  receiving  the  initial  remote  SMTP server
+              The  Postfix SMTP client time limit for sending the HELO or EHLO
+              command, and  for  receiving  the  initial  remote  SMTP  server
               response.
 
        <b><a href="postconf.5.html#lmtp_lhlo_timeout">lmtp_lhlo_timeout</a> (300s)</b>
@@ -792,19 +799,19 @@ SMTP,(LMTP)                                                        SMTP,(LMTP)
               mand, and for receiving the remote SMTP server response.
 
        <b><a href="postconf.5.html#smtp_mail_timeout">smtp_mail_timeout</a> (300s)</b>
-              The Postfix SMTP client time limit for  sending  the  MAIL  FROM
+              The  Postfix  SMTP  client  time limit for sending the MAIL FROM
               command, and for receiving the remote SMTP server response.
 
        <b><a href="postconf.5.html#smtp_rcpt_timeout">smtp_rcpt_timeout</a> (300s)</b>
-              The  Postfix SMTP client time limit for sending the SMTP RCPT TO
+              The Postfix SMTP client time limit for sending the SMTP RCPT  TO
               command, and for receiving the remote SMTP server response.
 
        <b><a href="postconf.5.html#smtp_data_init_timeout">smtp_data_init_timeout</a> (120s)</b>
-              The Postfix SMTP client time limit for  sending  the  SMTP  DATA
+              The  Postfix  SMTP  client  time limit for sending the SMTP DATA
               command, and for receiving the remote SMTP server response.
 
        <b><a href="postconf.5.html#smtp_data_xfer_timeout">smtp_data_xfer_timeout</a> (180s)</b>
-              The  Postfix SMTP client time limit for sending the SMTP message
+              The Postfix SMTP client time limit for sending the SMTP  message
               content.
 
        <b><a href="postconf.5.html#smtp_data_done_timeout">smtp_data_done_timeout</a> (600s)</b>
@@ -818,13 +825,13 @@ SMTP,(LMTP)                                                        SMTP,(LMTP)
        Available in Postfix version 2.1 and later:
 
        <b><a href="postconf.5.html#smtp_mx_address_limit">smtp_mx_address_limit</a> (5)</b>
-              The maximal number of MX (mail exchanger) IP addresses that  can
-              result  from Postfix SMTP client mail exchanger lookups, or zero
+              The  maximal number of MX (mail exchanger) IP addresses that can
+              result from Postfix SMTP client mail exchanger lookups, or  zero
               (no limit).
 
        <b><a href="postconf.5.html#smtp_mx_session_limit">smtp_mx_session_limit</a> (2)</b>
-              The maximal number of SMTP sessions per delivery request  before
-              the  Postfix  SMTP  client  gives  up or delivers to a fall-back
+              The  maximal number of SMTP sessions per delivery request before
+              the Postfix SMTP client gives up  or  delivers  to  a  fall-back
               <a href="postconf.5.html#relayhost">relay host</a>, or zero (no limit).
 
        <b><a href="postconf.5.html#smtp_rset_timeout">smtp_rset_timeout</a> (20s)</b>
@@ -834,17 +841,17 @@ SMTP,(LMTP)                                                        SMTP,(LMTP)
        Available in Postfix version 2.2 and earlier:
 
        <b><a href="postconf.5.html#lmtp_cache_connection">lmtp_cache_connection</a> (yes)</b>
-              Keep  Postfix  LMTP  client connections open for up to $<a href="postconf.5.html#max_idle">max_idle</a>
+              Keep Postfix LMTP client connections open for  up  to  $<a href="postconf.5.html#max_idle">max_idle</a>
               seconds.
 
        Available in Postfix version 2.2 and later:
 
        <b><a href="postconf.5.html#smtp_connection_cache_destinations">smtp_connection_cache_destinations</a> (empty)</b>
-              Permanently enable SMTP connection  caching  for  the  specified
+              Permanently  enable  SMTP  connection  caching for the specified
               destinations.
 
        <b><a href="postconf.5.html#smtp_connection_cache_on_demand">smtp_connection_cache_on_demand</a> (yes)</b>
-              Temporarily  enable  SMTP connection caching while a destination
+              Temporarily enable SMTP connection caching while  a  destination
               has a high volume of mail in the <a href="QSHAPE_README.html#active_queue">active queue</a>.
 
        <b><a href="postconf.5.html#smtp_connection_reuse_time_limit">smtp_connection_reuse_time_limit</a> (300s)</b>
@@ -858,23 +865,23 @@ SMTP,(LMTP)                                                        SMTP,(LMTP)
        Available in Postfix version 2.3 and later:
 
        <b><a href="postconf.5.html#connection_cache_protocol_timeout">connection_cache_protocol_timeout</a> (5s)</b>
-              Time limit for connection cache connect, send or receive  opera-
+              Time  limit for connection cache connect, send or receive opera-
               tions.
 
        Available in Postfix version 2.9 - 3.6:
 
        <b><a href="postconf.5.html#smtp_per_record_deadline">smtp_per_record_deadline</a> (no)</b>
-              Change  the  behavior  of the smtp_*_timeout time limits, from a
-              time limit per read or write system call, to  a  time  limit  to
-              send  or  receive  a complete record (an SMTP command line, SMTP
-              response line, SMTP message content line, or TLS  protocol  mes-
+              Change the behavior of the smtp_*_timeout time  limits,  from  a
+              time  limit  per  read  or write system call, to a time limit to
+              send or receive a complete record (an SMTP  command  line,  SMTP
+              response  line,  SMTP message content line, or TLS protocol mes-
               sage).
 
        Available in Postfix version 2.11 and later:
 
        <b><a href="postconf.5.html#smtp_connection_reuse_count_limit">smtp_connection_reuse_count_limit</a> (0)</b>
-              When  SMTP  connection  caching  is enabled, the number of times
-              that an SMTP session may be reused before it is closed, or  zero
+              When SMTP connection caching is enabled,  the  number  of  times
+              that  an SMTP session may be reused before it is closed, or zero
               (no limit).
 
        Available in Postfix version 3.4 and later:
@@ -885,13 +892,13 @@ SMTP,(LMTP)                                                        SMTP,(LMTP)
        Available in Postfix version 3.7 and later:
 
        <b><a href="postconf.5.html#smtp_per_request_deadline">smtp_per_request_deadline</a> (no)</b>
-              Change  the  behavior  of the smtp_*_timeout time limits, from a
-              time limit per plaintext or TLS read or write call,  to  a  com-
-              bined  time  limit  for  sending a complete SMTP request and for
+              Change the behavior of the smtp_*_timeout time  limits,  from  a
+              time  limit  per  plaintext or TLS read or write call, to a com-
+              bined time limit for sending a complete  SMTP  request  and  for
               receiving a complete SMTP response.
 
        <b><a href="postconf.5.html#smtp_min_data_rate">smtp_min_data_rate</a> (500)</b>
-              The minimum plaintext data transfer  rate  in  bytes/second  for
+              The  minimum  plaintext  data  transfer rate in bytes/second for
               DATA    requests,    when    deadlines    are    enabled    with
               <a href="postconf.5.html#smtp_per_request_deadline">smtp_per_request_deadline</a>.
 
@@ -899,54 +906,54 @@ SMTP,(LMTP)                                                        SMTP,(LMTP)
 
        <b><a href="postconf.5.html#transport_destination_concurrency_limit">transport_destination_concurrency_limit</a>   ($<a href="postconf.5.html#default_destination_concurrency_limit">default_destination_concur</a>-</b>
        <b><a href="postconf.5.html#default_destination_concurrency_limit">rency_limit</a>)</b>
-              A transport-specific override for  the  <a href="postconf.5.html#default_destination_concurrency_limit">default_destination_con</a>-
+              A  transport-specific  override for the <a href="postconf.5.html#default_destination_concurrency_limit">default_destination_con</a>-
               <a href="postconf.5.html#default_destination_concurrency_limit">currency_limit</a> parameter value, where <i>transport</i> is the <a href="master.5.html">master.cf</a>
               name of the message delivery transport.
 
        <b><a href="postconf.5.html#transport_destination_recipient_limit">transport_destination_recipient_limit</a>     ($<a href="postconf.5.html#default_destination_recipient_limit">default_destination_recipi</a>-</b>
        <b><a href="postconf.5.html#default_destination_recipient_limit">ent_limit</a>)</b>
               A transport-specific override for the <a href="postconf.5.html#default_destination_recipient_limit">default_destination_recip</a>-
-              <a href="postconf.5.html#default_destination_recipient_limit">ient_limit</a>  parameter  value,  where  <i>transport</i> is the <a href="master.5.html">master.cf</a>
+              <a href="postconf.5.html#default_destination_recipient_limit">ient_limit</a> parameter value, where  <i>transport</i>  is  the  <a href="master.5.html">master.cf</a>
               name of the message delivery transport.
 
 <b>SMTPUTF8 CONTROLS</b>
        Preliminary SMTPUTF8 support is introduced with Postfix 3.0.
 
        <b><a href="postconf.5.html#smtputf8_enable">smtputf8_enable</a> (yes)</b>
-              Enable preliminary SMTPUTF8 support for the protocols  described
+              Enable  preliminary SMTPUTF8 support for the protocols described
               in <a href="https://tools.ietf.org/html/rfc6531">RFC 6531</a>, <a href="https://tools.ietf.org/html/rfc6532">RFC 6532</a>, and <a href="https://tools.ietf.org/html/rfc6533">RFC 6533</a>.
 
        <b><a href="postconf.5.html#smtputf8_autodetect_classes">smtputf8_autodetect_classes</a> (sendmail, verify)</b>
-              Detect  that  a message requires SMTPUTF8 support for the speci-
+              Detect that a message requires SMTPUTF8 support for  the  speci-
               fied mail origin classes.
 
        Available in Postfix version 3.2 and later:
 
        <b><a href="postconf.5.html#enable_idna2003_compatibility">enable_idna2003_compatibility</a> (no)</b>
-              Enable  'transitional'  compatibility   between   IDNA2003   and
-              IDNA2008,  when  converting UTF-8 domain names to/from the ASCII
+              Enable   'transitional'   compatibility   between  IDNA2003  and
+              IDNA2008, when converting UTF-8 domain names to/from  the  ASCII
               form that is used for DNS lookups.
 
 <b>TROUBLE SHOOTING CONTROLS</b>
        <b><a href="postconf.5.html#debug_peer_level">debug_peer_level</a> (2)</b>
-              The increment in verbose logging level when a  nexthop  destina-
-              tion,  remote client or server name or network address matches a
+              The  increment  in verbose logging level when a nexthop destina-
+              tion, remote client or server name or network address matches  a
               pattern given with the <a href="postconf.5.html#debug_peer_list">debug_peer_list</a> parameter.
 
        <b><a href="postconf.5.html#debug_peer_list">debug_peer_list</a> (empty)</b>
-              Optional list of nexthop destination, remote  client  or  server
-              name  or  network  address  patterns that, if matched, cause the
-              verbose logging level to increase by  the  amount  specified  in
+              Optional  list  of  nexthop destination, remote client or server
+              name or network address patterns that,  if  matched,  cause  the
+              verbose  logging  level  to  increase by the amount specified in
               $<a href="postconf.5.html#debug_peer_level">debug_peer_level</a>.
 
        <b><a href="postconf.5.html#error_notice_recipient">error_notice_recipient</a> (postmaster)</b>
-              The  recipient  of  postmaster notifications about mail delivery
+              The recipient of postmaster notifications  about  mail  delivery
               problems that are caused by policy, resource, software or proto-
               col errors.
 
        <b><a href="postconf.5.html#internal_mail_filter_classes">internal_mail_filter_classes</a> (empty)</b>
-              What   categories  of  Postfix-generated  mail  are  subject  to
-              before-queue   content    inspection    by    <a href="postconf.5.html#non_smtpd_milters">non_smtpd_milters</a>,
+              What  categories  of  Postfix-generated  mail  are  subject   to
+              before-queue    content    inspection    by   <a href="postconf.5.html#non_smtpd_milters">non_smtpd_milters</a>,
               <a href="postconf.5.html#header_checks">header_checks</a> and <a href="postconf.5.html#body_checks">body_checks</a>.
 
        <b><a href="postconf.5.html#notify_classes">notify_classes</a> (resource, software)</b>
@@ -954,46 +961,46 @@ SMTP,(LMTP)                                                        SMTP,(LMTP)
 
 <b>MISCELLANEOUS CONTROLS</b>
        <b><a href="postconf.5.html#best_mx_transport">best_mx_transport</a> (empty)</b>
-              Where  the  Postfix  SMTP  client  should  deliver  mail when it
+              Where the Postfix  SMTP  client  should  deliver  mail  when  it
               detects a "mail loops back to myself" error condition.
 
        <b><a href="postconf.5.html#config_directory">config_directory</a> (see 'postconf -d' output)</b>
-              The default location of the Postfix <a href="postconf.5.html">main.cf</a> and  <a href="master.5.html">master.cf</a>  con-
+              The  default  location of the Postfix <a href="postconf.5.html">main.cf</a> and <a href="master.5.html">master.cf</a> con-
               figuration files.
 
        <b><a href="postconf.5.html#daemon_timeout">daemon_timeout</a> (18000s)</b>
-              How  much  time  a  Postfix  daemon process may take to handle a
+              How much time a Postfix daemon process  may  take  to  handle  a
               request before it is terminated by a built-in watchdog timer.
 
        <b><a href="postconf.5.html#delay_logging_resolution_limit">delay_logging_resolution_limit</a> (2)</b>
-              The maximal number of digits after the decimal point  when  log-
+              The  maximal  number of digits after the decimal point when log-
               ging sub-second delay values.
 
        <b><a href="postconf.5.html#disable_dns_lookups">disable_dns_lookups</a> (no)</b>
               Disable DNS lookups in the Postfix SMTP and LMTP clients.
 
        <b><a href="postconf.5.html#inet_interfaces">inet_interfaces</a> (all)</b>
-              The  local  network  interface  addresses  that this mail system
+              The local network interface  addresses  that  this  mail  system
               receives mail on.
 
        <b><a href="postconf.5.html#inet_protocols">inet_protocols</a> (see 'postconf -d' output)</b>
-              The Internet protocols Postfix will attempt to use  when  making
+              The  Internet  protocols Postfix will attempt to use when making
               or accepting connections.
 
        <b><a href="postconf.5.html#ipc_timeout">ipc_timeout</a> (3600s)</b>
-              The  time  limit  for  sending  or receiving information over an
+              The time limit for sending  or  receiving  information  over  an
               internal communication channel.
 
        <b><a href="postconf.5.html#lmtp_assume_final">lmtp_assume_final</a> (no)</b>
-              When a remote LMTP server announces no DSN support, assume  that
-              the  server performs final delivery, and send "delivered" deliv-
+              When  a remote LMTP server announces no DSN support, assume that
+              the server performs final delivery, and send "delivered"  deliv-
               ery status notifications instead of "relayed".
 
        <b><a href="postconf.5.html#lmtp_tcp_port">lmtp_tcp_port</a> (24)</b>
               The default TCP port that the Postfix LMTP client connects to.
 
        <b><a href="postconf.5.html#max_idle">max_idle</a> (100s)</b>
-              The maximum amount of time that an idle Postfix  daemon  process
+              The  maximum  amount of time that an idle Postfix daemon process
               waits for an incoming connection before terminating voluntarily.
 
        <b><a href="postconf.5.html#max_use">max_use</a> (100)</b>
@@ -1007,21 +1014,21 @@ SMTP,(LMTP)                                                        SMTP,(LMTP)
               The process name of a Postfix command or daemon process.
 
        <b><a href="postconf.5.html#proxy_interfaces">proxy_interfaces</a> (empty)</b>
-              The  remote  network  interface  addresses that this mail system
-              receives mail on by way of a proxy or network  address  transla-
+              The remote network interface addresses  that  this  mail  system
+              receives  mail  on by way of a proxy or network address transla-
               tion unit.
 
        <b><a href="postconf.5.html#smtp_address_preference">smtp_address_preference</a> (any)</b>
               The address type ("ipv6", "ipv4" or "any") that the Postfix SMTP
-              client will try first, when a  destination  has  IPv6  and  IPv4
+              client  will  try  first,  when  a destination has IPv6 and IPv4
               addresses with equal MX preference.
 
        <b><a href="postconf.5.html#smtp_bind_address">smtp_bind_address</a> (empty)</b>
-              An  optional  numerical  network  address  that the Postfix SMTP
+              An optional numerical network  address  that  the  Postfix  SMTP
               client should bind to when making an IPv4 connection.
 
        <b><a href="postconf.5.html#smtp_bind_address6">smtp_bind_address6</a> (empty)</b>
-              An optional numerical network  address  that  the  Postfix  SMTP
+              An  optional  numerical  network  address  that the Postfix SMTP
               client should bind to when making an IPv6 connection.
 
        <b><a href="postconf.5.html#smtp_helo_name">smtp_helo_name</a> ($<a href="postconf.5.html#myhostname">myhostname</a>)</b>
@@ -1041,7 +1048,7 @@ SMTP,(LMTP)                                                        SMTP,(LMTP)
               The syslog facility of Postfix logging.
 
        <b><a href="postconf.5.html#syslog_name">syslog_name</a> (see 'postconf -d' output)</b>
-              A prefix that  is  prepended  to  the  process  name  in  syslog
+              A  prefix  that  is  prepended  to  the  process  name in syslog
               records, so that, for example, "smtpd" becomes "prefix/smtpd".
 
        Available with Postfix 2.2 and earlier:
@@ -1053,14 +1060,14 @@ SMTP,(LMTP)                                                        SMTP,(LMTP)
        Available with Postfix 2.3 and later:
 
        <b><a href="postconf.5.html#smtp_fallback_relay">smtp_fallback_relay</a> ($<a href="postconf.5.html#fallback_relay">fallback_relay</a>)</b>
-              Optional list of relay destinations that will be  used  when  an
-              SMTP  destination  is not found, or when delivery fails due to a
+              Optional  list  of  relay destinations that will be used when an
+              SMTP destination is not found, or when delivery fails due  to  a
               non-permanent error.
 
        Available with Postfix 3.0 and later:
 
        <b><a href="postconf.5.html#smtp_address_verify_target">smtp_address_verify_target</a> (rcpt)</b>
-              In the context of email address verification, the SMTP  protocol
+              In  the context of email address verification, the SMTP protocol
               stage that determines whether an email address is deliverable.
 
        Available with Postfix 3.1 and later:
@@ -1082,7 +1089,7 @@ SMTP,(LMTP)                                                        SMTP,(LMTP)
        Available in Postfix 3.7 and later:
 
        <b><a href="postconf.5.html#smtp_bind_address_enforce">smtp_bind_address_enforce</a> (no)</b>
-              Defer delivery when the Postfix SMTP  client  cannot  apply  the
+              Defer  delivery  when  the  Postfix SMTP client cannot apply the
               <a href="postconf.5.html#smtp_bind_address">smtp_bind_address</a> or <a href="postconf.5.html#smtp_bind_address6">smtp_bind_address6</a> setting.
 
 <b>SEE ALSO</b>
index 57b9b13901500ee7bb7032a5d867183d22fbd2de..d816022fa5684b7af8cfa7f6e8cbad2ae946b92a 100644 (file)
@@ -885,10 +885,6 @@ To avoid mailer loops, automatic BCC recipients are not generated
 after Postfix forwards mail internally, or after Postfix generates
 mail itself. </p>
 
-<p> Note: automatic BCC recipients are subject to address
-canonicalization (add missing domain), <a href="postconf.5.html#canonical_maps">canonical_maps</a>, <a href="postconf.5.html#masquerade_domains">masquerade_domains</a>,
-and <a href="postconf.5.html#virtual_alias_maps">virtual_alias_maps</a>. </p>
-
 
 </DD>
 
@@ -1855,10 +1851,6 @@ currently used only to locate the $<a href="postconf.5.html#smtpd_sasl_path">smt
 Specify zero or more directories separated by a colon character,
 or an empty value to use Cyrus SASL's built-in search path.  </p>
 
-<p> Note: some Debian-based Postfix distributions ignore the
-"<a href="postconf.5.html#cyrus_sasl_config_path">cyrus_sasl_config_path</a>" parameter setting, and force Postfix to
-open the file <code>/etc/postfix/sasl/smtpd.conf</code>. </p>
-
 <p> This feature is available in Postfix 2.5 and later when compiled
 with Cyrus SASL 2.1.22 or later. </p>
 
@@ -6213,11 +6205,6 @@ prepend "<b>uid:</b>" to the numerical UID and use that instead. </p>
 <p> This feature ignores address extensions in the user-specified
 envelope sender address. </p>
 
-<p> Note: to enforce that the From: header address matches the envelope
-sender (MAIL FROM) address, specify an external filter such as a Milter,
-with the <a href="postconf.5.html#non_smtpd_milters">non_smtpd_milters</a> parameter. For example:
-<a href="https://github.com/magcks/milterfrom">https://github.com/magcks/milterfrom</a>. </p>
-
 <p> The following sender patterns are special; these cannot be used
 as part of a longer pattern. </p>
 
@@ -10010,10 +9997,6 @@ To avoid mailer loops, automatic BCC recipients are not generated
 after Postfix forwards mail internally, or after Postfix generates
 mail itself. </p>
 
-<p> Note: automatic BCC recipients are subject to address
-canonicalization (add missing domain), <a href="postconf.5.html#canonical_maps">canonical_maps</a>, <a href="postconf.5.html#masquerade_domains">masquerade_domains</a>,
-and <a href="postconf.5.html#virtual_alias_maps">virtual_alias_maps</a>. </p>
-
 <p>
 Example:
 </p>
@@ -10752,10 +10735,6 @@ To avoid mailer loops, automatic BCC recipients are not generated
 after Postfix forwards mail internally, or after Postfix generates
 mail itself. </p>
 
-<p> Note: automatic BCC recipients are subject to address
-canonicalization (add missing domain), <a href="postconf.5.html#canonical_maps">canonical_maps</a>, <a href="postconf.5.html#masquerade_domains">masquerade_domains</a>,
-and <a href="postconf.5.html#virtual_alias_maps">virtual_alias_maps</a>. </p>
-
 <p>
 Example:
 </p>
@@ -14800,6 +14779,33 @@ Postfix versions. </p>
 <p> This feature is available in Postfix 3.0 and later.  </p>
 
 
+</DD>
+
+<DT><b><a name="smtp_tlsrpt_enable">smtp_tlsrpt_enable</a>
+(default: no)</b></DT><DD>
+
+<p> Enable support for <a href="https://tools.ietf.org/html/rfc8460">RFC 8460</a> TLSRPT notifications. A mail receiving
+domain can publish a TLSRPT policy in DNS, to request periodic
+summaries of successful and failed SMTP over TLS connections to
+their mail servers. This feature requires that Postfix is built
+with a TLSRPT supporting library. </p>
+
+<p> This feature is available in Postfix &ge; 3.10. </p>
+
+
+</DD>
+
+<DT><b><a name="smtp_tlsrpt_socket_name">smtp_tlsrpt_socket_name</a>
+(default: empty)</b></DT><DD>
+
+<p> The pathname of a UNIX-domain datagram socket that is managed
+by a local TLSRPT reporting service. This parameter must specify a
+pathname (absolute, or relative to $<a href="postconf.5.html#queue_directory">queue_directory</a>) when
+"<a href="postconf.5.html#smtp_tlsrpt_enable">smtp_tlsrpt_enable</a> = yes". </p>
+
+<p> This feature is available in Postfix &ge; 3.10. </p>
+
+
 </DD>
 
 <DT><b><a name="smtp_use_tls">smtp_use_tls</a>
@@ -17780,17 +17786,10 @@ for authentication. The available types are listed with the
 (default: empty)</b></DT><DD>
 
 <p>
-Optional lookup table with the SASL login names that own the
-envelope sender
+Optional lookup table with the SASL login names that own the sender
 (MAIL FROM) addresses.
 </p>
 
-<blockquote> <p> Note: to enforce that the From: header address
-matches the envelope sender (MAIL FROM) address, use an external
-filter such as a Milter, for the submission, submissions, or smtps
-services. For example: <a href="https://github.com/magcks/milterfrom">https://github.com/magcks/milterfrom</a>. </p>
-</blockquote>
-
 <p>
 Specify zero or more "type:name" lookup tables, separated by
 whitespace or comma. Tables will be searched in the specified order
@@ -17893,11 +17892,6 @@ or the SASL login name is not an owner for that address.
 This prevents an authenticated client from using a MAIL FROM address
 that they do not explicitly own.
 <br>
-Note: to enforce that the From: header address matches the envelope
-sender (MAIL FROM) address, use an external filter such as a Milter,
-for the submission, submissions, or smtps services. For example:
-<a href="https://github.com/magcks/milterfrom">https://github.com/magcks/milterfrom</a>.
-<br>
 This feature is available in Postfix version 2.1 and later. </dd>
 
 <dt><b><a name="reject_known_sender_login_mismatch">reject_known_sender_login_mismatch</a></b></dt>
@@ -17914,11 +17908,6 @@ This protects any MAIL FROM address that is listed in
 $<a href="postconf.5.html#smtpd_sender_login_maps">smtpd_sender_login_maps</a>, while still allowing a client to use any
 unlisted MAIL FROM address.
 <br>
-Note: to enforce that the From: header address matches the envelope
-sender (MAIL FROM) address, use an external filter such as a Milter,
-for the submission, submissions, or smtps services. For example:
-<a href="https://github.com/magcks/milterfrom">https://github.com/magcks/milterfrom</a>.
-<br>
 This feature is available in Postfix version 2.11 and later.</dd>
 
 <dt><b><a name="reject_non_fqdn_sender">reject_non_fqdn_sender</a></b></dt>
@@ -17960,11 +17949,6 @@ authenticated with SASL.
 With SASL enabled, this prevents an unauthenticated client from
 using any MAIL FROM address that is listed in $<a href="postconf.5.html#smtpd_sender_login_maps">smtpd_sender_login_maps</a>.
 <br>
-Note: to enforce that the From: header address matches the envelope
-sender (MAIL FROM) address, use an external filter such as a Milter,
-for the submission, submissions, or smtps services. For example:
-<a href="https://github.com/magcks/milterfrom">https://github.com/magcks/milterfrom</a>.
-<br>
 This feature is available in Postfix version 2.1 and later.</dd>
 
 <dt><b><a name="reject_unknown_sender_domain">reject_unknown_sender_domain</a></b></dt>
index 4cc187c75174313bead975256ac969be83787590..dbf71d264c765c9ea55d750e7f2cb689de37aad3 100644 (file)
@@ -746,41 +746,48 @@ SMTP,(LMTP)                                                        SMTP,(LMTP)
               Request  that remote SMTP servers send an <a href="https://tools.ietf.org/html/rfc7250">RFC7250</a> raw public key
               instead of an X.509 certificate.
 
+       <b><a href="postconf.5.html#smtp_tlsrpt_enable">smtp_tlsrpt_enable</a> (no)</b>
+              Enable support for <a href="https://tools.ietf.org/html/rfc8460">RFC 8460</a> TLSRPT notifications.
+
+       <b><a href="postconf.5.html#smtp_tlsrpt_socket_name">smtp_tlsrpt_socket_name</a> (empty)</b>
+              The pathname of a UNIX-domain datagram socket that is managed by
+              a local TLSRPT reporting service.
+
 <b>OBSOLETE STARTTLS CONTROLS</b>
-       The following configuration parameters  exist  for  compatibility  with
-       Postfix  versions  before  2.3.  Support for these will be removed in a
+       The  following  configuration  parameters  exist for compatibility with
+       Postfix versions before 2.3. Support for these will  be  removed  in  a
        future release.
 
        <b><a href="postconf.5.html#smtp_use_tls">smtp_use_tls</a> (no)</b>
-              Opportunistic mode: use TLS when a remote SMTP server  announces
+              Opportunistic  mode: use TLS when a remote SMTP server announces
               STARTTLS support, otherwise send the mail in the clear.
 
        <b><a href="postconf.5.html#smtp_enforce_tls">smtp_enforce_tls</a> (no)</b>
-              Enforcement  mode:  require  that  remote  SMTP  servers use TLS
+              Enforcement mode: require  that  remote  SMTP  servers  use  TLS
               encryption, and never send mail in the clear.
 
        <b><a href="postconf.5.html#smtp_tls_enforce_peername">smtp_tls_enforce_peername</a> (yes)</b>
-              With mandatory TLS encryption,  require  that  the  remote  SMTP
-              server  hostname  matches  the  information  in  the remote SMTP
+              With  mandatory  TLS  encryption,  require  that the remote SMTP
+              server hostname matches  the  information  in  the  remote  SMTP
               server certificate.
 
        <b><a href="postconf.5.html#smtp_tls_per_site">smtp_tls_per_site</a> (empty)</b>
-              Optional lookup tables with the Postfix SMTP  client  TLS  usage
-              policy  by  next-hop destination and by remote SMTP server host-
+              Optional  lookup  tables  with the Postfix SMTP client TLS usage
+              policy by next-hop destination and by remote SMTP  server  host-
               name.
 
        <b><a href="postconf.5.html#smtp_tls_cipherlist">smtp_tls_cipherlist</a> (empty)</b>
-              Obsolete Postfix &lt; 2.3 control for the Postfix SMTP  client  TLS
+              Obsolete  Postfix  &lt; 2.3 control for the Postfix SMTP client TLS
               cipher list.
 
 <b>RESOURCE AND RATE CONTROLS</b>
        <b><a href="postconf.5.html#smtp_connect_timeout">smtp_connect_timeout</a> (30s)</b>
-              The  Postfix SMTP client time limit for completing a TCP connec-
+              The Postfix SMTP client time limit for completing a TCP  connec-
               tion, or zero (use the operating system built-in time limit).
 
        <b><a href="postconf.5.html#smtp_helo_timeout">smtp_helo_timeout</a> (300s)</b>
-              The Postfix SMTP client time limit for sending the HELO or  EHLO
-              command,  and  for  receiving  the  initial  remote  SMTP server
+              The  Postfix SMTP client time limit for sending the HELO or EHLO
+              command, and  for  receiving  the  initial  remote  SMTP  server
               response.
 
        <b><a href="postconf.5.html#lmtp_lhlo_timeout">lmtp_lhlo_timeout</a> (300s)</b>
@@ -792,19 +799,19 @@ SMTP,(LMTP)                                                        SMTP,(LMTP)
               mand, and for receiving the remote SMTP server response.
 
        <b><a href="postconf.5.html#smtp_mail_timeout">smtp_mail_timeout</a> (300s)</b>
-              The Postfix SMTP client time limit for  sending  the  MAIL  FROM
+              The  Postfix  SMTP  client  time limit for sending the MAIL FROM
               command, and for receiving the remote SMTP server response.
 
        <b><a href="postconf.5.html#smtp_rcpt_timeout">smtp_rcpt_timeout</a> (300s)</b>
-              The  Postfix SMTP client time limit for sending the SMTP RCPT TO
+              The Postfix SMTP client time limit for sending the SMTP RCPT  TO
               command, and for receiving the remote SMTP server response.
 
        <b><a href="postconf.5.html#smtp_data_init_timeout">smtp_data_init_timeout</a> (120s)</b>
-              The Postfix SMTP client time limit for  sending  the  SMTP  DATA
+              The  Postfix  SMTP  client  time limit for sending the SMTP DATA
               command, and for receiving the remote SMTP server response.
 
        <b><a href="postconf.5.html#smtp_data_xfer_timeout">smtp_data_xfer_timeout</a> (180s)</b>
-              The  Postfix SMTP client time limit for sending the SMTP message
+              The Postfix SMTP client time limit for sending the SMTP  message
               content.
 
        <b><a href="postconf.5.html#smtp_data_done_timeout">smtp_data_done_timeout</a> (600s)</b>
@@ -818,13 +825,13 @@ SMTP,(LMTP)                                                        SMTP,(LMTP)
        Available in Postfix version 2.1 and later:
 
        <b><a href="postconf.5.html#smtp_mx_address_limit">smtp_mx_address_limit</a> (5)</b>
-              The maximal number of MX (mail exchanger) IP addresses that  can
-              result  from Postfix SMTP client mail exchanger lookups, or zero
+              The  maximal number of MX (mail exchanger) IP addresses that can
+              result from Postfix SMTP client mail exchanger lookups, or  zero
               (no limit).
 
        <b><a href="postconf.5.html#smtp_mx_session_limit">smtp_mx_session_limit</a> (2)</b>
-              The maximal number of SMTP sessions per delivery request  before
-              the  Postfix  SMTP  client  gives  up or delivers to a fall-back
+              The  maximal number of SMTP sessions per delivery request before
+              the Postfix SMTP client gives up  or  delivers  to  a  fall-back
               <a href="postconf.5.html#relayhost">relay host</a>, or zero (no limit).
 
        <b><a href="postconf.5.html#smtp_rset_timeout">smtp_rset_timeout</a> (20s)</b>
@@ -834,17 +841,17 @@ SMTP,(LMTP)                                                        SMTP,(LMTP)
        Available in Postfix version 2.2 and earlier:
 
        <b><a href="postconf.5.html#lmtp_cache_connection">lmtp_cache_connection</a> (yes)</b>
-              Keep  Postfix  LMTP  client connections open for up to $<a href="postconf.5.html#max_idle">max_idle</a>
+              Keep Postfix LMTP client connections open for  up  to  $<a href="postconf.5.html#max_idle">max_idle</a>
               seconds.
 
        Available in Postfix version 2.2 and later:
 
        <b><a href="postconf.5.html#smtp_connection_cache_destinations">smtp_connection_cache_destinations</a> (empty)</b>
-              Permanently enable SMTP connection  caching  for  the  specified
+              Permanently  enable  SMTP  connection  caching for the specified
               destinations.
 
        <b><a href="postconf.5.html#smtp_connection_cache_on_demand">smtp_connection_cache_on_demand</a> (yes)</b>
-              Temporarily  enable  SMTP connection caching while a destination
+              Temporarily enable SMTP connection caching while  a  destination
               has a high volume of mail in the <a href="QSHAPE_README.html#active_queue">active queue</a>.
 
        <b><a href="postconf.5.html#smtp_connection_reuse_time_limit">smtp_connection_reuse_time_limit</a> (300s)</b>
@@ -858,23 +865,23 @@ SMTP,(LMTP)                                                        SMTP,(LMTP)
        Available in Postfix version 2.3 and later:
 
        <b><a href="postconf.5.html#connection_cache_protocol_timeout">connection_cache_protocol_timeout</a> (5s)</b>
-              Time limit for connection cache connect, send or receive  opera-
+              Time  limit for connection cache connect, send or receive opera-
               tions.
 
        Available in Postfix version 2.9 - 3.6:
 
        <b><a href="postconf.5.html#smtp_per_record_deadline">smtp_per_record_deadline</a> (no)</b>
-              Change  the  behavior  of the smtp_*_timeout time limits, from a
-              time limit per read or write system call, to  a  time  limit  to
-              send  or  receive  a complete record (an SMTP command line, SMTP
-              response line, SMTP message content line, or TLS  protocol  mes-
+              Change the behavior of the smtp_*_timeout time  limits,  from  a
+              time  limit  per  read  or write system call, to a time limit to
+              send or receive a complete record (an SMTP  command  line,  SMTP
+              response  line,  SMTP message content line, or TLS protocol mes-
               sage).
 
        Available in Postfix version 2.11 and later:
 
        <b><a href="postconf.5.html#smtp_connection_reuse_count_limit">smtp_connection_reuse_count_limit</a> (0)</b>
-              When  SMTP  connection  caching  is enabled, the number of times
-              that an SMTP session may be reused before it is closed, or  zero
+              When SMTP connection caching is enabled,  the  number  of  times
+              that  an SMTP session may be reused before it is closed, or zero
               (no limit).
 
        Available in Postfix version 3.4 and later:
@@ -885,13 +892,13 @@ SMTP,(LMTP)                                                        SMTP,(LMTP)
        Available in Postfix version 3.7 and later:
 
        <b><a href="postconf.5.html#smtp_per_request_deadline">smtp_per_request_deadline</a> (no)</b>
-              Change  the  behavior  of the smtp_*_timeout time limits, from a
-              time limit per plaintext or TLS read or write call,  to  a  com-
-              bined  time  limit  for  sending a complete SMTP request and for
+              Change the behavior of the smtp_*_timeout time  limits,  from  a
+              time  limit  per  plaintext or TLS read or write call, to a com-
+              bined time limit for sending a complete  SMTP  request  and  for
               receiving a complete SMTP response.
 
        <b><a href="postconf.5.html#smtp_min_data_rate">smtp_min_data_rate</a> (500)</b>
-              The minimum plaintext data transfer  rate  in  bytes/second  for
+              The  minimum  plaintext  data  transfer rate in bytes/second for
               DATA    requests,    when    deadlines    are    enabled    with
               <a href="postconf.5.html#smtp_per_request_deadline">smtp_per_request_deadline</a>.
 
@@ -899,54 +906,54 @@ SMTP,(LMTP)                                                        SMTP,(LMTP)
 
        <b><a href="postconf.5.html#transport_destination_concurrency_limit">transport_destination_concurrency_limit</a>   ($<a href="postconf.5.html#default_destination_concurrency_limit">default_destination_concur</a>-</b>
        <b><a href="postconf.5.html#default_destination_concurrency_limit">rency_limit</a>)</b>
-              A transport-specific override for  the  <a href="postconf.5.html#default_destination_concurrency_limit">default_destination_con</a>-
+              A  transport-specific  override for the <a href="postconf.5.html#default_destination_concurrency_limit">default_destination_con</a>-
               <a href="postconf.5.html#default_destination_concurrency_limit">currency_limit</a> parameter value, where <i>transport</i> is the <a href="master.5.html">master.cf</a>
               name of the message delivery transport.
 
        <b><a href="postconf.5.html#transport_destination_recipient_limit">transport_destination_recipient_limit</a>     ($<a href="postconf.5.html#default_destination_recipient_limit">default_destination_recipi</a>-</b>
        <b><a href="postconf.5.html#default_destination_recipient_limit">ent_limit</a>)</b>
               A transport-specific override for the <a href="postconf.5.html#default_destination_recipient_limit">default_destination_recip</a>-
-              <a href="postconf.5.html#default_destination_recipient_limit">ient_limit</a>  parameter  value,  where  <i>transport</i> is the <a href="master.5.html">master.cf</a>
+              <a href="postconf.5.html#default_destination_recipient_limit">ient_limit</a> parameter value, where  <i>transport</i>  is  the  <a href="master.5.html">master.cf</a>
               name of the message delivery transport.
 
 <b>SMTPUTF8 CONTROLS</b>
        Preliminary SMTPUTF8 support is introduced with Postfix 3.0.
 
        <b><a href="postconf.5.html#smtputf8_enable">smtputf8_enable</a> (yes)</b>
-              Enable preliminary SMTPUTF8 support for the protocols  described
+              Enable  preliminary SMTPUTF8 support for the protocols described
               in <a href="https://tools.ietf.org/html/rfc6531">RFC 6531</a>, <a href="https://tools.ietf.org/html/rfc6532">RFC 6532</a>, and <a href="https://tools.ietf.org/html/rfc6533">RFC 6533</a>.
 
        <b><a href="postconf.5.html#smtputf8_autodetect_classes">smtputf8_autodetect_classes</a> (sendmail, verify)</b>
-              Detect  that  a message requires SMTPUTF8 support for the speci-
+              Detect that a message requires SMTPUTF8 support for  the  speci-
               fied mail origin classes.
 
        Available in Postfix version 3.2 and later:
 
        <b><a href="postconf.5.html#enable_idna2003_compatibility">enable_idna2003_compatibility</a> (no)</b>
-              Enable  'transitional'  compatibility   between   IDNA2003   and
-              IDNA2008,  when  converting UTF-8 domain names to/from the ASCII
+              Enable   'transitional'   compatibility   between  IDNA2003  and
+              IDNA2008, when converting UTF-8 domain names to/from  the  ASCII
               form that is used for DNS lookups.
 
 <b>TROUBLE SHOOTING CONTROLS</b>
        <b><a href="postconf.5.html#debug_peer_level">debug_peer_level</a> (2)</b>
-              The increment in verbose logging level when a  nexthop  destina-
-              tion,  remote client or server name or network address matches a
+              The  increment  in verbose logging level when a nexthop destina-
+              tion, remote client or server name or network address matches  a
               pattern given with the <a href="postconf.5.html#debug_peer_list">debug_peer_list</a> parameter.
 
        <b><a href="postconf.5.html#debug_peer_list">debug_peer_list</a> (empty)</b>
-              Optional list of nexthop destination, remote  client  or  server
-              name  or  network  address  patterns that, if matched, cause the
-              verbose logging level to increase by  the  amount  specified  in
+              Optional  list  of  nexthop destination, remote client or server
+              name or network address patterns that,  if  matched,  cause  the
+              verbose  logging  level  to  increase by the amount specified in
               $<a href="postconf.5.html#debug_peer_level">debug_peer_level</a>.
 
        <b><a href="postconf.5.html#error_notice_recipient">error_notice_recipient</a> (postmaster)</b>
-              The  recipient  of  postmaster notifications about mail delivery
+              The recipient of postmaster notifications  about  mail  delivery
               problems that are caused by policy, resource, software or proto-
               col errors.
 
        <b><a href="postconf.5.html#internal_mail_filter_classes">internal_mail_filter_classes</a> (empty)</b>
-              What   categories  of  Postfix-generated  mail  are  subject  to
-              before-queue   content    inspection    by    <a href="postconf.5.html#non_smtpd_milters">non_smtpd_milters</a>,
+              What  categories  of  Postfix-generated  mail  are  subject   to
+              before-queue    content    inspection    by   <a href="postconf.5.html#non_smtpd_milters">non_smtpd_milters</a>,
               <a href="postconf.5.html#header_checks">header_checks</a> and <a href="postconf.5.html#body_checks">body_checks</a>.
 
        <b><a href="postconf.5.html#notify_classes">notify_classes</a> (resource, software)</b>
@@ -954,46 +961,46 @@ SMTP,(LMTP)                                                        SMTP,(LMTP)
 
 <b>MISCELLANEOUS CONTROLS</b>
        <b><a href="postconf.5.html#best_mx_transport">best_mx_transport</a> (empty)</b>
-              Where  the  Postfix  SMTP  client  should  deliver  mail when it
+              Where the Postfix  SMTP  client  should  deliver  mail  when  it
               detects a "mail loops back to myself" error condition.
 
        <b><a href="postconf.5.html#config_directory">config_directory</a> (see 'postconf -d' output)</b>
-              The default location of the Postfix <a href="postconf.5.html">main.cf</a> and  <a href="master.5.html">master.cf</a>  con-
+              The  default  location of the Postfix <a href="postconf.5.html">main.cf</a> and <a href="master.5.html">master.cf</a> con-
               figuration files.
 
        <b><a href="postconf.5.html#daemon_timeout">daemon_timeout</a> (18000s)</b>
-              How  much  time  a  Postfix  daemon process may take to handle a
+              How much time a Postfix daemon process  may  take  to  handle  a
               request before it is terminated by a built-in watchdog timer.
 
        <b><a href="postconf.5.html#delay_logging_resolution_limit">delay_logging_resolution_limit</a> (2)</b>
-              The maximal number of digits after the decimal point  when  log-
+              The  maximal  number of digits after the decimal point when log-
               ging sub-second delay values.
 
        <b><a href="postconf.5.html#disable_dns_lookups">disable_dns_lookups</a> (no)</b>
               Disable DNS lookups in the Postfix SMTP and LMTP clients.
 
        <b><a href="postconf.5.html#inet_interfaces">inet_interfaces</a> (all)</b>
-              The  local  network  interface  addresses  that this mail system
+              The local network interface  addresses  that  this  mail  system
               receives mail on.
 
        <b><a href="postconf.5.html#inet_protocols">inet_protocols</a> (see 'postconf -d' output)</b>
-              The Internet protocols Postfix will attempt to use  when  making
+              The  Internet  protocols Postfix will attempt to use when making
               or accepting connections.
 
        <b><a href="postconf.5.html#ipc_timeout">ipc_timeout</a> (3600s)</b>
-              The  time  limit  for  sending  or receiving information over an
+              The time limit for sending  or  receiving  information  over  an
               internal communication channel.
 
        <b><a href="postconf.5.html#lmtp_assume_final">lmtp_assume_final</a> (no)</b>
-              When a remote LMTP server announces no DSN support, assume  that
-              the  server performs final delivery, and send "delivered" deliv-
+              When  a remote LMTP server announces no DSN support, assume that
+              the server performs final delivery, and send "delivered"  deliv-
               ery status notifications instead of "relayed".
 
        <b><a href="postconf.5.html#lmtp_tcp_port">lmtp_tcp_port</a> (24)</b>
               The default TCP port that the Postfix LMTP client connects to.
 
        <b><a href="postconf.5.html#max_idle">max_idle</a> (100s)</b>
-              The maximum amount of time that an idle Postfix  daemon  process
+              The  maximum  amount of time that an idle Postfix daemon process
               waits for an incoming connection before terminating voluntarily.
 
        <b><a href="postconf.5.html#max_use">max_use</a> (100)</b>
@@ -1007,21 +1014,21 @@ SMTP,(LMTP)                                                        SMTP,(LMTP)
               The process name of a Postfix command or daemon process.
 
        <b><a href="postconf.5.html#proxy_interfaces">proxy_interfaces</a> (empty)</b>
-              The  remote  network  interface  addresses that this mail system
-              receives mail on by way of a proxy or network  address  transla-
+              The remote network interface addresses  that  this  mail  system
+              receives  mail  on by way of a proxy or network address transla-
               tion unit.
 
        <b><a href="postconf.5.html#smtp_address_preference">smtp_address_preference</a> (any)</b>
               The address type ("ipv6", "ipv4" or "any") that the Postfix SMTP
-              client will try first, when a  destination  has  IPv6  and  IPv4
+              client  will  try  first,  when  a destination has IPv6 and IPv4
               addresses with equal MX preference.
 
        <b><a href="postconf.5.html#smtp_bind_address">smtp_bind_address</a> (empty)</b>
-              An  optional  numerical  network  address  that the Postfix SMTP
+              An optional numerical network  address  that  the  Postfix  SMTP
               client should bind to when making an IPv4 connection.
 
        <b><a href="postconf.5.html#smtp_bind_address6">smtp_bind_address6</a> (empty)</b>
-              An optional numerical network  address  that  the  Postfix  SMTP
+              An  optional  numerical  network  address  that the Postfix SMTP
               client should bind to when making an IPv6 connection.
 
        <b><a href="postconf.5.html#smtp_helo_name">smtp_helo_name</a> ($<a href="postconf.5.html#myhostname">myhostname</a>)</b>
@@ -1041,7 +1048,7 @@ SMTP,(LMTP)                                                        SMTP,(LMTP)
               The syslog facility of Postfix logging.
 
        <b><a href="postconf.5.html#syslog_name">syslog_name</a> (see 'postconf -d' output)</b>
-              A prefix that  is  prepended  to  the  process  name  in  syslog
+              A  prefix  that  is  prepended  to  the  process  name in syslog
               records, so that, for example, "smtpd" becomes "prefix/smtpd".
 
        Available with Postfix 2.2 and earlier:
@@ -1053,14 +1060,14 @@ SMTP,(LMTP)                                                        SMTP,(LMTP)
        Available with Postfix 2.3 and later:
 
        <b><a href="postconf.5.html#smtp_fallback_relay">smtp_fallback_relay</a> ($<a href="postconf.5.html#fallback_relay">fallback_relay</a>)</b>
-              Optional list of relay destinations that will be  used  when  an
-              SMTP  destination  is not found, or when delivery fails due to a
+              Optional  list  of  relay destinations that will be used when an
+              SMTP destination is not found, or when delivery fails due  to  a
               non-permanent error.
 
        Available with Postfix 3.0 and later:
 
        <b><a href="postconf.5.html#smtp_address_verify_target">smtp_address_verify_target</a> (rcpt)</b>
-              In the context of email address verification, the SMTP  protocol
+              In  the context of email address verification, the SMTP protocol
               stage that determines whether an email address is deliverable.
 
        Available with Postfix 3.1 and later:
@@ -1082,7 +1089,7 @@ SMTP,(LMTP)                                                        SMTP,(LMTP)
        Available in Postfix 3.7 and later:
 
        <b><a href="postconf.5.html#smtp_bind_address_enforce">smtp_bind_address_enforce</a> (no)</b>
-              Defer delivery when the Postfix SMTP  client  cannot  apply  the
+              Defer  delivery  when  the  Postfix SMTP client cannot apply the
               <a href="postconf.5.html#smtp_bind_address">smtp_bind_address</a> or <a href="postconf.5.html#smtp_bind_address6">smtp_bind_address6</a> setting.
 
 <b>SEE ALSO</b>
index e21e648ada0c1ff1f966f34bb5265cfb2af6efdb..248c0aa8f59e55e8634d2e0cfab67a512ec0fca4 100644 (file)
@@ -973,7 +973,7 @@ CCARGS="$CCARGS -DSNAPSHOT"
 
 # Non-production: needs thorough testing, or major changes are still
 # needed before the code stabilizes.
-#CCARGS="$CCARGS -DNONPROD"
+CCARGS="$CCARGS -DNONPROD"
 
 # Workaround: prepend Postfix include files before other include files.
 CCARGS="-I. -I../../include $CCARGS"
index efbde6204fc465727d8b6e42f02c96cae5fd9ded..e2eb6779ec8b7e998fed56e029590be9f86254b6 100644 (file)
@@ -329,13 +329,9 @@ After the message is queued, send the message to the specified
 address instead of the intended recipient(s).  When multiple
 \fBREDIRECT\fR actions fire, only the last one takes effect.
 .sp
-Note 1: this action overrides the FILTER action, and currently
+Note: this action overrides the FILTER action, and currently
 overrides all recipients of the message.
 .sp
-Note 2: a REDIRECT address is subject to canonicalization
-(add missing domain) but NOT subject to canonical, masquerade,
-bcc, or virtual alias mapping.
-.sp
 This feature is available in Postfix 2.1 and later.
 .IP "\fBINFO \fIoptional text...\fR
 Log an informational record with the optional text, together
index fc9b6503f2b19ffb1b3060ee9c434da0427cfeff..92c1de95ed5900648dd4540fd4780e64c13a359f 100644 (file)
@@ -331,14 +331,10 @@ inspect the next input line. After the message is queued,
 it will be sent to the specified address instead of the
 intended recipient(s).
 .sp
-Note 1: this action overrides the \fBFILTER\fR action, and affects
+Note: this action overrides the \fBFILTER\fR action, and affects
 all recipients of the message. If multiple \fBREDIRECT\fR actions
 fire, only the last one is executed.
 .sp
-Note 2: a REDIRECT address is subject to canonicalization
-(add missing domain) but NOT subject to canonical, masquerade,
-bcc, or virtual alias mapping.
-.sp
 This feature is available in Postfix 2.1 and later.
 .sp
 This feature is not supported with smtp header/body checks.
index 91beac06d168c397ed2f28fa5bcba5d2e430c2df..19e359d300468bea6581b74e2b00a24188860b7e 100644 (file)
@@ -511,10 +511,6 @@ Note: automatic BCC recipients are produced only for new mail.
 To avoid mailer loops, automatic BCC recipients are not generated
 after Postfix forwards mail internally, or after Postfix generates
 mail itself.
-.PP
-Note: automatic BCC recipients are subject to address
-canonicalization (add missing domain), canonical_maps, masquerade_domains,
-and virtual_alias_maps.
 .SH anvil_rate_time_unit (default: 60s)
 The time unit over which client connection rates and other rates
 are calculated.
@@ -1115,10 +1111,6 @@ currently used only to locate the $smtpd_sasl_path.conf file.
 Specify zero or more directories separated by a colon character,
 or an empty value to use Cyrus SASL's built\-in search path.
 .PP
-Note: some Debian\-based Postfix distributions ignore the
-"cyrus_sasl_config_path" parameter setting, and force Postfix to
-open the file <code>/etc/postfix/sasl/smtpd.conf</code>.
-.PP
 This feature is available in Postfix 2.5 and later when compiled
 with Cyrus SASL 2.1.22 or later.
 .SH daemon_directory (default: see "postconf \-d" output)
@@ -3746,11 +3738,6 @@ prepend "\fBuid:\fR" to the numerical UID and use that instead.
 This feature ignores address extensions in the user\-specified
 envelope sender address.
 .PP
-Note: to enforce that the From: header address matches the envelope
-sender (MAIL FROM) address, specify an external filter such as a Milter,
-with the non_smtpd_milters parameter. For example:
-https://github.com/magcks/milterfrom.
-.PP
 The following sender patterns are special; these cannot be used
 as part of a longer pattern.
 .IP "\fB * \fR
@@ -6167,10 +6154,6 @@ To avoid mailer loops, automatic BCC recipients are not generated
 after Postfix forwards mail internally, or after Postfix generates
 mail itself.
 .PP
-Note: automatic BCC recipients are subject to address
-canonicalization (add missing domain), canonical_maps, masquerade_domains,
-and virtual_alias_maps.
-.PP
 Example:
 .PP
 .nf
@@ -6684,10 +6667,6 @@ To avoid mailer loops, automatic BCC recipients are not generated
 after Postfix forwards mail internally, or after Postfix generates
 mail itself.
 .PP
-Note: automatic BCC recipients are subject to address
-canonicalization (add missing domain), canonical_maps, masquerade_domains,
-and virtual_alias_maps.
-.PP
 Example:
 .PP
 .nf
@@ -9860,6 +9839,21 @@ More examples are in TLS_README, including examples for older
 Postfix versions.
 .PP
 This feature is available in Postfix 3.0 and later.
+.SH smtp_tlsrpt_enable (default: no)
+Enable support for RFC 8460 TLSRPT notifications. A mail receiving
+domain can publish a TLSRPT policy in DNS, to request periodic
+summaries of successful and failed SMTP over TLS connections to
+their mail servers. This feature requires that Postfix is built
+with a TLSRPT supporting library.
+.PP
+This feature is available in Postfix >= 3.10.
+.SH smtp_tlsrpt_socket_name (default: empty)
+The pathname of a UNIX\-domain datagram socket that is managed
+by a local TLSRPT reporting service. This parameter must specify a
+pathname (absolute, or relative to $queue_directory) when
+"smtp_tlsrpt_enable = yes".
+.PP
+This feature is available in Postfix >= 3.10.
 .SH smtp_use_tls (default: no)
 Opportunistic mode: use TLS when a remote SMTP server announces
 STARTTLS support, otherwise send the mail in the clear. Beware:
@@ -12052,16 +12046,8 @@ for authentication. The available types are listed with the
 .PP
 This feature is available in Postfix 2.3 and later.
 .SH smtpd_sender_login_maps (default: empty)
-Optional lookup table with the SASL login names that own the
-envelope sender
+Optional lookup table with the SASL login names that own the sender
 (MAIL FROM) addresses.
-.sp
-.in +4
-Note: to enforce that the From: header address
-matches the envelope sender (MAIL FROM) address, use an external
-filter such as a Milter, for the submission, submissions, or smtps
-services. For example: https://github.com/magcks/milterfrom.
-.in -4
 .PP
 Specify zero or more "type:name" lookup tables, separated by
 whitespace or comma. Tables will be searched in the specified order
@@ -12134,11 +12120,6 @@ or the SASL login name is not an owner for that address.
 This prevents an authenticated client from using a MAIL FROM address
 that they do not explicitly own.
 .br
-Note: to enforce that the From: header address matches the envelope
-sender (MAIL FROM) address, use an external filter such as a Milter,
-for the submission, submissions, or smtps services. For example:
-https://github.com/magcks/milterfrom.
-.br
 This feature is available in Postfix version 2.1 and later.
 .br
 .IP "\fBreject_known_sender_login_mismatch\fR"
@@ -12154,11 +12135,6 @@ This protects any MAIL FROM address that is listed in
 $smtpd_sender_login_maps, while still allowing a client to use any
 unlisted MAIL FROM address.
 .br
-Note: to enforce that the From: header address matches the envelope
-sender (MAIL FROM) address, use an external filter such as a Milter,
-for the submission, submissions, or smtps services. For example:
-https://github.com/magcks/milterfrom.
-.br
 This feature is available in Postfix version 2.11 and later.
 .br
 .IP "\fBreject_non_fqdn_sender\fR"
@@ -12200,11 +12176,6 @@ authenticated with SASL.
 With SASL enabled, this prevents an unauthenticated client from
 using any MAIL FROM address that is listed in $smtpd_sender_login_maps.
 .br
-Note: to enforce that the From: header address matches the envelope
-sender (MAIL FROM) address, use an external filter such as a Milter,
-for the submission, submissions, or smtps services. For example:
-https://github.com/magcks/milterfrom.
-.br
 This feature is available in Postfix version 2.1 and later.
 .br
 .IP "\fBreject_unknown_sender_domain\fR"
index 0145350cbd05ab52eb351610c916acf8b470ba11..a55d17636fcec64b2d0e2f8057d292f46012f285 100644 (file)
@@ -672,6 +672,12 @@ Available in Postfix version 3.9 and later:
 .IP "\fBsmtp_tls_enable_rpk (no)\fR"
 Request that remote SMTP servers send an RFC7250 raw public key
 instead of an X.509 certificate.
+.PP Available in Postfix version 3.10 and later:
+.IP "\fBsmtp_tlsrpt_enable (no)\fR"
+Enable support for RFC 8460 TLSRPT notifications.
+.IP "\fBsmtp_tlsrpt_socket_name (empty)\fR"
+The pathname of a UNIX\-domain datagram socket that is managed
+by a local TLSRPT reporting service.
 .SH "OBSOLETE STARTTLS CONTROLS"
 .na
 .nf
index 6ca24c63dc659801e6de61881ce69a6b2ab3e910..6e7ba6954f11dd7513df905e80896ced5048f20a 100755 (executable)
@@ -721,6 +721,10 @@ while (<>) {
     s;\bdnssec_probe\b;<a href="postconf.5.html#dnssec_probe">$&</a>;g;
     s;\bsmtp_tls_connection_reuse\b;<a href="postconf.5.html#smtp_tls_connection_reuse">$&</a>;g;
     s;\blmtp_tls_connection_reuse\b;<a href="postconf.5.html#lmtp_tls_connection_reuse">$&</a>;g;
+    s;\bsmtp_tlsrpt_enable\b;<a href="postconf.5.html#smtp_tlsrpt_enable">$&</a>;g;
+    s;\bsmtp_tlsrpt_socket_name\b;<a href="postconf.5.html#smtp_tlsrpt_socket_name">$&</a>;g;
+    s;\blmtp_tlsrpt_enable\b;<a href="postconf.5.html#lmtp_tlsrpt_enable">$&</a>;g;
+    s;\blmtp_tlsrpt_socket_name\b;<a href="postconf.5.html#lmtp_tlsrpt_socket_name">$&</a>;g;
     s;\bsmtpd_enforce_tls\b;<a href="postconf.5.html#smtpd_enforce_tls">$&</a>;g;
     s;\bsmtpd_sasl_tls_security_options\b;<a href="postconf.5.html#smtpd_sasl_tls_security_options">$&</a>;g;
     s;\bsmtpd_sasl_type\b;<a href="postconf.5.html#smtpd_sasl_type">$&</a>;g;
index f02ab1415744028734d4c6e1f2486055e697d89b..86476adf3755eff0e0143f40e45eacabc6075bba 100644 (file)
@@ -50,6 +50,7 @@ HTML  = ../html/ADDRESS_CLASS_README.html \
        ../html/STANDARD_CONFIGURATION_README.html \
        ../html/STRESS_README.html \
        ../html/TLS_README.html ../html/TLS_LEGACY_README.html \
+       ../html/TLSRPT_README.html \
        ../html/TUNING_README.html \
        ../html/UUCP_README.html \
        ../html/VERP_README.html ../html/VIRTUAL_README.html \
@@ -100,6 +101,7 @@ README      = ../README_FILES/ADDRESS_CLASS_README \
        ../README_FILES/STANDARD_CONFIGURATION_README \
        ../README_FILES/STRESS_README \
        ../README_FILES/TLS_README ../README_FILES/TLS_LEGACY_README \
+       ../README_FILES/TLSRPT_README \
        ../README_FILES/TUNING_README \
        ../README_FILES/UUCP_README \
        ../README_FILES/VERP_README ../README_FILES/VIRTUAL_README \
@@ -343,6 +345,9 @@ clobber:
 ../html/TLS_LEGACY_README.html: TLS_LEGACY_README.html
        $(DETAB) $? | $(POSTLINK) >$@
 
+../html/TLSRPT_README.html: TLSRPT_README.html
+       $(DETAB) $? | $(POSTLINK) >$@
+
 ../README_FILES/ADDRESS_CLASS_README: ADDRESS_CLASS_README.html
        $(DETAB) $? | $(HT2READ) >$@
 
@@ -529,6 +534,9 @@ clobber:
 ../README_FILES/TLS_LEGACY_README: TLS_LEGACY_README.html
        $(DETAB) $? | $(HT2READ) >$@
 
+../README_FILES/TLSRPT_README: TLSRPT_README.html
+       $(DETAB) $? | $(HT2READ) >$@
+
 ../README_FILES/AAAREADME: ../html/index.html $(MAKEAAA)
        $(MAKEAAA) ../html/index.html | $(HT2READ) | $(DETAB) >$@
 
diff --git a/postfix/proto/TLSRPT_README.html b/postfix/proto/TLSRPT_README.html
new file mode 100644 (file)
index 0000000..13d8aa6
--- /dev/null
@@ -0,0 +1,276 @@
+<!doctype html public "-//W3C//DTD HTML 4.01 Transitional//EN"
+  "http://www.w3.org/TR/html4/loose.dtd">
+
+<html>
+
+<head>
+
+<title>Postfix TLSRPT notification Howto</title>
+
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<link rel='stylesheet' type='text/css' href='postfix-doc.css'>
+
+</head>
+
+<body>
+
+<h1><img src="postfix-logo.jpg" width="203" height="98" ALT="">Postfix TLSRPT Howto</h1>
+
+<hr>
+
+<h2> TOC </h2>
+
+<ul>
+
+<li> <a href="#intro"> Introduction </a> </li>
+<li> <a href="#building"> Building Postfix with TLSRPT support </a>
+<li> <a href="#using"> Using TLSRPT </a> </li>
+<li> <a href="#mta-sts"> MTA-STS Support via smtp_tls_policy_maps </a> </li>
+<li> <a href="#limitations"> Limitations </a></li>
+<li> <a href="#credits"> Credits </a> </li>
+
+</ul>
+
+<h2> <a name="intro"> Introduction </a> </h2>
+
+<p> The TLSRPT protocol is defined in RFC 8460. With this, an email
+receiving domain can publish a policy in DNS to request daily summary
+reports for successful and failed TLS connections to that domain.
+Support for TLSRPT was added in Postfix 3.10. </p>
+
+<p> When Postfix TLSRPT support is enabled (with "smtp_tlsrpt_enable
+= yes"), the Postfix SMTP and TLS clients engines will generate
+"success" and "failure" events, and will pass those events to a
+TLSRPT client library and report generator that are maintained by
+sys4. The Postfix implementation supports both DANE (Postfix built-in)
+and MTA-STS (through an smtp_tls_policy_maps plug-in). </p>
+
+<p> The high-level diagram shows how Postfix events are reported
+to domains that publish a TLSRPT policy.
+
+<blockquote>
+
+<table>
+
+<tr> <td bgcolor="#f0f0ff"> Postfix SMTP and<br> TLS client engines
+</td> <td> <tt> --&gt; </tt> </td>
+
+<td bgcolor="#f0f0ff"> TLSRPT client library </td> <td> <tt> --&gt;
+</tt> </td>
+
+<td bgcolor="#f0f0ff"> TLSRPT report generator </td> <td> <tt>
+--&gt; </tt> </td>
+
+<td bgcolor="#f0f0ff"> Email or HTTP summary </td> </tr>
+
+</table>
+
+</blockquote>
+
+<p> The Postfix smtp(8) client process implements the SMTP client
+engine.  With "smtp_tls_connection_reuse = no", the smtp(8) client
+process also implements the TLS client engine. With
+"smtp_tls_connection_reuse = yes", the smtp(8) client process
+delegates TLS processing to a Postfix tlsproxy(8) process. Either
+way, Postfix will generate the exact same TLSRPT events. </p>
+
+<h2> <a name="building"> Building Postfix with TLSRPT support </a>
+</h2>
+
+<p> These instructions assume that you build Postfix from source
+code as described in the INSTALL document. Some modification may
+be required if you build Postfix from a vendor-specific source
+package. </p>
+
+<p> The Postfix TLSRPT client builds on a TLSRPT client library
+whose source code can be obtained from: </p>
+
+<blockquote>
+ <p> https://github.com/sys4/tlsrpt </p>
+</blockquote>
+
+<p> The library is typically installed as a header file in
+/usr/local/include/tlsrpt.h and an object library in
+/usr/local/lib/libtlsrpt.a or /usr/local/lib/libtlsrpt.so. The
+actual pathnames will depend on OS platform conventions. </p>
+
+<p> In order to build Postfix with TLSRPT support, you will need
+to add compiler options <b>-DUSE_TLSRPT</b> (to build with TLSRPT
+support), and <b>-I</b> (with the directory containing the tlsrpt.h
+header file), and you will need to add linker options to link with
+the TLSRPT client library, for example: </p>
+
+<blockquote>
+<pre>
+make -f Makefile.init makefiles \
+  "CCARGS=-DUSE_TLSRPT -I/usr/local/include" \
+  "AUXLIBS=-L/usr/local/lib -ltlsrpt"
+</pre>
+</blockquote>
+
+<p> Then, just run 'make'. </p>
+
+<blockquote>
+
+<p> Note: if your build command line already has CCARGS or AUXLIBS
+options, then simply append the above options to the existing CCARGS
+or AUXLIBS values. </p>
+
+</blockquote>
+
+<h2> <a name="using"> Using TLSRPT </a> </h2>
+
+<p> After installing Postfix TLSRPT support, you can enable TLSRPT
+support in main.cf like this: </p>
+
+<blockquote>
+<pre>
+smtp_tlsrpt_enable = yes
+smtp_tlsrpt_socket_name = /path/to/socket
+</pre>
+</blockquote>
+
+<p> The smtp_tlsrpt_socket_name parameter specifies an absolute
+pathname, or a pathname that is relative to $queue_directory. </p>
+
+<p> A good socket location would be under $queue_directory/run/tlsrpt
+or $queue_directory/var/run/tlsrpt. These can then be configured
+in Postfix as a relative pathname (run/tlsrpt/tlsrpt.sock or
+var/run/tlsrpt/tlsrpt.sock) so that the same name will work with
+and without Postfix chroot support. Do not specify a location under
+directory that is already used by Postfix programs. Only Postfix
+programs should create sockets there. </p>
+
+<h2> <a name="mta-sts"> MTA-STS Support via smtp_tls_policy_maps
+</a></h2>
+
+<p> Postfix supports MTA-STS though an smtp_tls_policy_maps policy
+plugin. Postfix TLSRPT support expects a response with the usual
+security level and matching requirements, plus any applicable
+name=value attributes described below. Specify { name = value }
+when a value may contain whitespace. </p>
+
+<blockquote>
+
+<p> Note 1: Postfix 3.10 and later will accept these attributes in
+an MTA-STS response even if TLSRPT support is disabled (at build
+time or run time), but it will not use most attributes except
+<tt>ttl</tt> and <tt>policy_failure</tt>.  </p>
+
+<p> Note 2: It is an error to specify these attributes for a non-STS
+policy. </p>
+
+</blockquote>
+
+<p> The examples in the table apply to the MTA-STS policy example
+given in https://datatracker.ietf.org/doc/html/rfc8460#section-4.5.
+<p>
+
+<ul>
+
+<li> <p> <tt> policy_type=<i>type</i> </tt>
+
+<p> Specify <tt>sts</tt> or <tt>no-policy-found</tt>. </p> </li>
+
+<li> <p> <tt> policy_domain=<i>name</i> </tt> </p>
+
+<p> The domain that the MTA-STS policy applies to. </p> </li>
+
+<li> <p> <tt> policy_ttl=<i>time</i> </tt> </p>
+
+<p> How long (in seconds) a Postfix SMTP client process will cache
+the MTA-STS plugin response.  </p> </li>
+
+<li> <p> <tt> { policy_string = <i>value</i> } </tt> </p>
+
+<p> Specify one <tt>policy_string</tt> instance for each MTA-STS
+policy feature, enclosed inside "{" and "}" to protect whitespace
+in attribute values. </p>
+
+<p> Example: </p>
+
+<blockquote>
+<pre>
+{ policy_string = version: STSv1 }, { policy_string = mode: testing }, ...
+</pre> 
+</blockquote> 
+
+<p> This form ignores whitespace after the opening "{", around the "=",
+and before the closing "}".</p> </li>
+
+<li> <p> <tt> mx_host_pattern=<i>pattern</i> </tt> </p>
+
+<p> Specify one <tt>mx_host_pattern</tt> instance for each "mx:" feature
+in the MTA-STS policy. </p>
+
+<p> Example: </p>
+
+<blockquote>
+<pre>
+mx_host_pattern=mx1.example.com, mx_host_pattern=mx2.example.com, ...
+</pre>
+</blockquote>
+</li>
+
+<li> <p> <tt> policy_failure=<i>type</i> </tt> </p>
+
+<p> If specified, forces MTA-STS policy enforcement to fail with
+the indicated error, even if a server certificate would satisfy
+conventional PKI constraints. </p>
+
+<p> Valid errors are <tt>sts-policy-fetch-error, sts-policy-invalid</tt>,
+<tt>sts-webpki-invalid</tt>, or the less informative
+<tt>validation-failure</tt>. </p>
+
+<p> Example: </p>
+
+<blockquote>
+<pre>
+policy_failure=sts-webpki-invalid
+</pre>
+</blockquote>
+</li>
+
+</ul>
+
+<h2> <a name="limitations"> Limitations </a></h2>
+
+<p> The following limitations exist primarily because some errors
+may be reported by a Postfix smtp(8) client process, and some errors
+by a Postfix tlsproxy(8) process. It is too difficult to propagate
+TLSRPT client library state between processes.</p>
+
+<p> The Postfix TLSRPT client reports one final status (either
+'success' or 'failure') for each MTA that it is able to connect to.
+It cannot report a final status 'success' with some recoverable
+'failure'. Specifically: </p>
+
+<ul>
+
+<li> <p> The Postfix TLSRPT client can report either successful TLS
+policy compliance, or an unrecoverable failure that prevents TLS
+policy compliance (examples: all TLSA records are unusable, or some
+PKI error during certificate verification). <p> </li>
+
+<li> <p> The Postfix TLSRPT client must not be used to report a
+potentially recoverable failure such as a non-parsable TLSA record,
+because some other TLSA record for the same host may still allow
+successful TLS policy compliance. </p> </li>
+
+</ul>
+
+<h2> <a name="credits"> Credits </a> </h2>
+
+<ul>
+
+<li> The TLSRPT client library and report generator are implemented
+and maintained by sys4 (sys4.de). </li>
+
+<li> Wietse Venema implemented the integration with Postfix.
+</li>
+
+</ul>
+
+</body>
+
+</html>
index 24b8295f2c03c34d4335332e318209fb5cfc9fa2..c8704c0d02dd6217ed7cc53a6f814ca966febfef 100644 (file)
@@ -19402,3 +19402,22 @@ announce 8BITMIME support, or when a message line exceeds the SMTP
 length limit. </p>
 
 <p> This feature is available in Postfix &ge; 3.9. </p>
+
+%PARAM smtp_tlsrpt_enable no
+
+<p> Enable support for RFC 8460 TLSRPT notifications. A mail receiving
+domain can publish a TLSRPT policy in DNS, to request periodic
+summaries of successful and failed SMTP over TLS connections to
+their mail servers. This feature requires that Postfix is built
+with a TLSRPT supporting library. </p>
+
+<p> This feature is available in Postfix &ge; 3.10. </p>
+
+%PARAM smtp_tlsrpt_socket_name
+
+<p> The pathname of a UNIX-domain datagram socket that is managed
+by a local TLSRPT reporting service. This parameter must specify a
+pathname (absolute, or relative to $queue_directory) when
+"smtp_tlsrpt_enable = yes". </p>
+
+<p> This feature is available in Postfix &ge; 3.10. </p>
index ec9542f1c9c7f0688ac9f3cffbb54e841949a96e..171198f88412bd2da122499af98ea0e7a2f3bdf5 100644 (file)
@@ -1615,3 +1615,28 @@ milterfrom
 canonicalization
 Orlitzky
 Typofix
+RPT
+TLSRPT
+TLSRPTv
+TODOS
+WSP
+addv
+bugprone
+errnum
+libtlsrpt
+munge
+mystrerror
+protcol
+punycode
+pval
+rpt
+rua
+sockname
+tlsproxied
+tlsrpt
+trw
+datagram
+RPC
+datatracker
+webpki
+parsable
index bff4534d17e4ad78f07e758f6d737ba471365293..62bac0323649eefad5da84b3e67a6a8c46357111 100644 (file)
@@ -335,3 +335,10 @@ length  length of 0 31 0 127
 address  address string length 
  whether the standard End of DATA sequence CRLF CRLF is required and
  Require CRLF CRLF 
+ must start with a version field v TLSRPTv1 followed by WSP WSP
+ policies policy policy type 
+ policies policy policy string Ignored if the tls_policy_type
+ policies policy policy domain 
+additional_detail  additional_detail 
+ignored  ignored 
+USE_TLSRPT  USE_TLSRPT 
index a4b2332a2a387e2d8cccfca228f4007090f98119..c63bcdaab94b16456f16dbc8261a322a510768c7 100644 (file)
@@ -358,3 +358,4 @@ expected to become a list of comma separated names br br This
 Postfix  Postfix can use MongoDB as a source for any of its lookups aliases 5 virtual 5 canonical 5 etc This allows you to keep information for your mail service in a replicated noSQL database with fine grained access controls By not storing it
  CCARGS CCARGS DHAS_MONGODB I usr include libmongoc 1 0 
  dt dt dd 2 Also enable verbose logging in the Postfix TLS
+Postfix  Postfix legacy TLS Support
index 1314e0c0e4c4ed6df4726cf2859973edb257b2b8..e68fbd1c1433258133df9ae939a8dd399ec6737a 100644 (file)
@@ -1841,3 +1841,7 @@ foqvx
 ILP
 xxfi
 optionsv
+rcv
+snd
+sts
+tlsrprt
index e76dbfa4de1a6178424db6d2ac7e8b9a86f4078d..65f9fa06219907731a9b1732975ce632bf2b6f9a 100644 (file)
@@ -379,3 +379,8 @@ Dextrous
 ar
 liveness
 superset
+ltlsrpt
+sts
+STS
+STSv
+Sys
index 987b988f150d767cc9558c058f27627ab963a069..0f8b0b92d5209062807752458a7403ee7605736c 100644 (file)
@@ -221,6 +221,7 @@ extern int dns_rr_compare_pref_any(DNS_RR *, DNS_RR *);
 extern int dns_rr_compare_pref(DNS_RR *, DNS_RR *);
 extern DNS_RR *dns_rr_shuffle(DNS_RR *);
 extern DNS_RR *dns_rr_remove(DNS_RR *, DNS_RR *);
+extern DNS_RR *dns_rr_detach(DNS_RR *, DNS_RR *);
 extern int var_dns_rr_list_limit;
 
  /*
index 882a42ffbeaa5a6a80df1561024b0e626b3ace77..e5775a276d9ff337b2b10c78663f9d3185e3fa66 100644 (file)
 /*     DNS_RR  *list;
 /*     DNS_RR  *record;
 /*
+/*     DNS_RR  *dns_rr_detach(list, record)
+/*     DNS_RR  *list;
+/*     DNS_RR  *record;
+/*
 /*     DNS_RR  *dns_srv_rr_sort(list)
 /*     DNS_RR  *list;
 /*
 /*
 /*     dns_rr_shuffle() randomly permutes a list of resource records.
 /*
-/*     dns_rr_remove() removes the specified record from the specified list.
+/*     dns_rr_remove() disconnects the specified record from the
+/*     specified list and destroys it.
 /*     The updated list is the result value.
 /*     The record MUST be a list member.
 /*
+/*     dns_rr_detach() disconnects the specified record from the
+/*     specified list. The updated list is the result value.
+/*     The record MUST be a list member.
+/*
 /*     dns_srv_rr_sort() sorts a list of SRV records according to
 /*     their priority and weight as described in RFC 2782.
 /* LICENSE
@@ -464,16 +473,24 @@ DNS_RR *dns_rr_shuffle(DNS_RR *list)
 /* dns_rr_remove - remove record from list, return new list */
 
 DNS_RR *dns_rr_remove(DNS_RR *list, DNS_RR *record)
+{
+    list = dns_rr_detach(list, record);
+    dns_rr_free(record);
+    return (list);
+}
+
+/* dns_rr_detach - detach record from list, return new list */
+
+DNS_RR *dns_rr_detach(DNS_RR *list, DNS_RR *record)
 {
     if (list == 0)
-       msg_panic("dns_rr_remove: record not found");
+       msg_panic("dns_rr_detach: record not found");
 
     if (list == record) {
        list = record->next;
        record->next = 0;
-       dns_rr_free(record);
     } else {
-       list->next = dns_rr_remove(list->next, record);
+       list->next = dns_rr_detach(list->next, record);
     }
     return (list);
 }
index 7bbe769270497d512fbfaf74fa49f279d9f81b02..12cf01c58fe7a6d0eef79831cd176ca92cc72e5d 100644 (file)
@@ -361,6 +361,93 @@ static int append_to_elem_from_list_exact_fit(void)
     return (eq_dns_rr_free(got, want));
 }
 
+static int delete_middle_element(void)
+{
+    DNS_RR *a = dns_rr_create_noport("qa", "ra", T_MX, C_IN, 3600, 1, "mxa", 4);
+    DNS_RR *b = dns_rr_create_noport("qb", "rb", T_MX, C_IN, 3600, 1, "mxb", 4);
+    DNS_RR *c = dns_rr_create_noport("qc", "rc", T_MX, C_IN, 3600, 1, "mxc", 4);
+    DNS_RR *got, *want, *list;
+
+    ((list = a)->next = b)->next = c;
+    (want = dns_rr_copy(a))->next = dns_rr_copy(c);
+    got = dns_rr_remove(list, b);
+
+    return (eq_dns_rr_free(got, want));
+}
+
+static int delete_first_element(void)
+{
+    DNS_RR *a = dns_rr_create_noport("qa", "ra", T_MX, C_IN, 3600, 1, "mxa", 4);
+    DNS_RR *b = dns_rr_create_noport("qb", "rb", T_MX, C_IN, 3600, 1, "mxb", 4);
+    DNS_RR *c = dns_rr_create_noport("qc", "rc", T_MX, C_IN, 3600, 1, "mxc", 4);
+    DNS_RR *got, *want, *list;
+
+    ((list = a)->next = b)->next = c;
+    (want = dns_rr_copy(b))->next = dns_rr_copy(c);
+    got = dns_rr_remove(list, a);
+
+    return (eq_dns_rr_free(got, want));
+}
+
+static int delete_last_element(void)
+{
+    DNS_RR *a = dns_rr_create_noport("qa", "ra", T_MX, C_IN, 3600, 1, "mxa", 4);
+    DNS_RR *b = dns_rr_create_noport("qb", "rb", T_MX, C_IN, 3600, 1, "mxb", 4);
+    DNS_RR *c = dns_rr_create_noport("qc", "rc", T_MX, C_IN, 3600, 1, "mxc", 4);
+    DNS_RR *got, *want, *list;
+
+    ((list = a)->next = b)->next = c;
+    (want = dns_rr_copy(a))->next = dns_rr_copy(b);
+    got = dns_rr_remove(list, c);
+
+    return (eq_dns_rr_free(got, want));
+}
+
+static int detach_middle_element(void)
+{
+    DNS_RR *a = dns_rr_create_noport("qa", "ra", T_MX, C_IN, 3600, 1, "mxa", 4);
+    DNS_RR *b = dns_rr_create_noport("qb", "rb", T_MX, C_IN, 3600, 1, "mxb", 4);
+    DNS_RR *c = dns_rr_create_noport("qc", "rc", T_MX, C_IN, 3600, 1, "mxc", 4);
+    DNS_RR *got, *want, *list;
+
+    ((list = a)->next = b)->next = c;
+    (want = dns_rr_copy(a))->next = dns_rr_copy(c);
+    got = dns_rr_detach(list, b);
+    dns_rr_free(b);
+
+    return (eq_dns_rr_free(got, want));
+}
+
+static int detach_first_element(void)
+{
+    DNS_RR *a = dns_rr_create_noport("qa", "ra", T_MX, C_IN, 3600, 1, "mxa", 4);
+    DNS_RR *b = dns_rr_create_noport("qb", "rb", T_MX, C_IN, 3600, 1, "mxb", 4);
+    DNS_RR *c = dns_rr_create_noport("qc", "rc", T_MX, C_IN, 3600, 1, "mxc", 4);
+    DNS_RR *got, *want, *list;
+
+    ((list = a)->next = b)->next = c;
+    (want = dns_rr_copy(b))->next = dns_rr_copy(c);
+    got = dns_rr_detach(list, a);
+    dns_rr_free(a);
+
+    return (eq_dns_rr_free(got, want));
+}
+
+static int detach_last_element(void)
+{
+    DNS_RR *a = dns_rr_create_noport("qa", "ra", T_MX, C_IN, 3600, 1, "mxa", 4);
+    DNS_RR *b = dns_rr_create_noport("qb", "rb", T_MX, C_IN, 3600, 1, "mxb", 4);
+    DNS_RR *c = dns_rr_create_noport("qc", "rc", T_MX, C_IN, 3600, 1, "mxc", 4);
+    DNS_RR *got, *want, *list;
+
+    ((list = a)->next = b)->next = c;
+    (want = dns_rr_copy(a))->next = dns_rr_copy(b);
+    got = dns_rr_detach(list, c);
+    dns_rr_free(c);
+
+    return (eq_dns_rr_free(got, want));
+}
+
  /*
   * The test cases.
   */
@@ -400,9 +487,15 @@ static const TEST_CASE test_cases[] = {
     "append to element from list exact fit", append_to_elem_from_list_exact_fit,
 
     /*
-     * TODO: tests dns_rr_sort(), dns_rr_srv_sort(), dns_rr_remove(),
-     * dns_rr_shuffle(), etc.
+     * TODO: tests for dns_rr_sort(), dns_rr_srv_sort(), dns_rr_shuffle(),
+     * etc.
      */
+    "delete element from list (middle)", delete_middle_element,
+    "delete element from list (first)", delete_first_element,
+    "delete element from list (last)", delete_last_element,
+    "detach element from list (middle)", detach_middle_element,
+    "detach element from list (first)", detach_first_element,
+    "detach element from list (last)", detach_last_element,
     0,
 };
 
index 1f03b0b34e7db79dc42f7557b701864ccbee0d0c..8b52145b0ccdafa6726463ece8b24acdef7c5025 100644 (file)
@@ -4455,6 +4455,22 @@ extern bool var_ign_srv_lookup_err;
 #define DEF_ALLOW_SRV_FALLBACK 0
 extern bool var_allow_srv_fallback;
 
+ /*
+  * TLSRPT notification support. The lmtp_ names must be defined because the
+  * build system enforces that every smtp_ parameter has an lmtp_ variant.
+  */
+#define VAR_SMTP_TLSRPT_ENABLE "smtp_tlsrpt_enable"
+#define DEF_SMTP_TLSRPT_ENABLE "no"
+#define VAR_LMTP_TLSRPT_ENABLE "lmtp_tlsrpt_enable"
+#define DEF_LMTP_TLSRPT_ENABLE DEF_SMTP_TLSRPT_ENABLE
+extern bool var_smtp_tlsrpt_enable;
+
+#define VAR_SMTP_TLSRPT_SOCKNAME "smtp_tlsrpt_socket_name"
+#define DEF_SMTP_TLSRPT_SOCKNAME ""
+#define VAR_LMTP_TLSRPT_SOCKNAME "lmtp_tlsrpt_socket_name"
+#define DEF_LMTP_TLSRPT_SOCKNAME DEF_SMTP_TLSRPT_SOCKNAME
+extern char *var_smtp_tlsrpt_sockname;
+
 /* LICENSE
 /* .ad
 /* .fi
@@ -4469,6 +4485,9 @@ extern bool var_allow_srv_fallback;
 /*     Google, Inc.
 /*     111 8th Avenue
 /*     New York, NY 10011, USA
+/*
+/*     Wietse Venema
+/*     porcupine.org
 /*--*/
 
 #endif
index b474a40066e1521fcd805cf369b73533b5e39f6a..193588ef410802903e9ddd08bb9760e02f46beb8 100644 (file)
@@ -835,6 +835,8 @@ static int starttls(STATE *state)
                                     = vstring_str(cipher_exclusions),
                                     matchargv = state->match,
                                     mdalg = state->mdalg,
+                                    tlsrpt = 0,
+                                    fail_type = 0,
                                     dane = state->ddane ?
                                     state->ddane : state->dane);
 
@@ -939,6 +941,8 @@ static int starttls(STATE *state)
                             = vstring_str(cipher_exclusions),
                             matchargv = state->match,
                             mdalg = state->mdalg,
+                            tlsrpt = 0,
+                            fail_type = 0,
                          dane = state->ddane ? state->ddane : state->dane);
     }                                          /* tlsproxy_mode */
     vstring_free(cipher_exclusions);
index b9f04ca1385d81d037cce4623ee875e62a1b7332..685a72b679d257675e4ff37a4bfa797e2e90fc8d 100644 (file)
@@ -2,11 +2,11 @@ SHELL = /bin/sh
 SRCS   = smtp.c smtp_connect.c smtp_proto.c smtp_chat.c smtp_session.c \
        smtp_addr.c smtp_trouble.c smtp_state.c smtp_rcpt.c smtp_tls_policy.c \
        smtp_sasl_proto.c smtp_sasl_glue.c smtp_reuse.c smtp_map11.c \
-       smtp_sasl_auth_cache.c smtp_key.c smtp_misc.c
+       smtp_sasl_auth_cache.c smtp_key.c smtp_misc.c smtp_tlsrpt.c
 OBJS   = smtp.o smtp_connect.o smtp_proto.o smtp_chat.o smtp_session.o \
        smtp_addr.o smtp_trouble.o smtp_state.o smtp_rcpt.o smtp_tls_policy.o \
        smtp_sasl_proto.o smtp_sasl_glue.o smtp_reuse.o smtp_map11.o \
-       smtp_sasl_auth_cache.o smtp_key.o smtp_misc.o
+       smtp_sasl_auth_cache.o smtp_key.o smtp_misc.o smtp_tlsrpt.o
 HDRS   = smtp.h smtp_sasl.h smtp_addr.h smtp_reuse.h smtp_sasl_auth_cache.h
 TESTSRC        = 
 DEFS   = -I. -I$(INC_DIR) -D$(SYSTYPE)
@@ -267,6 +267,7 @@ smtp_connect.o: ../../include/timed_connect.h
 smtp_connect.o: ../../include/tls.h
 smtp_connect.o: ../../include/tls_proxy.h
 smtp_connect.o: ../../include/tok822.h
+smtp_connect.o: ../../include/valid_hostname.h
 smtp_connect.o: ../../include/vbuf.h
 smtp_connect.o: ../../include/vstream.h
 smtp_connect.o: ../../include/vstring.h
@@ -447,6 +448,7 @@ smtp_proto.o: ../../include/stringops.h
 smtp_proto.o: ../../include/sys_defs.h
 smtp_proto.o: ../../include/tls.h
 smtp_proto.o: ../../include/tls_proxy.h
+smtp_proto.o: ../../include/tlsrpt_wrapper.h
 smtp_proto.o: ../../include/tok822.h
 smtp_proto.o: ../../include/uxtext.h
 smtp_proto.o: ../../include/vbuf.h
@@ -737,6 +739,7 @@ smtp_state.o: ../../include/string_list.h
 smtp_state.o: ../../include/sys_defs.h
 smtp_state.o: ../../include/tls.h
 smtp_state.o: ../../include/tls_proxy.h
+smtp_state.o: ../../include/tlsrpt_wrapper.h
 smtp_state.o: ../../include/tok822.h
 smtp_state.o: ../../include/vbuf.h
 smtp_state.o: ../../include/vstream.h
@@ -770,6 +773,7 @@ smtp_tls_policy.o: ../../include/name_mask.h
 smtp_tls_policy.o: ../../include/nvtable.h
 smtp_tls_policy.o: ../../include/recipient_list.h
 smtp_tls_policy.o: ../../include/resolve_clnt.h
+smtp_tls_policy.o: ../../include/sane_strtol.h
 smtp_tls_policy.o: ../../include/scache.h
 smtp_tls_policy.o: ../../include/sock_addr.h
 smtp_tls_policy.o: ../../include/string_list.h
@@ -777,6 +781,7 @@ smtp_tls_policy.o: ../../include/stringops.h
 smtp_tls_policy.o: ../../include/sys_defs.h
 smtp_tls_policy.o: ../../include/tls.h
 smtp_tls_policy.o: ../../include/tls_proxy.h
+smtp_tls_policy.o: ../../include/tlsrpt_wrapper.h
 smtp_tls_policy.o: ../../include/tok822.h
 smtp_tls_policy.o: ../../include/valid_hostname.h
 smtp_tls_policy.o: ../../include/valid_utf8_hostname.h
@@ -785,6 +790,48 @@ smtp_tls_policy.o: ../../include/vstream.h
 smtp_tls_policy.o: ../../include/vstring.h
 smtp_tls_policy.o: smtp.h
 smtp_tls_policy.o: smtp_tls_policy.c
+smtp_tlsrpt.o: ../../include/argv.h
+smtp_tlsrpt.o: ../../include/attr.h
+smtp_tlsrpt.o: ../../include/check_arg.h
+smtp_tlsrpt.o: ../../include/deliver_request.h
+smtp_tlsrpt.o: ../../include/dict.h
+smtp_tlsrpt.o: ../../include/dns.h
+smtp_tlsrpt.o: ../../include/dsn.h
+smtp_tlsrpt.o: ../../include/dsn_buf.h
+smtp_tlsrpt.o: ../../include/header_body_checks.h
+smtp_tlsrpt.o: ../../include/header_opts.h
+smtp_tlsrpt.o: ../../include/hex_code.h
+smtp_tlsrpt.o: ../../include/htable.h
+smtp_tlsrpt.o: ../../include/inet_proto.h
+smtp_tlsrpt.o: ../../include/mail_params.h
+smtp_tlsrpt.o: ../../include/maps.h
+smtp_tlsrpt.o: ../../include/match_list.h
+smtp_tlsrpt.o: ../../include/midna_domain.h
+smtp_tlsrpt.o: ../../include/mime_state.h
+smtp_tlsrpt.o: ../../include/msg.h
+smtp_tlsrpt.o: ../../include/msg_stats.h
+smtp_tlsrpt.o: ../../include/myaddrinfo.h
+smtp_tlsrpt.o: ../../include/myflock.h
+smtp_tlsrpt.o: ../../include/mymalloc.h
+smtp_tlsrpt.o: ../../include/name_code.h
+smtp_tlsrpt.o: ../../include/name_mask.h
+smtp_tlsrpt.o: ../../include/nvtable.h
+smtp_tlsrpt.o: ../../include/recipient_list.h
+smtp_tlsrpt.o: ../../include/resolve_clnt.h
+smtp_tlsrpt.o: ../../include/scache.h
+smtp_tlsrpt.o: ../../include/sock_addr.h
+smtp_tlsrpt.o: ../../include/string_list.h
+smtp_tlsrpt.o: ../../include/stringops.h
+smtp_tlsrpt.o: ../../include/sys_defs.h
+smtp_tlsrpt.o: ../../include/tls.h
+smtp_tlsrpt.o: ../../include/tls_proxy.h
+smtp_tlsrpt.o: ../../include/tlsrpt_wrapper.h
+smtp_tlsrpt.o: ../../include/tok822.h
+smtp_tlsrpt.o: ../../include/vbuf.h
+smtp_tlsrpt.o: ../../include/vstream.h
+smtp_tlsrpt.o: ../../include/vstring.h
+smtp_tlsrpt.o: smtp.h
+smtp_tlsrpt.o: smtp_tlsrpt.c
 smtp_trouble.o: ../../include/argv.h
 smtp_trouble.o: ../../include/attr.h
 smtp_trouble.o: ../../include/bounce.h
index 385c81ff4a493a80ce32045b59b1d6d37032dcde..c41cf91aec5d995fd144b49c70d617dce4367656 100644 (file)
@@ -67,6 +67,7 @@
        VAR_TLSPROXY_SERVICE, DEF_TLSPROXY_SERVICE, &var_tlsproxy_service, 1, 0,
        VAR_HFROM_FORMAT, DEF_HFROM_FORMAT, &var_hfrom_format, 1, 0,
        VAR_USE_SRV_LOOKUP, DEF_USE_SRV_LOOKUP, &var_use_srv_lookup, 0, 0,
+       VAR_LMTP_TLSRPT_SOCKNAME, DEF_LMTP_TLSRPT_SOCKNAME, &var_smtp_tlsrpt_sockname, 0, 0,
        0,
     };
     static const CONFIG_TIME_TABLE lmtp_time_table[] = {
     };
     static const CONFIG_NBOOL_TABLE lmtp_nbool_table[] = {
        VAR_LMTP_REQ_DEADLINE, DEF_LMTP_REQ_DEADLINE, &var_smtp_req_deadline,
+       VAR_LMTP_TLSRPT_ENABLE, DEF_LMTP_TLSRPT_ENABLE, &var_smtp_tlsrpt_enable,
        0,
     };
index 51b2e6dba67aa0b70d2788523b0a1b13d63ee83a..0c737cbd66846fb7d7c252a30c4c602c9f18c428 100644 (file)
 /* .IP "\fBsmtp_tls_enable_rpk (no)\fR"
 /*     Request that remote SMTP servers send an RFC7250 raw public key
 /*     instead of an X.509 certificate.
+/* .PP Available in Postfix version 3.10 and later:
+/* .IP "\fBsmtp_tlsrpt_enable (no)\fR"
+/*     Enable support for RFC 8460 TLSRPT notifications.
+/* .IP "\fBsmtp_tlsrpt_socket_name (empty)\fR"
+/*     The pathname of a UNIX-domain datagram socket that is managed
+/*     by a local TLSRPT reporting service.
 /* OBSOLETE STARTTLS CONTROLS
 /* .ad
 /* .fi
@@ -1146,6 +1152,8 @@ int     var_smtp_min_data_rate;
 char   *var_use_srv_lookup;
 bool    var_ign_srv_lookup_err;
 bool    var_allow_srv_fallback;
+bool    var_smtp_tlsrpt_enable;
+char   *var_smtp_tlsrpt_sockname;
 
  /* Special handling of 535 AUTH errors. */
 char   *var_smtp_sasl_auth_cache_name;
@@ -1575,6 +1583,21 @@ static void pre_init(char *unused_name, char **unused_argv)
                            mdalg = var_smtp_tls_fpt_dgst);
        smtp_tls_list_init();
        tls_dane_loglevel(VAR_LMTP_SMTP(TLS_LOGLEVEL), var_smtp_tls_loglevel);
+#ifdef USE_TLSRPT
+       if (var_smtp_tlsrpt_enable) {
+           if (smtp_mode) {
+               if (smtp_tlsrpt_pre_jail(VAR_SMTP_TLSRPT_SOCKNAME,
+                                        var_smtp_tlsrpt_sockname) < 0)
+                   var_smtp_tlsrpt_enable = 0;
+           } else {
+               msg_warn("TLSRPT support is not implemented for LMTP");
+               var_smtp_tlsrpt_enable = 0;
+           }
+       }
+#else                                          /* no USE_TLSRPT */
+       if (var_smtp_tlsrpt_enable)
+           msg_warn("TLSRPT is selected, but TLSRPT is not compiled in");
+#endif                                         /* USE_TLSRPT */
 #else
        msg_warn("TLS has been selected, but TLS support is not compiled in");
 #endif
index 60c68f845f660d9a14c532cb678979c9bd9ca094..f367ea1e0d299f348496b2807210323c0b029305 100644 (file)
@@ -108,8 +108,28 @@ typedef struct SMTP_TLS_POLICY {
     char   *sni;                       /* Optional SNI name when not DANE */
     int     conn_reuse;                        /* enable connection reuse */
     int     enable_rpk;                        /* Enable server->client RPK */
+    /* External policy info, for TLSRPT. */
+    int     ext_policy_ttl;            /* TTL from DNS etc. */
+    char   *ext_policy_type;           /* (sts) */
+    ARGV   *ext_policy_strings;                /* policy strings from DNS etc. */
+    char   *ext_policy_domain;         /* policy scope */
+    ARGV   *ext_mx_host_patterns;      /* (sts) MX host patterns */
+    char   *ext_policy_failure;                /* (sts) policy failure */
 } SMTP_TLS_POLICY;
 
+ /*
+  * Names and values for external policy attributes in smtp_tls_policy_maps.
+  * These are not #ifdef USE_TLSRPT, so that a TLSRPT-aware STS plugin can be
+  * used whether or not Postfix was built with TLSRPT support.
+  */
+#define EXT_POLICY_TTL         "policy_ttl"
+#define EXT_POLICY_TTL_UNSET   (-1)
+#define EXT_POLICY_TYPE                "policy_type"
+#define EXT_POLICY_DOMAIN      "policy_domain"
+#define EXT_POLICY_STRING      "policy_string"
+#define EXT_MX_HOST_PATTERN    "mx_host_pattern"
+#define EXT_POLICY_FAILURE     "policy_failure"
+
  /*
   * smtp_tls_policy.c
   */
@@ -144,6 +164,12 @@ extern void smtp_tls_policy_cache_flush(void);
        _tls_policy_init_tmp->sni = 0; \
        _tls_policy_init_tmp->conn_reuse = 0; \
        _tls_policy_init_tmp->enable_rpk = 0; \
+       _tls_policy_init_tmp->ext_policy_ttl = EXT_POLICY_TTL_UNSET; \
+       _tls_policy_init_tmp->ext_policy_type = 0; \
+       _tls_policy_init_tmp->ext_policy_domain = 0; \
+       _tls_policy_init_tmp->ext_policy_strings = 0; \
+       _tls_policy_init_tmp->ext_mx_host_patterns = 0; \
+       _tls_policy_init_tmp->ext_policy_failure = 0; \
     } while (0)
 
 #endif
@@ -171,6 +197,9 @@ typedef struct SMTP_STATE {
      */
 #ifdef USE_TLS
     SMTP_TLS_POLICY tls[1];            /* Usage: state->tls->member */
+#ifdef USE_TLSRPT
+    struct TLSRPT_WRAPPER *tlsrpt;
+#endif
 #endif
 
     /*
@@ -757,6 +786,18 @@ extern void smtp_quote_821_address(VSTRING *, const char *);
   */
 extern int smtp_hfrom_format;
 
+ /*
+  * smtp_tlsrpt.c.
+  */
+#if defined(USE_TLS) && defined(USE_TLSRPT)
+extern int smtp_tlsrpt_pre_jail(const char *sockname_pname, const char *sockname_pval);
+extern void smtp_tlsrpt_create_wrapper(SMTP_STATE *state, const char *domain);
+extern void smtp_tlsrpt_set_tls_policy(SMTP_STATE *state);
+extern void smtp_tlsrpt_set_tcp_connection(SMTP_STATE *state);
+extern void smtp_tlsrpt_set_ehlo_resp(SMTP_STATE *, const char *ehlo_resp);
+
+#endif                                 /* USE_TLSRPT && USE_TLS */
+
 /* LICENSE
 /* .ad
 /* .fi
index 68faca18ef821ab73c6434d2c2039f64ab0e7e62..df26d64baa791b6172d46ef5960307c95b41c94c 100644 (file)
 #include <mail_error.h>
 #include <dsn_buf.h>
 #include <mail_addr.h>
+#include <valid_hostname.h>
 
 /* DNS library. */
 
@@ -911,6 +912,21 @@ static void smtp_connect_inet(SMTP_STATE *state, const char *nexthop,
 
        SMTP_ITER_INIT(iter, dest, NO_HOST, NO_ADDR, port, state);
 
+       /*
+        * TODO(wietse) If the domain publishes a TLSRPT policy, they expect
+        * that clients use SMTP over TLS. Should we upgrade a TLS security
+        * level of "may" to "encrypt"? This would disable falling back to
+        * plaintext, and could break interoperability with receivers that
+        * crank up security up to 11.
+        */
+#ifdef USE_TLSRPT
+       if (smtp_mode && var_smtp_tlsrpt_enable
+           && !valid_hostaddr(domain, DONT_GRIPE))
+           smtp_tlsrpt_create_wrapper(state, domain);
+       else
+           state->tlsrpt = 0;
+#endif                                         /* USE_TLSRPT */
+
        /*
         * Resolve an SMTP or LMTP server. Skip MX or SRV lookups when a
         * quoted domain is specified or when DNS lookups are disabled.
@@ -1076,6 +1092,12 @@ static void smtp_connect_inet(SMTP_STATE *state, const char *nexthop,
                session->state = state;
 #ifdef USE_TLS
                session->tls_nexthop = domain;
+#ifdef USE_TLSRPT
+               if (state->tlsrpt && state->tls->level > TLS_LEV_NONE) {
+                   smtp_tlsrpt_set_tls_policy(state);
+                   smtp_tlsrpt_set_tcp_connection(state);
+               }
+#endif                                         /* USE_TLSRPT */
 #endif
                if (addr->pref == domain_best_pref)
                    session->features |= SMTP_FEATURE_BEST_MX;
index cebff938018da0e3a16f1b7af018d305ebf8ac1d..f58f9eb3461e7e86892b9de9eab18eb58af31e6c 100644 (file)
@@ -68,6 +68,7 @@
        VAR_TLSPROXY_SERVICE, DEF_TLSPROXY_SERVICE, &var_tlsproxy_service, 1, 0,
        VAR_HFROM_FORMAT, DEF_HFROM_FORMAT, &var_hfrom_format, 1, 0,
        VAR_USE_SRV_LOOKUP, DEF_USE_SRV_LOOKUP, &var_use_srv_lookup, 0, 0,
+       VAR_SMTP_TLSRPT_SOCKNAME, DEF_SMTP_TLSRPT_SOCKNAME, &var_smtp_tlsrpt_sockname, 0, 0,
        0,
     };
     static const CONFIG_TIME_TABLE smtp_time_table[] = {
     };
     static const CONFIG_NBOOL_TABLE smtp_nbool_table[] = {
        VAR_SMTP_REQ_DEADLINE, DEF_SMTP_REQ_DEADLINE, &var_smtp_req_deadline,
+       VAR_SMTP_TLSRPT_ENABLE, DEF_SMTP_TLSRPT_ENABLE, &var_smtp_tlsrpt_enable,
        0,
     };
index e022bc2cff262e14a2a43e8c4eb9372c90f3a1c9..bdca86ce85622cc6d0b184aa135cc7d816c67beb 100644 (file)
 #include <xtext.h>
 #include <uxtext.h>
 #include <smtputf8.h>
+#if defined(USE_TLS) && defined(USE_TLSRPT)
+#include <tlsrpt_wrapper.h>
+#endif
 
 /* Application-specific. */
 
@@ -475,6 +478,11 @@ int     smtp_helo(SMTP_STATE *state)
                else
                    session->features &= ~SMTP_FEATURE_ESMTP;
            }
+#ifdef USE_TLSRPT
+           if (state->tlsrpt
+               && (state->misc_flags & SMTP_MISC_FLAG_IN_STARTTLS) == 0)
+               trw_set_ehlo_resp(state->tlsrpt, resp->str);
+#endif
        }
        if ((session->features & SMTP_FEATURE_ESMTP) == 0) {
            where = "performing the HELO handshake";
@@ -484,6 +492,10 @@ int     smtp_helo(SMTP_STATE *state)
                                       "host %s refused to talk to me: %s",
                                       session->namaddr,
                                       translit(resp->str, "\n", " ")));
+#ifdef USE_TLSRPT
+           if (state->tlsrpt)
+               trw_set_ehlo_resp(state->tlsrpt, resp->str);
+#endif
        }
     } else {
        where = "performing the LHLO handshake";
@@ -798,11 +810,19 @@ int     smtp_helo(SMTP_STATE *state)
             * although support for it was announced in the EHLO response.
             */
            session->features &= ~SMTP_FEATURE_STARTTLS;
-           if (TLS_REQUIRED(state->tls->level))
+           if (TLS_REQUIRED(state->tls->level)) {
+#ifdef USE_TLSRPT
+               if (state->tlsrpt)
+                   trw_report_failure(state->tlsrpt,
+                                      TLSRPT_STARTTLS_NOT_SUPPORTED,
+                                       /* additional_detail= */ (char *) 0,
+                                       /* failure_reason= */ (char *) 0);
+#endif
                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. */
        }
 
@@ -815,6 +835,13 @@ int     smtp_helo(SMTP_STATE *state)
         */
        if (TLS_REQUIRED(state->tls->level)) {
            if (!(session->features & SMTP_FEATURE_STARTTLS)) {
+#ifdef USE_TLSRPT
+               if (state->tlsrpt)
+                   trw_report_failure(state->tlsrpt,
+                                      TLSRPT_STARTTLS_NOT_SUPPORTED,
+                                       /* additional_detail= */ (char *) 0,
+                                       /* failure_reason= */ (char *) 0);
+#endif
                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",
@@ -942,6 +969,12 @@ static int smtp_start_tls(SMTP_STATE *state)
                                     = vstring_str(state->tls->exclusions),
                                     matchargv = state->tls->matchargv,
                                     mdalg = var_smtp_tls_fpt_dgst,
+#ifdef USE_TLSRPT
+                                    tlsrpt = state->tlsrpt,
+#else
+                                    tlsrpt = 0,
+#endif
+                                    fail_type = 0,
                                     dane = state->tls->dane);
 
        /*
@@ -1065,6 +1098,12 @@ static int smtp_start_tls(SMTP_STATE *state)
                             = vstring_str(state->tls->exclusions),
                             matchargv = state->tls->matchargv,
                             mdalg = var_smtp_tls_fpt_dgst,
+#ifdef USE_TLSRPT
+                            tlsrpt = state->tlsrpt,
+#else
+                            tlsrpt = 0,
+#endif
+                            fail_type = state->tls->ext_policy_failure,
                             dane = state->tls->dane);
 
        /*
@@ -1125,10 +1164,42 @@ static int smtp_start_tls(SMTP_STATE *state)
      * we must check that here, and not state->tls->level.
      */
     if (TLS_MUST_MATCH(session->tls_context->level))
-       if (!TLS_CERT_IS_MATCHED(session->tls_context))
+       if (!TLS_CERT_IS_MATCHED(session->tls_context)) {
+#ifdef USE_TLSRPT
+
+           /*
+            * Don't create a TLSRPT failure report here, if the TLS engine
+            * already reported a more specific reason.
+            */
+           if (state->tlsrpt && session->tls_context->rpt_reported == 0) {
+               if (!TLS_CERT_IS_TRUSTED(session->tls_context)) {
+                   (void) trw_report_failure(state->tlsrpt,
+                                             TLSRPT_CERTIFICATE_NOT_TRUSTED,
+                                       /* additional_detail= */ (char *) 0,
+                                         /* failure_reason= */ (char *) 0);
+               } else {
+                   (void) trw_report_failure(state->tlsrpt,
+                                          TLSRPT_CERTIFICATE_HOST_MISMATCH,
+                                       /* additional_detail= */ (char *) 0,
+                                         /* failure_reason= */ (char *) 0);
+               }
+           }
+#endif
            return (smtp_site_fail(state, DSN_BY_LOCAL_MTA,
                                   SMTP_RESP_FAKE(&fake, "4.7.5"),
                                   "Server certificate not verified"));
+       }
+
+    /*
+     * Create a TLSRPT success report only if the TLS engine has not reported
+     * a failure (For example, the TLS handshake may be successful, but the
+     * security level was downgraded from opportunistic or half "dane" to
+     * "encrypt").
+     */
+#ifdef USE_TLSRPT
+    if (state->tlsrpt && session->tls_context->rpt_reported == 0)
+       (void) trw_report_success(state->tlsrpt);
+#endif
 
     /*
      * At this point we have to re-negotiate the "EHLO" to reget the
index 6b81fa4edb45bedc9c5e63b824ce113dff301984..c2df5a5d59ca1446040586cf960e62dee1bd825b 100644 (file)
 #include <mail_params.h>
 #include <debug_peer.h>
 
+ /*
+  * TLS library.
+  */
+#if defined(USE_TLS) && defined(USE_TLSRPT)
+#include <tlsrpt_wrapper.h>
+#endif
+
 /* Application-specific. */
 
 #include "smtp.h"
@@ -73,6 +80,9 @@ SMTP_STATE *smtp_state_alloc(void)
     state->iterator->host = vstring_alloc(100);
     state->iterator->addr = vstring_alloc(100);
     state->iterator->saved_dest = vstring_alloc(100);
+#ifdef TLSRPT
+    state->tlsrpt = 0;
+#endif
     if (var_smtp_cache_conn) {
        state->dest_label = vstring_alloc(10);
        state->dest_prop = vstring_alloc(10);
@@ -105,6 +115,10 @@ void    smtp_state_free(SMTP_STATE *state)
     vstring_free(state->iterator->host);
     vstring_free(state->iterator->addr);
     vstring_free(state->iterator->saved_dest);
+#ifdef USE_TLSRPT
+    if (state->tlsrpt)
+       trw_free(state->tlsrpt);
+#endif
     if (state->dest_label)
        vstring_free(state->dest_label);
     if (state->dest_prop)
index f407d65798ab30d17e2558672199e89d408087bb..9640f27a4eacf75a01bbb163dabaf9d13f82f494 100644 (file)
 #include <msg.h>
 #include <mymalloc.h>
 #include <vstring.h>
+#include <sane_strtol.h>
 #include <stringops.h>
 #include <valid_hostname.h>
 #include <valid_utf8_hostname.h>
 #include <maps.h>
 #include <dsn_buf.h>
 
+/* TLS library. */
+
+#include <tlsrpt_wrapper.h>
+
 /* DNS library. */
 
 #include <dns.h>
@@ -221,15 +226,21 @@ static void tls_policy_lookup_one(SMTP_TLS_POLICY *tls, int *site_level,
 {
     const char *lookup;
     char   *policy;
-    char   *saved_policy;
+    char   *saved_policy = 0;
     char   *tok;
-    const char *err;
     char   *name;
     char   *val;
     static VSTRING *cbuf;
+    char   *free_me = 0;
 
 #undef FREE_RETURN
-#define FREE_RETURN do { myfree(saved_policy); return; } while (0)
+#define FREE_RETURN do { \
+       if (saved_policy) \
+           myfree(saved_policy); \
+       if (free_me) \
+           myfree(free_me); \
+       return; \
+    } while (0)
 
 #define INVALID_RETURN(why, levelp) do { \
            MARK_INVALID((why), (levelp)); FREE_RETURN; } while (0)
@@ -250,7 +261,7 @@ static void tls_policy_lookup_one(SMTP_TLS_POLICY *tls, int *site_level,
     }
     saved_policy = policy = mystrdup(lookup);
 
-    if ((tok = mystrtok(&policy, CHARS_COMMA_SP)) == 0) {
+    if ((tok = mystrtokq(&policy, CHARS_COMMA_SP, CHARS_BRACE)) == 0) {
        msg_warn("%s: invalid empty policy", WHERE);
        INVALID_RETURN(tls->why, site_level);
     }
@@ -265,7 +276,7 @@ static void tls_policy_lookup_one(SMTP_TLS_POLICY *tls, int *site_level,
      * Warn about ignored attributes when TLS is disabled.
      */
     if (*site_level < TLS_LEV_MAY) {
-       while ((tok = mystrtok(&policy, CHARS_COMMA_SP)) != 0)
+       while ((tok = mystrtokq(&policy, CHARS_COMMA_SP, CHARS_BRACE)) != 0)
            msg_warn("%s: ignoring attribute \"%s\" with TLS disabled",
                     WHERE, tok);
        FREE_RETURN;
@@ -275,8 +286,12 @@ static void tls_policy_lookup_one(SMTP_TLS_POLICY *tls, int *site_level,
      * Errors in attributes may have security consequences, don't ignore
      * errors that can degrade security.
      */
-    while ((tok = mystrtok(&policy, CHARS_COMMA_SP)) != 0) {
-       if ((err = split_nameval(tok, &name, &val)) != 0) {
+    while ((tok = mystrtokq(&policy, CHARS_COMMA_SP, CHARS_BRACE)) != 0) {
+       const char *err;
+
+       if ((tok[0] == CHARS_BRACE[0]
+            && (err = free_me = extpar(&tok, CHARS_BRACE, EXTPAR_FLAG_STRIP)) != 0)
+           || (err = split_nameval(tok, &name, &val)) != 0) {
            msg_warn("%s: malformed attribute/value pair \"%s\": %s",
                     WHERE, tok, err);
            INVALID_RETURN(tls->why, site_level);
@@ -391,6 +406,7 @@ static void tls_policy_lookup_one(SMTP_TLS_POLICY *tls, int *site_level,
            }
            continue;
        }
+       /* Last one wins. */
        if (!strcasecmp(name, "enable_rpk")) {
            /* Ultimately ignored at some security levels */
            if (strcasecmp(val, "yes") == 0) {
@@ -404,10 +420,96 @@ static void tls_policy_lookup_one(SMTP_TLS_POLICY *tls, int *site_level,
            }
            continue;
        }
+       /* Only one instance per policy. */
+       if (!strcasecmp(name, EXT_POLICY_TTL)) {
+           char   *end;
+           long    lval;
+
+           if (tls->ext_policy_ttl != EXT_POLICY_TTL_UNSET) {
+               msg_warn("%s: attribute \"%s\" is specified multiple times",
+                        WHERE, name);
+               INVALID_RETURN(tls->why, site_level);
+           }
+           if (!alldig(val) || ((lval = sane_strtol(val, &end, 10)),
+                                ((tls->ext_policy_ttl = lval) != lval))
+               || *end != 0) {
+               msg_warn("%s: attribute \"%s\" has a malformed value: \"%s\"",
+                        WHERE, name, val);
+               INVALID_RETURN(tls->why, site_level);
+           }
+           continue;
+       }
+       /* Only one instance per policy. */
+       if (!strcasecmp(name, EXT_POLICY_TYPE)) {
+           if (tls->ext_policy_type) {
+               msg_warn("%s: attribute \"%s\" is specified multiple times",
+                        WHERE, name);
+               INVALID_RETURN(tls->why, site_level);
+           }
+           if (!valid_tlsrpt_policy_type(val)) {
+               msg_warn("%s: attribute \"%s\" has an unexpected value: \"%s\"",
+                        WHERE, name, val);
+               INVALID_RETURN(tls->why, site_level);
+           }
+           tls->ext_policy_type = mystrdup(val);
+           continue;
+       }
+       if (!strcasecmp(name, EXT_POLICY_DOMAIN)) {
+           if (tls->ext_policy_domain) {
+               msg_warn("%s: attribute \"%s\" is specified multiple times",
+                        WHERE, name);
+               INVALID_RETURN(tls->why, site_level);
+           }
+           if (!valid_hostname(val, DO_GRIPE)) {
+               msg_warn("%s: attribute \"%s\" has a malformed value: \"%s\"",
+                        WHERE, name, val);
+               INVALID_RETURN(tls->why, site_level);
+           }
+           tls->ext_policy_domain = mystrdup(val);
+           continue;
+       }
+       /* Multiple instances per policy are allowed. */
+       if (!strcasecmp(name, EXT_POLICY_STRING)) {
+           if (tls->ext_policy_strings == 0)
+               tls->ext_policy_strings = argv_alloc(1);
+           argv_add(tls->ext_policy_strings, val, (char *) 0);
+           continue;
+       }
+       /* Multiple instances per policy are allowed. */
+       if (!strcasecmp(name, EXT_MX_HOST_PATTERN)) {
+           if (tls->ext_mx_host_patterns == 0)
+               tls->ext_mx_host_patterns = argv_alloc(1);
+           argv_add(tls->ext_mx_host_patterns, val, (char *) 0);
+           continue;
+       }
+       /* Only one instance per policy. */
+       if (!strcasecmp(name, EXT_POLICY_FAILURE)) {
+           if (tls->ext_policy_failure != 0) {
+               msg_warn("%s: attribute \"%s\" is specified multiple times",
+                        WHERE, name);
+               INVALID_RETURN(tls->why, site_level);
+           }
+           if (!valid_tlsrpt_policy_failure(val)) {
+               msg_warn("%s: attribute \"%s\" has an unexpected value: \"%s\"",
+                        WHERE, name, val);
+               INVALID_RETURN(tls->why, site_level);
+           }
+           tls->ext_policy_failure = mystrdup(val);
+           continue;
+       }
        msg_warn("%s: invalid attribute name: \"%s\"", WHERE, name);
        INVALID_RETURN(tls->why, site_level);
     }
-
+    if (tls->ext_policy_type == 0) {
+       if (tls->ext_policy_ttl || tls->ext_policy_strings
+           || tls->ext_policy_domain || tls->ext_mx_host_patterns
+           || tls->ext_policy_failure) {
+           msg_warn("%s: built-in policy has unexpected attribute "
+                    "policy_ttl, policy_domain, policy_string, "
+                    "mx_host_pattern or policy_failure", WHERE);
+           INVALID_RETURN(tls->why, site_level);
+       }
+    }
     FREE_RETURN;
 }
 
@@ -707,6 +809,16 @@ static void policy_delete(void *item, void *unused_context)
     if (tls->dane)
        tls_dane_free(tls->dane);
     dsb_free(tls->why);
+    if (tls->ext_policy_type)
+       myfree(tls->ext_policy_type);
+    if (tls->ext_policy_domain)
+       myfree(tls->ext_policy_domain);
+    if (tls->ext_policy_strings)
+       argv_free(tls->ext_policy_strings);
+    if (tls->ext_mx_host_patterns)
+       argv_free(tls->ext_mx_host_patterns);
+    if (tls->ext_policy_failure)
+       myfree(tls->ext_policy_failure);
 
     myfree((void *) tls);
 }
diff --git a/postfix/src/smtp/smtp_tlsrpt.c b/postfix/src/smtp/smtp_tlsrpt.c
new file mode 100644 (file)
index 0000000..b0a6af6
--- /dev/null
@@ -0,0 +1,421 @@
+/*++
+/* NAME
+/*     smtp_tlsrpt 3
+/* SUMMARY
+/*     TLSRPT support for the SMTP protocol engine
+/* SYNOPSIS
+/*     #include <smtp_tlsrpt.h>
+/*
+/*     int     smtp_tlsrpt_pre_jail(
+/*     const char *sockname_pname,
+/*     const char *sockname_pval)
+/*
+/*     void    smtp_tlsrpt_create_wrapper(
+/*     SMTP_STATE *state,
+/*     const char *domain)
+/*
+/*     void    smtp_tlsrpt_set_tls_policy(
+/*     SMTP_STATE *state)
+/*
+/*     void    smtp_tlsrpt_set_tcp_connection(
+/*     SMTP_STATE *state)
+/*
+/*     void    smtp_tlsrpt_set_ehlo_resp(
+/*     SMTP_STATE *state,
+/*     const char *ehlo_resp)
+/* DESCRIPTION
+/*     This module collects TLSRPT policy information and selected SMTP
+/*     protocol engine state in a TLSRPT_WRAPPER object. This will be
+/*     passed to (possibly remote) TLS protocol engine, so that it
+/*     can report a TLS error to a TLSRPT library. The SMTP protocol
+/*     engine uses the information to report a TLS error or success.
+/*
+/*     smtp_tls_pre_jail() does configuration sanity checks and
+/*     returns 0 if successful, i.e. TLSRPT support is properly
+/*     configured. Otherwise it returns -1 and logs a warning. Arguments:
+/* .IP sockname_pname
+/*     The name of a configuration parameter for the endpoint that is
+/*     managed by TLSRPT infrastructure. This is used in a diagnostic
+/*     message.
+/* .IP sockname_pval
+/*     The value of said parameter.
+/* .PP
+/*     smtp_tlsrpt_create_wrapper() destroys any TLSRPT_WRAPPER
+/*     referenced by state->tlsrpt, and looks for a TLSRPT
+/*     policy for the specified domain. If one policy exists,
+/*     smtp_tlsrpt_create_wrapper() attaches a TLSRPT_WRAPPER instance
+/*     to state->tlsrpt. Otherwise, state->tlsrpt will be null, and
+/*     other smtp_tlsrpt_* calls must not be made. The TLSRPT_WRAPPER
+/*     instance may be reused for different SMTP connections with the
+/*     same TLSRPT policy domain. Arguments:
+/* .IP domain
+/*     The name of a domain that may publish a TLSRPT policy. An
+/*     internationalized domain name may be in U-label or A-label form
+/*     (it will be converted to A-label internally).
+/* .PP
+/*     smtp_tlsrpt_set_tls_policy() updates the TLSRPT_WRAPPER with
+/*     DANE or STS TLS policy information, and clears information
+/*     that was added with smtp_tlsrpt_set_tcp_connection() or
+/*     smtp_tlsrpt_set_ehlo_resp().
+/* .PP
+/*     smtp_tlsrpt_set_tcp_connection() updates the TLSRPT_WRAPPER with
+/*     TCP connection properties.
+/* .PP
+/*     smtp_tlsrpt_set_ehlo_resp() updates the TLSRPT_WRAPPER with the
+/*     SMTP server's EHLO response.
+/* BUGS
+/*     This module inherits all limitations from tlsrpt_wrapper(3).
+/* SEE ALSO
+/*     tlsrpt_wrapper(3) TLSRPT support for the TLS protocol engine.
+/* LICENSE
+/* .ad
+/* .fi
+/*     The Secure Mailer license must be distributed with this software.
+/* AUTHOR(S)
+/*     Wietse Venema
+/*     porcupine.org
+/*--*/
+
+ /*
+  * System library.
+  */
+#include <sys_defs.h>
+#include <sys/socket.h>
+
+ /*
+  * Utility library.
+  */
+#include <hex_code.h>
+#include <midna_domain.h>
+#include <msg.h>
+#include <myaddrinfo.h>
+#include <name_code.h>
+#include <stringops.h>
+
+ /*
+  * Global library.
+  */
+#include <mail_params.h>
+
+ /*
+  * TLS library.
+  */
+#include <tls.h>
+#include <tlsrpt_wrapper.h>
+
+ /*
+  * Application-specific.
+  */
+#include <smtp.h>
+
+#if defined(USE_TLS) && defined(USE_TLSRPT)
+
+static const char smtp_tlsrpt_support[] = "TLSRPT support";
+
+/* smtp_tlsrpt_pre_jail - pre-jail configuration sanity check */
+
+int     smtp_tlsrpt_pre_jail(const char *sockname_pname,
+                                    const char *sockname_pval)
+{
+    if (smtp_dns_support == SMTP_DNS_DISABLED) {
+       msg_warn("Cannot enable TLRPT support: DNS is disabled");
+       return (-1);
+    }
+    if (*sockname_pval == 0) {
+       msg_warn("%s: parameter %s has empty value -- %s will be disabled",
+                smtp_tlsrpt_support, sockname_pname, smtp_tlsrpt_support);
+       return (-1);
+    }
+    return (0);
+}
+
+/* smtp_tlsrpt_find_policy - look up TLSRPT policy and verify version ID */
+
+static DNS_RR *smtp_tlsrpt_find_policy(const char *adomain)
+{
+    VSTRING *why = vstring_alloc(100);
+    VSTRING *qname = vstring_alloc(100);
+    DNS_RR *rr_list = 0;
+    DNS_RR *rr_result = 0;
+    DNS_RR *rr;
+    DNS_RR *next;
+    int     res_opt = 0;
+    int     dns_status;
+
+    /*
+     * Preliminaries.
+     */
+    if (smtp_dns_support == SMTP_DNS_DNSSEC)
+       res_opt |= RES_USE_DNSSEC;
+
+    /*
+     * Lexical features: As specified in RFC 8460, a TLSRPT policy record
+     * must start with a version field ("v=TLSRPTv1") followed by *WSP;*WSP
+     * and at least one other field (we must not assume that the second field
+     * will be "rua"). We leave further validation to the TLSRPT library,
+     * where it belongs.
+     */
+#define TLSRPTv1_MAGIC         "v=TLSRPTv1"
+#define TLSRPTv1_MAGIC_LEN     (sizeof(TLSRPTv1_MAGIC) - 1)
+#define RFC5234_WSP            " \t"
+
+    /*
+     * Look up TXT records. Ignore records that don't start with the expected
+     * version ID, and require that there is exactly one such DNS record.
+     */
+    vstring_sprintf(qname, "_smtp._tls_.%s", adomain);
+    dns_status = dns_lookup(STR(qname), T_TXT, res_opt, &rr_list,
+                           (VSTRING *) 0, why);
+    vstring_free(qname);
+    if (dns_status != DNS_OK) {
+       switch (dns_status) {
+       case DNS_NOTFOUND:
+       case DNS_POLICY:
+           /* Expected results. */
+           break;
+       default:
+           /* Unexpected results. */
+           msg_warn("%s: policy lookup failed for %s: %s",
+                    smtp_tlsrpt_support, adomain, STR(why));
+       }
+    } else {
+       for (rr = rr_list; rr; rr = next) {
+           char   *cp;
+
+           next = rr->next;
+           if (strncmp(rr->data, TLSRPTv1_MAGIC, TLSRPTv1_MAGIC_LEN) != 0)
+               /* Ignore non-TLSRPT info. */
+               continue;
+           cp = rr->data + TLSRPTv1_MAGIC_LEN;
+
+           /*
+            * Should the TLSRPT library validate the entire policy for us?
+            */
+           if (cp[strspn(cp, RFC5234_WSP)] != ';') {
+               msg_warn("%s: ignoring malformed policy for %s:, \"%s\"",
+                        smtp_tlsrpt_support, adomain, rr->data);
+               continue;
+           }
+           if (rr_result) {
+               msg_warn("%s: Too many policies for %s",
+                        smtp_tlsrpt_support, adomain);
+               dns_rr_free(rr_result);
+               break;
+           }
+           rr_result = rr;
+           rr_list = dns_rr_detach(rr_list, rr);
+       }
+    }
+    vstring_free(why);
+    if (rr_list)
+       dns_rr_free(rr_list);
+    return (rr_result);
+}
+
+/* smtp_tlsrpt_create_wrapper - look up policy and attach TLSRPT_WRAPPER */
+
+void    smtp_tlsrpt_create_wrapper(SMTP_STATE *state, const char *domain)
+{
+    const char *adomain;
+    DNS_RR *rr;
+
+    /*
+     * TODO(wietse): document in a suitable place that state->tlsrpt exists
+     * only if the next-hop domain announces a TLSRPT policy.
+     */
+    if (state->tlsrpt) {
+       trw_free(state->tlsrpt);
+       state->tlsrpt = 0;
+    }
+
+    /*
+     * IDNA support. An internationalized domain name must be in A-label form
+     * 1) for TLSRPT summaries and 2) for DNS lookups. The A-label lookup
+     * result comes from a limited-size in-process cache, so it does not
+     * matter that the SMTP client requests the same mapping later.
+     */
+#ifndef NO_EAI
+    if (!allascii(domain) && (adomain = midna_domain_to_ascii(domain)) != 0) {
+       if (msg_verbose)
+           msg_info("%s: internationalized domain %s asciified to %s",
+                    smtp_tlsrpt_support, domain, adomain);
+    } else
+#endif
+       adomain = domain;
+
+    if ((rr = smtp_tlsrpt_find_policy(adomain)) != 0) {
+       if (msg_verbose)
+           msg_info("%s: domain %s has policy %.100s",
+                    smtp_tlsrpt_support, domain, rr->data);
+       state->tlsrpt = trw_create(
+                           /* rpt_socket_name= */ var_smtp_tlsrpt_sockname,
+                                   /* rpt_policy_domain= */ adomain,
+                                   /* rpt_policy_string= */ rr->data);
+       dns_rr_free(rr);
+    } else {
+       if (msg_verbose)
+           msg_info("%s: no policy for domain %s",
+                    smtp_tlsrpt_support, domain);
+    }
+}
+
+/* smtp_tlsrpt_set_dane_policy - add DANE policy properties */
+
+static void smtp_tlsrpt_set_dane_policy(SMTP_STATE *state)
+{
+    VSTRING *buf = vstring_alloc(200);
+    ARGV   *argv = argv_alloc(10);
+    TLS_DANE *dane = state->tls->dane;
+    TLS_TLSA *tlsa;
+
+    for (tlsa = dane->tlsa; tlsa != 0; tlsa = tlsa->next) {
+       vstring_sprintf(buf, "%d %d %d ", tlsa->usage,
+                       tlsa->selector, tlsa->mtype);
+       hex_encode_opt(buf, (char *) tlsa->data, tlsa->length,
+                      HEX_ENCODE_FLAG_APPEND);
+       argv_add(argv, STR(buf), (char *) 0);
+    }
+    trw_set_tls_policy(state->tlsrpt, TLSRPT_POLICY_TLSA,
+                      (const char *const *) argv->argv, dane->base_domain,
+                       /* mx_host_patterns= */ (const char *const *) 0);
+    argv_free(argv);
+    vstring_free(buf);
+}
+
+/* smtp_tlsrpt_set_ext_policy - add external policy from smtp_tls_policy_maps */
+
+static void smtp_tlsrpt_set_ext_policy(SMTP_STATE *state)
+{
+    SMTP_TLS_POLICY *tls = state->tls;
+    tlsrpt_policy_type_t policy_type_val;
+
+    switch (policy_type_val = convert_tlsrpt_policy_type(tls->ext_policy_type)) {
+    case TLSRPT_POLICY_STS:
+       trw_set_tls_policy(state->tlsrpt, policy_type_val,
+                       (const char *const *) tls->ext_policy_strings->argv,
+                          tls->ext_policy_domain,
+                    (const char *const *) tls->ext_mx_host_patterns->argv);
+       break;
+    case TLSRPT_NO_POLICY_FOUND:
+       trw_set_tls_policy(state->tlsrpt, policy_type_val,
+                         /* tls_policy_strings= */ (const char *const *) 0,
+                           /* tls_policy_domain= */ (const char *) 0,
+                           /* mx_host_patterns= */ (const char *const *) 0);
+       break;
+    default:
+       msg_panic("unexpected policy type: \"%s\"",
+                 tls->ext_policy_type);
+    }
+
+    /*
+     * TODO(wietse) propagate tls->policy_failure to force policy enforcement
+     * to fail with the indicated error, and prevent a false positive match
+     * when a certificate would satisfy conventional PKI constraints.
+     */
+}
+
+/* smtp_tlsrpt_set_tls_policy - set built-in or external policy */
+
+void    smtp_tlsrpt_set_tls_policy(SMTP_STATE *state)
+{
+    SMTP_TLS_POLICY *tls = state->tls;
+
+    if (TLS_DANE_BASED(tls->level)) {          /* Desired by local policy */
+       if (tls->dane != 0)                     /* Actual policy */
+           smtp_tlsrpt_set_dane_policy(state);
+    } else if (tls->ext_policy_type) {
+           smtp_tlsrpt_set_ext_policy(state);
+    }
+}
+
+/* sane_sockaddr_to_hostaddr - TODO(wietse) move to library */
+
+#include <inet_proto.h>
+
+static const INET_PROTO_INFO *proto_info;
+
+static int sane_sockaddr_to_hostaddr(struct sockaddr *addr_storage,
+                                            SOCKADDR_SIZE addr_storage_len,
+                                            MAI_HOSTADDR_STR *addr_buf,
+                                            MAI_SERVPORT_STR *port_buf,
+                                            int socktype)
+{
+    int     aierr;
+
+    if (proto_info == 0)
+       proto_info = inet_proto_info();
+
+    if ((aierr = sockaddr_to_hostaddr(addr_storage, addr_storage_len,
+                                     addr_buf, port_buf, socktype)) == 0
+       && strncasecmp("::ffff:", addr_buf->buf, 7) == 0
+       && strchr((char *) proto_info->sa_family_list, AF_INET) != 0)
+       memmove(addr_buf->buf, addr_buf->buf + 7,
+               sizeof(addr_buf->buf) - 7);
+    return (aierr);
+}
+
+/* smtp_tlsrpt_set_tcp_connection - set TCP connection info from SMTP_STATE */
+
+void    smtp_tlsrpt_set_tcp_connection(SMTP_STATE *state)
+{
+    SMTP_ITERATOR *iter = state->iterator;
+    SMTP_SESSION *session = state->session;
+    MAI_HOSTADDR_STR client_addr;
+    struct sockaddr_storage addr_storage;
+    SOCKADDR_SIZE addr_storage_len = sizeof(addr_storage);
+    int     aierr;
+
+    /*
+     * Get the IP client address string. The Postfix SMTP_ITERATOR already
+     * contains strings with other connection information.
+     */
+    if (getsockname(vstream_fileno(session->stream),
+                   (struct sockaddr *) &addr_storage,
+                   &addr_storage_len) < 0) {
+       msg_warn("%s: getsockname() failed (%m)"
+                " skipping the ignoring client-side IP address",
+                smtp_tlsrpt_support);
+       client_addr.buf[0] = 0;
+    } else if ((aierr = sane_sockaddr_to_hostaddr(
+                                         (struct sockaddr *) &addr_storage,
+                                            addr_storage_len, &client_addr,
+                                                 (MAI_SERVPORT_STR *) 0,
+                                                 SOCK_STREAM)) != 0) {
+       msg_warn("%s: cannot convert IP address to string (%s)"
+                " -- skipping the client-side IP address",
+                smtp_tlsrpt_support, MAI_STRERROR(aierr));
+       client_addr.buf[0] = 0;
+    }
+    trw_set_tcp_connection(state->tlsrpt, client_addr.buf, STR(iter->host),
+                          STR(iter->addr));
+}
+
+/* smtp_tlsrpt_set_ehlo_resp - format and set EHLO response */
+
+void    smtp_tlsrpt_set_ehlo_resp(SMTP_STATE *state, const char *reply)
+{
+    ARGV   *argv;
+    VSTRING *buf;
+    char  **cpp;
+
+    /*
+     * Generate SMTP-style line breaks ("\r\n") for a multiline response.
+     * Internally, smtp_chat_resp() returns a multiline response as text
+     * separated with "\n". This is because Postfix by design removes
+     * protocol-specific line endings on input, uses its own internal form to
+     * represent text lines, and generates protocol-specific line endings on
+     * output. The conversion to "\r\n" below is such an output conversion.
+     */
+    buf = vstring_alloc(100);
+    argv = argv_split(reply, "\n");
+    for (cpp = argv->argv; *cpp; cpp++) {
+       vstring_strcat(buf, *cpp);
+       if (cpp[1])
+           vstring_strcat(buf, "\r\n");
+    }
+    argv_free(argv);
+    trw_set_ehlo_resp(state->tlsrpt, STR(buf));
+    vstring_free(buf);
+}
+
+#endif                                 /* USE_TLSRPT  && USE_TLS */
index 4b562b3fb92f2e96d0507607c33dc618cc918b5b..3d3bf6e293f0fc28c03030d1eaed467668e4bf2f 100644 (file)
@@ -9,7 +9,7 @@ SRCS    = tls_prng_dev.c tls_prng_egd.c tls_prng_file.c tls_fprint.c \
        tls_proxy_server_init_print.c tls_proxy_server_init_scan.c \
        tls_proxy_client_start_print.c tls_proxy_client_start_scan.c \
        tls_proxy_server_start_print.c tls_proxy_server_start_scan.c \
-       tls_proxy_client_misc.c
+       tls_proxy_client_misc.c tlsrpt_wrapper.c
 OBJS   = tls_prng_dev.o tls_prng_egd.o tls_prng_file.o tls_fprint.o \
        tls_prng_exch.o tls_stream.o tls_bio_ops.o tls_misc.o tls_dh.o \
        tls_verify.o tls_dane.o tls_certkey.o tls_session.o \
@@ -18,8 +18,8 @@ OBJS  = tls_prng_dev.o tls_prng_egd.o tls_prng_file.o tls_fprint.o \
        tls_proxy_clnt.o tls_proxy_context_print.o tls_proxy_context_scan.o \
        tls_proxy_client_print.o tls_proxy_client_scan.o \
        tls_proxy_server_print.o tls_proxy_server_scan.o \
-       tls_proxy_client_misc.o
-HDRS   = tls.h tls_prng.h tls_scache.h tls_mgr.h tls_proxy.h
+       tls_proxy_client_misc.o tlsrpt_wrapper.o
+HDRS   = tls.h tls_prng.h tls_scache.h tls_mgr.h tls_proxy.h tlsrpt_wrapper.h
 TESTSRC        = 
 DEFS   = -I. -I$(INC_DIR) -D$(SYSTYPE)
 CFLAGS = $(DEBUG) $(OPT) $(DEFS)
@@ -182,6 +182,7 @@ tls_client.o: tls.h
 tls_client.o: tls_client.c
 tls_client.o: tls_mgr.h
 tls_client.o: tls_scache.h
+tls_client.o: tlsrpt_wrapper.h
 tls_dane.o: ../../include/argv.h
 tls_dane.o: ../../include/check_arg.h
 tls_dane.o: ../../include/ctable.h
@@ -365,6 +366,7 @@ tls_proxy_client_print.o: ../../include/vstring.h
 tls_proxy_client_print.o: tls.h
 tls_proxy_client_print.o: tls_proxy.h
 tls_proxy_client_print.o: tls_proxy_client_print.c
+tls_proxy_client_print.o: tlsrpt_wrapper.h
 tls_proxy_client_scan.o: ../../include/argv.h
 tls_proxy_client_scan.o: ../../include/argv_attr.h
 tls_proxy_client_scan.o: ../../include/attr.h
@@ -386,6 +388,7 @@ tls_proxy_client_scan.o: ../../include/vstring.h
 tls_proxy_client_scan.o: tls.h
 tls_proxy_client_scan.o: tls_proxy.h
 tls_proxy_client_scan.o: tls_proxy_client_scan.c
+tls_proxy_client_scan.o: tlsrpt_wrapper.h
 tls_proxy_clnt.o: ../../include/argv.h
 tls_proxy_clnt.o: ../../include/attr.h
 tls_proxy_clnt.o: ../../include/check_arg.h
@@ -587,3 +590,15 @@ tls_verify.o: ../../include/vstream.h
 tls_verify.o: ../../include/vstring.h
 tls_verify.o: tls.h
 tls_verify.o: tls_verify.c
+tls_verify.o: tlsrpt_wrapper.h
+tlsrpt_wrapper.o: ../../include/argv.h
+tlsrpt_wrapper.o: ../../include/check_arg.h
+tlsrpt_wrapper.o: ../../include/msg.h
+tlsrpt_wrapper.o: ../../include/mymalloc.h
+tlsrpt_wrapper.o: ../../include/name_code.h
+tlsrpt_wrapper.o: ../../include/stringops.h
+tlsrpt_wrapper.o: ../../include/sys_defs.h
+tlsrpt_wrapper.o: ../../include/vbuf.h
+tlsrpt_wrapper.o: ../../include/vstring.h
+tlsrpt_wrapper.o: tlsrpt_wrapper.c
+tlsrpt_wrapper.o: tlsrpt_wrapper.h
index 3ec41ba369510486ae25db62ddf774077726911b..b3e5b7cb2be92c7fdd6962a0eb5229bae30f32eb 100644 (file)
@@ -205,7 +205,7 @@ extern TLS_DANE *tls_dane_alloc(void);
 extern void tls_tlsa_free(TLS_TLSA *);
 extern void tls_dane_free(TLS_DANE *);
 extern void tls_dane_add_fpt_digests(TLS_DANE *, int, const char *,
-                                           const char *, int);
+                                            const char *, int);
 extern TLS_DANE *tls_dane_resolve(unsigned, const char *, DNS_RR *, int);
 extern int tls_dane_load_trustfile(TLS_DANE *, const char *);
 
@@ -261,6 +261,8 @@ typedef struct {
     int     errordepth;                        /* Chain depth of error cert */
     int     errorcode;                 /* First error at error depth */
     int     must_fail;                 /* Failed to load trust settings */
+    int     rpt_reported;              /* Failure was reported with TLSRPT */
+    char   *fail_type;         /* Doomed by policy */
 } TLS_SESS_STATE;
 
  /*
@@ -493,6 +495,8 @@ typedef struct {
     const ARGV *matchargv;             /* Cert match patterns */
     const char *mdalg;                 /* default message digest algorithm */
     const TLS_DANE *dane;              /* DANE TLSA verification */
+    struct TLSRPT_WRAPPER *tlsrpt;     /* RFC 8460 reporting */
+    char   *fail_type;         /* verification must fail by policy */
 } TLS_CLIENT_START_PROPS;
 
 extern TLS_APPL_STATE *tls_client_init(const TLS_CLIENT_INIT_PROPS *);
@@ -516,12 +520,13 @@ extern TLS_SESS_STATE *tls_client_post_connect(TLS_SESS_STATE *,
     a6, a7, a8, a9, a10, a11, a12, a13, a14))
 
 #define TLS_CLIENT_START(props, a1, a2, a3, a4, a5, a6, a7, a8, a9, \
-    a10, a11, a12, a13, a14, a15, a16, a17, a18) \
+    a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20) \
     tls_client_start((((props)->a1), ((props)->a2), ((props)->a3), \
     ((props)->a4), ((props)->a5), ((props)->a6), ((props)->a7), \
     ((props)->a8), ((props)->a9), ((props)->a10), ((props)->a11), \
     ((props)->a12), ((props)->a13), ((props)->a14), ((props)->a15), \
-    ((props)->a16), ((props)->a17), ((props)->a18), (props)))
+    ((props)->a16), ((props)->a17), ((props)->a18), ((props)->a19), \
+    ((props)->a20), (props)))
 
  /*
   * tls_server.c
@@ -654,7 +659,7 @@ extern void tls_auto_groups(SSL_CTX *, const char *, const char *);
 extern char *tls_peer_CN(X509 *, const TLS_SESS_STATE *);
 extern char *tls_issuer_CN(X509 *, const TLS_SESS_STATE *);
 extern int tls_verify_certificate_callback(int, X509_STORE_CTX *);
-extern void tls_log_verify_error(TLS_SESS_STATE *);
+extern void tls_log_verify_error(TLS_SESS_STATE *, struct TLSRPT_WRAPPER *);
 
  /*
   * tls_dane.c
index 3eda859cc0d039b49d4e39ea1a6d6c864c8a08cf..7834ef8ae12efde74e6683e663e2640c1ee560fe 100644 (file)
 
 #ifdef USE_TLS
 #include <string.h>
+#include <tlsrpt_wrapper.h>
 
 #ifdef STRCASECMP_IN_STRINGS_H
 #include <strings.h>
@@ -363,11 +364,12 @@ static void verify_x509(TLS_SESS_STATE *TLScontext, X509 *peercert,
     if (!TLS_CERT_IS_MATCHED(TLScontext)
        && (TLScontext->log_mask & TLS_LOG_UNTRUSTED)) {
        if (TLScontext->session_reused == 0)
-           tls_log_verify_error(TLScontext);
+           tls_log_verify_error(TLScontext, props->tlsrpt);
        else
            msg_info("%s: re-using session with untrusted peer credential, "
                     "look for details earlier in the log", props->namaddr);
     }
+    /* TODO(wietse) In the non-reuse case, tlsrprt the root cause? */
 }
 
 /* verify_rpk - process RFC7250 raw public key verification status */
@@ -407,11 +409,12 @@ static void verify_rpk(TLS_SESS_STATE *TLScontext, EVP_PKEY *peerpkey,
     if (!TLS_CERT_IS_MATCHED(TLScontext)
        && (TLScontext->log_mask & TLS_LOG_UNTRUSTED)) {
        if (TLScontext->session_reused == 0)
-           tls_log_verify_error(TLScontext);
+           tls_log_verify_error(TLScontext, props->tlsrpt);
        else
            msg_info("%s: re-using session with untrusted certificate, "
                     "look for details earlier in the log", props->namaddr);
     }
+    /* TODO(wietse) In the non-reuse case, tlsrprt the root cause? */
 }
 
 /* add_namechecks - tell OpenSSL what names to check */
@@ -579,6 +582,7 @@ static int tls_auth_enable(TLS_SESS_STATE *TLScontext,
         * therefore valid for use with SNI.
         */
        if (SSL_dane_enable(TLScontext->con, 0) <= 0) {
+           /* TLSRPT: Local resource error, don't report. */
            msg_warn("%s: error enabling DANE-based certificate validation",
                     TLScontext->namaddr);
            tls_print_errors();
@@ -595,6 +599,7 @@ static int tls_auth_enable(TLS_SESS_STATE *TLScontext,
     case TLS_LEV_FPRINT:
        /* Synthetic DANE for fingerprint security */
        if (SSL_dane_enable(TLScontext->con, 0) <= 0) {
+           /* TLSRPT: Local resource error, don't report. */
            msg_warn("%s: error enabling fingerprint certificate validation",
                     props->namaddr);
            tls_print_errors();
@@ -608,6 +613,7 @@ static int tls_auth_enable(TLS_SESS_STATE *TLScontext,
        if (TLScontext->dane != 0 && TLScontext->dane->tlsa != 0) {
            /* Synthetic DANE for per-destination trust-anchors */
            if (SSL_dane_enable(TLScontext->con, NULL) <= 0) {
+               /* TLSRPT: Local resource error, don't report. */
                msg_warn("%s: error configuring local trust anchors",
                         props->namaddr);
                tls_print_errors();
@@ -622,6 +628,7 @@ static int tls_auth_enable(TLS_SESS_STATE *TLScontext,
 
     if (sni) {
        if (strlen(sni) > TLSEXT_MAXLEN_host_name) {
+           /* TLSRPT: Local configuration error, don't report. */
            msg_warn("%s: ignoring too long SNI hostname: %.100s",
                     props->namaddr, sni);
            return (0);
@@ -633,6 +640,7 @@ static int tls_auth_enable(TLS_SESS_STATE *TLScontext,
         * failed to send the SNI name, we have little choice but to abort.
         */
        if (!SSL_set_tlsext_host_name(TLScontext->con, sni)) {
+           /* TLSRPT: Local resource or configuration error, don't report. */
            msg_warn("%s: error setting SNI hostname to: %s", props->namaddr,
                     sni);
            return (0);
@@ -975,6 +983,7 @@ TLS_SESS_STATE *tls_client_start(const TLS_CLIENT_START_PROPS *props)
      */
     protomask = tls_proto_mask_lims(props->protocols, &min_proto, &max_proto);
     if (protomask == TLS_PROTOCOL_INVALID) {
+       /* TLSRPT: Local configuration error, don't report. */
        /* tls_protocol_mask() logs no warning. */
        msg_warn("%s: Invalid TLS protocol list \"%s\": aborting TLS session",
                 props->namaddr, props->protocols);
@@ -1006,6 +1015,7 @@ TLS_SESS_STATE *tls_client_start(const TLS_CLIENT_START_PROPS *props)
     TLScontext->level = props->tls_level;
 
     if ((TLScontext->con = SSL_new(app_ctx->ssl_ctx)) == NULL) {
+       /* TLSRPT: Local resource error, don't report. */
        msg_warn("Could not allocate 'TLScontext->con' with SSL_new()");
        tls_print_errors();
        tls_free_context(TLScontext);
@@ -1022,6 +1032,7 @@ TLS_SESS_STATE *tls_client_start(const TLS_CLIENT_START_PROPS *props)
     cipher_list = tls_set_ciphers(TLScontext, props->cipher_grade,
                                  props->cipher_exclusions);
     if (cipher_list == 0) {
+       /* TLSRPT: Local configuration error, don't report. */
        /* already warned */
        tls_free_context(TLScontext);
        return (0);
@@ -1036,6 +1047,7 @@ TLS_SESS_STATE *tls_client_start(const TLS_CLIENT_START_PROPS *props)
     TLScontext->dane = props->dane;
 
     if (!SSL_set_ex_data(TLScontext->con, TLScontext_index, TLScontext)) {
+       /* TLSRPT: Local resource error, don't report. */
        msg_warn("Could not set application data for 'TLScontext->con'");
        tls_print_errors();
        tls_free_context(TLScontext);
@@ -1069,6 +1081,7 @@ TLS_SESS_STATE *tls_client_start(const TLS_CLIENT_START_PROPS *props)
      * early.
      */
     if (!tls_auth_enable(TLScontext, props)) {
+       /* Already warned and reported TLSRPT result. */
        tls_free_context(TLScontext);
        return (0);
     }
@@ -1105,6 +1118,13 @@ TLS_SESS_STATE *tls_client_start(const TLS_CLIENT_START_PROPS *props)
            switch (TLScontext->level) {
            case TLS_LEV_HALF_DANE:
            case TLS_LEV_DANE:
+#ifdef USE_TLSRPT
+               if (props->tlsrpt) {
+                   trw_report_failure(props->tlsrpt, TLSRPT_TLSA_INVALID,
+                                       /* additional_detail= */ (char *) 0,
+                                      "all-TLSA-records-unusable");
+               }
+#endif
                msg_warn("%s: all TLSA records unusable, fallback to "
                         "unauthenticated TLS", TLScontext->namaddr);
                must_fail = 0;
@@ -1112,13 +1132,34 @@ TLS_SESS_STATE *tls_client_start(const TLS_CLIENT_START_PROPS *props)
                break;
 
            case TLS_LEV_FPRINT:
+#ifdef USE_TLSRPT
+               if (props->tlsrpt) {
+                   trw_report_failure(props->tlsrpt, TLSRPT_VALIDATION_FAILURE,
+                                       /* additional_detail= */ (char *) 0,
+                                      "all-fingerprints-unusable");
+               }
+#endif
                msg_warn("%s: all fingerprints unusable", TLScontext->namaddr);
                break;
            case TLS_LEV_DANE_ONLY:
+#ifdef USE_TLSRPT
+               if (props->tlsrpt) {
+                   trw_report_failure(props->tlsrpt, TLSRPT_TLSA_INVALID,
+                                       /* additional_detail= */ (char *) 0,
+                                      "all-TLSA-records-unusable");
+               }
+#endif
                msg_warn("%s: all TLSA records unusable", TLScontext->namaddr);
                break;
            case TLS_LEV_SECURE:
            case TLS_LEV_VERIFY:
+#ifdef USE_TLSRPT
+               if (props->tlsrpt) {
+                   trw_report_failure(props->tlsrpt, TLSRPT_VALIDATION_FAILURE,
+                                       /* additional_detail= */ (char *) 0,
+                                      "all-trust-anchors-unusable");
+               }
+#endif
                msg_warn("%s: all trust anchors unusable", TLScontext->namaddr);
                break;
            }
@@ -1194,6 +1235,7 @@ TLS_SESS_STATE *tls_client_start(const TLS_CLIENT_START_PROPS *props)
      */
     if (SSL_set_fd(TLScontext->con, props->stream == 0 ? props->fd :
                   vstream_fileno(props->stream)) != 1) {
+       /* TLSRPT: Local resource error, don't report. */
        msg_info("SSL_set_fd error to %s", props->namaddr);
        tls_print_errors();
        uncache_session(app_ctx->ssl_ctx, TLScontext);
@@ -1213,6 +1255,16 @@ TLS_SESS_STATE *tls_client_start(const TLS_CLIENT_START_PROPS *props)
     if (log_mask & TLS_LOG_TLSPKTS)
        tls_set_bio_callback(SSL_get_rbio(TLScontext->con), tls_bio_dump_cb);
 
+    /*
+     * An external (STS) policy signaled a failure. Prevent false (PKI)
+     * certificate matches in tls_verify.c. TODO(wietse) how was this handled
+     * historically?
+     */
+    if (props->fail_type) {
+       TLScontext->fail_type = mystrdup(props->fail_type);
+       TLScontext->must_fail = 1;
+    }
+
     /*
      * If we don't trigger the handshake in the library, leave control over
      * SSL_connect/read/write/etc with the application.
@@ -1245,6 +1297,12 @@ TLS_SESS_STATE *tls_client_start(const TLS_CLIENT_START_PROPS *props)
            msg_info("SSL_connect error to %s: lost connection",
                     props->namaddr);
        }
+#ifdef USE_TLSRPT
+       if (props->tlsrpt)
+           trw_report_failure(props->tlsrpt, TLSRPT_VALIDATION_FAILURE,
+                               /* additional_detail= */ (char *) 0,
+                              "tls-handshake-failure");
+#endif
        uncache_session(app_ctx->ssl_ctx, TLScontext);
        tls_free_context(TLScontext);
        return (0);
@@ -1360,6 +1418,16 @@ TLS_SESS_STATE *tls_client_post_connect(TLS_SESS_STATE *TLScontext,
 
     tls_int_seed();
 
+    /*
+     * Inform the caller that we already reported a TLSRPT failure, so that
+     * the caller won't report success after a TLS level was degraded, or
+     * report some less informative failure reason after a more specific
+     * reason was already reported.
+     */
+#ifdef USE_TLSRPT
+    TLScontext->rpt_reported = trw_is_reported(props->tlsrpt);
+#endif
+
     return (TLScontext);
 }
 
index ac7f05f94ba53241d9b4a3f06ed7e02f551aeef9..f8c43870aea3900c55db7b084becb6830a3a2b02 100644 (file)
@@ -593,6 +593,7 @@ static void *dane_lookup(const char *tlsa_fqdn, void *unused_ctx)
            if (n == 0)
                dane->flags |= TLS_DANE_FLAG_EMPTY;
        } else
+           /* TODO(wietse) report non-parsable TLSA records in TLSRPT. */
            dane->flags |= TLS_DANE_FLAG_NORRS;
 
        if (rrs)
index f77d778acd52528bce30c4f3865276d1cf2f91c6..3d31cbbe43d36bdf0372f54b2d9b7c962fc36541 100644 (file)
@@ -1346,6 +1346,8 @@ TLS_SESS_STATE *tls_alloc_sess_context(int log_mask, const char *namaddr)
     TLScontext->errordepth = -1;
     TLScontext->errorcode = X509_V_OK;
     TLScontext->errorcert = 0;
+    TLScontext->rpt_reported = 0;
+    TLScontext->fail_type = 0;
 
     return (TLScontext);
 }
@@ -1396,6 +1398,8 @@ void    tls_free_context(TLS_SESS_STATE *TLScontext)
        myfree((void *) TLScontext->srvr_sig_dgst);
     if (TLScontext->errorcert)
        X509_free(TLScontext->errorcert);
+    if (TLScontext->fail_type)
+       myfree(TLScontext->fail_type);
 
     myfree((void *) TLScontext);
 }
index 65286398f2d526166e3d25ba364d68c2bb99e216..8e0c67088f838ca3f11d5f0438a7951357859e28 100644 (file)
@@ -108,11 +108,12 @@ extern VSTREAM *tls_proxy_open(const char *, int, VSTREAM *, const char *,
     ((props)->a12), ((props)->a13), ((props)->a14))
 
 #define TLS_PROXY_CLIENT_START_PROPS(props, a1, a2, a3, a4, a5, a6, a7, a8, \
-    a9, a10, a11, a12, a13, a14, a15) \
+    a9, a10, a11, a12, a13, a14, a15, a16, a17) \
     (((props)->a1), ((props)->a2), ((props)->a3), \
     ((props)->a4), ((props)->a5), ((props)->a6), ((props)->a7), \
     ((props)->a8), ((props)->a9), ((props)->a10), ((props)->a11), \
-    ((props)->a12), ((props)->a13), ((props)->a14), ((props)->a15))
+    ((props)->a12), ((props)->a13), ((props)->a14), ((props)->a15), \
+    ((props)->a16), ((props)->a17))
 
 extern TLS_SESS_STATE *tls_proxy_context_receive(VSTREAM *);
 extern void tls_proxy_context_free(TLS_SESS_STATE *);
@@ -181,6 +182,7 @@ extern void tls_proxy_server_start_free(TLS_SERVER_START_PROPS *);
 #define TLS_ATTR_SRVR_SIG_BITS "srvr_signature_bits"
 #define TLS_ATTR_SRVR_SIG_DGST "srvr_signature_digest"
 #define TLS_ATTR_NAMADDR       "namaddr"
+#define TLS_ATTR_RPT_REPORTED  "rpt_reported"
 
  /*
   * TLS_SERVER_INIT_PROPS attributes.
@@ -254,7 +256,9 @@ extern void tls_proxy_server_start_free(TLS_SERVER_START_PROPS *);
 #define TLS_ATTR_CIPHER_EXCLUSIONS "cipher_exclusions"
 #define TLS_ATTR_MATCHARGV     "matchargv"
 #define TLS_ATTR_MDALG         "mdalg"
-#define        TLS_ATTR_DANE           "dane"
+#define TLS_ATTR_DANE          "dane"
+#define TLS_ATTR_TLSRPT                "tlsrpt"
+#define FAIL_TYPE      "fail_type"
 
  /*
   * TLS_TLSA attributes.
index 81e50b9246fff80a6952e7646c5119b9f36e603d..b2502ff4345624771bd3f1f9a0fd92493718fe15 100644 (file)
 #include <tls.h>
 #include <tls_proxy.h>
 
+#ifdef USE_TLSRPT
+#define TLSRPT_WRAPPER_INTERNAL
+#include <tlsrpt_wrapper.h>
+#endif
 
 #define STR(x) vstring_str(x)
 #define LEN(x) VSTRING_LEN(x)
@@ -96,7 +100,7 @@ int     tls_proxy_client_param_print(ATTR_PRINT_COMMON_FN print_fn, VSTREAM *fp,
 
     ret = print_fn(fp, flags | ATTR_FLAG_MORE,
                   SEND_ATTR_STR(TLS_ATTR_CNF_FILE, params->tls_cnf_file),
-                  SEND_ATTR_STR(TLS_ATTR_CNF_NAME,  params->tls_cnf_name),
+                  SEND_ATTR_STR(TLS_ATTR_CNF_NAME, params->tls_cnf_name),
                   SEND_ATTR_STR(VAR_TLS_HIGH_CLIST, params->tls_high_clist),
                   SEND_ATTR_STR(VAR_TLS_MEDIUM_CLIST,
                                 params->tls_medium_clist),
@@ -242,6 +246,59 @@ static int tls_proxy_client_dane_print(ATTR_PRINT_COMMON_FN print_fn,
     return (ret);
 }
 
+#ifdef USE_TLSRPT
+
+/* tls_proxy_client_tlsrpt_print - send TLSRPT_WRAPPER over stream */
+
+static int tls_proxy_client_tlsrpt_print(ATTR_PRINT_COMMON_FN print_fn,
+                                   VSTREAM *fp, int flags, const void *ptr)
+{
+    const TLSRPT_WRAPPER *trw = (const TLSRPT_WRAPPER *) ptr;
+    int     have_trw = trw != 0;
+    int     ret;
+
+    ret = print_fn(fp, flags | ATTR_FLAG_MORE,
+                  SEND_ATTR_INT(TLS_ATTR_TLSRPT, have_trw),
+                  ATTR_TYPE_END);
+    if (msg_verbose)
+       msg_info("tls_proxy_client_tlsrpt_print have_trw=%d", have_trw);
+
+    if (ret == 0 && have_trw) {
+       ret = print_fn(fp, flags | ATTR_FLAG_MORE,
+                      SEND_ATTR_STR(TRW_RPT_SOCKET_NAME,
+                                    STRING_OR_EMPTY(trw->rpt_socket_name)),
+                      SEND_ATTR_STR(TRW_RPT_POLICY_DOMAIN,
+                                  STRING_OR_EMPTY(trw->rpt_policy_domain)),
+                      SEND_ATTR_STR(TRW_RPT_POLICY_STRING,
+                                  STRING_OR_EMPTY(trw->rpt_policy_string)),
+                      SEND_ATTR_INT(TRW_TLS_POLICY_TYPE,
+                                    (int) trw->tls_policy_type),
+                      SEND_ATTR_FUNC(argv_attr_print,
+                                   (const void *) trw->tls_policy_strings),
+                      SEND_ATTR_STR(TRW_TLS_POLICY_DOMAIN,
+                                  STRING_OR_EMPTY(trw->tls_policy_domain)),
+                      SEND_ATTR_FUNC(argv_attr_print,
+                                     (const void *) trw->mx_host_patterns),
+                      SEND_ATTR_STR(TRW_SRC_MTA_ADDR,
+                                    STRING_OR_EMPTY(trw->snd_mta_addr)),
+                      SEND_ATTR_STR(TRW_DST_MTA_NAME,
+                                    STRING_OR_EMPTY(trw->rcv_mta_name)),
+                      SEND_ATTR_STR(TRW_DST_MTA_ADDR,
+                                    STRING_OR_EMPTY(trw->rcv_mta_addr)),
+                      SEND_ATTR_STR(TRW_DST_MTA_EHLO,
+                                    STRING_OR_EMPTY(trw->rcv_mta_ehlo)),
+                      SEND_ATTR_INT(TRW_FLAGS,
+                                    trw->flags),
+                      ATTR_TYPE_END);
+    }
+    /* Do not flush the stream. */
+    if (msg_verbose)
+       msg_info("tls_proxy_client_tlsrpt_print ret=%d", ret);
+    return (ret);
+}
+
+#endif
+
 /* tls_proxy_client_start_print - send TLS_CLIENT_START_PROPS over stream */
 
 int     tls_proxy_client_start_print(ATTR_PRINT_COMMON_FN print_fn,
@@ -283,6 +340,12 @@ int     tls_proxy_client_start_print(ATTR_PRINT_COMMON_FN print_fn,
                                 STRING_OR_EMPTY(props->mdalg)),
                   SEND_ATTR_FUNC(tls_proxy_client_dane_print,
                                  (const void *) props->dane),
+#ifdef USE_TLSRPT
+                  SEND_ATTR_FUNC(tls_proxy_client_tlsrpt_print,
+                                 (const void *) props->tlsrpt),
+#endif
+                  SEND_ATTR_STR(FAIL_TYPE,
+                                 STRING_OR_EMPTY(props->fail_type)),
                   ATTR_TYPE_END);
     /* Do not flush the stream. */
     if (msg_verbose)
index d36cf4d7e593a6314f6e12ae9f53d746ac87b971..210704021eb97d32bfd46e059aec7e4b65f63995 100644 (file)
 #define TLS_INTERNAL
 #include <tls.h>
 #include <tls_proxy.h>
+#ifdef USE_TLSRPT
+#define TLSRPT_WRAPPER_INTERNAL
+#include <tlsrpt_wrapper.h>
+#endif
 
 #define STR(x) vstring_str(x)
 #define LEN(x) VSTRING_LEN(x)
@@ -329,6 +333,12 @@ void    tls_proxy_client_start_free(TLS_CLIENT_START_PROPS *props)
     myfree((void *) props->mdalg);
     if (props->dane)
        tls_dane_free((TLS_DANE *) props->dane);
+#ifdef USE_TLSRPT
+    if (props->tlsrpt)
+       trw_free(props->tlsrpt);
+#endif
+    if (props->fail_type)
+       myfree(props->fail_type);
     myfree((void *) props);
 }
 
@@ -419,6 +429,87 @@ static int tls_proxy_client_dane_scan(ATTR_SCAN_COMMON_FN scan_fn,
     return (ret);
 }
 
+#define EXPORT_OR_NULL(str, vstr) do { \
+       if (LEN(vstr) > 0) { \
+           (str) = vstring_export(vstr); \
+       } else { \
+           (str) = 0; \
+           vstring_free(vstr); \
+       } \
+    } while (0)
+
+#ifdef USE_TLSRPT
+
+/* tls_proxy_client_tlsrpt_scan - receive TLSRPT_WRAPPER from stream */
+
+static int tls_proxy_client_tlsrpt_scan(ATTR_SCAN_COMMON_FN scan_fn,
+                                         VSTREAM *fp, int flags, void *ptr)
+{
+    TLSRPT_WRAPPER *trw = 0;
+    int     ret;
+    int     have_tlsrpt = 0;
+
+    ret = scan_fn(fp, flags | ATTR_FLAG_MORE,
+                 RECV_ATTR_INT(TLS_ATTR_DANE, &have_tlsrpt),
+                 ATTR_TYPE_END);
+    if (msg_verbose)
+       msg_info("tls_proxy_client_tlsrpt_scan have_tlsrpt=%d", have_tlsrpt);
+
+    if (ret == 1 && have_tlsrpt) {
+       VSTRING *rpt_socket_name = vstring_alloc(100);
+       VSTRING *rpt_policy_domain = vstring_alloc(100);
+       VSTRING *rpt_policy_string = vstring_alloc(100);
+       int     tls_policy_type;
+       ARGV   *tls_policy_strings = argv_alloc(100);
+       VSTRING *tls_policy_domain = vstring_alloc(100);
+       ARGV   *mx_host_patterns = argv_alloc(100);
+       VSTRING *snd_mta_addr = vstring_alloc(100);
+       VSTRING *rcv_mta_name = vstring_alloc(100);
+       VSTRING *rcv_mta_addr = vstring_alloc(100);
+       VSTRING *rcv_mta_ehlo = vstring_alloc(100);
+
+       ret = scan_fn(fp, flags | ATTR_FLAG_MORE,
+                     RECV_ATTR_STR(TRW_RPT_SOCKET_NAME, rpt_socket_name),
+                   RECV_ATTR_STR(TRW_RPT_POLICY_DOMAIN, rpt_policy_domain),
+                   RECV_ATTR_STR(TRW_RPT_POLICY_STRING, rpt_policy_string),
+                     RECV_ATTR_INT(TRW_TLS_POLICY_TYPE, &tls_policy_type),
+                     RECV_ATTR_FUNC(argv_attr_scan, tls_policy_strings),
+                   RECV_ATTR_STR(TRW_TLS_POLICY_DOMAIN, tls_policy_domain),
+                     RECV_ATTR_FUNC(argv_attr_scan, mx_host_patterns),
+                     RECV_ATTR_STR(TRW_SRC_MTA_ADDR, snd_mta_addr),
+                     RECV_ATTR_STR(TRW_DST_MTA_NAME, rcv_mta_name),
+                     RECV_ATTR_STR(TRW_DST_MTA_ADDR, rcv_mta_addr),
+                     RECV_ATTR_STR(TRW_DST_MTA_EHLO, rcv_mta_ehlo),
+                     RECV_ATTR_INT(TRW_FLAGS, &trw->flags),
+                     ATTR_TYPE_END);
+
+       /* Always construct a well-formed structure. */
+       trw = (TLSRPT_WRAPPER *) mymalloc(sizeof(*trw));
+       trw->rpt_socket_name = vstring_export(rpt_socket_name);
+       trw->rpt_policy_domain = vstring_export(rpt_policy_domain);
+       trw->rpt_policy_string = vstring_export(rpt_policy_string);
+       trw->tls_policy_type = tls_policy_type;
+       trw->tls_policy_strings = tls_policy_strings;
+       EXPORT_OR_NULL(trw->tls_policy_domain, tls_policy_domain);
+       trw->mx_host_patterns = mx_host_patterns;
+       EXPORT_OR_NULL(trw->snd_mta_addr, snd_mta_addr);
+       EXPORT_OR_NULL(trw->rcv_mta_name, rcv_mta_name);
+       EXPORT_OR_NULL(trw->rcv_mta_addr, rcv_mta_addr);
+       EXPORT_OR_NULL(trw->rcv_mta_ehlo, rcv_mta_ehlo);
+       ret = (ret == 12 ? 1 : -1);
+       if (ret != 1) {
+           trw_free(trw);
+           trw = 0;
+       }
+    }
+    *(TLSRPT_WRAPPER **) ptr = trw;
+    if (msg_verbose)
+       msg_info("tls_proxy_client_tlsrpt_scan ret=%d", ret);
+    return (ret);
+}
+
+#endif
+
 /* tls_proxy_client_start_scan - receive TLS_CLIENT_START_PROPS from stream */
 
 int     tls_proxy_client_start_scan(ATTR_SCAN_COMMON_FN scan_fn, VSTREAM *fp,
@@ -437,6 +528,13 @@ int     tls_proxy_client_start_scan(ATTR_SCAN_COMMON_FN scan_fn, VSTREAM *fp,
     VSTRING *cipher_grade = vstring_alloc(25);
     VSTRING *cipher_exclusions = vstring_alloc(25);
     VSTRING *mdalg = vstring_alloc(25);
+    VSTRING *fail_type = vstring_alloc(25);
+
+#ifdef USE_TLSRPT
+#define EXPECT_START_SCAN_RETURN       17
+#else
+#define EXPECT_START_SCAN_RETURN       16
+#endif
 
     if (msg_verbose)
        msg_info("begin tls_proxy_client_start_scan");
@@ -467,6 +565,11 @@ int     tls_proxy_client_start_scan(ATTR_SCAN_COMMON_FN scan_fn, VSTREAM *fp,
                  RECV_ATTR_STR(TLS_ATTR_MDALG, mdalg),
                  RECV_ATTR_FUNC(tls_proxy_client_dane_scan,
                                 &props->dane),
+#ifdef USE_TLSRPT
+                 RECV_ATTR_FUNC(tls_proxy_client_tlsrpt_scan,
+                                &props->tlsrpt),
+#endif
+                 RECV_ATTR_STR(FAIL_TYPE, fail_type),
                  ATTR_TYPE_END);
     /* Always construct a well-formed structure. */
     props->nexthop = vstring_export(nexthop);
@@ -479,7 +582,8 @@ int     tls_proxy_client_start_scan(ATTR_SCAN_COMMON_FN scan_fn, VSTREAM *fp,
     props->cipher_grade = vstring_export(cipher_grade);
     props->cipher_exclusions = vstring_export(cipher_exclusions);
     props->mdalg = vstring_export(mdalg);
-    ret = (ret == 15 ? 1 : -1);
+    EXPORT_OR_NULL(props->fail_type, fail_type);
+    ret = (ret == EXPECT_START_SCAN_RETURN ? 1 : -1);
     if (ret != 1) {
        tls_proxy_client_start_free(props);
        props = 0;
index 930410a4661c5cda5db5fba9be4095ce65e81c13..808abbe73ecd64643d8f47e02a6e6220824f9c32 100644 (file)
@@ -110,6 +110,8 @@ int     tls_proxy_context_print(ATTR_PRINT_COMMON_FN print_fn, VSTREAM *fp,
                                 STRING_OR_EMPTY(tp->srvr_sig_dgst)),
                   SEND_ATTR_STR(TLS_ATTR_NAMADDR,
                                 STRING_OR_EMPTY(tp->namaddr)),
+                  SEND_ATTR_INT(TLS_ATTR_RPT_REPORTED,
+                                tp->rpt_reported),
                   ATTR_TYPE_END);
     /* Do not flush the stream. */
     return (ret);
index 48aaff627460759975e4a8ce5891794823bb51a7..fc23c528a8e4a3e9796574b59ff4885cad2da23b 100644 (file)
@@ -124,6 +124,8 @@ int     tls_proxy_context_scan(ATTR_SCAN_COMMON_FN scan_fn, VSTREAM *fp,
         RECV_ATTR_INT(TLS_ATTR_SRVR_SIG_BITS, &tls_context->srvr_sig_bits),
                  RECV_ATTR_STR(TLS_ATTR_SRVR_SIG_DGST, srvr_sig_dgst),
                  RECV_ATTR_STR(TLS_ATTR_NAMADDR, namaddr),
+                 RECV_ATTR_INT(TLS_ATTR_RPT_REPORTED,
+                               &tls_context->rpt_reported),
                  ATTR_TYPE_END);
     /* Always construct a well-formed structure. */
     tls_context->peer_CN = vstring_export(peer_CN);
@@ -141,7 +143,7 @@ int     tls_proxy_context_scan(ATTR_SCAN_COMMON_FN scan_fn, VSTREAM *fp,
     tls_context->srvr_sig_curve = vstring_export(srvr_sig_curve);
     tls_context->srvr_sig_dgst = vstring_export(srvr_sig_dgst);
     tls_context->namaddr = vstring_export(namaddr);
-    ret = (ret == 24 ? 1 : -1);
+    ret = (ret == 25 ? 1 : -1);
     if (ret != 1) {
        tls_proxy_context_free(tls_context);
        tls_context = 0;
index 88b33264208122b727b9979682aad1e2e898de7f..87433e935fff46f21eb9f03016d4c9d57008dcff 100644 (file)
@@ -1035,7 +1035,7 @@ TLS_SESS_STATE *tls_server_post_accept(TLS_SESS_STATE *TLScontext)
        if (!TLS_CERT_IS_TRUSTED(TLScontext)
            && (TLScontext->log_mask & TLS_LOG_UNTRUSTED)) {
            if (TLScontext->session_reused == 0)
-               tls_log_verify_error(TLScontext);
+               tls_log_verify_error(TLScontext, (struct TLSRPT_WRAPPER *) 0);
            else
                msg_info("%s: re-using session with untrusted certificate, "
                         "look for details earlier in the log",
index c643f18382ba2407a066ccf9b28fc1b3ba997e84..a719c2ca9ff92e6b458bd5da62bfaf53a3286648 100644 (file)
@@ -11,8 +11,9 @@
 /*     int     ok;
 /*     X509_STORE_CTX *ctx;
 /*
-/*     int     tls_log_verify_error(TLScontext)
+/*     int     tls_log_verify_error(TLScontext, tlsrpt)
 /*     TLS_SESS_STATE *TLScontext;
+/*     struct TLSRPT_WRAPPER *tlsrpt;
 /*
 /*     char *tls_peer_CN(peercert, TLScontext)
 /*     X509   *peercert;
 
 /* TLS library. */
 
+#ifdef USE_TLSRPT
+#include <tlsrpt_wrapper.h>
+#endif
+
 #define TLS_INTERNAL
 #include <tls.h>
 
@@ -194,18 +199,50 @@ int     tls_verify_certificate_callback(int ok, X509_STORE_CTX *ctx)
 
 /* tls_log_verify_error - Report final verification error status */
 
-void    tls_log_verify_error(TLS_SESS_STATE *TLScontext)
+void    tls_log_verify_error(TLS_SESS_STATE *TLScontext,
+                                    struct TLSRPT_WRAPPER *tlsrpt)
 {
     char    buf[CCERT_BUFSIZ];
     int     err = TLScontext->errorcode;
     X509   *cert = TLScontext->errorcert;
     int     depth = TLScontext->errordepth;
 
+#ifdef USE_TLSRPT
+    VSTRING *err_vstr = vstring_alloc(100);
+
+#define CERT_ERROR_TO_STRING(err) \
+    translit(vstring_str(vstring_strcpy(err_vstr, \
+                                       X509_verify_cert_error_string(err))), \
+            " ", "_")
+#endif
+
 #define PURPOSE ((depth>0) ? "CA": TLScontext->am_server ? "client": "server")
 
     if (err == X509_V_OK)
        return;
 
+    /*
+     * If an external policy flagged an error, report that instead.
+     */
+    if (TLScontext->fail_type) {
+       msg_info("certificate verification failed for %s: "
+               "external policy failure (%s)",
+                TLScontext->namaddr, TLScontext->fail_type);
+#ifdef USE_TLSRPT
+       if (tlsrpt) {
+           tlsrpt_failure_t failure_type;
+
+           if ((failure_type = convert_tlsrpt_policy_failure(TLScontext->fail_type)) < 0)
+               msg_panic("tls_log_verify_error: unexpected failure_reason: %s",
+                         TLScontext->fail_type);
+           trw_report_failure(tlsrpt, failure_type,
+                               /* additional_detail= */ (char *) 0,
+                               /* failure_reason= */ (char *) 0);
+       }
+#endif
+       return;
+    }
+
     /*
      * Specific causes for verification failure.
      */
@@ -218,10 +255,22 @@ void    tls_log_verify_error(TLS_SESS_STATE *TLScontext)
         */
        msg_info("certificate verification failed for %s: "
                 "not trusted by local or TLSA policy", TLScontext->namaddr);
+#ifdef USE_TLSRPT
+       if (tlsrpt)
+           trw_report_failure(tlsrpt, TLSRPT_CERTIFICATE_NOT_TRUSTED,
+                               /* additional_detail= */ (char *) 0,
+                               /* failure_code= */ (char *) 0);
+#endif
        break;
     case X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT:
        msg_info("certificate verification failed for %s: "
                 "self-signed certificate", TLScontext->namaddr);
+#ifdef USE_TLSRPT
+       if (tlsrpt)
+           trw_report_failure(tlsrpt, TLSRPT_VALIDATION_FAILURE,
+                               /* additional_detail= */ (char *) 0,
+                              CERT_ERROR_TO_STRING(err));
+#endif
        break;
     case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY:
     case X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN:
@@ -237,25 +286,55 @@ void    tls_log_verify_error(TLS_SESS_STATE *TLScontext)
            strcpy(buf, "<unknown>");
        msg_info("certificate verification failed for %s: untrusted issuer %s",
                 TLScontext->namaddr, printable(buf, '?'));
+#ifdef USE_TLSRPT
+       if (tlsrpt)
+           trw_report_failure(tlsrpt, TLSRPT_VALIDATION_FAILURE,
+                               /* additional_detail= */ (char *) 0,
+                              CERT_ERROR_TO_STRING(err));
+#endif
        break;
     case X509_V_ERR_CERT_NOT_YET_VALID:
     case X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD:
        msg_info("%s certificate verification failed for %s: certificate not"
                 " yet valid", PURPOSE, TLScontext->namaddr);
+#ifdef USE_TLSRPT
+       if (tlsrpt)
+           trw_report_failure(tlsrpt, TLSRPT_VALIDATION_FAILURE,
+                               /* additional_detail= */ (char *) 0,
+                              CERT_ERROR_TO_STRING(err));
+#endif
        break;
     case X509_V_ERR_CERT_HAS_EXPIRED:
     case X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD:
        msg_info("%s certificate verification failed for %s: certificate has"
                 " expired", PURPOSE, TLScontext->namaddr);
+#ifdef USE_TLSRPT
+       if (tlsrpt)
+           trw_report_failure(tlsrpt, TLSRPT_CERTIFICATE_EXPIRED,
+                               /* additional_detail= */ (char *) 0,
+                               /* failure_code= */ (char *) 8);
+#endif
        break;
     case X509_V_ERR_INVALID_PURPOSE:
        msg_info("certificate verification failed for %s: not designated for "
                 "use as a %s certificate", TLScontext->namaddr, PURPOSE);
+#ifdef USE_TLSRPT
+       if (tlsrpt)
+           trw_report_failure(tlsrpt, TLSRPT_VALIDATION_FAILURE,
+                               /* additional_detail= */ (char *) 0,
+                              CERT_ERROR_TO_STRING(err));
+#endif
        break;
     case X509_V_ERR_CERT_CHAIN_TOO_LONG:
        msg_info("certificate verification failed for %s: "
                 "certificate chain longer than limit(%d)",
                 TLScontext->namaddr, depth - 1);
+#ifdef USE_TLSRPT
+       if (tlsrpt)
+           trw_report_failure(tlsrpt, TLSRPT_VALIDATION_FAILURE,
+                               /* additional_detail= */ (char *) 0,
+                              CERT_ERROR_TO_STRING(err));
+#endif
        break;
     default:
        msg_info("%s certificate verification failed for %s: num=%d:%s",
@@ -263,6 +342,9 @@ void    tls_log_verify_error(TLS_SESS_STATE *TLScontext)
                 X509_verify_cert_error_string(err));
        break;
     }
+#ifdef USE_TLSRPT
+    vstring_free(err_vstr);
+#endif
 }
 
 #ifndef DONT_GRIPE
diff --git a/postfix/src/tls/tlsrpt_wrapper.c b/postfix/src/tls/tlsrpt_wrapper.c
new file mode 100644 (file)
index 0000000..4005d8e
--- /dev/null
@@ -0,0 +1,647 @@
+/*++
+/* NAME
+/*     tlsrpt_wrapper 3
+/* SUMMARY
+/*     TLSRPT support for the TLS protocol engine
+/* SYNOPSIS
+/*     #include <tlsrpt_wrapper.h>
+/*
+/*     #ifdef USE_TLS
+/*     #ifdef USE_TLSRPT
+/*     TLS_RPT *trw_create(
+/*     const char *rpt_socket_name,
+/*     const char *rpt_policy_domain,
+/*     const char *rpt_policy_string)
+/*
+/*     void    trw_free(
+/*     TLSRPT_WRAPPER *trw)
+/*
+/*     void    trw_set_tls_policy(
+/*     TLSRPT_WRAPPER *trw,
+/*     tlsrpt_policy_type_t tls_policy_type,
+/*     const char *const *tls_policy_strings,
+/*     const char *tls_policy_domain
+/*     const char *const *mx_host_patterns)
+/*
+/*     void    trw_set_tcp_connection(
+/*     TLSRPT_WRAPPER *trw,
+/*     const char *snd_mta_addr,
+/*     const char *rcv_mta_name,
+/*     const char *rcv_mta_addr)
+/*
+/*     void    trw_set_ehlo_resp(
+/*     TLSRPT_WRAPPER *trw,
+/*     const char *rcv_mta_ehlo)
+/*
+/*     void    trw_report_failure(
+/*     TLSRPT_WRAPPER *trw,
+/*     tlsrpt_failure_t failure_type,
+/*     const char *additional_detail,
+/*     const char *failure_reason)
+/*
+/*     void    trw_report_success(
+/*     TLSRPT_WRAPPER *trw)
+/*
+/*     int     trw_is_reported(
+/*     TLSRPT_WRAPPER *trw)
+/*
+/*     tlsrpt_policy_type_t convert_tlsrpt_policy_type(
+/*     const char *policy_type)
+/*
+/*     tlsrpt_failure_t convert_tlsrpt_policy_failure(
+/*     const char *policy_failure)
+/*     #endif /* USE_TLS_RPT */
+/*
+/*     int     valid_tlsrpt_policy_type(
+/*     const char *type_name)
+/*
+/*     int     valid_tlsrpt_policy_failure(
+/*     const char *failure_name)
+/*     #endif /* USE_TLS */
+/* ARCHITECTURE, BOTTOM-UP VIEW
+/*     Postfix TLSRPT support uses the TLSRPT client library from
+/*     sys4.de. That library makes the reasonable assumption that
+/*     all calls concerning one SMTP session will be made from within
+/*     one process.
+/*
+/*     With Postfix, the TLS protocol engine may be located in a
+/*     different process than the SMTP protocol engine, and both
+/*     processes need the ability to report a TLS error.
+/*
+/*     To bridge this gap, the SMTP protocol engine forwards SMTP
+/*     session and TLS policy information to the TLS protocol engine in
+/*     the form of a TLSRPT_WRAPPER object that contains SMTP and other
+/*     information that the TLSRPT client library needs.  The TLS engine
+/*     can pass that information to the TLSRPT client library to report
+/*     a TLS error. The SMTP protocol engine can use that same
+/*     information to report a TLS error or success.
+/* IMPLEMENTATION
+/* .ad
+/* .fi
+/*     The Postfix SMTP protocol engine (smtp_proto.c) reports TLS
+/*     errors when TLS support is required but unavailable, or requests
+/*     the Postfix TLS protocol engine to perform a TLS protocol
+/*     handshake over an open SMTP connection. The SMTP protocol engine
+/*     either calls the TLS protocol engine directly, or calls it over
+/*     RPC in a tlsproxy(8) process.
+/*
+/*     The TLS protocol engine may report a TLS error through the
+/*     tlsrpt_wrapper library, and either returns no TLS session object,
+/*     or a TLS session object for a completed handshake. The TLS
+/*     session object will indicate if the TLS protocol engine reported
+/*     any TLS error through TLSRPT.
+/*
+/*     The Postfix SMTP protocol engine reports success or failure
+/*     through the tlsrpt_wrapper library, depending on whether all
+/*     matching requirements were satisfied. SMTP protocol engine
+/*     does not report success or failure through the tlsrpt_wrapper
+/*     library if the TLS protocol engine already reported a failure.
+/* WRAPPER API
+/* .ad
+/* .fi
+/*     The functions below must be called in a specific order. All
+/*     string inputs are copied. If a required call is missing then
+/*     the request will be ignored, and a warning will be logged.
+/* .PP
+/*     trw_create() must be called before other trw_xxx() requests can
+/*     be made. Arguments:
+/* .IP rpt_socket_name
+/*     The name of a socket that will be managed by local TLSRPT
+/*     infrastructure.
+/* .IP rpt_policy_domain
+/*     The TLSRPT policy domain name, i.e. the domain that wishes to
+/*     receive TLSRPT summary reports. An internationalized domain name
+/*     must be in A-label form (i.e. punycode).
+/* .IP rpt_policy_string
+/*     The TLSRPT policy record content, i.e. how to submit TLSRPT
+/*     summary reports.
+/* .PP
+/*     trw_free() destroys storage allocated with other trw_xxx()
+/*     requests.
+/* .PP
+/*     trw_set_tls_policy() must be called by the SMTP protocol
+/*     engine after it found a DANE, STS, or no policy, and before it
+/*     tries to establish a new SMTP connection. This function clears
+/*     information that was specified earlier with trw_set_tls_policy()
+/*     or trw_set_tcp_connection(), and whether trw_report_failure()
+/*     or trw_report_success() were called. Mapping from arguments to
+/*     TLSRPT report fields:
+/* .IP tls_policy_type
+/*     policies[].policy.policy-type.
+/* .IP tls_policy_strings
+/*     policies[].policy.policy-string[]. Ignored if the tls_policy_type
+/*     value is TLSRPT_NO_POLICY_FOUND.
+/* .IP tls_policy_domain
+/*     policies[].policy.policy-domain.
+/* .IP mx_host_patterns (may be null)
+/*     policies[].policy.mx-host[]. Ignored if the tls_policy_type
+/*     value is TLSRPT_NO_POLICY_FOUND.
+/* .PP
+/*     trw_set_tcp_connection() and trw_set_ehlo_resp() are optionally
+/*     called by the SMTP protcol engine, after it has established
+/*     a new SMTP connection, before it requests a TLS protocol
+/*     handshake. Mapping from arguments to TLSRPT report fields:
+/* .IP snd_mta_addr (may be null)
+/*     policies[].failure-details[].sending-mta-ip.
+/* .IP rcv_mta_name (may be null)
+/*     policies[].failure-details[].receiving-mx-hostname.
+/* .IP rcv_mta_addr (may be null)
+/*     policies[].failure-details[].receiving-ip.
+/* .PP
+/*     trw_set_ehlo_resp() is optionally called by the SMTP protcol
+/*     engine to pass on the EHLO response. Presumably this is the EHLO
+/*     response before STARTTLS (TLSRPT is primarily interested in
+/*     pre-handshake and handshake errors).
+/* .IP rcv_mta_ehlo (may be null)
+/*     policies[].failure-details[].receiving-mx-helo.
+/* .PP
+/*     trw_report_failure() is called by the TLS protocol engine or
+/*     SMTP protocol engine to report a TLS error. The result value
+/*     is 0 for success, -1 for failure as indicated with the errno
+/*     value. The call is successfully skipped if information is missing
+/*     or if failure or success were already reported for the
+/*     connection. Mapping from arguments to TLSRPT report fields:
+/* .IP failure_type
+/*     policies[].failure-details[].result-type.
+/* .IP additional_detail (may be null)
+/*     policies[].failure-details[].additional-information.
+/* .IP failure_reason (may be null)
+/*     policies[].failure-details[].failure-reason-code
+/* .PP
+/*     trw_report_success() is called by the SMTP protocol engine
+/*     to report a successful TLS handshake. The result value is
+/*     0 for success, -1 for failure with errno indicating the
+/*     error type. The call is successfully skipped if information if
+/*     missing or if failure or success were already reported for
+/*     the connection.
+/* .PP
+/*     trw_is_reported() returns non-zero when the contents of the
+/*     specified TLSRPT_WRAPPER have been reported.
+/* .PP
+/*     convert_tlsrpt_policy_type() and convert_tlsrpt_policy_failure()
+/*     convert a valid policy type or failure name to the corresponding
+/*     enum value. The result is < 0 if the name is not valid.
+/* .PP
+/*     valid_tlsrpt_policy_type() and valid_tlsrpt_policy_failure()
+/*     return non-zero if the specified policy type or failure name
+/*     is valid in TLSRPT. These functions do not require that the
+/*     module is built with TLSRPT support. This allows the names to
+/*     be used even if TLSRPT is disabled.
+/* DIAGNOSTICS
+/*     Some functions will log a a warning when information is missing,
+/*     but such warnings will not affect the SMTP or TLS protocol engine.
+/* BUGS
+/*     This implementation is suitable to report successful TLS policy
+/*     compliance, and to report a failure that prevents TLS policy
+/*     compliance (example: all TLSA records are unusable). Do not use
+/*     this implementation to report other errors (example: some TLSA
+/*     record is non-parsable).
+/* SEE ALSO
+/*     https://github.com/sys4/tlsrpt, TLSRPT client library
+/* LICENSE
+/* .ad
+/* .fi
+/*     The Secure Mailer license must be distributed with this software.
+/* AUTHOR(S)
+/*     Wietse Venema
+/*     porcupine.org
+/*--*/
+
+#if defined(USE_TLS)
+
+ /*
+  * System library.
+  */
+#include <sys_defs.h>
+#include <errno.h>
+#include <string.h>
+#if defined(USE_TLSRPT)
+#include <tlsrpt.h>
+#endif
+
+ /*
+  * Utility library.
+  */
+#include <argv.h>
+#include <msg.h>
+#include <mymalloc.h>
+#include <name_code.h>
+#include <stringops.h>
+
+ /*
+  * Some functions are not #ifdef USE_TLSRPT.
+  */
+#define TLSRPT_WRAPPER_INTERNAL
+#include <tlsrpt_wrapper.h>
+#if defined(USE_TLSRPT)
+
+ /*
+  * Macros to make repetitive code more readable.
+  */
+#define MYFREE_IF_SET(member) do { \
+       if (member) \
+           myfree(member); \
+    } while (0)
+
+#define MYFREE_IF_SET_AND_CLEAR(member, value) do { \
+       if (member) { \
+           myfree(member); \
+           (member) = 0; \
+       } \
+    } while (0)
+
+#define MYFREE_IF_SET_AND_COPY(member, value) do { \
+       MYFREE_IF_SET(member); \
+       (member) = (value) ? mystrdup(value) : 0; \
+    } while (0)
+
+#define ARGV_FREE_IF_SET(member) do { \
+       if (member) \
+           argv_free(member); \
+    } while (0)
+
+#define ARGV_FREE_IF_SET_AND_CLEAR(member) do { \
+       if (member) { \
+           argv_free(member); \
+           (member) = 0; \
+       } \
+    } while (0)
+
+#define ARGV_FREE_IF_SET_AND_COPY(member, value) do { \
+       ARGV_FREE_IF_SET(member); \
+       (member) = (value) ? argv_addv((ARGV *) 0, value) : 0; \
+    } while (0)
+
+/* trw_create - create initial TLSRPT_WRAPPER instance */
+
+TLSRPT_WRAPPER *trw_create(const char *rpt_socket_name,
+                                  const char *rpt_policy_domain,
+                                  const char *rpt_policy_string)
+{
+    TLSRPT_WRAPPER *trw;
+
+    /*
+     * memset() is not portable for pointer etc. types.
+     */
+    trw = (TLSRPT_WRAPPER *) mymalloc(sizeof(*trw));
+    trw->rpt_socket_name = mystrdup(rpt_socket_name);
+    trw->rpt_policy_domain = mystrdup(rpt_policy_domain);
+    trw->rpt_policy_string = mystrdup(rpt_policy_string);;
+    trw->tls_policy_type = 0;
+    trw->tls_policy_strings = 0;
+    trw->tls_policy_domain = 0;
+    trw->mx_host_patterns = 0;
+    trw->snd_mta_addr = 0;
+    trw->rcv_mta_name = 0;
+    trw->rcv_mta_addr = 0;
+    trw->rcv_mta_ehlo = 0;
+    trw->flags = 0;
+    return (trw);
+}
+
+/* trw_free - destroy TLSRPT_WRAPPER instance. */
+
+void    trw_free(TLSRPT_WRAPPER *trw)
+{
+    /* Destroy fields set with trw_create(). */
+    myfree(trw->rpt_socket_name);
+    myfree(trw->rpt_policy_domain);
+    myfree(trw->rpt_policy_string);
+    /* Destroy fields set with trw_set_tls_policy(). */
+    ARGV_FREE_IF_SET(trw->tls_policy_strings);
+    MYFREE_IF_SET(trw->tls_policy_domain);
+    ARGV_FREE_IF_SET(trw->mx_host_patterns);
+    /* Destroy fields set with trw_set_tcp_connection(). */
+    trw_set_tcp_connection(trw, (char *) 0, (char *) 0, (char *) 0);
+    /* Destroy fields set with trw_set_ehlo_resp(). */
+    trw_set_ehlo_resp(trw, (char *) 0);
+    /* That's all. */
+    myfree((void *) trw);
+}
+
+/* trw_set_tls_policy - set TLS policy info, clear SMTP info */
+
+void    trw_set_tls_policy(TLSRPT_WRAPPER *trw,
+                                  tlsrpt_policy_type_t tls_policy_type,
+                                  const char *const * tls_policy_strings,
+                                  const char *tls_policy_domain,
+                                  const char *const * mx_host_patterns)
+{
+    trw->tls_policy_type = tls_policy_type;
+    MYFREE_IF_SET_AND_COPY(trw->tls_policy_domain, tls_policy_domain);
+    if (tls_policy_type == TLSRPT_NO_POLICY_FOUND) {
+       ARGV_FREE_IF_SET_AND_CLEAR(trw->tls_policy_strings);
+       ARGV_FREE_IF_SET_AND_CLEAR(trw->tls_policy_strings);
+    } else {
+       ARGV_FREE_IF_SET_AND_COPY(trw->tls_policy_strings, tls_policy_strings);
+       ARGV_FREE_IF_SET_AND_COPY(trw->tls_policy_strings, mx_host_patterns);
+    }
+    trw->flags = TRW_FLAG_HAVE_TLS_POLICY;
+    trw_set_tcp_connection(trw, (char *) 0, (char *) 0, (char *) 0);
+    trw_set_ehlo_resp(trw, (char *) 0);
+}
+
+/* trw_set_tcp_connection - set SMTP endpoint info */
+
+void    trw_set_tcp_connection(TLSRPT_WRAPPER *trw,
+                                      const char *snd_mta_addr,
+                                      const char *rcv_mta_name,
+                                      const char *rcv_mta_addr)
+{
+    const char myname[] = "trw_set_tcp_connection";
+
+    /*
+     * Sanity check: usage errors are not a show stopper.
+     */
+    if ((trw->flags & TRW_FLAG_HAVE_TLS_POLICY) == 0
+       || (trw->flags & TRW_FLAG_REPORTED)) {
+       msg_warn("%s: missing trw_set_tls_policy call", myname);
+       return;
+    }
+    MYFREE_IF_SET_AND_COPY(trw->snd_mta_addr, snd_mta_addr);
+    MYFREE_IF_SET_AND_COPY(trw->rcv_mta_name, rcv_mta_name);
+    MYFREE_IF_SET_AND_COPY(trw->rcv_mta_addr, rcv_mta_addr);
+}
+
+/* trw_set_ehlo_resp - set EHLO response */
+
+void    trw_set_ehlo_resp(TLSRPT_WRAPPER *trw, const char *rcv_mta_ehlo)
+{
+    const char myname[] = "trw_set_ehlo_resp";
+
+    /*
+     * Sanity check: usage errors are not a show stopper.
+     */
+    if ((trw->flags & TRW_FLAG_HAVE_TLS_POLICY) == 0
+       || (trw->flags & TRW_FLAG_REPORTED)) {
+       msg_warn("%s: missing trw_set_tls_policy call", myname);
+       return;
+    }
+    MYFREE_IF_SET_AND_COPY(trw->rcv_mta_ehlo, rcv_mta_ehlo);
+}
+
+/* trw_munge_report_result - helper to map and log libtlsrpt result value */
+
+static int trw_munge_report_result(int libtlsrpt_errorcode)
+{
+    int     err;
+
+    /*
+     * First, deal with the non-error cases.
+     */
+    if (libtlsrpt_errorcode == 0) {
+       return (0);
+    }
+
+    /*
+     * Do not report success if errno was zero.
+     */
+    else {
+       err = tlsrpt_errno_from_error_code(libtlsrpt_errorcode);
+       msg_warn("Could not report TLS handshake result to tlsrpt library:"
+                " %s (errno %d)", mystrerror(err), err);
+       errno = err;
+       return (-1);
+    }
+}
+
+/* trw_tlsrpt_failure_to_string - make debug logging readable */
+
+static const char *trw_failure_type_to_string(tlsrpt_failure_t failure_type)
+{
+    static const NAME_CODE failure_types[] = {
+       "TLSRPT_STARTTLS_NOT_SUPPORTED", TLSRPT_STARTTLS_NOT_SUPPORTED,
+       "TLSRPT_CERTIFICATE_HOST_MISMATCH", TLSRPT_CERTIFICATE_HOST_MISMATCH,
+       "TLSRPT_CERTIFICATE_NOT_TRUSTED", TLSRPT_CERTIFICATE_NOT_TRUSTED,
+       "TLSRPT_CERTIFICATE_EXPIRED", TLSRPT_CERTIFICATE_EXPIRED,
+       "TLSRPT_VALIDATION_FAILURE", TLSRPT_VALIDATION_FAILURE,
+       "TLSRPT_STS_POLICY_FETCH_ERROR", TLSRPT_STS_POLICY_FETCH_ERROR,
+       "TLSRPT_STS_POLICY_INVALID", TLSRPT_STS_POLICY_INVALID,
+       "TLSRPT_STS_WEBPKI_INVALID", TLSRPT_STS_WEBPKI_INVALID,
+       "TLSRPT_TLSA_INVALID", TLSRPT_TLSA_INVALID,
+       "TLSRPT_DNSSEC_INVALID", TLSRPT_DNSSEC_INVALID,
+       "TLSRPT_DANE_REQUIRED", TLSRPT_DANE_REQUIRED,
+       "TLSRPT_UNFINISHED_POLICY", TLSRPT_UNFINISHED_POLICY,
+       0, -1
+    };
+    const char *cp;
+    static VSTRING *buf;
+
+    if ((cp = str_name_code(failure_types, failure_type)) == 0) {
+       if (buf == 0)
+           buf = vstring_alloc(20);
+       msg_warn("unknown tlsrpt_failure_t value %d", failure_type);
+       vstring_sprintf(buf, "failure_type_%d", failure_type);
+       cp = vstring_str(buf);
+    }
+    return (cp);
+}
+
+/* trw_report_failure - one-shot failure reporter */
+
+int     trw_report_failure(TLSRPT_WRAPPER *trw,
+                                  tlsrpt_failure_t failure_type,
+                                  const char *additional_detail,
+                                  const char *failure_reason)
+{
+    const char myname[] = "trw_report_failure";
+    struct tlsrpt_connection_t *con;
+    int     res;
+
+    /*
+     * Sanity check: usage errors are not a show stopper.
+     */
+    if ((trw->flags & TRW_FLAG_HAVE_TLS_POLICY) == 0) {
+       msg_warn("%s: missing trw_set_tls_policy call", myname);
+       return (0);
+    }
+
+    /*
+     * Report a failure only when it is seen first. If a failure was already
+     * reported by a lower-level function close to the root cause, then skip
+     * the less detailed failure report from a later caller who is further
+     * away from the point where trouble was found.
+     * 
+     * TODO(wietse) Is it worthwhile to distinguish between failure versus
+     * success already reported?
+     */
+    if (trw->flags & TRW_FLAG_REPORTED) {
+       if (msg_verbose)
+           msg_info("%s: success or failure already reported", myname);
+       return (0);
+    }
+    trw->flags |= TRW_FLAG_REPORTED;
+
+    if (msg_verbose)
+       msg_info("%s: rpt_policy_domain=%s receiving_mx=%s failure_type=%s"
+                " failure_reason=%s",
+                myname, trw->rpt_policy_domain, trw->rcv_mta_name,
+                trw_failure_type_to_string(failure_type),
+                failure_reason ? failure_reason : "(null)");
+
+    if ((res = tlsrpt_open(&con, trw->rpt_socket_name)) == 0) {
+       struct tlsrpt_dr_t *dr;
+       char  **cpp;
+
+       if ((res = tlsrpt_init_delivery_request(&dr, con,
+                                               trw->rpt_policy_domain,
+                                           trw->rpt_policy_string)) == 0) {
+           if ((res = tlsrpt_init_policy(dr, trw->tls_policy_type,
+                                         trw->tls_policy_domain)) == 0) {
+               if (trw->tls_policy_strings)
+                   for (cpp = trw->tls_policy_strings->argv;
+                        res == 0 && *cpp; cpp++)
+                       res = tlsrpt_add_policy_string(dr, *cpp);
+               if (trw->mx_host_patterns)
+                   for (cpp = trw->mx_host_patterns->argv;
+                        res == 0 && *cpp; cpp++)
+                       res = tlsrpt_add_mx_host_pattern(dr, *cpp);
+               if (res == 0)
+                   res = tlsrpt_add_delivery_request_failure(dr,
+                                          /* failure_code= */ failure_type,
+                                   /* sending_mta_ip= */ trw->snd_mta_addr,
+                            /* receiving_mx_hostname= */ trw->rcv_mta_name,
+                                /* receiving_mx_helo= */ trw->rcv_mta_ehlo,
+                                     /* receiving_ip= */ trw->rcv_mta_addr,
+                           /* additional_information= */ additional_detail,
+                                /* failure_reason_code= */ failure_reason);
+               if (res == 0)
+                   res = tlsrpt_finish_policy(dr, TLSRPT_FINAL_FAILURE);
+           }
+           if (res == 0) {
+               res = tlsrpt_finish_delivery_request(&dr);
+           } else {
+               (void) tlsrpt_cancel_delivery_request(&dr);
+           }
+       }
+       (void) tlsrpt_close(&con);
+    }
+    return (trw_munge_report_result(res));
+}
+
+/* trw_report_success - one-shot success reporter */
+
+int     trw_report_success(TLSRPT_WRAPPER *trw)
+{
+    const char myname[] = "trw_report_success";
+    struct tlsrpt_connection_t *con;
+    int     res;
+
+    /*
+     * Sanity check: usage errors are not a show stopper.
+     */
+    if ((trw->flags & TRW_FLAG_HAVE_TLS_POLICY) == 0) {
+       msg_warn("%s: missing trw_set_tls_policy call", myname);
+       return (0);
+    }
+    /* This should not happen. Log a warning. */
+    if (trw->flags & TRW_FLAG_REPORTED) {
+       msg_warn("%s: success or failure was already reported", myname);
+       return (0);
+    }
+    trw->flags |= TRW_FLAG_REPORTED;
+
+    if (msg_verbose)
+       msg_info("%s: rpt_policy_domain=%s receiving_mx=%s",
+                myname, trw->rpt_policy_domain, trw->rcv_mta_name);
+
+    if ((res = tlsrpt_open(&con, trw->rpt_socket_name)) == 0) {
+       struct tlsrpt_dr_t *dr;
+
+       if ((res = tlsrpt_init_delivery_request(&dr, con,
+                                               trw->rpt_policy_domain,
+                                           trw->rpt_policy_string)) == 0) {
+           if ((res = tlsrpt_init_policy(dr, trw->tls_policy_type,
+                                         trw->tls_policy_domain)) == 0)
+               res = tlsrpt_finish_policy(dr, TLSRPT_FINAL_SUCCESS);
+           if (res == 0) {
+               res = tlsrpt_finish_delivery_request(&dr);
+           } else {
+               (void) tlsrpt_cancel_delivery_request(&dr);
+           }
+       }
+       (void) tlsrpt_close(&con);
+    }
+    return (trw_munge_report_result(res));
+}
+
+/* trw_is_reported - trw_report_success() or trw_report_failure() called */
+
+int     trw_is_reported(const TLSRPT_WRAPPER *trw)
+{
+    return (trw->flags & TRW_FLAG_REPORTED);
+}
+
+#endif                                 /* USE_TLS_RPT */
+
+ /*
+  * Dummy definitions for builds without the TLSRPT library, so that we can
+  * still validate names.
+  */
+#if !defined(USE_TLSRPT)
+#define TLSRPT_POLICY_DANE     0
+#define TLSRPT_POLICY_STS      0
+#define TLSRPT_NO_POLICY_FOUND  0
+
+#define TLSRPT_VALIDATION_FAILURE       0
+#define TLSRPT_STS_POLICY_FETCH_ERROR   0
+#define TLSRPT_STS_POLICY_INVALID       0
+#define TLSRPT_STS_WEBPKI_INVALID       0
+#endif
+
+ /*
+  * Mapping from RFC 8460 string to libtlsrpt enum for policy types and
+  * policy failures. The mapping assumes that all enum values are
+  * non-negative.
+  */
+const NAME_CODE tlsrpt_policy_type_mapping[] = {
+    "sts", TLSRPT_POLICY_STS,
+    "no-policy-found", TLSRPT_NO_POLICY_FOUND,
+    0, -1,
+};
+
+const NAME_CODE tlsrpt_policy_failure_mapping[] = {
+    "sts-policy-fetch-error", TLSRPT_STS_POLICY_FETCH_ERROR,
+    "sts-policy-invalid", TLSRPT_STS_POLICY_INVALID,
+    "sts-webpki-invalid", TLSRPT_STS_WEBPKI_INVALID,
+    "validation-failure", TLSRPT_VALIDATION_FAILURE,
+    0, -1,
+};
+
+/* valid_tlsrpt_policy_type - validate policy_type attribute value */
+
+int     valid_tlsrpt_policy_type(const char *policy_type)
+{
+    return (name_code(tlsrpt_policy_type_mapping, NAME_CODE_FLAG_NONE,
+                     policy_type) >= 0);
+}
+
+/* valid_tlsrpt_policy_failure - validate policy_failure attribute value */
+
+int     valid_tlsrpt_policy_failure(const char *policy_failure)
+{
+    return (name_code(tlsrpt_policy_failure_mapping, NAME_CODE_FLAG_NONE,
+                     policy_failure) >= 0);
+}
+
+#if defined(USE_TLSRPT)
+
+/* convert_tlsrpt_policy_type - convert string to enum */
+
+tlsrpt_policy_type_t convert_tlsrpt_policy_type(const char *policy_type)
+{
+    return (name_code(tlsrpt_policy_type_mapping, NAME_CODE_FLAG_NONE,
+                     policy_type));
+}
+
+/* convert_tlsrpt_policy_failure - convert string to enum */
+
+tlsrpt_failure_t convert_tlsrpt_policy_failure(const char *policy_failure)
+{
+    return (name_code(tlsrpt_policy_failure_mapping, NAME_CODE_FLAG_NONE,
+                     policy_failure));
+}
+
+#endif                                 /* USE_TLSRPT */
+
+#endif                                 /* USE_TLS */
diff --git a/postfix/src/tls/tlsrpt_wrapper.h b/postfix/src/tls/tlsrpt_wrapper.h
new file mode 100644 (file)
index 0000000..2107d3a
--- /dev/null
@@ -0,0 +1,122 @@
+#ifndef _TLSRPT_WRAPPER_INCLUDED_
+#define _TLSRPT_WRAPPER_INCLUDED_
+
+/*++
+/* NAME
+/*     tlsrpt_wrapper 3h
+/* SUMMARY
+/*     TLSRPT support for the TLS protocol engine
+/* SYNOPSIS
+/*     #include <tlsrpt_wrapper.h>
+/* DESCRIPTION
+/* .nf
+
+ /*
+  * System library.
+  */
+#if defined(USE_TLS)
+
+#if defined(USE_TLSRPT)
+
+#include <tlsrpt.h>
+
+ /*
+  * External interface, with convenient setters for each SMTP protocol engine
+  * stage. Many functions have multiple arguments of the same type. Include
+  * parameter names in function prototypes here, and in call sites include
+  * comments before parameter values, to prepare for future clang-tidy
+  * bugprone-argument-comment checks.
+  */
+typedef struct TLSRPT_WRAPPER TLSRPT_WRAPPER;
+
+extern TLSRPT_WRAPPER *trw_create(const char *rpt_socket_name,
+                                         const char *rpt_policy_domain,
+                                         const char *rpt_policy_string);
+extern void trw_free(TLSRPT_WRAPPER *trw);
+extern void trw_set_tls_policy(TLSRPT_WRAPPER *trw,
+                                      tlsrpt_policy_type_t tls_policy_type,
+                                    const char *const * tls_policy_strings,
+                                      const char *tls_policy_domain,
+                                   const char *const * mx_policy_patterns);
+extern void trw_set_tcp_connection(TLSRPT_WRAPPER *trw,
+                                          const char *snd_mta_addr,
+                                          const char *rcv_mta_name,
+                                          const char *rcv_mta_addr);
+extern void trw_set_ehlo_resp(TLSRPT_WRAPPER *trw,
+                                     const char *rcv_mta_ehlo);
+extern int trw_report_failure(TLSRPT_WRAPPER *trw,
+                                     tlsrpt_failure_t policy_failure,
+                                     const char *additional_detail,
+                                     const char *failure_reason);
+extern int trw_report_success(TLSRPT_WRAPPER *trw);
+extern int trw_is_reported(const TLSRPT_WRAPPER *trw);
+
+ /*
+  * The internals declarations are also needed for functions that transmit
+  * and receive TLSRPT_WRAPPER objects.
+  */
+#ifdef TLSRPT_WRAPPER_INTERNAL
+
+ /*
+  * Utility library.
+  */
+#include <argv.h>
+
+struct TLSRPT_WRAPPER {
+    /* Set with trw_create(). */
+    char   *rpt_socket_name;
+    char   *rpt_policy_domain;
+    char   *rpt_policy_string;
+    /* Set with trw_set_policy(). */
+    tlsrpt_policy_type_t tls_policy_type;
+    ARGV   *tls_policy_strings;
+    char   *tls_policy_domain;
+    ARGV   *mx_host_patterns;
+    /* Set with trw_set_tcp_connection(). */
+    char   *snd_mta_addr;
+    char   *rcv_mta_name;
+    char   *rcv_mta_addr;
+    /* Set with trw_set_ehlo_resp(). */
+    char   *rcv_mta_ehlo;
+    int     flags;
+};
+
+#define TRW_FLAG_HAVE_TLS_POLICY (1<<0)
+#define TRW_FLAG_HAVE_TCP_CONN (1<<1)
+#define TRW_FLAG_HAVE_EHLO_RESP        (1<<2)
+#define TRW_FLAG_REPORTED      (1<<3)
+
+#define TRW_RPT_SOCKET_NAME    "rpt_socket_name"
+#define TRW_RPT_POLICY_DOMAIN  "rpt_policy_domain"
+#define TRW_RPT_POLICY_STRING  "rpt_policy_string"
+#define TRW_TLS_POLICY_TYPE    "tls_policy_type"
+#define TRW_TLS_POLICY_STRINGS "tls_policy_strings"    /* XXX Not checked */
+#define TRW_TLS_POLICY_DOMAIN  "tls_policy_domain"
+#define TRW_MX_HOST_PATTERNS   "mx_host_patterns"      /* XXX Not checked */
+#define TRW_SRC_MTA_ADDR       "snd_mta_addr"
+#define TRW_DST_MTA_NAME       "rcv_mta_name"
+#define TRW_DST_MTA_ADDR       "rcv_mta_addr"
+#define TRW_DST_MTA_EHLO       "rcv_mta_ehlo"  /* Optional */
+#define TRW_FLAGS              "flags"
+
+#endif                                 /* TLSRPT_WRAPPER_INTERNAL */
+
+extern tlsrpt_policy_type_t convert_tlsrpt_policy_type(const char *policy_type);
+extern tlsrpt_failure_t convert_tlsrpt_policy_failure(const char *policy_failure);
+
+#endif                                 /* USE_TLSRPT */
+
+extern int valid_tlsrpt_policy_type(const char *policy_type);
+extern int valid_tlsrpt_policy_failure(const char *policy_failure);
+
+#endif                                 /* USE_TLS */
+
+/* LICENSE
+/* .ad
+/* .fi
+/*     The Secure Mailer license must be distributed with this software.
+/* AUTHOR(S)
+/*     Wietse Venema
+/*--*/
+
+#endif                                 /* _TLSRPT_WRAPPER_INCLUDED_ */
index 51120af063f6c6427bc51a1339074b68c6de5037..2b6d34589595da9138039b806dada683b0eeea85 100644 (file)
@@ -75,6 +75,7 @@ tlsproxy.o: ../../include/split_at.h
 tlsproxy.o: ../../include/sys_defs.h
 tlsproxy.o: ../../include/tls.h
 tlsproxy.o: ../../include/tls_proxy.h
+tlsproxy.o: ../../include/tlsrpt_wrapper.h
 tlsproxy.o: ../../include/vbuf.h
 tlsproxy.o: ../../include/vstream.h
 tlsproxy.o: ../../include/vstring.h
index 0ebf52c68ec81444690f8813a58504b551fb5835..dd35d3e42b50b5e9e6a817b7bddce9406c4fb2f0 100644 (file)
 #define TLS_INTERNAL                   /* XXX */
 #include <tls.h>
 #include <tls_proxy.h>
+#include <tlsrpt_wrapper.h>
 
  /*
   * Application-specific.
@@ -731,6 +732,19 @@ static int tlsp_eval_tls_error(TLSP_STATE *state, int err)
            state->flags |= TLSP_FLAG_NO_MORE_CIPHERTEXT_IO;
            return (TLSP_STAT_OK);
        }
+
+       /*
+        * Report a generic failure only if a more specific failure wasn't
+        * already reported.
+        */
+#ifdef USE_TLSRPT
+       if ((state->flags & TLSP_FLAG_DO_HANDSHAKE)
+           && state->is_server_role == 0)
+           trw_report_failure(state->client_start_props->tlsrpt,
+                              TLSRPT_VALIDATION_FAILURE,
+                               /* additional_detail= */ (char *) 0,
+                              "tls-handshake-failure");
+#endif
        tlsp_state_free(state);
        return (TLSP_STAT_ERR);
     }
index bd21e6af3fb90e2d5a050486ff09d00605754b3c..0bb2c689b3db5352cd8635123bcda04edf4b43c1 100644 (file)
@@ -45,7 +45,7 @@ SRCS  = alldig.c allprint.c argv.c argv_split.c attr_clnt.c attr_print0.c \
        byte_mask.c known_tcp_ports.c argv_split_at.c dict_stream.c \
        sane_strtol.c hash_fnv.c ldseed.c mkmap_cdb.c mkmap_db.c mkmap_dbm.c \
        mkmap_fail.c mkmap_lmdb.c mkmap_open.c mkmap_sdbm.c inet_prefix_top.c \
-       inet_addr_sizes.c quote_for_json.c
+       inet_addr_sizes.c quote_for_json.c mystrerror.c
 OBJS   = alldig.o allprint.o argv.o argv_split.o attr_clnt.o attr_print0.o \
        attr_print64.o attr_print_plain.o attr_scan0.o attr_scan64.o \
        attr_scan_plain.o auto_clnt.o base64_code.o basename.o binhash.o \
@@ -92,7 +92,7 @@ OBJS  = alldig.o allprint.o argv.o argv_split.o attr_clnt.o attr_print0.o \
        byte_mask.o known_tcp_ports.o argv_split_at.o dict_stream.o \
        sane_strtol.o hash_fnv.o ldseed.o mkmap_db.o mkmap_dbm.o \
        mkmap_fail.o mkmap_open.o inet_prefix_top.o inet_addr_sizes.o \
-       quote_for_json.o
+       quote_for_json.o mystrerror.o
 # MAP_OBJ is for maps that may be dynamically loaded with dynamicmaps.cf.
 # When hard-linking these, makedefs sets NON_PLUGIN_MAP_OBJ=$(MAP_OBJ),
 # otherwise it sets the PLUGIN_* macros.
@@ -2444,6 +2444,12 @@ mymalloc.o: sys_defs.h
 myrand.o: myrand.c
 myrand.o: myrand.h
 myrand.o: sys_defs.h
+mystrerror.o: check_arg.h
+mystrerror.o: mystrerror.c
+mystrerror.o: stringops.h
+mystrerror.o: sys_defs.h
+mystrerror.o: vbuf.h
+mystrerror.o: vstring.h
 mystrtok.o: check_arg.h
 mystrtok.o: msg.h
 mystrtok.o: mystrtok.c
@@ -2549,9 +2555,11 @@ printable.o: stringops.h
 printable.o: sys_defs.h
 printable.o: vbuf.h
 printable.o: vstring.h
+quote_for_json.o: check_arg.h
 quote_for_json.o: quote_for_json.c
 quote_for_json.o: stringops.h
 quote_for_json.o: sys_defs.h
+quote_for_json.o: vbuf.h
 quote_for_json.o: vstring.h
 rand_sleep.o: iostuff.h
 rand_sleep.o: msg.h
@@ -2883,6 +2891,7 @@ vbuf.o: vbuf.h
 vbuf_print.o: check_arg.h
 vbuf_print.o: msg.h
 vbuf_print.o: mymalloc.h
+vbuf_print.o: stringops.h
 vbuf_print.o: sys_defs.h
 vbuf_print.o: vbuf.h
 vbuf_print.o: vbuf_print.c
index 332426e88790ba9e51935207c2a7fc931cbd1e35..112603164ecf41bb6948324f48baa923acfaaa6a 100644 (file)
 /*     char    *arg;
 /*     ssize_t arg_len;
 /*
+/*     ARGV    *argv_addv(argvp, argv)
+/*     ARGV    *argvp;
+/*     const char **argv;
+/*
 /*     void    argv_terminate(argvp);
 /*     ARGV    *argvp;
 /*
 /*     argv_addn() is like argv_add(), but each string is followed
 /*     by a string length argument.
 /*
+/*     argv_addv() optionally creates an ARGV when the first argument
+/*     is a null pointer, and appends a null-terminated list of
+/*     strings. The result is null terminated.
+/*
 /*     argv_free() releases storage for a string array, and conveniently
 /*     returns a null pointer.
 /*
@@ -301,6 +309,23 @@ void    argv_addn(ARGV *argvp,...)
     argvp->argv[argvp->argc] = 0;
 }
 
+/* argv_addv - optionally create ARGV, append string vector */
+
+ARGV   *argv_addv(ARGV *argvp, const char *const * argv)
+{
+    const char *const * cpp;
+
+    if (argvp == 0) {
+       for (cpp = argv; *cpp; cpp++)
+            /* void */ ;
+       argvp = argv_alloc(cpp - argv);
+    }
+    for (cpp = argv; *cpp; cpp++)
+       argv_add(argvp, *cpp, (char *) 0);
+    argvp->argv[argvp->argc] = 0;
+    return (argvp);
+}
+
 /* argv_terminate - terminate string array */
 
 void    argv_terminate(ARGV *argvp)
@@ -602,6 +627,23 @@ static ARGV *test_argv_join(const TEST_CASE *tp, ARGV *argvp)
     return (argvp);
 }
 
+/* test_argv_addv_appends - populate result */
+
+static ARGV *test_argv_addv_appends(const TEST_CASE *tp, ARGV *argvp)
+{
+    argvp = argv_addv(argvp, tp->inputs);
+    return (argvp);
+}
+
+/* test_argv_addv_creates_appends - populate result */
+
+static ARGV *test_argv_addv_creates(const TEST_CASE *tp, ARGV *argvp)
+{
+    argv_free(argvp);
+    argvp = argv_addv((ARGV *) 0, tp->inputs);
+    return (argvp);
+}
+
 /* test_argv_verify - verify result */
 
 static int test_argv_verify(const TEST_CASE *tp, ARGV *argvp)
@@ -737,6 +779,14 @@ static const TEST_CASE test_cases[] = {
        {0}, 0, test_argv_join,
        0, 1, {"", 0}, ':'
     },
+    {"argv_addv appends to ARGV",
+       {"foo", "baz", "bar", 0}, /* ignored */ 0, test_argv_addv_appends,
+       0, 3, {"foo", "baz", "bar", 0}
+    },
+    {"argv_addv creates ARGV",
+       {"foo", "baz", "bar", 0}, /* ignored */ 0, test_argv_addv_creates,
+       0, 3, {"foo", "baz", "bar", 0}
+    },
     0,
 };
 
index f1e746ad89cda6b5a1fbdb715ddc2ea617e706f1..1c479069644e827e227925a5962addca10307095 100644 (file)
@@ -20,7 +20,7 @@ typedef struct ARGV {
     char  **argv;                      /* string array */
 } ARGV;
 
-typedef int (*ARGV_COMPAR_FN)(const void *, const void *);
+typedef int (*ARGV_COMPAR_FN) (const void *, const void *);
 
 extern ARGV *argv_alloc(ssize_t);
 extern ARGV *argv_sort(ARGV *);                /* backwards compatibility */
@@ -28,6 +28,7 @@ extern ARGV *argv_qsort(ARGV *, ARGV_COMPAR_FN);
 extern ARGV *argv_uniq(ARGV *, ARGV_COMPAR_FN);
 extern void argv_add(ARGV *,...);
 extern void argv_addn(ARGV *,...);
+extern ARGV *argv_addv(ARGV *, const char *const *);
 extern void argv_terminate(ARGV *);
 extern void argv_truncate(ARGV *, ssize_t);
 extern void argv_insert_one(ARGV *, ssize_t, const char *);
index 3dfcb9818c2cb481a5e72fe40e0eb7d42b246a0f..6ea9a5161e79397b00465d686558e96f9a9f82c5 100644 (file)
@@ -44,6 +44,8 @@
 /*     functionality.
 /* .IP HEX_ENCODE_FLAG_USE_COLON
 /*     Inserts one ":" between bytes.
+/* .IP HEX_ENCODE_FLAG_APPEND
+/*     Append output to the buffer.
 /* .PP
 /*     hex_decode_opt() enables extended functionality as controlled
 /*     with \fIflags\fR.
@@ -69,6 +71,9 @@
 /*     Google, Inc.
 /*     111 8th Avenue
 /*     New York, NY 10011, USA
+/*
+/*     Wietse Venema
+/*     porcupine.org
 /*--*/
 
 /* System library. */
@@ -107,7 +112,8 @@ VSTRING *hex_encode_opt(VSTRING *result, const char *in, ssize_t len, int flags)
     int     ch;
     ssize_t count;
 
-    VSTRING_RESET(result);
+    if ((flags & HEX_ENCODE_FLAG_APPEND) == 0)
+       VSTRING_RESET(result);
     for (cp = UCHAR_PTR(in), count = len; count > 0; count--, cp++) {
        ch = *cp;
        VSTRING_ADDCH(result, hex_chars[(ch >> 4) & 0xf]);
index 720977adb5895ad5f4141221028fe40de245ae3d..ad923c9e24695cf1d33b78e8421a375de45c929b 100644 (file)
@@ -21,6 +21,7 @@
   */
 #define HEX_ENCODE_FLAG_NONE           (0)
 #define HEX_ENCODE_FLAG_USE_COLON      (1<<0)
+#define HEX_ENCODE_FLAG_APPEND         (1<<1)
 
 #define HEX_DECODE_FLAG_NONE   (0)
 #define HEX_DECODE_FLAG_ALLOW_COLON    (1<<0)
@@ -49,6 +50,9 @@ extern VSTRING *WARN_UNUSED_RESULT hex_decode_opt(VSTRING *, const char *, ssize
 /*     Google, Inc.
 /*     111 8th Avenue
 /*     New York, NY 10011, USA
+/*
+/*     Wietse Venema
+/*     porcupine.org
 /*--*/
 
 #endif
diff --git a/postfix/src/util/mystrerror.c b/postfix/src/util/mystrerror.c
new file mode 100644 (file)
index 0000000..0de07f1
--- /dev/null
@@ -0,0 +1,39 @@
+/*++
+/* NAME
+/*     mystrerror 3
+/* SUMMARY
+/*     convert error number to string
+/* SYNOPSIS
+/*     #include <stringops.h>
+/*
+/*     const char *mystrerror()
+/*     int     errnum)
+/* DESCRIPTION
+/*     mystrerror() maps an error number to string. Unlike strerror(3)
+/*     it returns "Application error" instead of "Success".
+/* LICENSE
+/* .ad
+/* .fi
+/*     The Secure Mailer license must be distributed with this software.
+/* AUTHOR(S)
+/*     Wietse Venema
+/*     porcupine.org
+/*--*/
+
+ /*
+  * System library.
+  */
+#include <sys_defs.h>
+#include <string.h>
+
+ /*
+  * Utility library.
+  */
+#include <stringops.h>
+
+/* mystrerror - convert error number to string */
+
+const char *mystrerror(int errnum)
+{
+    return (errnum ? strerror(errnum) : "Application error");
+}
index db56f237a73fdf37096550f88e701a04d4f5ccd7..4c357c81e12f3260b2174b1f876ab2d0355e75a4 100644 (file)
@@ -67,6 +67,7 @@ extern int strcasecmp_utf8x(int, const char *, const char *);
 extern int strncasecmp_utf8x(int, const char *, const char *, ssize_t);
 extern char *quote_for_json(VSTRING *, const char *, ssize_t);
 extern char *quote_for_json_append(VSTRING *, const char *, ssize_t);
+extern const char *mystrerror(int);
 
 #define EXTPAR_FLAG_NONE       (0)
 #define EXTPAR_FLAG_STRIP      (1<<0)  /* "{ text }" -> "text" */
index d7a323f241dd7cd6039bf6272c32da267703a37f..2e3266ed7105d24a57d1bab0a2fe7952c49fa5d9 100644 (file)
@@ -67,6 +67,7 @@
 #include "mymalloc.h"
 #include "vbuf.h"
 #include "vstring.h"
+#include "stringops.h"
 #include "vbuf_print.h"
 
  /*
@@ -290,8 +291,7 @@ VBUF   *vbuf_print(VBUF *bp, const char *format, va_list ap)
                break;
            case 'm':
                /* Ignore the 'l' modifier, width and precision. */
-               VBUF_STRCAT(bp, saved_errno ?
-                           strerror(saved_errno) : "Application error");
+               VBUF_STRCAT(bp, mystrerror(saved_errno));
                break;
            case 'p':
                if (long_flag)