-TTLS_PRNG_SEED_INFO
-TTLS_PRNG_SRC
-TTLS_ROLE
+-TTLSRPT_WRAPPER
-TTLS_SCACHE
-TTLS_SCACHE_ENTRY
-TTLS_SERVER_INIT_PROPS
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];
* 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
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
--- /dev/null
+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.
+
$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
$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
<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>
--- /dev/null
+<!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> --> </tt> </td>
+
+<td bgcolor="#f0f0ff"> TLSRPT client library </td> <td> <tt> -->
+</tt> </td>
+
+<td bgcolor="#f0f0ff"> TLSRPT report generator </td> <td> <tt>
+--> </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>
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>
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.
<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>
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 < 2.3 control for the Postfix SMTP client TLS
+ Obsolete Postfix < 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>
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>
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>
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>
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:
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>.
<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>
<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>
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>
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:
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:
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>
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>
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>
<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>
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>
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>
<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 ≥ 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 ≥ 3.10. </p>
+
+
</DD>
<DT><b><a name="smtp_use_tls">smtp_use_tls</a>
(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
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>
$<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>
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>
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 < 2.3 control for the Postfix SMTP client TLS
+ Obsolete Postfix < 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>
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>
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>
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>
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:
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>.
<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>
<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>
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>
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:
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:
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>
# 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"
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
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.
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.
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)
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
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
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
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:
.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
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"
$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"
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"
.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
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;
../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 \
../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 \
../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) >$@
../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) >$@
--- /dev/null
+<!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> --> </tt> </td>
+
+<td bgcolor="#f0f0ff"> TLSRPT client library </td> <td> <tt> -->
+</tt> </td>
+
+<td bgcolor="#f0f0ff"> TLSRPT report generator </td> <td> <tt>
+--> </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>
length limit. </p>
<p> This feature is available in Postfix ≥ 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 ≥ 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 ≥ 3.10. </p>
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
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
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
ILP
xxfi
optionsv
+rcv
+snd
+sts
+tlsrprt
ar
liveness
superset
+ltlsrpt
+sts
+STS
+STSv
+Sys
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;
/*
/* 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
/* 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);
}
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.
*/
"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,
};
#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
/* Google, Inc.
/* 111 8th Avenue
/* New York, NY 10011, USA
+/*
+/* Wietse Venema
+/* porcupine.org
/*--*/
#endif
= vstring_str(cipher_exclusions),
matchargv = state->match,
mdalg = state->mdalg,
+ tlsrpt = 0,
+ fail_type = 0,
dane = state->ddane ?
state->ddane : state->dane);
= 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);
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)
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
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
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
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
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
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
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,
};
/* .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
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;
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
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
*/
_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
*/
#ifdef USE_TLS
SMTP_TLS_POLICY tls[1]; /* Usage: state->tls->member */
+#ifdef USE_TLSRPT
+ struct TLSRPT_WRAPPER *tlsrpt;
+#endif
#endif
/*
*/
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
#include <mail_error.h>
#include <dsn_buf.h>
#include <mail_addr.h>
+#include <valid_hostname.h>
/* DNS library. */
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.
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;
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,
};
#include <xtext.h>
#include <uxtext.h>
#include <smtputf8.h>
+#if defined(USE_TLS) && defined(USE_TLSRPT)
+#include <tlsrpt_wrapper.h>
+#endif
/* Application-specific. */
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";
"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";
* 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. */
}
*/
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",
= 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);
/*
= 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);
/*
* 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
#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"
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);
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)
#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>
{
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)
}
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);
}
* 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;
* 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);
}
continue;
}
+ /* Last one wins. */
if (!strcasecmp(name, "enable_rpk")) {
/* Ultimately ignored at some security levels */
if (strcasecmp(val, "yes") == 0) {
}
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;
}
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);
}
--- /dev/null
+/*++
+/* 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 */
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 \
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)
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
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
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
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
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 *);
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;
/*
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 *);
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
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
#ifdef USE_TLS
#include <string.h>
+#include <tlsrpt_wrapper.h>
#ifdef STRCASECMP_IN_STRINGS_H
#include <strings.h>
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 */
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 */
* 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();
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();
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();
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);
* 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);
*/
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);
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);
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);
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);
* early.
*/
if (!tls_auth_enable(TLScontext, props)) {
+ /* Already warned and reported TLSRPT result. */
tls_free_context(TLScontext);
return (0);
}
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;
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;
}
*/
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);
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.
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);
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);
}
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)
TLScontext->errordepth = -1;
TLScontext->errorcode = X509_V_OK;
TLScontext->errorcert = 0;
+ TLScontext->rpt_reported = 0;
+ TLScontext->fail_type = 0;
return (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);
}
((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 *);
#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.
#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.
#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)
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),
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,
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)
#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)
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);
}
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,
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");
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);
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;
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);
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);
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;
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",
/* 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>
/* 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.
*/
*/
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:
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",
X509_verify_cert_error_string(err));
break;
}
+#ifdef USE_TLSRPT
+ vstring_free(err_vstr);
+#endif
}
#ifndef DONT_GRIPE
--- /dev/null
+/*++
+/* 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 */
--- /dev/null
+#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_ */
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
#define TLS_INTERNAL /* XXX */
#include <tls.h>
#include <tls_proxy.h>
+#include <tlsrpt_wrapper.h>
/*
* Application-specific.
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);
}
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 \
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.
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
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
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
/* 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.
/*
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)
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)
{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,
};
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 */
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 *);
/* 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.
/* Google, Inc.
/* 111 8th Avenue
/* New York, NY 10011, USA
+/*
+/* Wietse Venema
+/* porcupine.org
/*--*/
/* System library. */
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]);
*/
#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)
/* Google, Inc.
/* 111 8th Avenue
/* New York, NY 10011, USA
+/*
+/* Wietse Venema
+/* porcupine.org
/*--*/
#endif
--- /dev/null
+/*++
+/* 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");
+}
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" */
#include "mymalloc.h"
#include "vbuf.h"
#include "vstring.h"
+#include "stringops.h"
#include "vbuf_print.h"
/*
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)