mirror of
https://github.com/vdukhovni/postfix
synced 2025-08-22 01:49:47 +00:00
postfix-3.10-20240926
This commit is contained in:
parent
67b02e7393
commit
c42df8386b
1
postfix/.indent.pro
vendored
1
postfix/.indent.pro
vendored
@ -360,6 +360,7 @@
|
||||
-TTEST_CASE
|
||||
-TTLSMGR_SCACHE
|
||||
-TTLSP_STATE
|
||||
-TTLSRPT_WRAPPER
|
||||
-TTLS_APPL_STATE
|
||||
-TTLS_CERTS
|
||||
-TTLS_CLIENT_INIT_PROPS
|
||||
|
@ -28186,6 +28186,27 @@ Apologies for any names omitted.
|
||||
20240808
|
||||
|
||||
Typofix in comment. File: global/normalize_mailhost_addr.c.
|
||||
|
||||
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];
|
||||
|
||||
20240831
|
||||
|
||||
@ -28237,7 +28258,46 @@ Apologies for any names omitted.
|
||||
OpenSSL 3.2) SSL_get0_group_name() function. Viktor Dukhovni.
|
||||
Files: src/tls/tls.h, src/tls/tls_dh.c, src/tls/tls_misc.c.
|
||||
|
||||
20240923
|
||||
|
||||
Cleanup: No user-visible change. Updated TLSRPT related
|
||||
internal comments and internal identifiers; updated error
|
||||
logging after changes in libtlsrpt error-to-string conversion
|
||||
functions; minor changes to improve robustness.
|
||||
|
||||
20240924
|
||||
|
||||
Misc. cleanups. Viktor Dukhovni. Files: src/tls/tls_dh.c,
|
||||
proto/postconf.proto, src/global/mail_params.h.
|
||||
|
||||
TLSRPT documentation cleanups. File: proto/TLSRPT_README.html.
|
||||
|
||||
20240924
|
||||
|
||||
Code health: added proper unit tests to hex_code.c.
|
||||
|
||||
Code health: deduplicated code instances that convert an
|
||||
IPv4-in-IPv6 address (::ffff:a.b.c.d) to IPv4 form, but
|
||||
only if IPv4 support is enabled. Files: myaddrinfo,h,
|
||||
sane_sockaddr_to_hostaddr.c, global/haproxy_srvr.c,
|
||||
postscreen/postscreen_endpt.c, smtp/smtp_tlsrpt.c.
|
||||
|
||||
20240925
|
||||
|
||||
TLSRPT support: add routine logging of TLSRPT 'success' and
|
||||
'failure' events, as there is no other easy way to find out
|
||||
what the Postfix TLSRPT client is doing. Document what this
|
||||
logging looks like, that it is not logged for reused TCP
|
||||
connections, and how to recognize such connections. Files:
|
||||
tls/tlsrpt_wrapper.c, proto/TLSRPT_README.html.
|
||||
|
||||
TLSRPT support: simplified the handling of reused TLS
|
||||
sessions. Report all TLS handshakes regardless of whether
|
||||
or not a session is reused. Note that there is only one TLS
|
||||
handshake for a reused SMTP connection. Files: smtp/smtp_proto.c,
|
||||
tls/tls_client.c, proto/TLSRPT_README.html.
|
||||
|
||||
Cleanup: pre-release checks for snapshot and nonprod releases.
|
||||
File: mantools/check-snapshot-nonprod.
|
||||
|
||||
First general Postfix release with TLSRPT support.
|
||||
|
@ -115,9 +115,9 @@ manpages:
|
||||
done </dev/null
|
||||
|
||||
# Some checks require a bin/postconf executable.
|
||||
pre-release-checks: typo-check missing-proxy-read-maps-check \
|
||||
postlink-check postfix-files-check check-spell-history \
|
||||
check-double-history check-table-proto check-see-postconf-d-output \
|
||||
pre-release-checks: typo-check double-check missing-proxy-read-maps-check \
|
||||
postlink-check postfix-files-check \
|
||||
check-table-proto check-see-postconf-d-output \
|
||||
check-snapshot-nonprod
|
||||
|
||||
postfix-files-check:
|
||||
@ -130,7 +130,10 @@ missing-proxy-read-maps-check:
|
||||
$(SHLIB_ENV) mantools/missing-proxy-read-maps | diff /dev/null -
|
||||
|
||||
typo-check: spell-cc spell-install-proto-text spell-proto-html \
|
||||
double-cc double-install-proto-text double-proto-html
|
||||
check-spell-history
|
||||
|
||||
double-check: double-cc double-install-proto-text double-proto-html \
|
||||
check-double-history
|
||||
|
||||
spell-cc:
|
||||
mantools/check-spell-cc | diff /dev/null -
|
||||
|
@ -11,6 +11,7 @@ GGeenneerraall ccoonnffiigguurraattiioonn
|
||||
* SASL_README: SASL Authentication
|
||||
* TLS_README: TLS Encryption and authentication
|
||||
* FORWARD_SECRECY_README: TLS Forward Secrecy
|
||||
* TLSRPT_README: TLSRPT Protocol Support
|
||||
* IPV6_README: IP Version 6 Support
|
||||
* SMTPUTF8_README: SMTPUTF8 Support
|
||||
* MAILLOG_README: Postfix logging to file or stdout
|
||||
|
277
postfix/README_FILES/TLSRPT_README
Normal file
277
postfix/README_FILES/TLSRPT_README
Normal file
@ -0,0 +1,277 @@
|
||||
PPoossttffiixx TTLLSSRRPPTT HHoowwttoo
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
TTaabbllee ooff CCoonntteennttss
|
||||
|
||||
* Introduction
|
||||
* Building Postfix with TLSRPT support
|
||||
* Turning on TLSRPT
|
||||
* TLSRPT Status logging
|
||||
* Delivering TLSRPT summaries via email
|
||||
* MTA-STS Support via smtp_tls_policy_maps
|
||||
* Limitations
|
||||
* Credits
|
||||
|
||||
IInnttrroodduuccttiioonn
|
||||
|
||||
The TLSRPT protocol is defined in RFC 8460. With this, an email receiving
|
||||
domain can publish a policy in DNS, and request daily summary reports for
|
||||
successful and failed SMTP over TLS connections to that domain's MX hosts.
|
||||
Support for TLSRPT was added in Postfix 3.10.
|
||||
|
||||
A policy example looks like this:
|
||||
|
||||
_smtp._tls.example.com. IN TXT "v=TLSRPTv1; rua=mailto:smtp-tls-
|
||||
report@example.com"
|
||||
|
||||
Translation: email sending systems are requested to generate daily summaries of
|
||||
successful and failed SMTP over TLS connections to domain example.com, and to
|
||||
report those summaries via email to the specified address. Instead of mailto:,
|
||||
a policy may specify an https: destination.
|
||||
|
||||
The high-level diagram shows how Postfix reports summaries to domains that
|
||||
publish a TLSRPT policy.
|
||||
|
||||
Postfix SMTP and TLSRPT client TLSRPT summary Email or HTTP
|
||||
TLS client --> library --> generator --> delivery
|
||||
engines
|
||||
|
||||
When Postfix TLSRPT support is enabled (with "smtp_tlsrpt_enable = yes"):
|
||||
|
||||
* The Postfix SMTP and TLS client engines will generate a "success" or
|
||||
"failure" event for each TLS handshake,
|
||||
|
||||
* They will pass those events to an in-process TLSRPT client library that
|
||||
sends data over a local socket to
|
||||
|
||||
* A TLSRPT report generator that produces daily summary reports.
|
||||
|
||||
The TLSRPT client library and report generator 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 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.
|
||||
|
||||
BBuuiillddiinngg PPoossttffiixx wwiitthh TTLLSSRRPPTT ssuuppppoorrtt
|
||||
|
||||
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 -DUSE_TLSRPT (to build with TLSRPT support), and -I (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 settings,
|
||||
then simply append the above settings to the existing CCARGS or AUXLIBS
|
||||
values.
|
||||
|
||||
make -f Makefile.init makefiles \
|
||||
"CCARGS=existing settings... -DUSE_TLSRPT -I/usr/local/include" \
|
||||
"AUXLIBS=existing settings... -L/usr/local/lib -ltlsrpt"
|
||||
|
||||
TTuurrnniinngg oonn TTLLSSRRPPTT
|
||||
|
||||
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.
|
||||
|
||||
Note: the recommended socket location is still to be determined. A good
|
||||
socket location would be under the Postfix queue directory, for example:
|
||||
"smtp_tlsrpt_socket_name = run/tlsrpt/tlsrpt.sock". The advantage of using
|
||||
a relative name is that it will work equally well whether or not Postfix
|
||||
chroot is turned on.
|
||||
|
||||
Do not specify a location under a directory such as private or public that is
|
||||
already used by Postfix programs. Only Postfix programs should create sockets
|
||||
there.
|
||||
|
||||
TTLLSSRRPPTT SSttaattuuss llooggggiinngg
|
||||
|
||||
With TLSRPT support turned on, the Postfix TLSRPT client will not only report
|
||||
an event to an invisible daily success/fail summary queue, but it will also log
|
||||
a visible record to the mail logfile.
|
||||
|
||||
Below are a few examples of logging from a Postfix SMTP client or tlsproxy
|
||||
daemon:
|
||||
|
||||
TLSRPT: status=success, domain=example.com, receiving_mx=mail.example.com
|
||||
[ipaddr]
|
||||
|
||||
TLSRPT: status=failure, domain=example.org, receiving_mx=mail.example.org
|
||||
[ipaddr],
|
||||
failure_type=starttls_not_supported
|
||||
|
||||
TLSRPT: status=failure, domain=example.net, receiving_mx=mail.example.net
|
||||
[ipaddr],
|
||||
failure_type=validation_failure, failure_reason=self-signed_certificate
|
||||
|
||||
Note: Postfix logs and reports TLSRPT status only for TLS handshakes on a new
|
||||
SMTP connection. There is no TLSRPT status logging for a reused SMTP
|
||||
connection. Such connections have Postfix SMTP client logging like this:
|
||||
|
||||
Verified TTLLSS ccoonnnneeccttiioonn rreeuusseedd to mail.example.com[ipaddr]:25:
|
||||
TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)
|
||||
|
||||
Untrusted TTLLSS ccoonnnneeccttiioonn rreeuusseedd to mail.example.com[ipaddr]:25:
|
||||
TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)
|
||||
|
||||
Postfix logs certificate verification failures with a level of detail that is
|
||||
different for a new or reused TLS session.
|
||||
|
||||
* A new TLS session is logged with certificate verification failure details:
|
||||
|
||||
TLSRPT: status=failure, domain=example.org, receiving_mx=mail.example.org
|
||||
[ipaddr],
|
||||
ffaaiilluurree__ttyyppee==vvaalliiddaattiioonn__ffaaiilluurree, ffaaiilluurree__rreeaassoonn==sseellff--ssiiggnneedd__cceerrttiiffiiccaattee
|
||||
|
||||
* A reused TLS session is indicated as shown below, and has no certificate
|
||||
verification details:
|
||||
|
||||
mail.example.org[ipaddr]:25: rree--uussiinngg sseessssiioonn with untrusted peer
|
||||
credential, look for details earlier in the log
|
||||
TLSRPT: status=failure, domain=example.org, receiving_mx=mail.example.org
|
||||
[ipaddr],
|
||||
ffaaiilluurree__ttyyppee==cceerrttiiffiiccaattee__nnoott__ttrruusstteedd
|
||||
|
||||
Some Postfix users may wonder where the difference comes from. So this is why.
|
||||
|
||||
DDeelliivveerriinngg TTLLSSRRPPTT ssuummmmaarriieess vviiaa eemmaaiill
|
||||
|
||||
RFC 8460 suggests not to enforce strict TLS security when sending daily
|
||||
success/failure summaries via email, to avoid delivery delays caused by a
|
||||
failure to enforce TLS security. Postfix currently does not have a mechanism to
|
||||
disable TLS security enforcement when submitting an email message; this section
|
||||
provides a workaround.
|
||||
|
||||
By design, TLSRPT is not a real-time notification system; it takes on average
|
||||
12 hours before a failure is reported in a daily success/failure summary. If a
|
||||
TLS-related delay of a day or more is undesirable, one could set up a transport
|
||||
map to make TLS security optional for specific TLSRPT email notification email
|
||||
addresses.
|
||||
|
||||
/etc/postfix/main.cf:
|
||||
transport_maps = hash:/etc/postfix/transport
|
||||
|
||||
/etc/postfix/transport:
|
||||
smtp-tls-report@example.com allow-plaintext:
|
||||
...
|
||||
|
||||
/etc/postfix/master.cf:
|
||||
# service name type private unpriv chroot wakeup maxproc
|
||||
command
|
||||
allow-plaintext unix - - n - - smtp
|
||||
-o smtp_tls_security_level=may
|
||||
-o smtp_tls_policy_maps=static:may
|
||||
|
||||
MMTTAA--SSTTSS SSuuppppoorrtt vviiaa ssmmttpp__ttllss__ppoolliiccyy__mmaappss
|
||||
|
||||
Postfix supports MTA-STS though an smtp_tls_policy_maps policy plugin. Postfix
|
||||
3.10 and later expect a policy 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).
|
||||
With TLSRPT support turned off, Postfix will use the ttl and policy_failure
|
||||
attributes, and will ignore the attributes that are used only for TLSRPT.
|
||||
|
||||
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
|
||||
|
||||
LLiimmiittaattiioonnss
|
||||
|
||||
The Postfix TLSRPT implementation reports at most one final TLS handshake
|
||||
status (either 'success' or 'failure') per connection. Postfix TLSRPT cannot
|
||||
report a failure and then later report a final status of 'success' for that
|
||||
same connection. The reason is that it's too complicated to filter TLS errors
|
||||
and to report error details from the TLS engine back to the SMTP protocol
|
||||
engine. It just is not how Postfix works internally.
|
||||
|
||||
The Postfix TLSRPT implementation reports only TLS handshake success or
|
||||
failure. It does not report failure to connect, or connections that break after
|
||||
a successful TLS handshake.
|
||||
|
||||
CCrreeddiittss
|
||||
|
||||
* The TLSRPT client library and report generator are implemented and
|
||||
maintained by sys4.
|
||||
* Wietse Venema implemented the integration with Postfix.
|
||||
|
@ -25,3 +25,13 @@ now also distributed with the more recent Eclipse Public License
|
||||
(EPL) 2.0. Recipients can choose to take the software under the
|
||||
license of their choice. Those who are more comfortable with the
|
||||
IPL can continue with that license.
|
||||
|
||||
[Feature 20240926]
|
||||
|
||||
Support for the TLSRPT protocol (defined in RFC 8460). With this,
|
||||
an email receiving domain can publish a policy in DNS, and request
|
||||
daily summary reports for successful and failed SMTP-over-TLS
|
||||
connections to that domain's MX hosts.
|
||||
|
||||
Postfix supports TLSRPT summaries for DANE (built-in) and MTA-STS
|
||||
(via an smtp_tls_policy_maps plugin). For details, see TLSRPT_README.
|
||||
|
@ -6,6 +6,11 @@ Wish list:
|
||||
|
||||
Disable -DSNAPSHOT and -DNONPROD in makedefs.
|
||||
|
||||
Add smtp_tlsrpt_allow_list feature (default: static:all) to limit
|
||||
the domains for which Postfix generates TLSRPT daily sumamries.
|
||||
|
||||
Add unit tests for smtp_tlsrpt.c, tlstrpd_wrapper.c, ...
|
||||
|
||||
Add tests for Message-ID extraction in the cleanup daemon.
|
||||
|
||||
When debug logging is enabled, dict_db_open() logs a newline
|
||||
|
@ -330,6 +330,7 @@ $readme_directory/STANDARD_CONFIGURATION_README:f:root:-:644
|
||||
$readme_directory/STRESS_README:f:root:-:644
|
||||
$readme_directory/TLS_LEGACY_README:f:root:-:644
|
||||
$readme_directory/TLS_README:f:root:-:644
|
||||
$readme_directory/TLSRPT_README:f:root:-:644
|
||||
$readme_directory/TUNING_README:f:root:-:644
|
||||
$readme_directory/ULTRIX_README:f:root:-:644
|
||||
$readme_directory/UUCP_README:f:root:-:644
|
||||
@ -392,6 +393,7 @@ $html_directory/STANDARD_CONFIGURATION_README.html:f:root:-:644
|
||||
$html_directory/STRESS_README.html:f:root:-:644
|
||||
$html_directory/TLS_LEGACY_README.html:f:root:-:644
|
||||
$html_directory/TLS_README.html:f:root:-:644
|
||||
$html_directory/TLSRPT_README.html:f:root:-:644
|
||||
$html_directory/TUNING_README.html:f:root:-:644
|
||||
$html_directory/ULTRIX_README.html:f:root:-:644:o
|
||||
$html_directory/UUCP_README.html:f:root:-:644
|
||||
|
410
postfix/html/TLSRPT_README.html
Normal file
410
postfix/html/TLSRPT_README.html
Normal file
@ -0,0 +1,410 @@
|
||||
<!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> Table of Contents </h2>
|
||||
|
||||
<ul>
|
||||
|
||||
<li> <a href="#intro"> Introduction </a> </li>
|
||||
<li> <a href="#building"> Building Postfix with TLSRPT support </a>
|
||||
<li> <a href="#using"> Turning on TLSRPT </a> </li>
|
||||
<li> <a href="#logging"> TLSRPT Status logging </a> </li>
|
||||
<li> <a href="#delivering"> Delivering TLSRPT summaries via email</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, and request daily
|
||||
summary reports for successful and failed SMTP over TLS connections
|
||||
to that domain's MX hosts. Support for TLSRPT was added in Postfix
|
||||
3.10. </p>
|
||||
|
||||
<p> A policy example looks like this: </p>
|
||||
|
||||
<blockquote>
|
||||
<pre>
|
||||
_smtp._tls.example.com. IN TXT "v=TLSRPTv1; rua=mailto:smtp-tls-report@example.com"
|
||||
</pre>
|
||||
</blockquote>
|
||||
|
||||
<p> Translation: email sending systems are requested to generate daily
|
||||
summaries of successful and failed SMTP over TLS connections to domain
|
||||
<tt>example.com</tt>, and to report those summaries via email to the
|
||||
specified address. Instead of <tt>mailto:</tt>, a policy may specify an
|
||||
<tt>https:</tt> destination. </p>
|
||||
|
||||
<p> The high-level diagram shows how Postfix reports summaries to
|
||||
domains that publish a TLSRPT policy.
|
||||
|
||||
<blockquote>
|
||||
|
||||
<table>
|
||||
|
||||
<tr> <td align="center" bgcolor="#f0f0ff"> Postfix SMTP and<br> TLS
|
||||
client engines </td> <td> <tt> --> </tt> </td>
|
||||
|
||||
<td align="center" bgcolor="#f0f0ff"> TLSRPT client <br> library
|
||||
</td> <td> <tt> --> </tt> </td>
|
||||
|
||||
<td align="center" bgcolor="#f0f0ff"> TLSRPT summary <br> generator
|
||||
</td> <td> <tt> --> </tt> </td>
|
||||
|
||||
<td align="center" bgcolor="#f0f0ff"> Email or HTTP <br> delivery
|
||||
</td> </tr>
|
||||
|
||||
</table>
|
||||
|
||||
</blockquote>
|
||||
|
||||
<p> When Postfix TLSRPT support is enabled (with "<a href="postconf.5.html#smtp_tlsrpt_enable">smtp_tlsrpt_enable</a>
|
||||
= yes"): </p>
|
||||
|
||||
<ul>
|
||||
|
||||
<li> <p> The Postfix SMTP and TLS client engines will generate a
|
||||
"success" or "failure" event for each TLS handshake, </p>
|
||||
|
||||
<li> <p> They will pass those events to an in-process TLSRPT client
|
||||
library that sends data over a local socket to </p>
|
||||
|
||||
<li> <p> A TLSRPT report generator that produces daily summary
|
||||
reports. </p>
|
||||
|
||||
</ul>
|
||||
|
||||
<p> The TLSRPT client library and report generator are maintained
|
||||
by sys4. </p>
|
||||
|
||||
<p> 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 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 <tt>-DUSE_TLSRPT</tt> (to build with TLSRPT
|
||||
support), and <tt>-I</tt> (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
|
||||
settings, then simply append the above settings to the existing CCARGS
|
||||
or AUXLIBS values. </p>
|
||||
|
||||
<blockquote>
|
||||
<pre>
|
||||
make -f Makefile.init makefiles \
|
||||
"CCARGS=<i>existing settings...</i> -DUSE_TLSRPT -I/usr/local/include" \
|
||||
"AUXLIBS=<i>existing settings...</i> -L/usr/local/lib -ltlsrpt"
|
||||
</pre>
|
||||
</blockquote>
|
||||
|
||||
</blockquote>
|
||||
|
||||
<h2> <a name="using"> Turning on 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>
|
||||
|
||||
<blockquote>
|
||||
|
||||
<p> Note: the recommended socket location is still to be determined.
|
||||
A good socket location would be under the Postfix queue directory,
|
||||
for example: "<a href="postconf.5.html#smtp_tlsrpt_socket_name">smtp_tlsrpt_socket_name</a> = run/tlsrpt/tlsrpt.sock".
|
||||
The advantage of using a relative name is that it will work equally
|
||||
well whether or not Postfix chroot is turned on. </p>
|
||||
|
||||
</blockquote>
|
||||
|
||||
<p> Do not specify a location under a directory such as <tt>private</tt>
|
||||
or <tt>public</tt> that is already used by Postfix programs. Only Postfix
|
||||
programs should create sockets there. </p>
|
||||
|
||||
<h2> <a name="logging"> TLSRPT Status logging </a> </h2>
|
||||
|
||||
<p> With TLSRPT support turned on, the Postfix TLSRPT client will
|
||||
not only report an event to an invisible daily success/fail summary
|
||||
queue, but it will also log a visible record to the mail logfile.
|
||||
</p>
|
||||
|
||||
<p> Below are a few examples of logging from a Postfix SMTP client
|
||||
or tlsproxy daemon: </p>
|
||||
|
||||
<blockquote>
|
||||
<pre>
|
||||
TLSRPT: status=success, domain=example.com, receiving_mx=mail.example.com[ipaddr]
|
||||
|
||||
TLSRPT: status=failure, domain=example.org, receiving_mx=mail.example.org[ipaddr],
|
||||
failure_type=starttls_not_supported
|
||||
|
||||
TLSRPT: status=failure, domain=example.net, receiving_mx=mail.example.net[ipaddr],
|
||||
failure_type=validation_failure, failure_reason=self-signed_certificate
|
||||
</pre>
|
||||
</blockquote>
|
||||
|
||||
<p> Note: Postfix logs and reports TLSRPT status only for TLS
|
||||
handshakes on a new SMTP connection. There is no TLSRPT status
|
||||
logging for a reused SMTP connection. Such connections have
|
||||
Postfix SMTP client logging like this: </p>
|
||||
|
||||
<blockquote>
|
||||
<pre>
|
||||
Verified <b>TLS connection reused</b> to mail.example.com[ipaddr]:25:
|
||||
TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)
|
||||
|
||||
Untrusted <b>TLS connection reused</b> to mail.example.com[ipaddr]:25:
|
||||
TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)
|
||||
</pre>
|
||||
</blockquote>
|
||||
|
||||
<p> Postfix logs certificate verification failures with a level of
|
||||
detail that is different for a new or reused TLS session. </p>
|
||||
|
||||
<ul>
|
||||
|
||||
<li> <p> A new TLS session is logged with certificate verification
|
||||
failure details: </p>
|
||||
|
||||
<pre>
|
||||
TLSRPT: status=failure, domain=example.org, receiving_mx=mail.example.org[ipaddr],
|
||||
<b>failure_type=validation_failure</b>, <b>failure_reason=self-signed_certificate</b>
|
||||
</pre>
|
||||
|
||||
<li> <p> A reused TLS session is indicated as shown below, and has
|
||||
no certificate verification details: </p>
|
||||
|
||||
<pre>
|
||||
mail.example.org[ipaddr]:25: <b>re-using session</b> with untrusted peer
|
||||
credential, look for details earlier in the log
|
||||
TLSRPT: status=failure, domain=example.org, receiving_mx=mail.example.org[ipaddr],
|
||||
<b>failure_type=certificate_not_trusted</b>
|
||||
</pre>
|
||||
|
||||
</ul>
|
||||
|
||||
<p> Some Postfix users may wonder where the difference comes from.
|
||||
So this is why. </p>
|
||||
|
||||
<h2> <a name="delivering"> Delivering TLSRPT summaries via email</a> </h2>
|
||||
|
||||
<p> <a href="https://tools.ietf.org/html/rfc8460">RFC 8460</a> suggests not to enforce strict TLS security when sending
|
||||
daily success/failure summaries via email, to avoid delivery delays
|
||||
caused by a failure to enforce TLS security. Postfix currently does
|
||||
not have a mechanism to disable TLS security enforcement when
|
||||
submitting an email message; this section provides a workaround. </p>
|
||||
|
||||
<p> By design, TLSRPT is not a real-time notification system; it
|
||||
takes on average 12 hours before a failure is reported in a daily
|
||||
success/failure summary. If a TLS-related delay of a day or more
|
||||
is undesirable, one could set up a transport map to make TLS security
|
||||
optional for specific TLSRPT email notification email addresses.
|
||||
</p>
|
||||
|
||||
<blockquote>
|
||||
<pre>
|
||||
/etc/postfix/<a href="postconf.5.html">main.cf</a>:
|
||||
<a href="postconf.5.html#transport_maps">transport_maps</a> = <a href="DATABASE_README.html#types">hash</a>:/etc/postfix/transport
|
||||
 
|
||||
/etc/postfix/transport:
|
||||
smtp-tls-report@example.com allow-plaintext:
|
||||
...
|
||||
 
|
||||
/etc/postfix/<a href="master.5.html">master.cf</a>:
|
||||
# service name type private unpriv chroot wakeup maxproc command
|
||||
allow-plaintext unix - - n - - smtp
|
||||
-o <a href="postconf.5.html#smtp_tls_security_level">smtp_tls_security_level</a>=may
|
||||
-o <a href="postconf.5.html#smtp_tls_policy_maps">smtp_tls_policy_maps</a>=<a href="DATABASE_README.html#types">static</a>:may
|
||||
</pre>
|
||||
</blockquote>
|
||||
|
||||
<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 3.10 and later expect a policy response with
|
||||
the usual security level and matching requirements, plus any
|
||||
applicable name=value attributes described below. Specify <tt>{
|
||||
name = value }</tt> 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). With TLSRPT support turned off, Postfix
|
||||
will use the <tt>ttl</tt> and <tt>policy_failure</tt> attributes,
|
||||
and will ignore the attributes that are used only for TLSRPT. </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 Postfix TLSRPT implementation reports at most one final TLS
|
||||
handshake status (either 'success' or 'failure') per connection.
|
||||
Postfix TLSRPT cannot report a failure and then later report a final
|
||||
status of 'success' for that same connection. The reason is that
|
||||
it's too complicated to filter TLS errors and to report error details
|
||||
from the TLS engine back to the SMTP protocol engine. It just is
|
||||
not how Postfix works internally. </p>
|
||||
|
||||
<p> The Postfix TLSRPT implementation reports only TLS handshake
|
||||
success or failure. It does not report failure to connect, or
|
||||
connections that break after a successful TLS handshake. </p>
|
||||
|
||||
<h2> <a name="credits"> Credits </a> </h2>
|
||||
|
||||
<ul>
|
||||
|
||||
<li> The TLSRPT client library and report generator are implemented
|
||||
and maintained by sys4. </li>
|
||||
|
||||
<li> Wietse Venema implemented the integration with Postfix.
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
@ -45,6 +45,8 @@ configuration examples </a>
|
||||
|
||||
<li> <a href="FORWARD_SECRECY_README.html"> TLS Forward Secrecy </a>
|
||||
|
||||
<li> <a href="TLSRPT_README.html"> TLSRPT Protocol Support </a>
|
||||
|
||||
<li> <a href="IPV6_README.html"> IP Version 6 Support </a>
|
||||
|
||||
<li> <a href="SMTPUTF8_README.html"> SMTPUTF8 Support </a>
|
||||
|
@ -746,41 +746,48 @@ SMTP,(LMTP) SMTP,(LMTP)
|
||||
Request that remote SMTP servers send an <a href="https://tools.ietf.org/html/rfc7250">RFC7250</a> raw public key
|
||||
instead of an X.509 certificate.
|
||||
|
||||
<b><a href="postconf.5.html#smtp_tlsrpt_enable">smtp_tlsrpt_enable</a> (no)</b>
|
||||
Enable support for <a href="https://tools.ietf.org/html/rfc8460">RFC 8460</a> TLSRPT notifications.
|
||||
|
||||
<b><a href="postconf.5.html#smtp_tlsrpt_socket_name">smtp_tlsrpt_socket_name</a> (empty)</b>
|
||||
The pathname of a UNIX-domain datagram socket that is managed by
|
||||
a local TLSRPT reporting service.
|
||||
|
||||
<b>OBSOLETE STARTTLS CONTROLS</b>
|
||||
The following configuration parameters exist for compatibility with
|
||||
Postfix versions before 2.3. Support for these will be removed in a
|
||||
The following configuration parameters exist for compatibility with
|
||||
Postfix versions before 2.3. Support for these will be removed in a
|
||||
future release.
|
||||
|
||||
<b><a href="postconf.5.html#smtp_use_tls">smtp_use_tls</a> (no)</b>
|
||||
Opportunistic mode: use TLS when a remote SMTP server announces
|
||||
Opportunistic mode: use TLS when a remote SMTP server announces
|
||||
STARTTLS support, otherwise send the mail in the clear.
|
||||
|
||||
<b><a href="postconf.5.html#smtp_enforce_tls">smtp_enforce_tls</a> (no)</b>
|
||||
Enforcement mode: require that remote SMTP servers use TLS
|
||||
Enforcement mode: require that remote SMTP servers use TLS
|
||||
encryption, and never send mail in the clear.
|
||||
|
||||
<b><a href="postconf.5.html#smtp_tls_enforce_peername">smtp_tls_enforce_peername</a> (yes)</b>
|
||||
With mandatory TLS encryption, require that the remote SMTP
|
||||
server hostname matches the information in the remote SMTP
|
||||
With mandatory TLS encryption, require that the remote SMTP
|
||||
server hostname matches the information in the remote SMTP
|
||||
server certificate.
|
||||
|
||||
<b><a href="postconf.5.html#smtp_tls_per_site">smtp_tls_per_site</a> (empty)</b>
|
||||
Optional lookup tables with the Postfix SMTP client TLS usage
|
||||
policy by next-hop destination and by remote SMTP server host-
|
||||
Optional lookup tables with the Postfix SMTP client TLS usage
|
||||
policy by next-hop destination and by remote SMTP server host-
|
||||
name.
|
||||
|
||||
<b><a href="postconf.5.html#smtp_tls_cipherlist">smtp_tls_cipherlist</a> (empty)</b>
|
||||
Obsolete Postfix < 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>
|
||||
@ -792,19 +799,19 @@ SMTP,(LMTP) SMTP,(LMTP)
|
||||
mand, and for receiving the remote SMTP server response.
|
||||
|
||||
<b><a href="postconf.5.html#smtp_mail_timeout">smtp_mail_timeout</a> (300s)</b>
|
||||
The Postfix SMTP client time limit for sending the MAIL FROM
|
||||
The Postfix SMTP client time limit for sending the MAIL FROM
|
||||
command, and for receiving the remote SMTP server response.
|
||||
|
||||
<b><a href="postconf.5.html#smtp_rcpt_timeout">smtp_rcpt_timeout</a> (300s)</b>
|
||||
The Postfix SMTP client time limit for sending the SMTP RCPT TO
|
||||
The Postfix SMTP client time limit for sending the SMTP RCPT TO
|
||||
command, and for receiving the remote SMTP server response.
|
||||
|
||||
<b><a href="postconf.5.html#smtp_data_init_timeout">smtp_data_init_timeout</a> (120s)</b>
|
||||
The Postfix SMTP client time limit for sending the SMTP DATA
|
||||
The Postfix SMTP client time limit for sending the SMTP DATA
|
||||
command, and for receiving the remote SMTP server response.
|
||||
|
||||
<b><a href="postconf.5.html#smtp_data_xfer_timeout">smtp_data_xfer_timeout</a> (180s)</b>
|
||||
The Postfix SMTP client time limit for sending the SMTP message
|
||||
The Postfix SMTP client time limit for sending the SMTP message
|
||||
content.
|
||||
|
||||
<b><a href="postconf.5.html#smtp_data_done_timeout">smtp_data_done_timeout</a> (600s)</b>
|
||||
@ -818,13 +825,13 @@ SMTP,(LMTP) SMTP,(LMTP)
|
||||
Available in Postfix version 2.1 and later:
|
||||
|
||||
<b><a href="postconf.5.html#smtp_mx_address_limit">smtp_mx_address_limit</a> (5)</b>
|
||||
The maximal number of MX (mail exchanger) IP addresses that can
|
||||
result from Postfix SMTP client mail exchanger lookups, or zero
|
||||
The maximal number of MX (mail exchanger) IP addresses that can
|
||||
result from Postfix SMTP client mail exchanger lookups, or zero
|
||||
(no limit).
|
||||
|
||||
<b><a href="postconf.5.html#smtp_mx_session_limit">smtp_mx_session_limit</a> (2)</b>
|
||||
The maximal number of SMTP sessions per delivery request before
|
||||
the Postfix SMTP client gives up or delivers to a fall-back
|
||||
The maximal number of SMTP sessions per delivery request before
|
||||
the Postfix SMTP client gives up or delivers to a fall-back
|
||||
<a href="postconf.5.html#relayhost">relay host</a>, or zero (no limit).
|
||||
|
||||
<b><a href="postconf.5.html#smtp_rset_timeout">smtp_rset_timeout</a> (20s)</b>
|
||||
@ -834,17 +841,17 @@ SMTP,(LMTP) SMTP,(LMTP)
|
||||
Available in Postfix version 2.2 and earlier:
|
||||
|
||||
<b><a href="postconf.5.html#lmtp_cache_connection">lmtp_cache_connection</a> (yes)</b>
|
||||
Keep Postfix LMTP client connections open for up to $<a href="postconf.5.html#max_idle">max_idle</a>
|
||||
Keep Postfix LMTP client connections open for up to $<a href="postconf.5.html#max_idle">max_idle</a>
|
||||
seconds.
|
||||
|
||||
Available in Postfix version 2.2 and later:
|
||||
|
||||
<b><a href="postconf.5.html#smtp_connection_cache_destinations">smtp_connection_cache_destinations</a> (empty)</b>
|
||||
Permanently enable SMTP connection caching for the specified
|
||||
Permanently enable SMTP connection caching for the specified
|
||||
destinations.
|
||||
|
||||
<b><a href="postconf.5.html#smtp_connection_cache_on_demand">smtp_connection_cache_on_demand</a> (yes)</b>
|
||||
Temporarily enable SMTP connection caching while a destination
|
||||
Temporarily enable SMTP connection caching while a destination
|
||||
has a high volume of mail in the <a href="QSHAPE_README.html#active_queue">active queue</a>.
|
||||
|
||||
<b><a href="postconf.5.html#smtp_connection_reuse_time_limit">smtp_connection_reuse_time_limit</a> (300s)</b>
|
||||
@ -858,23 +865,23 @@ SMTP,(LMTP) SMTP,(LMTP)
|
||||
Available in Postfix version 2.3 and later:
|
||||
|
||||
<b><a href="postconf.5.html#connection_cache_protocol_timeout">connection_cache_protocol_timeout</a> (5s)</b>
|
||||
Time limit for connection cache connect, send or receive opera-
|
||||
Time limit for connection cache connect, send or receive opera-
|
||||
tions.
|
||||
|
||||
Available in Postfix version 2.9 - 3.6:
|
||||
|
||||
<b><a href="postconf.5.html#smtp_per_record_deadline">smtp_per_record_deadline</a> (no)</b>
|
||||
Change the behavior of the smtp_*_timeout time limits, from a
|
||||
time limit per read or write system call, to a time limit to
|
||||
send or receive a complete record (an SMTP command line, SMTP
|
||||
response line, SMTP message content line, or TLS protocol mes-
|
||||
Change the behavior of the smtp_*_timeout time limits, from a
|
||||
time limit per read or write system call, to a time limit to
|
||||
send or receive a complete record (an SMTP command line, SMTP
|
||||
response line, SMTP message content line, or TLS protocol mes-
|
||||
sage).
|
||||
|
||||
Available in Postfix version 2.11 and later:
|
||||
|
||||
<b><a href="postconf.5.html#smtp_connection_reuse_count_limit">smtp_connection_reuse_count_limit</a> (0)</b>
|
||||
When SMTP connection caching is enabled, the number of times
|
||||
that an SMTP session may be reused before it is closed, or zero
|
||||
When SMTP connection caching is enabled, the number of times
|
||||
that an SMTP session may be reused before it is closed, or zero
|
||||
(no limit).
|
||||
|
||||
Available in Postfix version 3.4 and later:
|
||||
@ -885,13 +892,13 @@ SMTP,(LMTP) SMTP,(LMTP)
|
||||
Available in Postfix version 3.7 and later:
|
||||
|
||||
<b><a href="postconf.5.html#smtp_per_request_deadline">smtp_per_request_deadline</a> (no)</b>
|
||||
Change the behavior of the smtp_*_timeout time limits, from a
|
||||
time limit per plaintext or TLS read or write call, to a com-
|
||||
bined time limit for sending a complete SMTP request and for
|
||||
Change the behavior of the smtp_*_timeout time limits, from a
|
||||
time limit per plaintext or TLS read or write call, to a com-
|
||||
bined time limit for sending a complete SMTP request and for
|
||||
receiving a complete SMTP response.
|
||||
|
||||
<b><a href="postconf.5.html#smtp_min_data_rate">smtp_min_data_rate</a> (500)</b>
|
||||
The minimum plaintext data transfer rate in bytes/second for
|
||||
The minimum plaintext data transfer rate in bytes/second for
|
||||
DATA requests, when deadlines are enabled with
|
||||
<a href="postconf.5.html#smtp_per_request_deadline">smtp_per_request_deadline</a>.
|
||||
|
||||
@ -899,54 +906,54 @@ SMTP,(LMTP) SMTP,(LMTP)
|
||||
|
||||
<b><a href="postconf.5.html#transport_destination_concurrency_limit">transport_destination_concurrency_limit</a> ($<a href="postconf.5.html#default_destination_concurrency_limit">default_destination_concur</a>-</b>
|
||||
<b><a href="postconf.5.html#default_destination_concurrency_limit">rency_limit</a>)</b>
|
||||
A transport-specific override for the <a href="postconf.5.html#default_destination_concurrency_limit">default_destination_con</a>-
|
||||
A transport-specific override for the <a href="postconf.5.html#default_destination_concurrency_limit">default_destination_con</a>-
|
||||
<a href="postconf.5.html#default_destination_concurrency_limit">currency_limit</a> parameter value, where <i>transport</i> is the <a href="master.5.html">master.cf</a>
|
||||
name of the message delivery transport.
|
||||
|
||||
<b><a href="postconf.5.html#transport_destination_recipient_limit">transport_destination_recipient_limit</a> ($<a href="postconf.5.html#default_destination_recipient_limit">default_destination_recipi</a>-</b>
|
||||
<b><a href="postconf.5.html#default_destination_recipient_limit">ent_limit</a>)</b>
|
||||
A transport-specific override for the <a href="postconf.5.html#default_destination_recipient_limit">default_destination_recip</a>-
|
||||
<a href="postconf.5.html#default_destination_recipient_limit">ient_limit</a> parameter value, where <i>transport</i> is the <a href="master.5.html">master.cf</a>
|
||||
<a href="postconf.5.html#default_destination_recipient_limit">ient_limit</a> parameter value, where <i>transport</i> is the <a href="master.5.html">master.cf</a>
|
||||
name of the message delivery transport.
|
||||
|
||||
<b>SMTPUTF8 CONTROLS</b>
|
||||
Preliminary SMTPUTF8 support is introduced with Postfix 3.0.
|
||||
|
||||
<b><a href="postconf.5.html#smtputf8_enable">smtputf8_enable</a> (yes)</b>
|
||||
Enable preliminary SMTPUTF8 support for the protocols described
|
||||
Enable preliminary SMTPUTF8 support for the protocols described
|
||||
in <a href="https://tools.ietf.org/html/rfc6531">RFC 6531</a>, <a href="https://tools.ietf.org/html/rfc6532">RFC 6532</a>, and <a href="https://tools.ietf.org/html/rfc6533">RFC 6533</a>.
|
||||
|
||||
<b><a href="postconf.5.html#smtputf8_autodetect_classes">smtputf8_autodetect_classes</a> (sendmail, verify)</b>
|
||||
Detect that a message requires SMTPUTF8 support for the speci-
|
||||
Detect that a message requires SMTPUTF8 support for the speci-
|
||||
fied mail origin classes.
|
||||
|
||||
Available in Postfix version 3.2 and later:
|
||||
|
||||
<b><a href="postconf.5.html#enable_idna2003_compatibility">enable_idna2003_compatibility</a> (no)</b>
|
||||
Enable 'transitional' compatibility between IDNA2003 and
|
||||
IDNA2008, when converting UTF-8 domain names to/from the ASCII
|
||||
Enable 'transitional' compatibility between IDNA2003 and
|
||||
IDNA2008, when converting UTF-8 domain names to/from the ASCII
|
||||
form that is used for DNS lookups.
|
||||
|
||||
<b>TROUBLE SHOOTING CONTROLS</b>
|
||||
<b><a href="postconf.5.html#debug_peer_level">debug_peer_level</a> (2)</b>
|
||||
The increment in verbose logging level when a nexthop destina-
|
||||
tion, remote client or server name or network address matches a
|
||||
The increment in verbose logging level when a nexthop destina-
|
||||
tion, remote client or server name or network address matches a
|
||||
pattern given with the <a href="postconf.5.html#debug_peer_list">debug_peer_list</a> parameter.
|
||||
|
||||
<b><a href="postconf.5.html#debug_peer_list">debug_peer_list</a> (empty)</b>
|
||||
Optional list of nexthop destination, remote client or server
|
||||
name or network address patterns that, if matched, cause the
|
||||
verbose logging level to increase by the amount specified in
|
||||
Optional list of nexthop destination, remote client or server
|
||||
name or network address patterns that, if matched, cause the
|
||||
verbose logging level to increase by the amount specified in
|
||||
$<a href="postconf.5.html#debug_peer_level">debug_peer_level</a>.
|
||||
|
||||
<b><a href="postconf.5.html#error_notice_recipient">error_notice_recipient</a> (postmaster)</b>
|
||||
The recipient of postmaster notifications about mail delivery
|
||||
The recipient of postmaster notifications about mail delivery
|
||||
problems that are caused by policy, resource, software or proto-
|
||||
col errors.
|
||||
|
||||
<b><a href="postconf.5.html#internal_mail_filter_classes">internal_mail_filter_classes</a> (empty)</b>
|
||||
What categories of Postfix-generated mail are subject to
|
||||
before-queue content inspection by <a href="postconf.5.html#non_smtpd_milters">non_smtpd_milters</a>,
|
||||
What categories of Postfix-generated mail are subject to
|
||||
before-queue content inspection by <a href="postconf.5.html#non_smtpd_milters">non_smtpd_milters</a>,
|
||||
<a href="postconf.5.html#header_checks">header_checks</a> and <a href="postconf.5.html#body_checks">body_checks</a>.
|
||||
|
||||
<b><a href="postconf.5.html#notify_classes">notify_classes</a> (resource, software)</b>
|
||||
@ -954,46 +961,46 @@ SMTP,(LMTP) SMTP,(LMTP)
|
||||
|
||||
<b>MISCELLANEOUS CONTROLS</b>
|
||||
<b><a href="postconf.5.html#best_mx_transport">best_mx_transport</a> (empty)</b>
|
||||
Where the Postfix SMTP client should deliver mail when it
|
||||
Where the Postfix SMTP client should deliver mail when it
|
||||
detects a "mail loops back to myself" error condition.
|
||||
|
||||
<b><a href="postconf.5.html#config_directory">config_directory</a> (see 'postconf -d' output)</b>
|
||||
The default location of the Postfix <a href="postconf.5.html">main.cf</a> and <a href="master.5.html">master.cf</a> con-
|
||||
The default location of the Postfix <a href="postconf.5.html">main.cf</a> and <a href="master.5.html">master.cf</a> con-
|
||||
figuration files.
|
||||
|
||||
<b><a href="postconf.5.html#daemon_timeout">daemon_timeout</a> (18000s)</b>
|
||||
How much time a Postfix daemon process may take to handle a
|
||||
How much time a Postfix daemon process may take to handle a
|
||||
request before it is terminated by a built-in watchdog timer.
|
||||
|
||||
<b><a href="postconf.5.html#delay_logging_resolution_limit">delay_logging_resolution_limit</a> (2)</b>
|
||||
The maximal number of digits after the decimal point when log-
|
||||
The maximal number of digits after the decimal point when log-
|
||||
ging sub-second delay values.
|
||||
|
||||
<b><a href="postconf.5.html#disable_dns_lookups">disable_dns_lookups</a> (no)</b>
|
||||
Disable DNS lookups in the Postfix SMTP and LMTP clients.
|
||||
|
||||
<b><a href="postconf.5.html#inet_interfaces">inet_interfaces</a> (all)</b>
|
||||
The local network interface addresses that this mail system
|
||||
The local network interface addresses that this mail system
|
||||
receives mail on.
|
||||
|
||||
<b><a href="postconf.5.html#inet_protocols">inet_protocols</a> (see 'postconf -d' output)</b>
|
||||
The Internet protocols Postfix will attempt to use when making
|
||||
The Internet protocols Postfix will attempt to use when making
|
||||
or accepting connections.
|
||||
|
||||
<b><a href="postconf.5.html#ipc_timeout">ipc_timeout</a> (3600s)</b>
|
||||
The time limit for sending or receiving information over an
|
||||
The time limit for sending or receiving information over an
|
||||
internal communication channel.
|
||||
|
||||
<b><a href="postconf.5.html#lmtp_assume_final">lmtp_assume_final</a> (no)</b>
|
||||
When a remote LMTP server announces no DSN support, assume that
|
||||
the server performs final delivery, and send "delivered" deliv-
|
||||
When a remote LMTP server announces no DSN support, assume that
|
||||
the server performs final delivery, and send "delivered" deliv-
|
||||
ery status notifications instead of "relayed".
|
||||
|
||||
<b><a href="postconf.5.html#lmtp_tcp_port">lmtp_tcp_port</a> (24)</b>
|
||||
The default TCP port that the Postfix LMTP client connects to.
|
||||
|
||||
<b><a href="postconf.5.html#max_idle">max_idle</a> (100s)</b>
|
||||
The maximum amount of time that an idle Postfix daemon process
|
||||
The maximum amount of time that an idle Postfix daemon process
|
||||
waits for an incoming connection before terminating voluntarily.
|
||||
|
||||
<b><a href="postconf.5.html#max_use">max_use</a> (100)</b>
|
||||
@ -1007,21 +1014,21 @@ SMTP,(LMTP) SMTP,(LMTP)
|
||||
The process name of a Postfix command or daemon process.
|
||||
|
||||
<b><a href="postconf.5.html#proxy_interfaces">proxy_interfaces</a> (empty)</b>
|
||||
The remote network interface addresses that this mail system
|
||||
receives mail on by way of a proxy or network address transla-
|
||||
The remote network interface addresses that this mail system
|
||||
receives mail on by way of a proxy or network address transla-
|
||||
tion unit.
|
||||
|
||||
<b><a href="postconf.5.html#smtp_address_preference">smtp_address_preference</a> (any)</b>
|
||||
The address type ("ipv6", "ipv4" or "any") that the Postfix SMTP
|
||||
client will try first, when a destination has IPv6 and IPv4
|
||||
client will try first, when a destination has IPv6 and IPv4
|
||||
addresses with equal MX preference.
|
||||
|
||||
<b><a href="postconf.5.html#smtp_bind_address">smtp_bind_address</a> (empty)</b>
|
||||
An optional numerical network address that the Postfix SMTP
|
||||
An optional numerical network address that the Postfix SMTP
|
||||
client should bind to when making an IPv4 connection.
|
||||
|
||||
<b><a href="postconf.5.html#smtp_bind_address6">smtp_bind_address6</a> (empty)</b>
|
||||
An optional numerical network address that the Postfix SMTP
|
||||
An optional numerical network address that the Postfix SMTP
|
||||
client should bind to when making an IPv6 connection.
|
||||
|
||||
<b><a href="postconf.5.html#smtp_helo_name">smtp_helo_name</a> ($<a href="postconf.5.html#myhostname">myhostname</a>)</b>
|
||||
@ -1041,7 +1048,7 @@ SMTP,(LMTP) SMTP,(LMTP)
|
||||
The syslog facility of Postfix logging.
|
||||
|
||||
<b><a href="postconf.5.html#syslog_name">syslog_name</a> (see 'postconf -d' output)</b>
|
||||
A prefix that is prepended to the process name in syslog
|
||||
A prefix that is prepended to the process name in syslog
|
||||
records, so that, for example, "smtpd" becomes "prefix/smtpd".
|
||||
|
||||
Available with Postfix 2.2 and earlier:
|
||||
@ -1053,14 +1060,14 @@ SMTP,(LMTP) SMTP,(LMTP)
|
||||
Available with Postfix 2.3 and later:
|
||||
|
||||
<b><a href="postconf.5.html#smtp_fallback_relay">smtp_fallback_relay</a> ($<a href="postconf.5.html#fallback_relay">fallback_relay</a>)</b>
|
||||
Optional list of relay destinations that will be used when an
|
||||
SMTP destination is not found, or when delivery fails due to a
|
||||
Optional list of relay destinations that will be used when an
|
||||
SMTP destination is not found, or when delivery fails due to a
|
||||
non-permanent error.
|
||||
|
||||
Available with Postfix 3.0 and later:
|
||||
|
||||
<b><a href="postconf.5.html#smtp_address_verify_target">smtp_address_verify_target</a> (rcpt)</b>
|
||||
In the context of email address verification, the SMTP protocol
|
||||
In the context of email address verification, the SMTP protocol
|
||||
stage that determines whether an email address is deliverable.
|
||||
|
||||
Available with Postfix 3.1 and later:
|
||||
@ -1082,7 +1089,7 @@ SMTP,(LMTP) SMTP,(LMTP)
|
||||
Available in Postfix 3.7 and later:
|
||||
|
||||
<b><a href="postconf.5.html#smtp_bind_address_enforce">smtp_bind_address_enforce</a> (no)</b>
|
||||
Defer delivery when the Postfix SMTP client cannot apply the
|
||||
Defer delivery when the Postfix SMTP client cannot apply the
|
||||
<a href="postconf.5.html#smtp_bind_address">smtp_bind_address</a> or <a href="postconf.5.html#smtp_bind_address6">smtp_bind_address6</a> setting.
|
||||
|
||||
<b>SEE ALSO</b>
|
||||
|
@ -43,6 +43,8 @@ POSTCAT(1) POSTCAT(1)
|
||||
|
||||
<b>-f</b> Prepend the file name to each output line.
|
||||
|
||||
This feature is available in Postfix 3.10 and later.
|
||||
|
||||
<b>-h</b> Show message header content. The <b>-h</b> option produces output from
|
||||
the beginning of the message up to, but not including, the first
|
||||
non-header line.
|
||||
|
@ -14800,6 +14800,33 @@ Postfix versions. </p>
|
||||
<p> This feature is available in Postfix 3.0 and later. </p>
|
||||
|
||||
|
||||
</DD>
|
||||
|
||||
<DT><b><a name="smtp_tlsrpt_enable">smtp_tlsrpt_enable</a>
|
||||
(default: no)</b></DT><DD>
|
||||
|
||||
<p> Enable support for <a href="https://tools.ietf.org/html/rfc8460">RFC 8460</a> TLSRPT notifications. A mail receiving
|
||||
domain can publish a TLSRPT policy in DNS, to request periodic
|
||||
summaries of successful and failed SMTP over TLS connections to
|
||||
their mail servers. This feature requires that Postfix is built
|
||||
with a TLSRPT supporting library. </p>
|
||||
|
||||
<p> This feature is available in Postfix ≥ 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>
|
||||
|
@ -746,41 +746,48 @@ SMTP,(LMTP) SMTP,(LMTP)
|
||||
Request that remote SMTP servers send an <a href="https://tools.ietf.org/html/rfc7250">RFC7250</a> raw public key
|
||||
instead of an X.509 certificate.
|
||||
|
||||
<b><a href="postconf.5.html#smtp_tlsrpt_enable">smtp_tlsrpt_enable</a> (no)</b>
|
||||
Enable support for <a href="https://tools.ietf.org/html/rfc8460">RFC 8460</a> TLSRPT notifications.
|
||||
|
||||
<b><a href="postconf.5.html#smtp_tlsrpt_socket_name">smtp_tlsrpt_socket_name</a> (empty)</b>
|
||||
The pathname of a UNIX-domain datagram socket that is managed by
|
||||
a local TLSRPT reporting service.
|
||||
|
||||
<b>OBSOLETE STARTTLS CONTROLS</b>
|
||||
The following configuration parameters exist for compatibility with
|
||||
Postfix versions before 2.3. Support for these will be removed in a
|
||||
The following configuration parameters exist for compatibility with
|
||||
Postfix versions before 2.3. Support for these will be removed in a
|
||||
future release.
|
||||
|
||||
<b><a href="postconf.5.html#smtp_use_tls">smtp_use_tls</a> (no)</b>
|
||||
Opportunistic mode: use TLS when a remote SMTP server announces
|
||||
Opportunistic mode: use TLS when a remote SMTP server announces
|
||||
STARTTLS support, otherwise send the mail in the clear.
|
||||
|
||||
<b><a href="postconf.5.html#smtp_enforce_tls">smtp_enforce_tls</a> (no)</b>
|
||||
Enforcement mode: require that remote SMTP servers use TLS
|
||||
Enforcement mode: require that remote SMTP servers use TLS
|
||||
encryption, and never send mail in the clear.
|
||||
|
||||
<b><a href="postconf.5.html#smtp_tls_enforce_peername">smtp_tls_enforce_peername</a> (yes)</b>
|
||||
With mandatory TLS encryption, require that the remote SMTP
|
||||
server hostname matches the information in the remote SMTP
|
||||
With mandatory TLS encryption, require that the remote SMTP
|
||||
server hostname matches the information in the remote SMTP
|
||||
server certificate.
|
||||
|
||||
<b><a href="postconf.5.html#smtp_tls_per_site">smtp_tls_per_site</a> (empty)</b>
|
||||
Optional lookup tables with the Postfix SMTP client TLS usage
|
||||
policy by next-hop destination and by remote SMTP server host-
|
||||
Optional lookup tables with the Postfix SMTP client TLS usage
|
||||
policy by next-hop destination and by remote SMTP server host-
|
||||
name.
|
||||
|
||||
<b><a href="postconf.5.html#smtp_tls_cipherlist">smtp_tls_cipherlist</a> (empty)</b>
|
||||
Obsolete Postfix < 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>
|
||||
@ -792,19 +799,19 @@ SMTP,(LMTP) SMTP,(LMTP)
|
||||
mand, and for receiving the remote SMTP server response.
|
||||
|
||||
<b><a href="postconf.5.html#smtp_mail_timeout">smtp_mail_timeout</a> (300s)</b>
|
||||
The Postfix SMTP client time limit for sending the MAIL FROM
|
||||
The Postfix SMTP client time limit for sending the MAIL FROM
|
||||
command, and for receiving the remote SMTP server response.
|
||||
|
||||
<b><a href="postconf.5.html#smtp_rcpt_timeout">smtp_rcpt_timeout</a> (300s)</b>
|
||||
The Postfix SMTP client time limit for sending the SMTP RCPT TO
|
||||
The Postfix SMTP client time limit for sending the SMTP RCPT TO
|
||||
command, and for receiving the remote SMTP server response.
|
||||
|
||||
<b><a href="postconf.5.html#smtp_data_init_timeout">smtp_data_init_timeout</a> (120s)</b>
|
||||
The Postfix SMTP client time limit for sending the SMTP DATA
|
||||
The Postfix SMTP client time limit for sending the SMTP DATA
|
||||
command, and for receiving the remote SMTP server response.
|
||||
|
||||
<b><a href="postconf.5.html#smtp_data_xfer_timeout">smtp_data_xfer_timeout</a> (180s)</b>
|
||||
The Postfix SMTP client time limit for sending the SMTP message
|
||||
The Postfix SMTP client time limit for sending the SMTP message
|
||||
content.
|
||||
|
||||
<b><a href="postconf.5.html#smtp_data_done_timeout">smtp_data_done_timeout</a> (600s)</b>
|
||||
@ -818,13 +825,13 @@ SMTP,(LMTP) SMTP,(LMTP)
|
||||
Available in Postfix version 2.1 and later:
|
||||
|
||||
<b><a href="postconf.5.html#smtp_mx_address_limit">smtp_mx_address_limit</a> (5)</b>
|
||||
The maximal number of MX (mail exchanger) IP addresses that can
|
||||
result from Postfix SMTP client mail exchanger lookups, or zero
|
||||
The maximal number of MX (mail exchanger) IP addresses that can
|
||||
result from Postfix SMTP client mail exchanger lookups, or zero
|
||||
(no limit).
|
||||
|
||||
<b><a href="postconf.5.html#smtp_mx_session_limit">smtp_mx_session_limit</a> (2)</b>
|
||||
The maximal number of SMTP sessions per delivery request before
|
||||
the Postfix SMTP client gives up or delivers to a fall-back
|
||||
The maximal number of SMTP sessions per delivery request before
|
||||
the Postfix SMTP client gives up or delivers to a fall-back
|
||||
<a href="postconf.5.html#relayhost">relay host</a>, or zero (no limit).
|
||||
|
||||
<b><a href="postconf.5.html#smtp_rset_timeout">smtp_rset_timeout</a> (20s)</b>
|
||||
@ -834,17 +841,17 @@ SMTP,(LMTP) SMTP,(LMTP)
|
||||
Available in Postfix version 2.2 and earlier:
|
||||
|
||||
<b><a href="postconf.5.html#lmtp_cache_connection">lmtp_cache_connection</a> (yes)</b>
|
||||
Keep Postfix LMTP client connections open for up to $<a href="postconf.5.html#max_idle">max_idle</a>
|
||||
Keep Postfix LMTP client connections open for up to $<a href="postconf.5.html#max_idle">max_idle</a>
|
||||
seconds.
|
||||
|
||||
Available in Postfix version 2.2 and later:
|
||||
|
||||
<b><a href="postconf.5.html#smtp_connection_cache_destinations">smtp_connection_cache_destinations</a> (empty)</b>
|
||||
Permanently enable SMTP connection caching for the specified
|
||||
Permanently enable SMTP connection caching for the specified
|
||||
destinations.
|
||||
|
||||
<b><a href="postconf.5.html#smtp_connection_cache_on_demand">smtp_connection_cache_on_demand</a> (yes)</b>
|
||||
Temporarily enable SMTP connection caching while a destination
|
||||
Temporarily enable SMTP connection caching while a destination
|
||||
has a high volume of mail in the <a href="QSHAPE_README.html#active_queue">active queue</a>.
|
||||
|
||||
<b><a href="postconf.5.html#smtp_connection_reuse_time_limit">smtp_connection_reuse_time_limit</a> (300s)</b>
|
||||
@ -858,23 +865,23 @@ SMTP,(LMTP) SMTP,(LMTP)
|
||||
Available in Postfix version 2.3 and later:
|
||||
|
||||
<b><a href="postconf.5.html#connection_cache_protocol_timeout">connection_cache_protocol_timeout</a> (5s)</b>
|
||||
Time limit for connection cache connect, send or receive opera-
|
||||
Time limit for connection cache connect, send or receive opera-
|
||||
tions.
|
||||
|
||||
Available in Postfix version 2.9 - 3.6:
|
||||
|
||||
<b><a href="postconf.5.html#smtp_per_record_deadline">smtp_per_record_deadline</a> (no)</b>
|
||||
Change the behavior of the smtp_*_timeout time limits, from a
|
||||
time limit per read or write system call, to a time limit to
|
||||
send or receive a complete record (an SMTP command line, SMTP
|
||||
response line, SMTP message content line, or TLS protocol mes-
|
||||
Change the behavior of the smtp_*_timeout time limits, from a
|
||||
time limit per read or write system call, to a time limit to
|
||||
send or receive a complete record (an SMTP command line, SMTP
|
||||
response line, SMTP message content line, or TLS protocol mes-
|
||||
sage).
|
||||
|
||||
Available in Postfix version 2.11 and later:
|
||||
|
||||
<b><a href="postconf.5.html#smtp_connection_reuse_count_limit">smtp_connection_reuse_count_limit</a> (0)</b>
|
||||
When SMTP connection caching is enabled, the number of times
|
||||
that an SMTP session may be reused before it is closed, or zero
|
||||
When SMTP connection caching is enabled, the number of times
|
||||
that an SMTP session may be reused before it is closed, or zero
|
||||
(no limit).
|
||||
|
||||
Available in Postfix version 3.4 and later:
|
||||
@ -885,13 +892,13 @@ SMTP,(LMTP) SMTP,(LMTP)
|
||||
Available in Postfix version 3.7 and later:
|
||||
|
||||
<b><a href="postconf.5.html#smtp_per_request_deadline">smtp_per_request_deadline</a> (no)</b>
|
||||
Change the behavior of the smtp_*_timeout time limits, from a
|
||||
time limit per plaintext or TLS read or write call, to a com-
|
||||
bined time limit for sending a complete SMTP request and for
|
||||
Change the behavior of the smtp_*_timeout time limits, from a
|
||||
time limit per plaintext or TLS read or write call, to a com-
|
||||
bined time limit for sending a complete SMTP request and for
|
||||
receiving a complete SMTP response.
|
||||
|
||||
<b><a href="postconf.5.html#smtp_min_data_rate">smtp_min_data_rate</a> (500)</b>
|
||||
The minimum plaintext data transfer rate in bytes/second for
|
||||
The minimum plaintext data transfer rate in bytes/second for
|
||||
DATA requests, when deadlines are enabled with
|
||||
<a href="postconf.5.html#smtp_per_request_deadline">smtp_per_request_deadline</a>.
|
||||
|
||||
@ -899,54 +906,54 @@ SMTP,(LMTP) SMTP,(LMTP)
|
||||
|
||||
<b><a href="postconf.5.html#transport_destination_concurrency_limit">transport_destination_concurrency_limit</a> ($<a href="postconf.5.html#default_destination_concurrency_limit">default_destination_concur</a>-</b>
|
||||
<b><a href="postconf.5.html#default_destination_concurrency_limit">rency_limit</a>)</b>
|
||||
A transport-specific override for the <a href="postconf.5.html#default_destination_concurrency_limit">default_destination_con</a>-
|
||||
A transport-specific override for the <a href="postconf.5.html#default_destination_concurrency_limit">default_destination_con</a>-
|
||||
<a href="postconf.5.html#default_destination_concurrency_limit">currency_limit</a> parameter value, where <i>transport</i> is the <a href="master.5.html">master.cf</a>
|
||||
name of the message delivery transport.
|
||||
|
||||
<b><a href="postconf.5.html#transport_destination_recipient_limit">transport_destination_recipient_limit</a> ($<a href="postconf.5.html#default_destination_recipient_limit">default_destination_recipi</a>-</b>
|
||||
<b><a href="postconf.5.html#default_destination_recipient_limit">ent_limit</a>)</b>
|
||||
A transport-specific override for the <a href="postconf.5.html#default_destination_recipient_limit">default_destination_recip</a>-
|
||||
<a href="postconf.5.html#default_destination_recipient_limit">ient_limit</a> parameter value, where <i>transport</i> is the <a href="master.5.html">master.cf</a>
|
||||
<a href="postconf.5.html#default_destination_recipient_limit">ient_limit</a> parameter value, where <i>transport</i> is the <a href="master.5.html">master.cf</a>
|
||||
name of the message delivery transport.
|
||||
|
||||
<b>SMTPUTF8 CONTROLS</b>
|
||||
Preliminary SMTPUTF8 support is introduced with Postfix 3.0.
|
||||
|
||||
<b><a href="postconf.5.html#smtputf8_enable">smtputf8_enable</a> (yes)</b>
|
||||
Enable preliminary SMTPUTF8 support for the protocols described
|
||||
Enable preliminary SMTPUTF8 support for the protocols described
|
||||
in <a href="https://tools.ietf.org/html/rfc6531">RFC 6531</a>, <a href="https://tools.ietf.org/html/rfc6532">RFC 6532</a>, and <a href="https://tools.ietf.org/html/rfc6533">RFC 6533</a>.
|
||||
|
||||
<b><a href="postconf.5.html#smtputf8_autodetect_classes">smtputf8_autodetect_classes</a> (sendmail, verify)</b>
|
||||
Detect that a message requires SMTPUTF8 support for the speci-
|
||||
Detect that a message requires SMTPUTF8 support for the speci-
|
||||
fied mail origin classes.
|
||||
|
||||
Available in Postfix version 3.2 and later:
|
||||
|
||||
<b><a href="postconf.5.html#enable_idna2003_compatibility">enable_idna2003_compatibility</a> (no)</b>
|
||||
Enable 'transitional' compatibility between IDNA2003 and
|
||||
IDNA2008, when converting UTF-8 domain names to/from the ASCII
|
||||
Enable 'transitional' compatibility between IDNA2003 and
|
||||
IDNA2008, when converting UTF-8 domain names to/from the ASCII
|
||||
form that is used for DNS lookups.
|
||||
|
||||
<b>TROUBLE SHOOTING CONTROLS</b>
|
||||
<b><a href="postconf.5.html#debug_peer_level">debug_peer_level</a> (2)</b>
|
||||
The increment in verbose logging level when a nexthop destina-
|
||||
tion, remote client or server name or network address matches a
|
||||
The increment in verbose logging level when a nexthop destina-
|
||||
tion, remote client or server name or network address matches a
|
||||
pattern given with the <a href="postconf.5.html#debug_peer_list">debug_peer_list</a> parameter.
|
||||
|
||||
<b><a href="postconf.5.html#debug_peer_list">debug_peer_list</a> (empty)</b>
|
||||
Optional list of nexthop destination, remote client or server
|
||||
name or network address patterns that, if matched, cause the
|
||||
verbose logging level to increase by the amount specified in
|
||||
Optional list of nexthop destination, remote client or server
|
||||
name or network address patterns that, if matched, cause the
|
||||
verbose logging level to increase by the amount specified in
|
||||
$<a href="postconf.5.html#debug_peer_level">debug_peer_level</a>.
|
||||
|
||||
<b><a href="postconf.5.html#error_notice_recipient">error_notice_recipient</a> (postmaster)</b>
|
||||
The recipient of postmaster notifications about mail delivery
|
||||
The recipient of postmaster notifications about mail delivery
|
||||
problems that are caused by policy, resource, software or proto-
|
||||
col errors.
|
||||
|
||||
<b><a href="postconf.5.html#internal_mail_filter_classes">internal_mail_filter_classes</a> (empty)</b>
|
||||
What categories of Postfix-generated mail are subject to
|
||||
before-queue content inspection by <a href="postconf.5.html#non_smtpd_milters">non_smtpd_milters</a>,
|
||||
What categories of Postfix-generated mail are subject to
|
||||
before-queue content inspection by <a href="postconf.5.html#non_smtpd_milters">non_smtpd_milters</a>,
|
||||
<a href="postconf.5.html#header_checks">header_checks</a> and <a href="postconf.5.html#body_checks">body_checks</a>.
|
||||
|
||||
<b><a href="postconf.5.html#notify_classes">notify_classes</a> (resource, software)</b>
|
||||
@ -954,46 +961,46 @@ SMTP,(LMTP) SMTP,(LMTP)
|
||||
|
||||
<b>MISCELLANEOUS CONTROLS</b>
|
||||
<b><a href="postconf.5.html#best_mx_transport">best_mx_transport</a> (empty)</b>
|
||||
Where the Postfix SMTP client should deliver mail when it
|
||||
Where the Postfix SMTP client should deliver mail when it
|
||||
detects a "mail loops back to myself" error condition.
|
||||
|
||||
<b><a href="postconf.5.html#config_directory">config_directory</a> (see 'postconf -d' output)</b>
|
||||
The default location of the Postfix <a href="postconf.5.html">main.cf</a> and <a href="master.5.html">master.cf</a> con-
|
||||
The default location of the Postfix <a href="postconf.5.html">main.cf</a> and <a href="master.5.html">master.cf</a> con-
|
||||
figuration files.
|
||||
|
||||
<b><a href="postconf.5.html#daemon_timeout">daemon_timeout</a> (18000s)</b>
|
||||
How much time a Postfix daemon process may take to handle a
|
||||
How much time a Postfix daemon process may take to handle a
|
||||
request before it is terminated by a built-in watchdog timer.
|
||||
|
||||
<b><a href="postconf.5.html#delay_logging_resolution_limit">delay_logging_resolution_limit</a> (2)</b>
|
||||
The maximal number of digits after the decimal point when log-
|
||||
The maximal number of digits after the decimal point when log-
|
||||
ging sub-second delay values.
|
||||
|
||||
<b><a href="postconf.5.html#disable_dns_lookups">disable_dns_lookups</a> (no)</b>
|
||||
Disable DNS lookups in the Postfix SMTP and LMTP clients.
|
||||
|
||||
<b><a href="postconf.5.html#inet_interfaces">inet_interfaces</a> (all)</b>
|
||||
The local network interface addresses that this mail system
|
||||
The local network interface addresses that this mail system
|
||||
receives mail on.
|
||||
|
||||
<b><a href="postconf.5.html#inet_protocols">inet_protocols</a> (see 'postconf -d' output)</b>
|
||||
The Internet protocols Postfix will attempt to use when making
|
||||
The Internet protocols Postfix will attempt to use when making
|
||||
or accepting connections.
|
||||
|
||||
<b><a href="postconf.5.html#ipc_timeout">ipc_timeout</a> (3600s)</b>
|
||||
The time limit for sending or receiving information over an
|
||||
The time limit for sending or receiving information over an
|
||||
internal communication channel.
|
||||
|
||||
<b><a href="postconf.5.html#lmtp_assume_final">lmtp_assume_final</a> (no)</b>
|
||||
When a remote LMTP server announces no DSN support, assume that
|
||||
the server performs final delivery, and send "delivered" deliv-
|
||||
When a remote LMTP server announces no DSN support, assume that
|
||||
the server performs final delivery, and send "delivered" deliv-
|
||||
ery status notifications instead of "relayed".
|
||||
|
||||
<b><a href="postconf.5.html#lmtp_tcp_port">lmtp_tcp_port</a> (24)</b>
|
||||
The default TCP port that the Postfix LMTP client connects to.
|
||||
|
||||
<b><a href="postconf.5.html#max_idle">max_idle</a> (100s)</b>
|
||||
The maximum amount of time that an idle Postfix daemon process
|
||||
The maximum amount of time that an idle Postfix daemon process
|
||||
waits for an incoming connection before terminating voluntarily.
|
||||
|
||||
<b><a href="postconf.5.html#max_use">max_use</a> (100)</b>
|
||||
@ -1007,21 +1014,21 @@ SMTP,(LMTP) SMTP,(LMTP)
|
||||
The process name of a Postfix command or daemon process.
|
||||
|
||||
<b><a href="postconf.5.html#proxy_interfaces">proxy_interfaces</a> (empty)</b>
|
||||
The remote network interface addresses that this mail system
|
||||
receives mail on by way of a proxy or network address transla-
|
||||
The remote network interface addresses that this mail system
|
||||
receives mail on by way of a proxy or network address transla-
|
||||
tion unit.
|
||||
|
||||
<b><a href="postconf.5.html#smtp_address_preference">smtp_address_preference</a> (any)</b>
|
||||
The address type ("ipv6", "ipv4" or "any") that the Postfix SMTP
|
||||
client will try first, when a destination has IPv6 and IPv4
|
||||
client will try first, when a destination has IPv6 and IPv4
|
||||
addresses with equal MX preference.
|
||||
|
||||
<b><a href="postconf.5.html#smtp_bind_address">smtp_bind_address</a> (empty)</b>
|
||||
An optional numerical network address that the Postfix SMTP
|
||||
An optional numerical network address that the Postfix SMTP
|
||||
client should bind to when making an IPv4 connection.
|
||||
|
||||
<b><a href="postconf.5.html#smtp_bind_address6">smtp_bind_address6</a> (empty)</b>
|
||||
An optional numerical network address that the Postfix SMTP
|
||||
An optional numerical network address that the Postfix SMTP
|
||||
client should bind to when making an IPv6 connection.
|
||||
|
||||
<b><a href="postconf.5.html#smtp_helo_name">smtp_helo_name</a> ($<a href="postconf.5.html#myhostname">myhostname</a>)</b>
|
||||
@ -1041,7 +1048,7 @@ SMTP,(LMTP) SMTP,(LMTP)
|
||||
The syslog facility of Postfix logging.
|
||||
|
||||
<b><a href="postconf.5.html#syslog_name">syslog_name</a> (see 'postconf -d' output)</b>
|
||||
A prefix that is prepended to the process name in syslog
|
||||
A prefix that is prepended to the process name in syslog
|
||||
records, so that, for example, "smtpd" becomes "prefix/smtpd".
|
||||
|
||||
Available with Postfix 2.2 and earlier:
|
||||
@ -1053,14 +1060,14 @@ SMTP,(LMTP) SMTP,(LMTP)
|
||||
Available with Postfix 2.3 and later:
|
||||
|
||||
<b><a href="postconf.5.html#smtp_fallback_relay">smtp_fallback_relay</a> ($<a href="postconf.5.html#fallback_relay">fallback_relay</a>)</b>
|
||||
Optional list of relay destinations that will be used when an
|
||||
SMTP destination is not found, or when delivery fails due to a
|
||||
Optional list of relay destinations that will be used when an
|
||||
SMTP destination is not found, or when delivery fails due to a
|
||||
non-permanent error.
|
||||
|
||||
Available with Postfix 3.0 and later:
|
||||
|
||||
<b><a href="postconf.5.html#smtp_address_verify_target">smtp_address_verify_target</a> (rcpt)</b>
|
||||
In the context of email address verification, the SMTP protocol
|
||||
In the context of email address verification, the SMTP protocol
|
||||
stage that determines whether an email address is deliverable.
|
||||
|
||||
Available with Postfix 3.1 and later:
|
||||
@ -1082,7 +1089,7 @@ SMTP,(LMTP) SMTP,(LMTP)
|
||||
Available in Postfix 3.7 and later:
|
||||
|
||||
<b><a href="postconf.5.html#smtp_bind_address_enforce">smtp_bind_address_enforce</a> (no)</b>
|
||||
Defer delivery when the Postfix SMTP client cannot apply the
|
||||
Defer delivery when the Postfix SMTP client cannot apply the
|
||||
<a href="postconf.5.html#smtp_bind_address">smtp_bind_address</a> or <a href="postconf.5.html#smtp_bind_address6">smtp_bind_address6</a> setting.
|
||||
|
||||
<b>SEE ALSO</b>
|
||||
|
@ -41,6 +41,8 @@ Show message envelope content.
|
||||
This feature is available in Postfix 2.7 and later.
|
||||
.IP \fB\-f\fR
|
||||
Prepend the file name to each output line.
|
||||
.sp
|
||||
This feature is available in Postfix 3.10 and later.
|
||||
.IP \fB\-h\fR
|
||||
Show message header content. The \fB\-h\fR option produces
|
||||
output from the beginning of the message up to, but not
|
||||
|
@ -9860,6 +9860,21 @@ More examples are in TLS_README, including examples for older
|
||||
Postfix versions.
|
||||
.PP
|
||||
This feature is available in Postfix 3.0 and later.
|
||||
.SH smtp_tlsrpt_enable (default: no)
|
||||
Enable support for RFC 8460 TLSRPT notifications. A mail receiving
|
||||
domain can publish a TLSRPT policy in DNS, to request periodic
|
||||
summaries of successful and failed SMTP over TLS connections to
|
||||
their mail servers. This feature requires that Postfix is built
|
||||
with a TLSRPT supporting library.
|
||||
.PP
|
||||
This feature is available in Postfix >= 3.10.
|
||||
.SH smtp_tlsrpt_socket_name (default: empty)
|
||||
The pathname of a UNIX\-domain datagram socket that is managed
|
||||
by a local TLSRPT reporting service. This parameter must specify a
|
||||
pathname (absolute, or relative to $queue_directory) when
|
||||
"smtp_tlsrpt_enable = yes".
|
||||
.PP
|
||||
This feature is available in Postfix >= 3.10.
|
||||
.SH smtp_use_tls (default: no)
|
||||
Opportunistic mode: use TLS when a remote SMTP server announces
|
||||
STARTTLS support, otherwise send the mail in the clear. Beware:
|
||||
|
@ -672,6 +672,12 @@ Available in Postfix version 3.9 and later:
|
||||
.IP "\fBsmtp_tls_enable_rpk (no)\fR"
|
||||
Request that remote SMTP servers send an RFC7250 raw public key
|
||||
instead of an X.509 certificate.
|
||||
.PP Available in Postfix version 3.10 and later:
|
||||
.IP "\fBsmtp_tlsrpt_enable (no)\fR"
|
||||
Enable support for RFC 8460 TLSRPT notifications.
|
||||
.IP "\fBsmtp_tlsrpt_socket_name (empty)\fR"
|
||||
The pathname of a UNIX\-domain datagram socket that is managed
|
||||
by a local TLSRPT reporting service.
|
||||
.SH "OBSOLETE STARTTLS CONTROLS"
|
||||
.na
|
||||
.nf
|
||||
|
@ -6,9 +6,23 @@ postfix-[0-9]*.[0-9]*.[0-9]*)
|
||||
test -f conf/makedefs.out || {
|
||||
echo "Error: no conf/makedefs.out" 1>&2; exit 1; }
|
||||
grep 'CCARGS.*-DSNAPSHOT' conf/makedefs.out && {
|
||||
echo "Error: stable release builds with -DSNAPSHOT" 1>&2, exit 1; }
|
||||
echo "Error: stable release builds with -DSNAPSHOT" 1>&2; exit 1; }
|
||||
grep 'CCARGS.*-DNONPROD' conf/makedefs.out && {
|
||||
echo "Error: stable release builds with -DNONPROD" 1>&2, exit 1; }
|
||||
echo "Error: stable release builds with -DNONPROD" 1>&2; exit 1; }
|
||||
mail_version=$(sh postfix-env.sh bin/postconf -h mail_version) || exit 1
|
||||
test "postfix-$mail_version" = "$version" || {
|
||||
echo "Error: version '$mail_version' in src/global/mail_version.h does not match version in pathname '$(env - pwd)'" 1>&2; exit 1; }
|
||||
;;
|
||||
postfix-[0-9]*.[0-9]*-*nonprod*)
|
||||
grep 'CCARGS.*-DNONPROD' conf/makedefs.out || {
|
||||
echo "Error: non-prod release builds without -DNONPROD" 1>&2; exit 1; }
|
||||
mail_version=$(sh postfix-env.sh bin/postconf -h mail_version) || exit 1
|
||||
test "postfix-$mail_version" = "$version" || {
|
||||
echo "Error: version '$mail_version' in src/global/mail_version.h does not match version in pathname '$(env - pwd)'" 1>&2; exit 1; }
|
||||
;;
|
||||
postfix-[0-9]*.[0-9]*-*)
|
||||
grep 'CCARGS.*-DNONPROD' conf/makedefs.out && {
|
||||
echo "Error: snapshot release builds with -DNONPROD" 1>&2; exit 1; }
|
||||
mail_version=$(sh postfix-env.sh bin/postconf -h mail_version) || exit 1
|
||||
test "postfix-$mail_version" = "$version" || {
|
||||
echo "Error: version '$mail_version' in src/global/mail_version.h does not match version in pathname '$(env - pwd)'" 1>&2; exit 1; }
|
||||
|
@ -721,6 +721,10 @@ while (<>) {
|
||||
s;\bdnssec_probe\b;<a href="postconf.5.html#dnssec_probe">$&</a>;g;
|
||||
s;\bsmtp_tls_connection_reuse\b;<a href="postconf.5.html#smtp_tls_connection_reuse">$&</a>;g;
|
||||
s;\blmtp_tls_connection_reuse\b;<a href="postconf.5.html#lmtp_tls_connection_reuse">$&</a>;g;
|
||||
s;\bsmtp_tlsrpt_enable\b;<a href="postconf.5.html#smtp_tlsrpt_enable">$&</a>;g;
|
||||
s;\bsmtp_tlsrpt_socket_name\b;<a href="postconf.5.html#smtp_tlsrpt_socket_name">$&</a>;g;
|
||||
s;\blmtp_tlsrpt_enable\b;<a href="postconf.5.html#lmtp_tlsrpt_enable">$&</a>;g;
|
||||
s;\blmtp_tlsrpt_socket_name\b;<a href="postconf.5.html#lmtp_tlsrpt_socket_name">$&</a>;g;
|
||||
s;\bsmtpd_enforce_tls\b;<a href="postconf.5.html#smtpd_enforce_tls">$&</a>;g;
|
||||
s;\bsmtpd_sasl_tls_security_options\b;<a href="postconf.5.html#smtpd_sasl_tls_security_options">$&</a>;g;
|
||||
s;\bsmtpd_sasl_type\b;<a href="postconf.5.html#smtpd_sasl_type">$&</a>;g;
|
||||
|
@ -50,6 +50,7 @@ HTML = ../html/ADDRESS_CLASS_README.html \
|
||||
../html/STANDARD_CONFIGURATION_README.html \
|
||||
../html/STRESS_README.html \
|
||||
../html/TLS_README.html ../html/TLS_LEGACY_README.html \
|
||||
../html/TLSRPT_README.html \
|
||||
../html/TUNING_README.html \
|
||||
../html/UUCP_README.html \
|
||||
../html/VERP_README.html ../html/VIRTUAL_README.html \
|
||||
@ -100,6 +101,7 @@ README = ../README_FILES/ADDRESS_CLASS_README \
|
||||
../README_FILES/STANDARD_CONFIGURATION_README \
|
||||
../README_FILES/STRESS_README \
|
||||
../README_FILES/TLS_README ../README_FILES/TLS_LEGACY_README \
|
||||
../README_FILES/TLSRPT_README \
|
||||
../README_FILES/TUNING_README \
|
||||
../README_FILES/UUCP_README \
|
||||
../README_FILES/VERP_README ../README_FILES/VIRTUAL_README \
|
||||
@ -343,6 +345,9 @@ clobber:
|
||||
../html/TLS_LEGACY_README.html: TLS_LEGACY_README.html
|
||||
$(DETAB) $? | $(POSTLINK) >$@
|
||||
|
||||
../html/TLSRPT_README.html: TLSRPT_README.html
|
||||
$(DETAB) $? | $(POSTLINK) >$@
|
||||
|
||||
../README_FILES/ADDRESS_CLASS_README: ADDRESS_CLASS_README.html
|
||||
$(DETAB) $? | $(HT2READ) >$@
|
||||
|
||||
@ -529,6 +534,9 @@ clobber:
|
||||
../README_FILES/TLS_LEGACY_README: TLS_LEGACY_README.html
|
||||
$(DETAB) $? | $(HT2READ) >$@
|
||||
|
||||
../README_FILES/TLSRPT_README: TLSRPT_README.html
|
||||
$(DETAB) $? | $(HT2READ) >$@
|
||||
|
||||
../README_FILES/AAAREADME: ../html/index.html $(MAKEAAA)
|
||||
$(MAKEAAA) ../html/index.html | $(HT2READ) | $(DETAB) >$@
|
||||
|
||||
|
410
postfix/proto/TLSRPT_README.html
Normal file
410
postfix/proto/TLSRPT_README.html
Normal file
@ -0,0 +1,410 @@
|
||||
<!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> Table of Contents </h2>
|
||||
|
||||
<ul>
|
||||
|
||||
<li> <a href="#intro"> Introduction </a> </li>
|
||||
<li> <a href="#building"> Building Postfix with TLSRPT support </a>
|
||||
<li> <a href="#using"> Turning on TLSRPT </a> </li>
|
||||
<li> <a href="#logging"> TLSRPT Status logging </a> </li>
|
||||
<li> <a href="#delivering"> Delivering TLSRPT summaries via email</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, and request daily
|
||||
summary reports for successful and failed SMTP over TLS connections
|
||||
to that domain's MX hosts. Support for TLSRPT was added in Postfix
|
||||
3.10. </p>
|
||||
|
||||
<p> A policy example looks like this: </p>
|
||||
|
||||
<blockquote>
|
||||
<pre>
|
||||
_smtp._tls.example.com. IN TXT "v=TLSRPTv1; rua=mailto:smtp-tls-report@example.com"
|
||||
</pre>
|
||||
</blockquote>
|
||||
|
||||
<p> Translation: email sending systems are requested to generate daily
|
||||
summaries of successful and failed SMTP over TLS connections to domain
|
||||
<tt>example.com</tt>, and to report those summaries via email to the
|
||||
specified address. Instead of <tt>mailto:</tt>, a policy may specify an
|
||||
<tt>https:</tt> destination. </p>
|
||||
|
||||
<p> The high-level diagram shows how Postfix reports summaries to
|
||||
domains that publish a TLSRPT policy.
|
||||
|
||||
<blockquote>
|
||||
|
||||
<table>
|
||||
|
||||
<tr> <td align="center" bgcolor="#f0f0ff"> Postfix SMTP and<br> TLS
|
||||
client engines </td> <td> <tt> --> </tt> </td>
|
||||
|
||||
<td align="center" bgcolor="#f0f0ff"> TLSRPT client <br> library
|
||||
</td> <td> <tt> --> </tt> </td>
|
||||
|
||||
<td align="center" bgcolor="#f0f0ff"> TLSRPT summary <br> generator
|
||||
</td> <td> <tt> --> </tt> </td>
|
||||
|
||||
<td align="center" bgcolor="#f0f0ff"> Email or HTTP <br> delivery
|
||||
</td> </tr>
|
||||
|
||||
</table>
|
||||
|
||||
</blockquote>
|
||||
|
||||
<p> When Postfix TLSRPT support is enabled (with "smtp_tlsrpt_enable
|
||||
= yes"): </p>
|
||||
|
||||
<ul>
|
||||
|
||||
<li> <p> The Postfix SMTP and TLS client engines will generate a
|
||||
"success" or "failure" event for each TLS handshake, </p>
|
||||
|
||||
<li> <p> They will pass those events to an in-process TLSRPT client
|
||||
library that sends data over a local socket to </p>
|
||||
|
||||
<li> <p> A TLSRPT report generator that produces daily summary
|
||||
reports. </p>
|
||||
|
||||
</ul>
|
||||
|
||||
<p> The TLSRPT client library and report generator are maintained
|
||||
by sys4. </p>
|
||||
|
||||
<p> The Postfix implementation supports both DANE (Postfix built-in)
|
||||
and MTA-STS (through an smtp_tls_policy_maps plug-in).
|
||||
</p>
|
||||
|
||||
<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 <tt>-DUSE_TLSRPT</tt> (to build with TLSRPT
|
||||
support), and <tt>-I</tt> (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
|
||||
settings, then simply append the above settings to the existing CCARGS
|
||||
or AUXLIBS values. </p>
|
||||
|
||||
<blockquote>
|
||||
<pre>
|
||||
make -f Makefile.init makefiles \
|
||||
"CCARGS=<i>existing settings...</i> -DUSE_TLSRPT -I/usr/local/include" \
|
||||
"AUXLIBS=<i>existing settings...</i> -L/usr/local/lib -ltlsrpt"
|
||||
</pre>
|
||||
</blockquote>
|
||||
|
||||
</blockquote>
|
||||
|
||||
<h2> <a name="using"> Turning on 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>
|
||||
|
||||
<blockquote>
|
||||
|
||||
<p> Note: the recommended socket location is still to be determined.
|
||||
A good socket location would be under the Postfix queue directory,
|
||||
for example: "smtp_tlsrpt_socket_name = run/tlsrpt/tlsrpt.sock".
|
||||
The advantage of using a relative name is that it will work equally
|
||||
well whether or not Postfix chroot is turned on. </p>
|
||||
|
||||
</blockquote>
|
||||
|
||||
<p> Do not specify a location under a directory such as <tt>private</tt>
|
||||
or <tt>public</tt> that is already used by Postfix programs. Only Postfix
|
||||
programs should create sockets there. </p>
|
||||
|
||||
<h2> <a name="logging"> TLSRPT Status logging </a> </h2>
|
||||
|
||||
<p> With TLSRPT support turned on, the Postfix TLSRPT client will
|
||||
not only report an event to an invisible daily success/fail summary
|
||||
queue, but it will also log a visible record to the mail logfile.
|
||||
</p>
|
||||
|
||||
<p> Below are a few examples of logging from a Postfix SMTP client
|
||||
or tlsproxy daemon: </p>
|
||||
|
||||
<blockquote>
|
||||
<pre>
|
||||
TLSRPT: status=success, domain=example.com, receiving_mx=mail.example.com[ipaddr]
|
||||
|
||||
TLSRPT: status=failure, domain=example.org, receiving_mx=mail.example.org[ipaddr],
|
||||
failure_type=starttls_not_supported
|
||||
|
||||
TLSRPT: status=failure, domain=example.net, receiving_mx=mail.example.net[ipaddr],
|
||||
failure_type=validation_failure, failure_reason=self-signed_certificate
|
||||
</pre>
|
||||
</blockquote>
|
||||
|
||||
<p> Note: Postfix logs and reports TLSRPT status only for TLS
|
||||
handshakes on a new SMTP connection. There is no TLSRPT status
|
||||
logging for a reused SMTP connection. Such connections have
|
||||
Postfix SMTP client logging like this: </p>
|
||||
|
||||
<blockquote>
|
||||
<pre>
|
||||
Verified <b>TLS connection reused</b> to mail.example.com[ipaddr]:25:
|
||||
TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)
|
||||
|
||||
Untrusted <b>TLS connection reused</b> to mail.example.com[ipaddr]:25:
|
||||
TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)
|
||||
</pre>
|
||||
</blockquote>
|
||||
|
||||
<p> Postfix logs certificate verification failures with a level of
|
||||
detail that is different for a new or reused TLS session. </p>
|
||||
|
||||
<ul>
|
||||
|
||||
<li> <p> A new TLS session is logged with certificate verification
|
||||
failure details: </p>
|
||||
|
||||
<pre>
|
||||
TLSRPT: status=failure, domain=example.org, receiving_mx=mail.example.org[ipaddr],
|
||||
<b>failure_type=validation_failure</b>, <b>failure_reason=self-signed_certificate</b>
|
||||
</pre>
|
||||
|
||||
<li> <p> A reused TLS session is indicated as shown below, and has
|
||||
no certificate verification details: </p>
|
||||
|
||||
<pre>
|
||||
mail.example.org[ipaddr]:25: <b>re-using session</b> with untrusted peer
|
||||
credential, look for details earlier in the log
|
||||
TLSRPT: status=failure, domain=example.org, receiving_mx=mail.example.org[ipaddr],
|
||||
<b>failure_type=certificate_not_trusted</b>
|
||||
</pre>
|
||||
|
||||
</ul>
|
||||
|
||||
<p> Some Postfix users may wonder where the difference comes from.
|
||||
So this is why. </p>
|
||||
|
||||
<h2> <a name="delivering"> Delivering TLSRPT summaries via email</a> </h2>
|
||||
|
||||
<p> RFC 8460 suggests not to enforce strict TLS security when sending
|
||||
daily success/failure summaries via email, to avoid delivery delays
|
||||
caused by a failure to enforce TLS security. Postfix currently does
|
||||
not have a mechanism to disable TLS security enforcement when
|
||||
submitting an email message; this section provides a workaround. </p>
|
||||
|
||||
<p> By design, TLSRPT is not a real-time notification system; it
|
||||
takes on average 12 hours before a failure is reported in a daily
|
||||
success/failure summary. If a TLS-related delay of a day or more
|
||||
is undesirable, one could set up a transport map to make TLS security
|
||||
optional for specific TLSRPT email notification email addresses.
|
||||
</p>
|
||||
|
||||
<blockquote>
|
||||
<pre>
|
||||
/etc/postfix/main.cf:
|
||||
transport_maps = hash:/etc/postfix/transport
|
||||
 
|
||||
/etc/postfix/transport:
|
||||
smtp-tls-report@example.com allow-plaintext:
|
||||
...
|
||||
 
|
||||
/etc/postfix/master.cf:
|
||||
# service name type private unpriv chroot wakeup maxproc command
|
||||
allow-plaintext unix - - n - - smtp
|
||||
-o smtp_tls_security_level=may
|
||||
-o smtp_tls_policy_maps=static:may
|
||||
</pre>
|
||||
</blockquote>
|
||||
|
||||
<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 3.10 and later expect a policy response with
|
||||
the usual security level and matching requirements, plus any
|
||||
applicable name=value attributes described below. Specify <tt>{
|
||||
name = value }</tt> 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). With TLSRPT support turned off, Postfix
|
||||
will use the <tt>ttl</tt> and <tt>policy_failure</tt> attributes,
|
||||
and will ignore the attributes that are used only for TLSRPT. </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 Postfix TLSRPT implementation reports at most one final TLS
|
||||
handshake status (either 'success' or 'failure') per connection.
|
||||
Postfix TLSRPT cannot report a failure and then later report a final
|
||||
status of 'success' for that same connection. The reason is that
|
||||
it's too complicated to filter TLS errors and to report error details
|
||||
from the TLS engine back to the SMTP protocol engine. It just is
|
||||
not how Postfix works internally. </p>
|
||||
|
||||
<p> The Postfix TLSRPT implementation reports only TLS handshake
|
||||
success or failure. It does not report failure to connect, or
|
||||
connections that break after a successful TLS handshake. </p>
|
||||
|
||||
<h2> <a name="credits"> Credits </a> </h2>
|
||||
|
||||
<ul>
|
||||
|
||||
<li> The TLSRPT client library and report generator are implemented
|
||||
and maintained by sys4. </li>
|
||||
|
||||
<li> Wietse Venema implemented the integration with Postfix.
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
@ -19408,3 +19408,22 @@ announce 8BITMIME support, or when a message line exceeds the SMTP
|
||||
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>
|
||||
|
@ -1623,3 +1623,31 @@ KEMs
|
||||
kex
|
||||
keyshare
|
||||
pkg
|
||||
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
|
||||
mailto
|
||||
ipaddr
|
||||
STS
|
||||
|
@ -335,3 +335,10 @@ length length of 0 31 0 127
|
||||
address address string length
|
||||
whether the standard End of DATA sequence CRLF CRLF is required and
|
||||
Require CRLF CRLF
|
||||
must start with a version field v TLSRPTv1 followed by WSP WSP
|
||||
policies policy policy type
|
||||
policies policy policy string Ignored if the tls_policy_type
|
||||
policies policy policy domain
|
||||
additional_info additional_info
|
||||
ignored ignored
|
||||
USE_TLSRPT USE_TLSRPT
|
||||
|
@ -358,3 +358,8 @@ expected to become a list of comma separated names br br This
|
||||
Postfix Postfix can use MongoDB as a source for any of its lookups aliases 5 virtual 5 canonical 5 etc This allows you to keep information for your mail service in a replicated noSQL database with fine grained access controls By not storing it
|
||||
CCARGS CCARGS DHAS_MONGODB I usr include libmongoc 1 0
|
||||
dt dt dd 2 Also enable verbose logging in the Postfix TLS
|
||||
Postfix Postfix legacy TLS Support
|
||||
var run tlsrpt tlsrpt sock Relative names will work with and without Postfix chroot support Do not specify a location under a directory such as private or public that is already used by Postfix programs Only Postfix programs should create
|
||||
Note the recommended socket location is still to be determined A good socket location would be under the Postfix queue directory for example smtp_tlsrpt_socket_name run tlsrpt tlsrpt sock The advantage of using a relative name is that
|
||||
with cipher ECDHE RSA AES256 GCM SHA384 256 256 bits
|
||||
TLSv1 2 with cipher ECDHE RSA AES256 GCM SHA384 256 256 bits
|
||||
|
@ -1841,4 +1841,9 @@ foqvx
|
||||
ILP
|
||||
xxfi
|
||||
optionsv
|
||||
rcv
|
||||
snd
|
||||
sts
|
||||
tlsrprt
|
||||
bdefhnoqv
|
||||
deduplicated
|
||||
|
@ -379,3 +379,11 @@ Dextrous
|
||||
ar
|
||||
liveness
|
||||
superset
|
||||
ltlsrpt
|
||||
sts
|
||||
STS
|
||||
STSv
|
||||
Sys
|
||||
Qsmtp
|
||||
Qsts
|
||||
gmail
|
||||
|
@ -221,6 +221,7 @@ extern int dns_rr_compare_pref_any(DNS_RR *, DNS_RR *);
|
||||
extern int dns_rr_compare_pref(DNS_RR *, DNS_RR *);
|
||||
extern DNS_RR *dns_rr_shuffle(DNS_RR *);
|
||||
extern DNS_RR *dns_rr_remove(DNS_RR *, DNS_RR *);
|
||||
extern DNS_RR *dns_rr_detach(DNS_RR *, DNS_RR *);
|
||||
extern int var_dns_rr_list_limit;
|
||||
|
||||
/*
|
||||
|
@ -52,6 +52,10 @@
|
||||
/* 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;
|
||||
/*
|
||||
@ -118,10 +122,15 @@
|
||||
/*
|
||||
/* dns_rr_shuffle() randomly permutes a list of resource records.
|
||||
/*
|
||||
/* dns_rr_remove() removes the specified record from the specified list.
|
||||
/* dns_rr_remove() disconnects the specified record from the
|
||||
/* specified list and destroys it.
|
||||
/* The updated list is the result value.
|
||||
/* The record MUST be a list member.
|
||||
/*
|
||||
/* dns_rr_detach() disconnects the specified record from the
|
||||
/* specified list. The updated list is the result value.
|
||||
/* The record MUST be a list member.
|
||||
/*
|
||||
/* dns_srv_rr_sort() sorts a list of SRV records according to
|
||||
/* their priority and weight as described in RFC 2782.
|
||||
/* LICENSE
|
||||
@ -464,16 +473,24 @@ DNS_RR *dns_rr_shuffle(DNS_RR *list)
|
||||
/* dns_rr_remove - remove record from list, return new list */
|
||||
|
||||
DNS_RR *dns_rr_remove(DNS_RR *list, DNS_RR *record)
|
||||
{
|
||||
list = dns_rr_detach(list, record);
|
||||
dns_rr_free(record);
|
||||
return (list);
|
||||
}
|
||||
|
||||
/* dns_rr_detach - detach record from list, return new list */
|
||||
|
||||
DNS_RR *dns_rr_detach(DNS_RR *list, DNS_RR *record)
|
||||
{
|
||||
if (list == 0)
|
||||
msg_panic("dns_rr_remove: record not found");
|
||||
msg_panic("dns_rr_detach: record not found");
|
||||
|
||||
if (list == record) {
|
||||
list = record->next;
|
||||
record->next = 0;
|
||||
dns_rr_free(record);
|
||||
} else {
|
||||
list->next = dns_rr_remove(list->next, record);
|
||||
list->next = dns_rr_detach(list->next, record);
|
||||
}
|
||||
return (list);
|
||||
}
|
||||
|
@ -361,6 +361,93 @@ static int append_to_elem_from_list_exact_fit(void)
|
||||
return (eq_dns_rr_free(got, want));
|
||||
}
|
||||
|
||||
static int delete_middle_element(void)
|
||||
{
|
||||
DNS_RR *a = dns_rr_create_noport("qa", "ra", T_MX, C_IN, 3600, 1, "mxa", 4);
|
||||
DNS_RR *b = dns_rr_create_noport("qb", "rb", T_MX, C_IN, 3600, 1, "mxb", 4);
|
||||
DNS_RR *c = dns_rr_create_noport("qc", "rc", T_MX, C_IN, 3600, 1, "mxc", 4);
|
||||
DNS_RR *got, *want, *list;
|
||||
|
||||
((list = a)->next = b)->next = c;
|
||||
(want = dns_rr_copy(a))->next = dns_rr_copy(c);
|
||||
got = dns_rr_remove(list, b);
|
||||
|
||||
return (eq_dns_rr_free(got, want));
|
||||
}
|
||||
|
||||
static int delete_first_element(void)
|
||||
{
|
||||
DNS_RR *a = dns_rr_create_noport("qa", "ra", T_MX, C_IN, 3600, 1, "mxa", 4);
|
||||
DNS_RR *b = dns_rr_create_noport("qb", "rb", T_MX, C_IN, 3600, 1, "mxb", 4);
|
||||
DNS_RR *c = dns_rr_create_noport("qc", "rc", T_MX, C_IN, 3600, 1, "mxc", 4);
|
||||
DNS_RR *got, *want, *list;
|
||||
|
||||
((list = a)->next = b)->next = c;
|
||||
(want = dns_rr_copy(b))->next = dns_rr_copy(c);
|
||||
got = dns_rr_remove(list, a);
|
||||
|
||||
return (eq_dns_rr_free(got, want));
|
||||
}
|
||||
|
||||
static int delete_last_element(void)
|
||||
{
|
||||
DNS_RR *a = dns_rr_create_noport("qa", "ra", T_MX, C_IN, 3600, 1, "mxa", 4);
|
||||
DNS_RR *b = dns_rr_create_noport("qb", "rb", T_MX, C_IN, 3600, 1, "mxb", 4);
|
||||
DNS_RR *c = dns_rr_create_noport("qc", "rc", T_MX, C_IN, 3600, 1, "mxc", 4);
|
||||
DNS_RR *got, *want, *list;
|
||||
|
||||
((list = a)->next = b)->next = c;
|
||||
(want = dns_rr_copy(a))->next = dns_rr_copy(b);
|
||||
got = dns_rr_remove(list, c);
|
||||
|
||||
return (eq_dns_rr_free(got, want));
|
||||
}
|
||||
|
||||
static int detach_middle_element(void)
|
||||
{
|
||||
DNS_RR *a = dns_rr_create_noport("qa", "ra", T_MX, C_IN, 3600, 1, "mxa", 4);
|
||||
DNS_RR *b = dns_rr_create_noport("qb", "rb", T_MX, C_IN, 3600, 1, "mxb", 4);
|
||||
DNS_RR *c = dns_rr_create_noport("qc", "rc", T_MX, C_IN, 3600, 1, "mxc", 4);
|
||||
DNS_RR *got, *want, *list;
|
||||
|
||||
((list = a)->next = b)->next = c;
|
||||
(want = dns_rr_copy(a))->next = dns_rr_copy(c);
|
||||
got = dns_rr_detach(list, b);
|
||||
dns_rr_free(b);
|
||||
|
||||
return (eq_dns_rr_free(got, want));
|
||||
}
|
||||
|
||||
static int detach_first_element(void)
|
||||
{
|
||||
DNS_RR *a = dns_rr_create_noport("qa", "ra", T_MX, C_IN, 3600, 1, "mxa", 4);
|
||||
DNS_RR *b = dns_rr_create_noport("qb", "rb", T_MX, C_IN, 3600, 1, "mxb", 4);
|
||||
DNS_RR *c = dns_rr_create_noport("qc", "rc", T_MX, C_IN, 3600, 1, "mxc", 4);
|
||||
DNS_RR *got, *want, *list;
|
||||
|
||||
((list = a)->next = b)->next = c;
|
||||
(want = dns_rr_copy(b))->next = dns_rr_copy(c);
|
||||
got = dns_rr_detach(list, a);
|
||||
dns_rr_free(a);
|
||||
|
||||
return (eq_dns_rr_free(got, want));
|
||||
}
|
||||
|
||||
static int detach_last_element(void)
|
||||
{
|
||||
DNS_RR *a = dns_rr_create_noport("qa", "ra", T_MX, C_IN, 3600, 1, "mxa", 4);
|
||||
DNS_RR *b = dns_rr_create_noport("qb", "rb", T_MX, C_IN, 3600, 1, "mxb", 4);
|
||||
DNS_RR *c = dns_rr_create_noport("qc", "rc", T_MX, C_IN, 3600, 1, "mxc", 4);
|
||||
DNS_RR *got, *want, *list;
|
||||
|
||||
((list = a)->next = b)->next = c;
|
||||
(want = dns_rr_copy(a))->next = dns_rr_copy(b);
|
||||
got = dns_rr_detach(list, c);
|
||||
dns_rr_free(c);
|
||||
|
||||
return (eq_dns_rr_free(got, want));
|
||||
}
|
||||
|
||||
/*
|
||||
* The test cases.
|
||||
*/
|
||||
@ -400,9 +487,15 @@ static const TEST_CASE test_cases[] = {
|
||||
"append to element from list exact fit", append_to_elem_from_list_exact_fit,
|
||||
|
||||
/*
|
||||
* TODO: tests dns_rr_sort(), dns_rr_srv_sort(), dns_rr_remove(),
|
||||
* dns_rr_shuffle(), etc.
|
||||
* TODO: tests for dns_rr_sort(), dns_rr_srv_sort(), dns_rr_shuffle(),
|
||||
* etc.
|
||||
*/
|
||||
"delete element from list (middle)", delete_middle_element,
|
||||
"delete element from list (first)", delete_first_element,
|
||||
"delete element from list (last)", delete_last_element,
|
||||
"detach element from list (middle)", detach_middle_element,
|
||||
"detach element from list (first)", detach_first_element,
|
||||
"detach element from list (last)", detach_last_element,
|
||||
0,
|
||||
};
|
||||
|
||||
|
@ -250,15 +250,12 @@ static int haproxy_srvr_parse_addr(const char *str, MAI_HOSTADDR_STR *addr,
|
||||
}
|
||||
if (err == 0)
|
||||
err = (hostaddr_to_sockaddr(str, (char *) 0, 0, &res)
|
||||
|| sockaddr_to_hostaddr(res->ai_addr, res->ai_addrlen,
|
||||
addr, (MAI_SERVPORT_STR *) 0, 0));
|
||||
|| sane_sockaddr_to_hostaddr(res->ai_addr, res->ai_addrlen,
|
||||
addr, (MAI_SERVPORT_STR *) 0, 0));
|
||||
if (res)
|
||||
freeaddrinfo(res);
|
||||
if (err)
|
||||
return (-1);
|
||||
if (addr->buf[0] == ':' && strncasecmp("::ffff:", addr->buf, 7) == 0
|
||||
&& strchr((char *) proto_info->sa_family_list, AF_INET) != 0)
|
||||
memmove(addr->buf, addr->buf + 7, strlen(addr->buf) + 1 - 7);
|
||||
return (0);
|
||||
}
|
||||
|
||||
|
@ -4459,6 +4459,22 @@ extern bool var_ign_srv_lookup_err;
|
||||
#define DEF_ALLOW_SRV_FALLBACK 0
|
||||
extern bool var_allow_srv_fallback;
|
||||
|
||||
/*
|
||||
* TLSRPT notification support. The lmtp_ names must be defined because the
|
||||
* build system enforces that every smtp_ parameter has an lmtp_ variant.
|
||||
*/
|
||||
#define VAR_SMTP_TLSRPT_ENABLE "smtp_tlsrpt_enable"
|
||||
#define DEF_SMTP_TLSRPT_ENABLE "no"
|
||||
#define VAR_LMTP_TLSRPT_ENABLE "lmtp_tlsrpt_enable"
|
||||
#define DEF_LMTP_TLSRPT_ENABLE DEF_SMTP_TLSRPT_ENABLE
|
||||
extern bool var_smtp_tlsrpt_enable;
|
||||
|
||||
#define VAR_SMTP_TLSRPT_SOCKNAME "smtp_tlsrpt_socket_name"
|
||||
#define DEF_SMTP_TLSRPT_SOCKNAME ""
|
||||
#define VAR_LMTP_TLSRPT_SOCKNAME "lmtp_tlsrpt_socket_name"
|
||||
#define DEF_LMTP_TLSRPT_SOCKNAME DEF_SMTP_TLSRPT_SOCKNAME
|
||||
extern char *var_smtp_tlsrpt_sockname;
|
||||
|
||||
/* LICENSE
|
||||
/* .ad
|
||||
/* .fi
|
||||
@ -4473,6 +4489,9 @@ extern bool var_allow_srv_fallback;
|
||||
/* Google, Inc.
|
||||
/* 111 8th Avenue
|
||||
/* New York, NY 10011, USA
|
||||
/*
|
||||
/* Wietse Venema
|
||||
/* porcupine.org
|
||||
/*--*/
|
||||
|
||||
#endif
|
||||
|
@ -20,7 +20,7 @@
|
||||
* Patches change both the patchlevel and the release date. Snapshots have no
|
||||
* patchlevel; they change the release date only.
|
||||
*/
|
||||
#define MAIL_RELEASE_DATE "20240924"
|
||||
#define MAIL_RELEASE_DATE "20240926"
|
||||
#define MAIL_VERSION_NUMBER "3.10"
|
||||
|
||||
#ifdef SNAPSHOT
|
||||
|
@ -35,6 +35,8 @@
|
||||
/* This feature is available in Postfix 2.7 and later.
|
||||
/* .IP \fB-f\fR
|
||||
/* Prepend the file name to each output line.
|
||||
/* .sp
|
||||
/* This feature is available in Postfix 3.10 and later.
|
||||
/* .IP \fB-h\fR
|
||||
/* Show message header content. The \fB-h\fR option produces
|
||||
/* output from the beginning of the message up to, but not
|
||||
|
@ -110,25 +110,6 @@
|
||||
|
||||
static const INET_PROTO_INFO *proto_info;
|
||||
|
||||
/* psc_sockaddr_to_hostaddr - transform endpoint address and port to string */
|
||||
|
||||
static int psc_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 ((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);
|
||||
}
|
||||
|
||||
/* psc_endpt_local_lookup - look up local system connection information */
|
||||
|
||||
void psc_endpt_local_lookup(VSTREAM *smtp_client_stream,
|
||||
@ -156,7 +137,7 @@ void psc_endpt_local_lookup(VSTREAM *smtp_client_stream,
|
||||
* Convert the remote SMTP client address and port to printable form for
|
||||
* logging and access control.
|
||||
*/
|
||||
else if ((aierr = psc_sockaddr_to_hostaddr(
|
||||
else if ((aierr = sane_sockaddr_to_hostaddr(
|
||||
(struct sockaddr *) &addr_storage,
|
||||
addr_storage_len, &smtp_client_addr,
|
||||
&smtp_client_port, SOCK_STREAM)) != 0) {
|
||||
@ -180,7 +161,7 @@ void psc_endpt_local_lookup(VSTREAM *smtp_client_stream,
|
||||
* Convert the local SMTP server address and port to printable form for
|
||||
* logging.
|
||||
*/
|
||||
else if ((aierr = psc_sockaddr_to_hostaddr(
|
||||
else if ((aierr = sane_sockaddr_to_hostaddr(
|
||||
(struct sockaddr *) &addr_storage,
|
||||
addr_storage_len, &smtp_server_addr,
|
||||
&smtp_server_port, SOCK_STREAM)) != 0) {
|
||||
|
@ -835,6 +835,8 @@ static int starttls(STATE *state)
|
||||
= vstring_str(cipher_exclusions),
|
||||
matchargv = state->match,
|
||||
mdalg = state->mdalg,
|
||||
tlsrpt = 0,
|
||||
ffail_type = 0,
|
||||
dane = state->ddane ?
|
||||
state->ddane : state->dane);
|
||||
|
||||
@ -939,6 +941,8 @@ static int starttls(STATE *state)
|
||||
= vstring_str(cipher_exclusions),
|
||||
matchargv = state->match,
|
||||
mdalg = state->mdalg,
|
||||
tlsrpt = 0,
|
||||
ffail_type = 0,
|
||||
dane = state->ddane ? state->ddane : state->dane);
|
||||
} /* tlsproxy_mode */
|
||||
vstring_free(cipher_exclusions);
|
||||
|
@ -2,11 +2,11 @@ SHELL = /bin/sh
|
||||
SRCS = smtp.c smtp_connect.c smtp_proto.c smtp_chat.c smtp_session.c \
|
||||
smtp_addr.c smtp_trouble.c smtp_state.c smtp_rcpt.c smtp_tls_policy.c \
|
||||
smtp_sasl_proto.c smtp_sasl_glue.c smtp_reuse.c smtp_map11.c \
|
||||
smtp_sasl_auth_cache.c smtp_key.c smtp_misc.c
|
||||
smtp_sasl_auth_cache.c smtp_key.c smtp_misc.c smtp_tlsrpt.c
|
||||
OBJS = smtp.o smtp_connect.o smtp_proto.o smtp_chat.o smtp_session.o \
|
||||
smtp_addr.o smtp_trouble.o smtp_state.o smtp_rcpt.o smtp_tls_policy.o \
|
||||
smtp_sasl_proto.o smtp_sasl_glue.o smtp_reuse.o smtp_map11.o \
|
||||
smtp_sasl_auth_cache.o smtp_key.o smtp_misc.o
|
||||
smtp_sasl_auth_cache.o smtp_key.o smtp_misc.o smtp_tlsrpt.o
|
||||
HDRS = smtp.h smtp_sasl.h smtp_addr.h smtp_reuse.h smtp_sasl_auth_cache.h
|
||||
TESTSRC =
|
||||
DEFS = -I. -I$(INC_DIR) -D$(SYSTYPE)
|
||||
@ -267,6 +267,7 @@ smtp_connect.o: ../../include/timed_connect.h
|
||||
smtp_connect.o: ../../include/tls.h
|
||||
smtp_connect.o: ../../include/tls_proxy.h
|
||||
smtp_connect.o: ../../include/tok822.h
|
||||
smtp_connect.o: ../../include/valid_hostname.h
|
||||
smtp_connect.o: ../../include/vbuf.h
|
||||
smtp_connect.o: ../../include/vstream.h
|
||||
smtp_connect.o: ../../include/vstring.h
|
||||
@ -447,6 +448,7 @@ smtp_proto.o: ../../include/stringops.h
|
||||
smtp_proto.o: ../../include/sys_defs.h
|
||||
smtp_proto.o: ../../include/tls.h
|
||||
smtp_proto.o: ../../include/tls_proxy.h
|
||||
smtp_proto.o: ../../include/tlsrpt_wrapper.h
|
||||
smtp_proto.o: ../../include/tok822.h
|
||||
smtp_proto.o: ../../include/uxtext.h
|
||||
smtp_proto.o: ../../include/vbuf.h
|
||||
@ -737,6 +739,7 @@ smtp_state.o: ../../include/string_list.h
|
||||
smtp_state.o: ../../include/sys_defs.h
|
||||
smtp_state.o: ../../include/tls.h
|
||||
smtp_state.o: ../../include/tls_proxy.h
|
||||
smtp_state.o: ../../include/tlsrpt_wrapper.h
|
||||
smtp_state.o: ../../include/tok822.h
|
||||
smtp_state.o: ../../include/vbuf.h
|
||||
smtp_state.o: ../../include/vstream.h
|
||||
@ -770,6 +773,7 @@ smtp_tls_policy.o: ../../include/name_mask.h
|
||||
smtp_tls_policy.o: ../../include/nvtable.h
|
||||
smtp_tls_policy.o: ../../include/recipient_list.h
|
||||
smtp_tls_policy.o: ../../include/resolve_clnt.h
|
||||
smtp_tls_policy.o: ../../include/sane_strtol.h
|
||||
smtp_tls_policy.o: ../../include/scache.h
|
||||
smtp_tls_policy.o: ../../include/sock_addr.h
|
||||
smtp_tls_policy.o: ../../include/string_list.h
|
||||
@ -777,6 +781,7 @@ smtp_tls_policy.o: ../../include/stringops.h
|
||||
smtp_tls_policy.o: ../../include/sys_defs.h
|
||||
smtp_tls_policy.o: ../../include/tls.h
|
||||
smtp_tls_policy.o: ../../include/tls_proxy.h
|
||||
smtp_tls_policy.o: ../../include/tlsrpt_wrapper.h
|
||||
smtp_tls_policy.o: ../../include/tok822.h
|
||||
smtp_tls_policy.o: ../../include/valid_hostname.h
|
||||
smtp_tls_policy.o: ../../include/valid_utf8_hostname.h
|
||||
@ -785,6 +790,48 @@ smtp_tls_policy.o: ../../include/vstream.h
|
||||
smtp_tls_policy.o: ../../include/vstring.h
|
||||
smtp_tls_policy.o: smtp.h
|
||||
smtp_tls_policy.o: smtp_tls_policy.c
|
||||
smtp_tlsrpt.o: ../../include/argv.h
|
||||
smtp_tlsrpt.o: ../../include/attr.h
|
||||
smtp_tlsrpt.o: ../../include/check_arg.h
|
||||
smtp_tlsrpt.o: ../../include/deliver_request.h
|
||||
smtp_tlsrpt.o: ../../include/dict.h
|
||||
smtp_tlsrpt.o: ../../include/dns.h
|
||||
smtp_tlsrpt.o: ../../include/dsn.h
|
||||
smtp_tlsrpt.o: ../../include/dsn_buf.h
|
||||
smtp_tlsrpt.o: ../../include/header_body_checks.h
|
||||
smtp_tlsrpt.o: ../../include/header_opts.h
|
||||
smtp_tlsrpt.o: ../../include/hex_code.h
|
||||
smtp_tlsrpt.o: ../../include/htable.h
|
||||
smtp_tlsrpt.o: ../../include/inet_proto.h
|
||||
smtp_tlsrpt.o: ../../include/mail_params.h
|
||||
smtp_tlsrpt.o: ../../include/maps.h
|
||||
smtp_tlsrpt.o: ../../include/match_list.h
|
||||
smtp_tlsrpt.o: ../../include/midna_domain.h
|
||||
smtp_tlsrpt.o: ../../include/mime_state.h
|
||||
smtp_tlsrpt.o: ../../include/msg.h
|
||||
smtp_tlsrpt.o: ../../include/msg_stats.h
|
||||
smtp_tlsrpt.o: ../../include/myaddrinfo.h
|
||||
smtp_tlsrpt.o: ../../include/myflock.h
|
||||
smtp_tlsrpt.o: ../../include/mymalloc.h
|
||||
smtp_tlsrpt.o: ../../include/name_code.h
|
||||
smtp_tlsrpt.o: ../../include/name_mask.h
|
||||
smtp_tlsrpt.o: ../../include/nvtable.h
|
||||
smtp_tlsrpt.o: ../../include/recipient_list.h
|
||||
smtp_tlsrpt.o: ../../include/resolve_clnt.h
|
||||
smtp_tlsrpt.o: ../../include/scache.h
|
||||
smtp_tlsrpt.o: ../../include/sock_addr.h
|
||||
smtp_tlsrpt.o: ../../include/string_list.h
|
||||
smtp_tlsrpt.o: ../../include/stringops.h
|
||||
smtp_tlsrpt.o: ../../include/sys_defs.h
|
||||
smtp_tlsrpt.o: ../../include/tls.h
|
||||
smtp_tlsrpt.o: ../../include/tls_proxy.h
|
||||
smtp_tlsrpt.o: ../../include/tlsrpt_wrapper.h
|
||||
smtp_tlsrpt.o: ../../include/tok822.h
|
||||
smtp_tlsrpt.o: ../../include/vbuf.h
|
||||
smtp_tlsrpt.o: ../../include/vstream.h
|
||||
smtp_tlsrpt.o: ../../include/vstring.h
|
||||
smtp_tlsrpt.o: smtp.h
|
||||
smtp_tlsrpt.o: smtp_tlsrpt.c
|
||||
smtp_trouble.o: ../../include/argv.h
|
||||
smtp_trouble.o: ../../include/attr.h
|
||||
smtp_trouble.o: ../../include/bounce.h
|
||||
|
@ -67,6 +67,7 @@
|
||||
VAR_TLSPROXY_SERVICE, DEF_TLSPROXY_SERVICE, &var_tlsproxy_service, 1, 0,
|
||||
VAR_HFROM_FORMAT, DEF_HFROM_FORMAT, &var_hfrom_format, 1, 0,
|
||||
VAR_USE_SRV_LOOKUP, DEF_USE_SRV_LOOKUP, &var_use_srv_lookup, 0, 0,
|
||||
VAR_LMTP_TLSRPT_SOCKNAME, DEF_LMTP_TLSRPT_SOCKNAME, &var_smtp_tlsrpt_sockname, 0, 0,
|
||||
0,
|
||||
};
|
||||
static const CONFIG_TIME_TABLE lmtp_time_table[] = {
|
||||
@ -137,5 +138,6 @@
|
||||
};
|
||||
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,
|
||||
};
|
||||
|
@ -638,6 +638,12 @@
|
||||
/* .IP "\fBsmtp_tls_enable_rpk (no)\fR"
|
||||
/* Request that remote SMTP servers send an RFC7250 raw public key
|
||||
/* instead of an X.509 certificate.
|
||||
/* .PP Available in Postfix version 3.10 and later:
|
||||
/* .IP "\fBsmtp_tlsrpt_enable (no)\fR"
|
||||
/* Enable support for RFC 8460 TLSRPT notifications.
|
||||
/* .IP "\fBsmtp_tlsrpt_socket_name (empty)\fR"
|
||||
/* The pathname of a UNIX-domain datagram socket that is managed
|
||||
/* by a local TLSRPT reporting service.
|
||||
/* OBSOLETE STARTTLS CONTROLS
|
||||
/* .ad
|
||||
/* .fi
|
||||
@ -1146,6 +1152,8 @@ int var_smtp_min_data_rate;
|
||||
char *var_use_srv_lookup;
|
||||
bool var_ign_srv_lookup_err;
|
||||
bool var_allow_srv_fallback;
|
||||
bool var_smtp_tlsrpt_enable;
|
||||
char *var_smtp_tlsrpt_sockname;
|
||||
|
||||
/* Special handling of 535 AUTH errors. */
|
||||
char *var_smtp_sasl_auth_cache_name;
|
||||
@ -1399,7 +1407,23 @@ static void post_init(char *unused_name, char **argv)
|
||||
var_disable_dns = (smtp_dns_support == SMTP_DNS_DISABLED);
|
||||
}
|
||||
|
||||
#if !defined(USE_TLS) || !defined(USE_TLSRPT)
|
||||
if (var_smtp_tlsrpt_enable)
|
||||
msg_warn("TLSRPT is selected, but TLSRPT is not compiled in");
|
||||
#endif
|
||||
#ifdef USE_TLS
|
||||
#ifdef USE_TLSRPT
|
||||
if (var_smtp_tlsrpt_enable) {
|
||||
if (smtp_mode) {
|
||||
if (smtp_tlsrpt_post_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;
|
||||
}
|
||||
}
|
||||
#endif /* USE_TLSRPT */
|
||||
if (smtp_mode) {
|
||||
smtp_tls_insecure_mx_policy =
|
||||
tls_level_lookup(var_smtp_tls_insecure_mx_policy);
|
||||
|
@ -108,8 +108,28 @@ typedef struct SMTP_TLS_POLICY {
|
||||
char *sni; /* Optional SNI name when not DANE */
|
||||
int conn_reuse; /* enable connection reuse */
|
||||
int enable_rpk; /* Enable server->client RPK */
|
||||
/* External policy info, for TLSRPT. */
|
||||
int ext_policy_ttl; /* TTL from DNS etc. */
|
||||
char *ext_policy_type; /* (sts) */
|
||||
ARGV *ext_policy_strings; /* policy strings from DNS etc. */
|
||||
char *ext_policy_domain; /* policy scope */
|
||||
ARGV *ext_mx_host_patterns; /* (sts) MX host patterns */
|
||||
char *ext_policy_failure; /* (sts) policy failure */
|
||||
} SMTP_TLS_POLICY;
|
||||
|
||||
/*
|
||||
* Names and values for external policy attributes in smtp_tls_policy_maps.
|
||||
* These are not #ifdef USE_TLSRPT, so that a TLSRPT-aware STS plugin can be
|
||||
* used whether or not Postfix was built with TLSRPT support.
|
||||
*/
|
||||
#define EXT_POLICY_TTL "policy_ttl"
|
||||
#define EXT_POLICY_TTL_UNSET (-1)
|
||||
#define EXT_POLICY_TYPE "policy_type"
|
||||
#define EXT_POLICY_DOMAIN "policy_domain"
|
||||
#define EXT_POLICY_STRING "policy_string"
|
||||
#define EXT_MX_HOST_PATTERN "mx_host_pattern"
|
||||
#define EXT_POLICY_FAILURE "policy_failure"
|
||||
|
||||
/*
|
||||
* smtp_tls_policy.c
|
||||
*/
|
||||
@ -144,6 +164,12 @@ extern void smtp_tls_policy_cache_flush(void);
|
||||
_tls_policy_init_tmp->sni = 0; \
|
||||
_tls_policy_init_tmp->conn_reuse = 0; \
|
||||
_tls_policy_init_tmp->enable_rpk = 0; \
|
||||
_tls_policy_init_tmp->ext_policy_ttl = EXT_POLICY_TTL_UNSET; \
|
||||
_tls_policy_init_tmp->ext_policy_type = 0; \
|
||||
_tls_policy_init_tmp->ext_policy_domain = 0; \
|
||||
_tls_policy_init_tmp->ext_policy_strings = 0; \
|
||||
_tls_policy_init_tmp->ext_mx_host_patterns = 0; \
|
||||
_tls_policy_init_tmp->ext_policy_failure = 0; \
|
||||
} while (0)
|
||||
|
||||
#endif
|
||||
@ -171,6 +197,9 @@ typedef struct SMTP_STATE {
|
||||
*/
|
||||
#ifdef USE_TLS
|
||||
SMTP_TLS_POLICY tls[1]; /* Usage: state->tls->member */
|
||||
#ifdef USE_TLSRPT
|
||||
struct TLSRPT_WRAPPER *tlsrpt;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/*
|
||||
@ -757,6 +786,18 @@ extern void smtp_quote_821_address(VSTRING *, const char *);
|
||||
*/
|
||||
extern int smtp_hfrom_format;
|
||||
|
||||
/*
|
||||
* smtp_tlsrpt.c.
|
||||
*/
|
||||
#if defined(USE_TLS) && defined(USE_TLSRPT)
|
||||
extern int smtp_tlsrpt_post_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
|
||||
|
@ -104,6 +104,7 @@
|
||||
#include <mail_error.h>
|
||||
#include <dsn_buf.h>
|
||||
#include <mail_addr.h>
|
||||
#include <valid_hostname.h>
|
||||
|
||||
/* DNS library. */
|
||||
|
||||
@ -911,6 +912,21 @@ static void smtp_connect_inet(SMTP_STATE *state, const char *nexthop,
|
||||
|
||||
SMTP_ITER_INIT(iter, dest, NO_HOST, NO_ADDR, port, state);
|
||||
|
||||
/*
|
||||
* TODO(wietse) If the domain publishes a TLSRPT policy, they expect
|
||||
* that clients use SMTP over TLS. Should we upgrade a TLS security
|
||||
* level of "may" to "encrypt"? This would disable falling back to
|
||||
* plaintext, and could break interoperability with receivers that
|
||||
* crank up security up to 11.
|
||||
*/
|
||||
#ifdef USE_TLSRPT
|
||||
if (smtp_mode && var_smtp_tlsrpt_enable
|
||||
&& !valid_hostaddr(domain, DONT_GRIPE))
|
||||
smtp_tlsrpt_create_wrapper(state, domain);
|
||||
else
|
||||
state->tlsrpt = 0;
|
||||
#endif /* USE_TLSRPT */
|
||||
|
||||
/*
|
||||
* Resolve an SMTP or LMTP server. Skip MX or SRV lookups when a
|
||||
* quoted domain is specified or when DNS lookups are disabled.
|
||||
@ -1076,6 +1092,18 @@ static void smtp_connect_inet(SMTP_STATE *state, const char *nexthop,
|
||||
session->state = state;
|
||||
#ifdef USE_TLS
|
||||
session->tls_nexthop = domain;
|
||||
|
||||
/*
|
||||
* Update TLSRPT state even if this is a reused SMTP
|
||||
* connection. If for some unlikely reason we must report a
|
||||
* problem, then we must report correct information.
|
||||
*/
|
||||
#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;
|
||||
|
@ -68,6 +68,7 @@
|
||||
VAR_TLSPROXY_SERVICE, DEF_TLSPROXY_SERVICE, &var_tlsproxy_service, 1, 0,
|
||||
VAR_HFROM_FORMAT, DEF_HFROM_FORMAT, &var_hfrom_format, 1, 0,
|
||||
VAR_USE_SRV_LOOKUP, DEF_USE_SRV_LOOKUP, &var_use_srv_lookup, 0, 0,
|
||||
VAR_SMTP_TLSRPT_SOCKNAME, DEF_SMTP_TLSRPT_SOCKNAME, &var_smtp_tlsrpt_sockname, 0, 0,
|
||||
0,
|
||||
};
|
||||
static const CONFIG_TIME_TABLE smtp_time_table[] = {
|
||||
@ -141,5 +142,6 @@
|
||||
};
|
||||
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,
|
||||
};
|
||||
|
@ -78,6 +78,9 @@
|
||||
/* 111 8th Avenue
|
||||
/* New York, NY 10011, USA
|
||||
/*
|
||||
/* Wietse Venema
|
||||
/* porcupine.org
|
||||
/*
|
||||
/* Pipelining code in cooperation with:
|
||||
/* Jon Ribbens
|
||||
/* Oaktree Internet Solutions Ltd.,
|
||||
@ -155,6 +158,9 @@
|
||||
#include <xtext.h>
|
||||
#include <uxtext.h>
|
||||
#include <smtputf8.h>
|
||||
#if defined(USE_TLS) && defined(USE_TLSRPT)
|
||||
#include <tlsrpt_wrapper.h>
|
||||
#endif
|
||||
|
||||
/* Application-specific. */
|
||||
|
||||
@ -475,6 +481,11 @@ int smtp_helo(SMTP_STATE *state)
|
||||
else
|
||||
session->features &= ~SMTP_FEATURE_ESMTP;
|
||||
}
|
||||
#ifdef USE_TLSRPT
|
||||
if (state->tlsrpt
|
||||
&& (state->misc_flags & SMTP_MISC_FLAG_IN_STARTTLS) == 0)
|
||||
smtp_tlsrpt_set_ehlo_resp(state, resp->str);
|
||||
#endif
|
||||
}
|
||||
if ((session->features & SMTP_FEATURE_ESMTP) == 0) {
|
||||
where = "performing the HELO handshake";
|
||||
@ -484,6 +495,10 @@ int smtp_helo(SMTP_STATE *state)
|
||||
"host %s refused to talk to me: %s",
|
||||
session->namaddr,
|
||||
translit(resp->str, "\n", " ")));
|
||||
#ifdef USE_TLSRPT
|
||||
if (state->tlsrpt)
|
||||
trw_set_ehlo_resp(state->tlsrpt, resp->str);
|
||||
#endif
|
||||
}
|
||||
} else {
|
||||
where = "performing the LHLO handshake";
|
||||
@ -798,11 +813,19 @@ int smtp_helo(SMTP_STATE *state)
|
||||
* although support for it was announced in the EHLO response.
|
||||
*/
|
||||
session->features &= ~SMTP_FEATURE_STARTTLS;
|
||||
if (TLS_REQUIRED(state->tls->level))
|
||||
if (TLS_REQUIRED(state->tls->level)) {
|
||||
#ifdef USE_TLSRPT
|
||||
if (state->tlsrpt)
|
||||
trw_report_failure(state->tlsrpt,
|
||||
TLSRPT_STARTTLS_NOT_SUPPORTED,
|
||||
/* additional_info= */ (char *) 0,
|
||||
/* failure_reason= */ (char *) 0);
|
||||
#endif
|
||||
return (smtp_site_fail(state, STR(iter->host), resp,
|
||||
"TLS is required, but host %s refused to start TLS: %s",
|
||||
session->namaddr,
|
||||
translit(resp->str, "\n", " ")));
|
||||
}
|
||||
/* Else try to continue in plain-text mode. */
|
||||
}
|
||||
|
||||
@ -815,6 +838,13 @@ int smtp_helo(SMTP_STATE *state)
|
||||
*/
|
||||
if (TLS_REQUIRED(state->tls->level)) {
|
||||
if (!(session->features & SMTP_FEATURE_STARTTLS)) {
|
||||
#ifdef USE_TLSRPT
|
||||
if (state->tlsrpt)
|
||||
trw_report_failure(state->tlsrpt,
|
||||
TLSRPT_STARTTLS_NOT_SUPPORTED,
|
||||
/* additional_info= */ (char *) 0,
|
||||
/* failure_reason= */ (char *) 0);
|
||||
#endif
|
||||
return (smtp_site_fail(state, DSN_BY_LOCAL_MTA,
|
||||
SMTP_RESP_FAKE(&fake, "4.7.4"),
|
||||
"TLS is required, but was not offered by host %s",
|
||||
@ -942,6 +972,12 @@ static int smtp_start_tls(SMTP_STATE *state)
|
||||
= vstring_str(state->tls->exclusions),
|
||||
matchargv = state->tls->matchargv,
|
||||
mdalg = var_smtp_tls_fpt_dgst,
|
||||
#ifdef USE_TLSRPT
|
||||
tlsrpt = state->tlsrpt,
|
||||
#else
|
||||
tlsrpt = 0,
|
||||
#endif
|
||||
ffail_type = 0,
|
||||
dane = state->tls->dane);
|
||||
|
||||
/*
|
||||
@ -1065,6 +1101,12 @@ static int smtp_start_tls(SMTP_STATE *state)
|
||||
= vstring_str(state->tls->exclusions),
|
||||
matchargv = state->tls->matchargv,
|
||||
mdalg = var_smtp_tls_fpt_dgst,
|
||||
#ifdef USE_TLSRPT
|
||||
tlsrpt = state->tlsrpt,
|
||||
#else
|
||||
tlsrpt = 0,
|
||||
#endif
|
||||
ffail_type = state->tls->ext_policy_failure,
|
||||
dane = state->tls->dane);
|
||||
|
||||
/*
|
||||
@ -1125,10 +1167,43 @@ static int smtp_start_tls(SMTP_STATE *state)
|
||||
* we must check that here, and not state->tls->level.
|
||||
*/
|
||||
if (TLS_MUST_MATCH(session->tls_context->level))
|
||||
if (!TLS_CERT_IS_MATCHED(session->tls_context))
|
||||
if (!TLS_CERT_IS_MATCHED(session->tls_context)) {
|
||||
#ifdef USE_TLSRPT
|
||||
|
||||
/*
|
||||
* Don't create a TLSRPT 'failure' event 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_info= */ (char *) 0,
|
||||
/* failure_reason= */ (char *) 0);
|
||||
} else {
|
||||
(void) trw_report_failure(state->tlsrpt,
|
||||
TLSRPT_CERTIFICATE_HOST_MISMATCH,
|
||||
/* additional_info= */ (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' event only if the TLS engine has not created
|
||||
* TLSRPT event. For example, The TLS engine will create a TLSRPT
|
||||
* 'failure' event when the TLS handshake was be successful, but the
|
||||
* security level was downgraded from opportunistic "dane" to
|
||||
* unauthenticated "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
|
||||
|
@ -50,6 +50,13 @@
|
||||
#include <mail_params.h>
|
||||
#include <debug_peer.h>
|
||||
|
||||
/*
|
||||
* TLS library.
|
||||
*/
|
||||
#if defined(USE_TLS) && defined(USE_TLSRPT)
|
||||
#include <tlsrpt_wrapper.h>
|
||||
#endif
|
||||
|
||||
/* Application-specific. */
|
||||
|
||||
#include "smtp.h"
|
||||
@ -73,6 +80,9 @@ SMTP_STATE *smtp_state_alloc(void)
|
||||
state->iterator->host = vstring_alloc(100);
|
||||
state->iterator->addr = vstring_alloc(100);
|
||||
state->iterator->saved_dest = vstring_alloc(100);
|
||||
#ifdef USE_TLSRPT
|
||||
state->tlsrpt = 0;
|
||||
#endif
|
||||
if (var_smtp_cache_conn) {
|
||||
state->dest_label = vstring_alloc(10);
|
||||
state->dest_prop = vstring_alloc(10);
|
||||
@ -105,6 +115,10 @@ void smtp_state_free(SMTP_STATE *state)
|
||||
vstring_free(state->iterator->host);
|
||||
vstring_free(state->iterator->addr);
|
||||
vstring_free(state->iterator->saved_dest);
|
||||
#ifdef USE_TLSRPT
|
||||
if (state->tlsrpt)
|
||||
trw_free(state->tlsrpt);
|
||||
#endif
|
||||
if (state->dest_label)
|
||||
vstring_free(state->dest_label);
|
||||
if (state->dest_prop)
|
||||
|
@ -102,6 +102,7 @@
|
||||
#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>
|
||||
@ -113,6 +114,10 @@
|
||||
#include <maps.h>
|
||||
#include <dsn_buf.h>
|
||||
|
||||
/* TLS library. */
|
||||
|
||||
#include <tlsrpt_wrapper.h>
|
||||
|
||||
/* DNS library. */
|
||||
|
||||
#include <dns.h>
|
||||
@ -221,15 +226,21 @@ static void tls_policy_lookup_one(SMTP_TLS_POLICY *tls, int *site_level,
|
||||
{
|
||||
const char *lookup;
|
||||
char *policy;
|
||||
char *saved_policy;
|
||||
char *saved_policy = 0;
|
||||
char *tok;
|
||||
const char *err;
|
||||
char *name;
|
||||
char *val;
|
||||
static VSTRING *cbuf;
|
||||
char *free_me = 0;
|
||||
|
||||
#undef FREE_RETURN
|
||||
#define FREE_RETURN do { myfree(saved_policy); return; } while (0)
|
||||
#define FREE_RETURN do { \
|
||||
if (saved_policy) \
|
||||
myfree(saved_policy); \
|
||||
if (free_me) \
|
||||
myfree(free_me); \
|
||||
return; \
|
||||
} while (0)
|
||||
|
||||
#define INVALID_RETURN(why, levelp) do { \
|
||||
MARK_INVALID((why), (levelp)); FREE_RETURN; } while (0)
|
||||
@ -250,7 +261,7 @@ static void tls_policy_lookup_one(SMTP_TLS_POLICY *tls, int *site_level,
|
||||
}
|
||||
saved_policy = policy = mystrdup(lookup);
|
||||
|
||||
if ((tok = mystrtok(&policy, CHARS_COMMA_SP)) == 0) {
|
||||
if ((tok = mystrtokq(&policy, CHARS_COMMA_SP, CHARS_BRACE)) == 0) {
|
||||
msg_warn("%s: invalid empty policy", WHERE);
|
||||
INVALID_RETURN(tls->why, site_level);
|
||||
}
|
||||
@ -265,7 +276,7 @@ static void tls_policy_lookup_one(SMTP_TLS_POLICY *tls, int *site_level,
|
||||
* Warn about ignored attributes when TLS is disabled.
|
||||
*/
|
||||
if (*site_level < TLS_LEV_MAY) {
|
||||
while ((tok = mystrtok(&policy, CHARS_COMMA_SP)) != 0)
|
||||
while ((tok = mystrtokq(&policy, CHARS_COMMA_SP, CHARS_BRACE)) != 0)
|
||||
msg_warn("%s: ignoring attribute \"%s\" with TLS disabled",
|
||||
WHERE, tok);
|
||||
FREE_RETURN;
|
||||
@ -275,8 +286,12 @@ static void tls_policy_lookup_one(SMTP_TLS_POLICY *tls, int *site_level,
|
||||
* Errors in attributes may have security consequences, don't ignore
|
||||
* errors that can degrade security.
|
||||
*/
|
||||
while ((tok = mystrtok(&policy, CHARS_COMMA_SP)) != 0) {
|
||||
if ((err = split_nameval(tok, &name, &val)) != 0) {
|
||||
while ((tok = mystrtokq(&policy, CHARS_COMMA_SP, CHARS_BRACE)) != 0) {
|
||||
const char *err;
|
||||
|
||||
if ((tok[0] == CHARS_BRACE[0]
|
||||
&& (err = free_me = extpar(&tok, CHARS_BRACE, EXTPAR_FLAG_STRIP)) != 0)
|
||||
|| (err = split_nameval(tok, &name, &val)) != 0) {
|
||||
msg_warn("%s: malformed attribute/value pair \"%s\": %s",
|
||||
WHERE, tok, err);
|
||||
INVALID_RETURN(tls->why, site_level);
|
||||
@ -391,6 +406,7 @@ static void tls_policy_lookup_one(SMTP_TLS_POLICY *tls, int *site_level,
|
||||
}
|
||||
continue;
|
||||
}
|
||||
/* Last one wins. */
|
||||
if (!strcasecmp(name, "enable_rpk")) {
|
||||
/* Ultimately ignored at some security levels */
|
||||
if (strcasecmp(val, "yes") == 0) {
|
||||
@ -404,10 +420,98 @@ static void tls_policy_lookup_one(SMTP_TLS_POLICY *tls, int *site_level,
|
||||
}
|
||||
continue;
|
||||
}
|
||||
/* Only one instance per policy. */
|
||||
if (!strcasecmp(name, EXT_POLICY_TTL)) {
|
||||
char *end;
|
||||
long lval;
|
||||
|
||||
if (tls->ext_policy_ttl != EXT_POLICY_TTL_UNSET) {
|
||||
msg_warn("%s: attribute \"%s\" is specified multiple times",
|
||||
WHERE, name);
|
||||
INVALID_RETURN(tls->why, site_level);
|
||||
}
|
||||
if (!alldig(val) || ((lval = sane_strtol(val, &end, 10)),
|
||||
((tls->ext_policy_ttl = lval) != lval))
|
||||
|| *end != 0) {
|
||||
msg_warn("%s: attribute \"%s\" has a malformed value: \"%s\"",
|
||||
WHERE, name, val);
|
||||
INVALID_RETURN(tls->why, site_level);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
/* Only one instance per policy. */
|
||||
if (!strcasecmp(name, EXT_POLICY_TYPE)) {
|
||||
if (tls->ext_policy_type) {
|
||||
msg_warn("%s: attribute \"%s\" is specified multiple times",
|
||||
WHERE, name);
|
||||
INVALID_RETURN(tls->why, site_level);
|
||||
}
|
||||
if (!valid_tlsrpt_policy_type(val)) {
|
||||
msg_warn("%s: attribute \"%s\" has an unexpected value: \"%s\"",
|
||||
WHERE, name, val);
|
||||
INVALID_RETURN(tls->why, site_level);
|
||||
}
|
||||
tls->ext_policy_type = mystrdup(val);
|
||||
continue;
|
||||
}
|
||||
/* Only one instance per policy. */
|
||||
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 != EXT_POLICY_TTL_UNSET
|
||||
|| tls->ext_policy_strings
|
||||
|| tls->ext_policy_domain || tls->ext_mx_host_patterns
|
||||
|| tls->ext_policy_failure) {
|
||||
msg_warn("%s: built-in policy has unexpected attribute "
|
||||
"policy_ttl, policy_domain, policy_string, "
|
||||
"mx_host_pattern or policy_failure", WHERE);
|
||||
INVALID_RETURN(tls->why, site_level);
|
||||
}
|
||||
}
|
||||
FREE_RETURN;
|
||||
}
|
||||
|
||||
@ -707,6 +811,16 @@ static void policy_delete(void *item, void *unused_context)
|
||||
if (tls->dane)
|
||||
tls_dane_free(tls->dane);
|
||||
dsb_free(tls->why);
|
||||
if (tls->ext_policy_type)
|
||||
myfree(tls->ext_policy_type);
|
||||
if (tls->ext_policy_domain)
|
||||
myfree(tls->ext_policy_domain);
|
||||
if (tls->ext_policy_strings)
|
||||
argv_free(tls->ext_policy_strings);
|
||||
if (tls->ext_mx_host_patterns)
|
||||
argv_free(tls->ext_mx_host_patterns);
|
||||
if (tls->ext_policy_failure)
|
||||
myfree(tls->ext_policy_failure);
|
||||
|
||||
myfree((void *) tls);
|
||||
}
|
||||
|
414
postfix/src/smtp/smtp_tlsrpt.c
Normal file
414
postfix/src/smtp/smtp_tlsrpt.c
Normal file
@ -0,0 +1,414 @@
|
||||
/*++
|
||||
/* NAME
|
||||
/* smtp_tlsrpt 3
|
||||
/* SUMMARY
|
||||
/* TLSRPT support for the SMTP protocol engine
|
||||
/* SYNOPSIS
|
||||
/* #include <smtp_tlsrpt.h>
|
||||
/*
|
||||
/* int smtp_tlsrpt_post_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 populates a TLSRPT_WRAPPER object with a)
|
||||
/* remote TLSRPT policy information, b) remote TLSA or STS policy
|
||||
/* information, and c) selected SMTP connection information. This
|
||||
/* object is passed to a TLS protocol engine, which may run in a
|
||||
/* different process than the SMTP protocol engine. The TLS protocol
|
||||
/* engine uses the TLSRPT_WRAPPER object to report a TLS handshake
|
||||
/* error to a TLSRPT library. The SMTP protocol engine uses the
|
||||
/* object to report a TLS handshake error or success.
|
||||
/*
|
||||
/* smtp_tls_post_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 name is used in a
|
||||
/* diagnostic message.
|
||||
/* .IP sockname_pval
|
||||
/* The value of said parameter.
|
||||
/* .PP
|
||||
/* smtp_tlsrpt_create_wrapper() destroys a 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 for 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
|
||||
/* (the U-label form will be converted to A-label internally).
|
||||
/* .PP
|
||||
/* smtp_tlsrpt_set_tls_policy() updates the TLSRPT_WRAPPER
|
||||
/* object 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
|
||||
/* object with TCP connection properties.
|
||||
/* .PP
|
||||
/* smtp_tlsrpt_set_ehlo_resp() updates the TLSRPT_WRAPPER object
|
||||
/* 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_post_jail - post-jail configuration sanity check */
|
||||
|
||||
int smtp_tlsrpt_post_jail(const char *sockname_pname,
|
||||
const char *sockname_pval)
|
||||
{
|
||||
if (smtp_dns_support == SMTP_DNS_DISABLED) {
|
||||
msg_warn("Cannot enable %s: DNS is disabled", smtp_tlsrpt_support);
|
||||
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 code that actually
|
||||
* needs it.
|
||||
*/
|
||||
#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-TLSRPTv1 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 TLSRPT policies for %s",
|
||||
smtp_tlsrpt_support, adomain);
|
||||
dns_rr_free(rr_result);
|
||||
rr_result = 0;
|
||||
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_no_policy - no policy found */
|
||||
|
||||
static void smtp_tlsrpt_set_no_policy(SMTP_STATE *state)
|
||||
{
|
||||
trw_set_tls_policy(state->tlsrpt, TLSRPT_NO_POLICY_FOUND,
|
||||
/* tls_policy_strings= */ (const char *const *) 0,
|
||||
/* tls_policy_domain= */ (char *) 0,
|
||||
/* mx_host_patterns= */ (const char *const *) 0);
|
||||
}
|
||||
|
||||
/* 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;
|
||||
|
||||
if (tls->ext_policy_type == 0)
|
||||
msg_panic("smtp_tlsrpt_set_ext_policy: no policy type");
|
||||
|
||||
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:
|
||||
smtp_tlsrpt_set_no_policy(state);
|
||||
break;
|
||||
default:
|
||||
/* Policy type must be validated in smtp_tls_policy_maps parser. */
|
||||
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 /* No policy */
|
||||
smtp_tlsrpt_set_no_policy(state);
|
||||
} else if (tls->ext_policy_type) {
|
||||
smtp_tlsrpt_set_ext_policy(state);
|
||||
} else {
|
||||
smtp_tlsrpt_set_no_policy(state);
|
||||
}
|
||||
}
|
||||
|
||||
/* 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 server-side 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 */
|
@ -9,7 +9,7 @@ SRCS = tls_prng_dev.c tls_prng_egd.c tls_prng_file.c tls_fprint.c \
|
||||
tls_proxy_server_init_print.c tls_proxy_server_init_scan.c \
|
||||
tls_proxy_client_start_print.c tls_proxy_client_start_scan.c \
|
||||
tls_proxy_server_start_print.c tls_proxy_server_start_scan.c \
|
||||
tls_proxy_client_misc.c
|
||||
tls_proxy_client_misc.c tlsrpt_wrapper.c
|
||||
OBJS = tls_prng_dev.o tls_prng_egd.o tls_prng_file.o tls_fprint.o \
|
||||
tls_prng_exch.o tls_stream.o tls_bio_ops.o tls_misc.o tls_dh.o \
|
||||
tls_verify.o tls_dane.o tls_certkey.o tls_session.o \
|
||||
@ -18,8 +18,8 @@ OBJS = tls_prng_dev.o tls_prng_egd.o tls_prng_file.o tls_fprint.o \
|
||||
tls_proxy_clnt.o tls_proxy_context_print.o tls_proxy_context_scan.o \
|
||||
tls_proxy_client_print.o tls_proxy_client_scan.o \
|
||||
tls_proxy_server_print.o tls_proxy_server_scan.o \
|
||||
tls_proxy_client_misc.o
|
||||
HDRS = tls.h tls_prng.h tls_scache.h tls_mgr.h tls_proxy.h
|
||||
tls_proxy_client_misc.o tlsrpt_wrapper.o
|
||||
HDRS = tls.h tls_prng.h tls_scache.h tls_mgr.h tls_proxy.h tlsrpt_wrapper.h
|
||||
TESTSRC =
|
||||
DEFS = -I. -I$(INC_DIR) -D$(SYSTYPE)
|
||||
CFLAGS = $(DEBUG) $(OPT) $(DEFS)
|
||||
@ -182,6 +182,7 @@ tls_client.o: tls.h
|
||||
tls_client.o: tls_client.c
|
||||
tls_client.o: tls_mgr.h
|
||||
tls_client.o: tls_scache.h
|
||||
tls_client.o: tlsrpt_wrapper.h
|
||||
tls_dane.o: ../../include/argv.h
|
||||
tls_dane.o: ../../include/check_arg.h
|
||||
tls_dane.o: ../../include/ctable.h
|
||||
@ -366,6 +367,7 @@ tls_proxy_client_print.o: ../../include/vstring.h
|
||||
tls_proxy_client_print.o: tls.h
|
||||
tls_proxy_client_print.o: tls_proxy.h
|
||||
tls_proxy_client_print.o: tls_proxy_client_print.c
|
||||
tls_proxy_client_print.o: tlsrpt_wrapper.h
|
||||
tls_proxy_client_scan.o: ../../include/argv.h
|
||||
tls_proxy_client_scan.o: ../../include/argv_attr.h
|
||||
tls_proxy_client_scan.o: ../../include/attr.h
|
||||
@ -387,6 +389,7 @@ tls_proxy_client_scan.o: ../../include/vstring.h
|
||||
tls_proxy_client_scan.o: tls.h
|
||||
tls_proxy_client_scan.o: tls_proxy.h
|
||||
tls_proxy_client_scan.o: tls_proxy_client_scan.c
|
||||
tls_proxy_client_scan.o: tlsrpt_wrapper.h
|
||||
tls_proxy_clnt.o: ../../include/argv.h
|
||||
tls_proxy_clnt.o: ../../include/attr.h
|
||||
tls_proxy_clnt.o: ../../include/check_arg.h
|
||||
@ -588,3 +591,15 @@ tls_verify.o: ../../include/vstream.h
|
||||
tls_verify.o: ../../include/vstring.h
|
||||
tls_verify.o: tls.h
|
||||
tls_verify.o: tls_verify.c
|
||||
tls_verify.o: tlsrpt_wrapper.h
|
||||
tlsrpt_wrapper.o: ../../include/argv.h
|
||||
tlsrpt_wrapper.o: ../../include/check_arg.h
|
||||
tlsrpt_wrapper.o: ../../include/msg.h
|
||||
tlsrpt_wrapper.o: ../../include/mymalloc.h
|
||||
tlsrpt_wrapper.o: ../../include/name_code.h
|
||||
tlsrpt_wrapper.o: ../../include/stringops.h
|
||||
tlsrpt_wrapper.o: ../../include/sys_defs.h
|
||||
tlsrpt_wrapper.o: ../../include/vbuf.h
|
||||
tlsrpt_wrapper.o: ../../include/vstring.h
|
||||
tlsrpt_wrapper.o: tlsrpt_wrapper.c
|
||||
tlsrpt_wrapper.o: tlsrpt_wrapper.h
|
||||
|
@ -214,7 +214,7 @@ extern TLS_DANE *tls_dane_alloc(void);
|
||||
extern void tls_tlsa_free(TLS_TLSA *);
|
||||
extern void tls_dane_free(TLS_DANE *);
|
||||
extern void tls_dane_add_fpt_digests(TLS_DANE *, int, const char *,
|
||||
const char *, int);
|
||||
const char *, int);
|
||||
extern TLS_DANE *tls_dane_resolve(unsigned, const char *, DNS_RR *, int);
|
||||
extern int tls_dane_load_trustfile(TLS_DANE *, const char *);
|
||||
|
||||
@ -270,6 +270,8 @@ typedef struct {
|
||||
int errordepth; /* Chain depth of error cert */
|
||||
int errorcode; /* First error at error depth */
|
||||
int must_fail; /* Failed to load trust settings */
|
||||
int rpt_reported; /* Failure was reported with TLSRPT */
|
||||
char *ffail_type; /* Forced verification failure */
|
||||
} TLS_SESS_STATE;
|
||||
|
||||
/*
|
||||
@ -502,6 +504,8 @@ typedef struct {
|
||||
const ARGV *matchargv; /* Cert match patterns */
|
||||
const char *mdalg; /* default message digest algorithm */
|
||||
const TLS_DANE *dane; /* DANE TLSA verification */
|
||||
struct TLSRPT_WRAPPER *tlsrpt; /* RFC 8460 reporting */
|
||||
char *ffail_type; /* Forced verification failure */
|
||||
} TLS_CLIENT_START_PROPS;
|
||||
|
||||
extern TLS_APPL_STATE *tls_client_init(const TLS_CLIENT_INIT_PROPS *);
|
||||
@ -525,12 +529,13 @@ extern TLS_SESS_STATE *tls_client_post_connect(TLS_SESS_STATE *,
|
||||
a6, a7, a8, a9, a10, a11, a12, a13, a14))
|
||||
|
||||
#define TLS_CLIENT_START(props, a1, a2, a3, a4, a5, a6, a7, a8, a9, \
|
||||
a10, a11, a12, a13, a14, a15, a16, a17, a18) \
|
||||
a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20) \
|
||||
tls_client_start((((props)->a1), ((props)->a2), ((props)->a3), \
|
||||
((props)->a4), ((props)->a5), ((props)->a6), ((props)->a7), \
|
||||
((props)->a8), ((props)->a9), ((props)->a10), ((props)->a11), \
|
||||
((props)->a12), ((props)->a13), ((props)->a14), ((props)->a15), \
|
||||
((props)->a16), ((props)->a17), ((props)->a18), (props)))
|
||||
((props)->a16), ((props)->a17), ((props)->a18), ((props)->a19), \
|
||||
((props)->a20), (props)))
|
||||
|
||||
/*
|
||||
* tls_server.c
|
||||
@ -663,7 +668,7 @@ extern void tls_auto_groups(SSL_CTX *, const char *, const char *);
|
||||
extern char *tls_peer_CN(X509 *, const TLS_SESS_STATE *);
|
||||
extern char *tls_issuer_CN(X509 *, const TLS_SESS_STATE *);
|
||||
extern int tls_verify_certificate_callback(int, X509_STORE_CTX *);
|
||||
extern void tls_log_verify_error(TLS_SESS_STATE *);
|
||||
extern void tls_log_verify_error(TLS_SESS_STATE *, struct TLSRPT_WRAPPER *);
|
||||
|
||||
/*
|
||||
* tls_dane.c
|
||||
|
@ -152,6 +152,9 @@
|
||||
/*
|
||||
/* Victor Duchovni
|
||||
/* Morgan Stanley
|
||||
/*
|
||||
/* Wietse Venema
|
||||
/* porcupine.org
|
||||
/*--*/
|
||||
|
||||
/* System library. */
|
||||
@ -160,6 +163,7 @@
|
||||
|
||||
#ifdef USE_TLS
|
||||
#include <string.h>
|
||||
#include <tlsrpt_wrapper.h>
|
||||
|
||||
#ifdef STRCASECMP_IN_STRINGS_H
|
||||
#include <strings.h>
|
||||
@ -363,7 +367,7 @@ static void verify_x509(TLS_SESS_STATE *TLScontext, X509 *peercert,
|
||||
if (!TLS_CERT_IS_MATCHED(TLScontext)
|
||||
&& (TLScontext->log_mask & TLS_LOG_UNTRUSTED)) {
|
||||
if (TLScontext->session_reused == 0)
|
||||
tls_log_verify_error(TLScontext);
|
||||
tls_log_verify_error(TLScontext, props->tlsrpt);
|
||||
else
|
||||
msg_info("%s: re-using session with untrusted peer credential, "
|
||||
"look for details earlier in the log", props->namaddr);
|
||||
@ -407,7 +411,7 @@ static void verify_rpk(TLS_SESS_STATE *TLScontext, EVP_PKEY *peerpkey,
|
||||
if (!TLS_CERT_IS_MATCHED(TLScontext)
|
||||
&& (TLScontext->log_mask & TLS_LOG_UNTRUSTED)) {
|
||||
if (TLScontext->session_reused == 0)
|
||||
tls_log_verify_error(TLScontext);
|
||||
tls_log_verify_error(TLScontext, props->tlsrpt);
|
||||
else
|
||||
msg_info("%s: re-using session with untrusted certificate, "
|
||||
"look for details earlier in the log", props->namaddr);
|
||||
@ -579,6 +583,7 @@ static int tls_auth_enable(TLS_SESS_STATE *TLScontext,
|
||||
* therefore valid for use with SNI.
|
||||
*/
|
||||
if (SSL_dane_enable(TLScontext->con, 0) <= 0) {
|
||||
/* TLSRPT: Local resource error, don't report. */
|
||||
msg_warn("%s: error enabling DANE-based certificate validation",
|
||||
TLScontext->namaddr);
|
||||
tls_print_errors();
|
||||
@ -595,6 +600,7 @@ static int tls_auth_enable(TLS_SESS_STATE *TLScontext,
|
||||
case TLS_LEV_FPRINT:
|
||||
/* Synthetic DANE for fingerprint security */
|
||||
if (SSL_dane_enable(TLScontext->con, 0) <= 0) {
|
||||
/* TLSRPT: Local resource error, don't report. */
|
||||
msg_warn("%s: error enabling fingerprint certificate validation",
|
||||
props->namaddr);
|
||||
tls_print_errors();
|
||||
@ -608,6 +614,7 @@ static int tls_auth_enable(TLS_SESS_STATE *TLScontext,
|
||||
if (TLScontext->dane != 0 && TLScontext->dane->tlsa != 0) {
|
||||
/* Synthetic DANE for per-destination trust-anchors */
|
||||
if (SSL_dane_enable(TLScontext->con, NULL) <= 0) {
|
||||
/* TLSRPT: Local resource error, don't report. */
|
||||
msg_warn("%s: error configuring local trust anchors",
|
||||
props->namaddr);
|
||||
tls_print_errors();
|
||||
@ -622,6 +629,7 @@ static int tls_auth_enable(TLS_SESS_STATE *TLScontext,
|
||||
|
||||
if (sni) {
|
||||
if (strlen(sni) > TLSEXT_MAXLEN_host_name) {
|
||||
/* TLSRPT: Local configuration error, don't report. */
|
||||
msg_warn("%s: ignoring too long SNI hostname: %.100s",
|
||||
props->namaddr, sni);
|
||||
return (0);
|
||||
@ -633,6 +641,7 @@ static int tls_auth_enable(TLS_SESS_STATE *TLScontext,
|
||||
* failed to send the SNI name, we have little choice but to abort.
|
||||
*/
|
||||
if (!SSL_set_tlsext_host_name(TLScontext->con, sni)) {
|
||||
/* TLSRPT: Local resource or configuration error, don't report. */
|
||||
msg_warn("%s: error setting SNI hostname to: %s", props->namaddr,
|
||||
sni);
|
||||
return (0);
|
||||
@ -975,6 +984,7 @@ TLS_SESS_STATE *tls_client_start(const TLS_CLIENT_START_PROPS *props)
|
||||
*/
|
||||
protomask = tls_proto_mask_lims(props->protocols, &min_proto, &max_proto);
|
||||
if (protomask == TLS_PROTOCOL_INVALID) {
|
||||
/* TLSRPT: Local configuration error, don't report. */
|
||||
/* tls_protocol_mask() logs no warning. */
|
||||
msg_warn("%s: Invalid TLS protocol list \"%s\": aborting TLS session",
|
||||
props->namaddr, props->protocols);
|
||||
@ -1006,6 +1016,7 @@ TLS_SESS_STATE *tls_client_start(const TLS_CLIENT_START_PROPS *props)
|
||||
TLScontext->level = props->tls_level;
|
||||
|
||||
if ((TLScontext->con = SSL_new(app_ctx->ssl_ctx)) == NULL) {
|
||||
/* TLSRPT: Local resource error, don't report. */
|
||||
msg_warn("Could not allocate 'TLScontext->con' with SSL_new()");
|
||||
tls_print_errors();
|
||||
tls_free_context(TLScontext);
|
||||
@ -1022,6 +1033,7 @@ TLS_SESS_STATE *tls_client_start(const TLS_CLIENT_START_PROPS *props)
|
||||
cipher_list = tls_set_ciphers(TLScontext, props->cipher_grade,
|
||||
props->cipher_exclusions);
|
||||
if (cipher_list == 0) {
|
||||
/* TLSRPT: Local configuration error, don't report. */
|
||||
/* already warned */
|
||||
tls_free_context(TLScontext);
|
||||
return (0);
|
||||
@ -1036,6 +1048,7 @@ TLS_SESS_STATE *tls_client_start(const TLS_CLIENT_START_PROPS *props)
|
||||
TLScontext->dane = props->dane;
|
||||
|
||||
if (!SSL_set_ex_data(TLScontext->con, TLScontext_index, TLScontext)) {
|
||||
/* TLSRPT: Local resource error, don't report. */
|
||||
msg_warn("Could not set application data for 'TLScontext->con'");
|
||||
tls_print_errors();
|
||||
tls_free_context(TLScontext);
|
||||
@ -1069,6 +1082,7 @@ TLS_SESS_STATE *tls_client_start(const TLS_CLIENT_START_PROPS *props)
|
||||
* early.
|
||||
*/
|
||||
if (!tls_auth_enable(TLScontext, props)) {
|
||||
/* Already warned and reported TLSRPT result. */
|
||||
tls_free_context(TLScontext);
|
||||
return (0);
|
||||
}
|
||||
@ -1105,6 +1119,13 @@ TLS_SESS_STATE *tls_client_start(const TLS_CLIENT_START_PROPS *props)
|
||||
switch (TLScontext->level) {
|
||||
case TLS_LEV_HALF_DANE:
|
||||
case TLS_LEV_DANE:
|
||||
#ifdef USE_TLSRPT
|
||||
if (props->tlsrpt) {
|
||||
trw_report_failure(props->tlsrpt, TLSRPT_TLSA_INVALID,
|
||||
/* additional_info= */ (char *) 0,
|
||||
"all-TLSA-records-unusable");
|
||||
}
|
||||
#endif
|
||||
msg_warn("%s: all TLSA records unusable, fallback to "
|
||||
"unauthenticated TLS", TLScontext->namaddr);
|
||||
must_fail = 0;
|
||||
@ -1112,13 +1133,34 @@ TLS_SESS_STATE *tls_client_start(const TLS_CLIENT_START_PROPS *props)
|
||||
break;
|
||||
|
||||
case TLS_LEV_FPRINT:
|
||||
#ifdef USE_TLSRPT
|
||||
if (props->tlsrpt) {
|
||||
trw_report_failure(props->tlsrpt, TLSRPT_VALIDATION_FAILURE,
|
||||
/* additional_info= */ (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_info= */ (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_info= */ (char *) 0,
|
||||
"all-trust-anchors-unusable");
|
||||
}
|
||||
#endif
|
||||
msg_warn("%s: all trust anchors unusable", TLScontext->namaddr);
|
||||
break;
|
||||
}
|
||||
@ -1194,6 +1236,7 @@ TLS_SESS_STATE *tls_client_start(const TLS_CLIENT_START_PROPS *props)
|
||||
*/
|
||||
if (SSL_set_fd(TLScontext->con, props->stream == 0 ? props->fd :
|
||||
vstream_fileno(props->stream)) != 1) {
|
||||
/* TLSRPT: Local resource error, don't report. */
|
||||
msg_info("SSL_set_fd error to %s", props->namaddr);
|
||||
tls_print_errors();
|
||||
uncache_session(app_ctx->ssl_ctx, TLScontext);
|
||||
@ -1213,6 +1256,16 @@ TLS_SESS_STATE *tls_client_start(const TLS_CLIENT_START_PROPS *props)
|
||||
if (log_mask & TLS_LOG_TLSPKTS)
|
||||
tls_set_bio_callback(SSL_get_rbio(TLScontext->con), tls_bio_dump_cb);
|
||||
|
||||
/*
|
||||
* An external (STS) policy signaled a failure. Prevent false (PKI)
|
||||
* certificate matches in tls_verify.c. TODO(wietse) how was this handled
|
||||
* historically?
|
||||
*/
|
||||
if (props->ffail_type) {
|
||||
TLScontext->ffail_type = mystrdup(props->ffail_type);
|
||||
TLScontext->must_fail = 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* If we don't trigger the handshake in the library, leave control over
|
||||
* SSL_connect/read/write/etc with the application.
|
||||
@ -1245,6 +1298,12 @@ TLS_SESS_STATE *tls_client_start(const TLS_CLIENT_START_PROPS *props)
|
||||
msg_info("SSL_connect error to %s: lost connection",
|
||||
props->namaddr);
|
||||
}
|
||||
#ifdef USE_TLSRPT
|
||||
if (props->tlsrpt)
|
||||
trw_report_failure(props->tlsrpt, TLSRPT_VALIDATION_FAILURE,
|
||||
/* additional_info= */ (char *) 0,
|
||||
"tls-handshake-failure");
|
||||
#endif
|
||||
uncache_session(app_ctx->ssl_ctx, TLScontext);
|
||||
tls_free_context(TLScontext);
|
||||
return (0);
|
||||
@ -1360,6 +1419,19 @@ TLS_SESS_STATE *tls_client_post_connect(TLS_SESS_STATE *TLScontext,
|
||||
|
||||
tls_int_seed();
|
||||
|
||||
/*
|
||||
* Precondition: tls_client_start() is called only for a new TCP
|
||||
* connection. It is never called for a reused TCP connection.
|
||||
*
|
||||
* Inform the caller that they should not generate a TLSRPT 'success' or
|
||||
* 'failure' event: this TLS protocol engine has already generated a
|
||||
* TLSRPT 'failure' event for this session.
|
||||
*/
|
||||
#ifdef USE_TLSRPT
|
||||
TLScontext->rpt_reported = props->tlsrpt != 0
|
||||
&& trw_is_reported(props->tlsrpt);
|
||||
#endif
|
||||
|
||||
return (TLScontext);
|
||||
}
|
||||
|
||||
|
@ -1363,6 +1363,8 @@ TLS_SESS_STATE *tls_alloc_sess_context(int log_mask, const char *namaddr)
|
||||
TLScontext->errordepth = -1;
|
||||
TLScontext->errorcode = X509_V_OK;
|
||||
TLScontext->errorcert = 0;
|
||||
TLScontext->rpt_reported = 0;
|
||||
TLScontext->ffail_type = 0;
|
||||
|
||||
return (TLScontext);
|
||||
}
|
||||
@ -1413,6 +1415,8 @@ void tls_free_context(TLS_SESS_STATE *TLScontext)
|
||||
myfree((void *) TLScontext->srvr_sig_dgst);
|
||||
if (TLScontext->errorcert)
|
||||
X509_free(TLScontext->errorcert);
|
||||
if (TLScontext->ffail_type)
|
||||
myfree(TLScontext->ffail_type);
|
||||
|
||||
myfree((void *) TLScontext);
|
||||
}
|
||||
|
@ -108,11 +108,12 @@ extern VSTREAM *tls_proxy_open(const char *, int, VSTREAM *, const char *,
|
||||
((props)->a12), ((props)->a13), ((props)->a14))
|
||||
|
||||
#define TLS_PROXY_CLIENT_START_PROPS(props, a1, a2, a3, a4, a5, a6, a7, a8, \
|
||||
a9, a10, a11, a12, a13, a14, a15) \
|
||||
a9, a10, a11, a12, a13, a14, a15, a16, a17) \
|
||||
(((props)->a1), ((props)->a2), ((props)->a3), \
|
||||
((props)->a4), ((props)->a5), ((props)->a6), ((props)->a7), \
|
||||
((props)->a8), ((props)->a9), ((props)->a10), ((props)->a11), \
|
||||
((props)->a12), ((props)->a13), ((props)->a14), ((props)->a15))
|
||||
((props)->a12), ((props)->a13), ((props)->a14), ((props)->a15), \
|
||||
((props)->a16), ((props)->a17))
|
||||
|
||||
extern TLS_SESS_STATE *tls_proxy_context_receive(VSTREAM *);
|
||||
extern void tls_proxy_context_free(TLS_SESS_STATE *);
|
||||
@ -181,6 +182,7 @@ extern void tls_proxy_server_start_free(TLS_SERVER_START_PROPS *);
|
||||
#define TLS_ATTR_SRVR_SIG_BITS "srvr_signature_bits"
|
||||
#define TLS_ATTR_SRVR_SIG_DGST "srvr_signature_digest"
|
||||
#define TLS_ATTR_NAMADDR "namaddr"
|
||||
#define TLS_ATTR_RPT_REPORTED "rpt_reported"
|
||||
|
||||
/*
|
||||
* TLS_SERVER_INIT_PROPS attributes.
|
||||
@ -254,7 +256,9 @@ extern void tls_proxy_server_start_free(TLS_SERVER_START_PROPS *);
|
||||
#define TLS_ATTR_CIPHER_EXCLUSIONS "cipher_exclusions"
|
||||
#define TLS_ATTR_MATCHARGV "matchargv"
|
||||
#define TLS_ATTR_MDALG "mdalg"
|
||||
#define TLS_ATTR_DANE "dane"
|
||||
#define TLS_ATTR_DANE "dane"
|
||||
#define TLS_ATTR_TLSRPT "tlsrpt"
|
||||
#define TLS_ATTR_FFAIL_TYPE "forced_failure_type"
|
||||
|
||||
/*
|
||||
* TLS_TLSA attributes.
|
||||
|
@ -79,6 +79,10 @@
|
||||
#include <tls.h>
|
||||
#include <tls_proxy.h>
|
||||
|
||||
#ifdef USE_TLSRPT
|
||||
#define TLSRPT_WRAPPER_INTERNAL
|
||||
#include <tlsrpt_wrapper.h>
|
||||
#endif
|
||||
|
||||
#define STR(x) vstring_str(x)
|
||||
#define LEN(x) VSTRING_LEN(x)
|
||||
@ -96,7 +100,7 @@ int tls_proxy_client_param_print(ATTR_PRINT_COMMON_FN print_fn, VSTREAM *fp,
|
||||
|
||||
ret = print_fn(fp, flags | ATTR_FLAG_MORE,
|
||||
SEND_ATTR_STR(TLS_ATTR_CNF_FILE, params->tls_cnf_file),
|
||||
SEND_ATTR_STR(TLS_ATTR_CNF_NAME, params->tls_cnf_name),
|
||||
SEND_ATTR_STR(TLS_ATTR_CNF_NAME, params->tls_cnf_name),
|
||||
SEND_ATTR_STR(VAR_TLS_HIGH_CLIST, params->tls_high_clist),
|
||||
SEND_ATTR_STR(VAR_TLS_MEDIUM_CLIST,
|
||||
params->tls_medium_clist),
|
||||
@ -242,6 +246,59 @@ static int tls_proxy_client_dane_print(ATTR_PRINT_COMMON_FN print_fn,
|
||||
return (ret);
|
||||
}
|
||||
|
||||
#ifdef USE_TLSRPT
|
||||
|
||||
/* tls_proxy_client_tlsrpt_print - send TLSRPT_WRAPPER over stream */
|
||||
|
||||
static int tls_proxy_client_tlsrpt_print(ATTR_PRINT_COMMON_FN print_fn,
|
||||
VSTREAM *fp, int flags, const void *ptr)
|
||||
{
|
||||
const TLSRPT_WRAPPER *trw = (const TLSRPT_WRAPPER *) ptr;
|
||||
int have_trw = trw != 0;
|
||||
int ret;
|
||||
|
||||
ret = print_fn(fp, flags | ATTR_FLAG_MORE,
|
||||
SEND_ATTR_INT(TLS_ATTR_TLSRPT, have_trw),
|
||||
ATTR_TYPE_END);
|
||||
if (msg_verbose)
|
||||
msg_info("tls_proxy_client_tlsrpt_print have_trw=%d", have_trw);
|
||||
|
||||
if (ret == 0 && have_trw) {
|
||||
ret = print_fn(fp, flags | ATTR_FLAG_MORE,
|
||||
SEND_ATTR_STR(TRW_RPT_SOCKET_NAME,
|
||||
STRING_OR_EMPTY(trw->rpt_socket_name)),
|
||||
SEND_ATTR_STR(TRW_RPT_POLICY_DOMAIN,
|
||||
STRING_OR_EMPTY(trw->rpt_policy_domain)),
|
||||
SEND_ATTR_STR(TRW_RPT_POLICY_STRING,
|
||||
STRING_OR_EMPTY(trw->rpt_policy_string)),
|
||||
SEND_ATTR_INT(TRW_TLS_POLICY_TYPE,
|
||||
(int) trw->tls_policy_type),
|
||||
SEND_ATTR_FUNC(argv_attr_print,
|
||||
(const void *) trw->tls_policy_strings),
|
||||
SEND_ATTR_STR(TRW_TLS_POLICY_DOMAIN,
|
||||
STRING_OR_EMPTY(trw->tls_policy_domain)),
|
||||
SEND_ATTR_FUNC(argv_attr_print,
|
||||
(const void *) trw->mx_host_patterns),
|
||||
SEND_ATTR_STR(TRW_SRC_MTA_ADDR,
|
||||
STRING_OR_EMPTY(trw->snd_mta_addr)),
|
||||
SEND_ATTR_STR(TRW_DST_MTA_NAME,
|
||||
STRING_OR_EMPTY(trw->rcv_mta_name)),
|
||||
SEND_ATTR_STR(TRW_DST_MTA_ADDR,
|
||||
STRING_OR_EMPTY(trw->rcv_mta_addr)),
|
||||
SEND_ATTR_STR(TRW_DST_MTA_EHLO,
|
||||
STRING_OR_EMPTY(trw->rcv_mta_ehlo)),
|
||||
SEND_ATTR_INT(TRW_FLAGS,
|
||||
trw->flags),
|
||||
ATTR_TYPE_END);
|
||||
}
|
||||
/* Do not flush the stream. */
|
||||
if (msg_verbose)
|
||||
msg_info("tls_proxy_client_tlsrpt_print ret=%d", ret);
|
||||
return (ret);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/* tls_proxy_client_start_print - send TLS_CLIENT_START_PROPS over stream */
|
||||
|
||||
int tls_proxy_client_start_print(ATTR_PRINT_COMMON_FN print_fn,
|
||||
@ -283,6 +340,12 @@ int tls_proxy_client_start_print(ATTR_PRINT_COMMON_FN print_fn,
|
||||
STRING_OR_EMPTY(props->mdalg)),
|
||||
SEND_ATTR_FUNC(tls_proxy_client_dane_print,
|
||||
(const void *) props->dane),
|
||||
#ifdef USE_TLSRPT
|
||||
SEND_ATTR_FUNC(tls_proxy_client_tlsrpt_print,
|
||||
(const void *) props->tlsrpt),
|
||||
#endif
|
||||
SEND_ATTR_STR(TLS_ATTR_FFAIL_TYPE,
|
||||
STRING_OR_EMPTY(props->ffail_type)),
|
||||
ATTR_TYPE_END);
|
||||
/* Do not flush the stream. */
|
||||
if (msg_verbose)
|
||||
|
@ -113,6 +113,10 @@
|
||||
#define TLS_INTERNAL
|
||||
#include <tls.h>
|
||||
#include <tls_proxy.h>
|
||||
#ifdef USE_TLSRPT
|
||||
#define TLSRPT_WRAPPER_INTERNAL
|
||||
#include <tlsrpt_wrapper.h>
|
||||
#endif
|
||||
|
||||
#define STR(x) vstring_str(x)
|
||||
#define LEN(x) VSTRING_LEN(x)
|
||||
@ -329,6 +333,12 @@ void tls_proxy_client_start_free(TLS_CLIENT_START_PROPS *props)
|
||||
myfree((void *) props->mdalg);
|
||||
if (props->dane)
|
||||
tls_dane_free((TLS_DANE *) props->dane);
|
||||
#ifdef USE_TLSRPT
|
||||
if (props->tlsrpt)
|
||||
trw_free(props->tlsrpt);
|
||||
#endif
|
||||
if (props->ffail_type)
|
||||
myfree(props->ffail_type);
|
||||
myfree((void *) props);
|
||||
}
|
||||
|
||||
@ -419,6 +429,89 @@ static int tls_proxy_client_dane_scan(ATTR_SCAN_COMMON_FN scan_fn,
|
||||
return (ret);
|
||||
}
|
||||
|
||||
#define EXPORT_OR_NULL(str, vstr) do { \
|
||||
if (LEN(vstr) > 0) { \
|
||||
(str) = vstring_export(vstr); \
|
||||
} else { \
|
||||
(str) = 0; \
|
||||
vstring_free(vstr); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#ifdef USE_TLSRPT
|
||||
|
||||
/* tls_proxy_client_tlsrpt_scan - receive TLSRPT_WRAPPER from stream */
|
||||
|
||||
static int tls_proxy_client_tlsrpt_scan(ATTR_SCAN_COMMON_FN scan_fn,
|
||||
VSTREAM *fp, int flags, void *ptr)
|
||||
{
|
||||
TLSRPT_WRAPPER *trw = 0;
|
||||
int ret;
|
||||
int have_tlsrpt = 0;
|
||||
|
||||
ret = scan_fn(fp, flags | ATTR_FLAG_MORE,
|
||||
RECV_ATTR_INT(TLS_ATTR_TLSRPT, &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 = 0;
|
||||
VSTRING *tls_policy_domain = vstring_alloc(100);
|
||||
ARGV *mx_host_patterns = 0;
|
||||
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);
|
||||
int trw_flags;
|
||||
|
||||
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);
|
||||
trw->flags = trw_flags;
|
||||
ret = (ret == 12 ? 1 : -1);
|
||||
if (ret != 1) {
|
||||
trw_free(trw);
|
||||
trw = 0;
|
||||
}
|
||||
}
|
||||
*(TLSRPT_WRAPPER **) ptr = trw;
|
||||
if (msg_verbose)
|
||||
msg_info("tls_proxy_client_tlsrpt_scan ret=%d", ret);
|
||||
return (ret);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/* tls_proxy_client_start_scan - receive TLS_CLIENT_START_PROPS from stream */
|
||||
|
||||
int tls_proxy_client_start_scan(ATTR_SCAN_COMMON_FN scan_fn, VSTREAM *fp,
|
||||
@ -437,6 +530,13 @@ int tls_proxy_client_start_scan(ATTR_SCAN_COMMON_FN scan_fn, VSTREAM *fp,
|
||||
VSTRING *cipher_grade = vstring_alloc(25);
|
||||
VSTRING *cipher_exclusions = vstring_alloc(25);
|
||||
VSTRING *mdalg = vstring_alloc(25);
|
||||
VSTRING *ffail_type = vstring_alloc(25);
|
||||
|
||||
#ifdef USE_TLSRPT
|
||||
#define EXPECT_START_SCAN_RETURN 17
|
||||
#else
|
||||
#define EXPECT_START_SCAN_RETURN 16
|
||||
#endif
|
||||
|
||||
if (msg_verbose)
|
||||
msg_info("begin tls_proxy_client_start_scan");
|
||||
@ -467,6 +567,11 @@ int tls_proxy_client_start_scan(ATTR_SCAN_COMMON_FN scan_fn, VSTREAM *fp,
|
||||
RECV_ATTR_STR(TLS_ATTR_MDALG, mdalg),
|
||||
RECV_ATTR_FUNC(tls_proxy_client_dane_scan,
|
||||
&props->dane),
|
||||
#ifdef USE_TLSRPT
|
||||
RECV_ATTR_FUNC(tls_proxy_client_tlsrpt_scan,
|
||||
&props->tlsrpt),
|
||||
#endif
|
||||
RECV_ATTR_STR(TLS_ATTR_FFAIL_TYPE, ffail_type),
|
||||
ATTR_TYPE_END);
|
||||
/* Always construct a well-formed structure. */
|
||||
props->nexthop = vstring_export(nexthop);
|
||||
@ -479,7 +584,8 @@ int tls_proxy_client_start_scan(ATTR_SCAN_COMMON_FN scan_fn, VSTREAM *fp,
|
||||
props->cipher_grade = vstring_export(cipher_grade);
|
||||
props->cipher_exclusions = vstring_export(cipher_exclusions);
|
||||
props->mdalg = vstring_export(mdalg);
|
||||
ret = (ret == 15 ? 1 : -1);
|
||||
EXPORT_OR_NULL(props->ffail_type, ffail_type);
|
||||
ret = (ret == EXPECT_START_SCAN_RETURN ? 1 : -1);
|
||||
if (ret != 1) {
|
||||
tls_proxy_client_start_free(props);
|
||||
props = 0;
|
||||
|
@ -110,6 +110,8 @@ int tls_proxy_context_print(ATTR_PRINT_COMMON_FN print_fn, VSTREAM *fp,
|
||||
STRING_OR_EMPTY(tp->srvr_sig_dgst)),
|
||||
SEND_ATTR_STR(TLS_ATTR_NAMADDR,
|
||||
STRING_OR_EMPTY(tp->namaddr)),
|
||||
SEND_ATTR_INT(TLS_ATTR_RPT_REPORTED,
|
||||
tp->rpt_reported),
|
||||
ATTR_TYPE_END);
|
||||
/* Do not flush the stream. */
|
||||
return (ret);
|
||||
|
@ -124,6 +124,8 @@ int tls_proxy_context_scan(ATTR_SCAN_COMMON_FN scan_fn, VSTREAM *fp,
|
||||
RECV_ATTR_INT(TLS_ATTR_SRVR_SIG_BITS, &tls_context->srvr_sig_bits),
|
||||
RECV_ATTR_STR(TLS_ATTR_SRVR_SIG_DGST, srvr_sig_dgst),
|
||||
RECV_ATTR_STR(TLS_ATTR_NAMADDR, namaddr),
|
||||
RECV_ATTR_INT(TLS_ATTR_RPT_REPORTED,
|
||||
&tls_context->rpt_reported),
|
||||
ATTR_TYPE_END);
|
||||
/* Always construct a well-formed structure. */
|
||||
tls_context->peer_CN = vstring_export(peer_CN);
|
||||
@ -141,7 +143,7 @@ int tls_proxy_context_scan(ATTR_SCAN_COMMON_FN scan_fn, VSTREAM *fp,
|
||||
tls_context->srvr_sig_curve = vstring_export(srvr_sig_curve);
|
||||
tls_context->srvr_sig_dgst = vstring_export(srvr_sig_dgst);
|
||||
tls_context->namaddr = vstring_export(namaddr);
|
||||
ret = (ret == 24 ? 1 : -1);
|
||||
ret = (ret == 25 ? 1 : -1);
|
||||
if (ret != 1) {
|
||||
tls_proxy_context_free(tls_context);
|
||||
tls_context = 0;
|
||||
|
@ -1035,7 +1035,7 @@ TLS_SESS_STATE *tls_server_post_accept(TLS_SESS_STATE *TLScontext)
|
||||
if (!TLS_CERT_IS_TRUSTED(TLScontext)
|
||||
&& (TLScontext->log_mask & TLS_LOG_UNTRUSTED)) {
|
||||
if (TLScontext->session_reused == 0)
|
||||
tls_log_verify_error(TLScontext);
|
||||
tls_log_verify_error(TLScontext, (struct TLSRPT_WRAPPER *) 0);
|
||||
else
|
||||
msg_info("%s: re-using session with untrusted certificate, "
|
||||
"look for details earlier in the log",
|
||||
|
@ -11,8 +11,9 @@
|
||||
/* int ok;
|
||||
/* X509_STORE_CTX *ctx;
|
||||
/*
|
||||
/* int tls_log_verify_error(TLScontext)
|
||||
/* int tls_log_verify_error(TLScontext, tlsrpt)
|
||||
/* TLS_SESS_STATE *TLScontext;
|
||||
/* struct TLSRPT_WRAPPER *tlsrpt;
|
||||
/*
|
||||
/* char *tls_peer_CN(peercert, TLScontext)
|
||||
/* X509 *peercert;
|
||||
@ -89,6 +90,9 @@
|
||||
/*
|
||||
/* Victor Duchovni
|
||||
/* Morgan Stanley
|
||||
/*
|
||||
/* Wietse Venema
|
||||
/* porcupine.org
|
||||
/*--*/
|
||||
|
||||
/* System library. */
|
||||
@ -107,6 +111,10 @@
|
||||
|
||||
/* TLS library. */
|
||||
|
||||
#ifdef USE_TLSRPT
|
||||
#include <tlsrpt_wrapper.h>
|
||||
#endif
|
||||
|
||||
#define TLS_INTERNAL
|
||||
#include <tls.h>
|
||||
|
||||
@ -194,18 +202,50 @@ int tls_verify_certificate_callback(int ok, X509_STORE_CTX *ctx)
|
||||
|
||||
/* tls_log_verify_error - Report final verification error status */
|
||||
|
||||
void tls_log_verify_error(TLS_SESS_STATE *TLScontext)
|
||||
void tls_log_verify_error(TLS_SESS_STATE *TLScontext,
|
||||
struct TLSRPT_WRAPPER *tlsrpt)
|
||||
{
|
||||
char buf[CCERT_BUFSIZ];
|
||||
int err = TLScontext->errorcode;
|
||||
X509 *cert = TLScontext->errorcert;
|
||||
int depth = TLScontext->errordepth;
|
||||
|
||||
#ifdef USE_TLSRPT
|
||||
VSTRING *err_vstr = vstring_alloc(100);
|
||||
|
||||
#define CERT_ERROR_TO_STRING(err) \
|
||||
translit(vstring_str(vstring_strcpy(err_vstr, \
|
||||
X509_verify_cert_error_string(err))), \
|
||||
" ", "_")
|
||||
#endif
|
||||
|
||||
#define PURPOSE ((depth>0) ? "CA": TLScontext->am_server ? "client": "server")
|
||||
|
||||
if (err == X509_V_OK)
|
||||
return;
|
||||
|
||||
/*
|
||||
* If an external policy flagged an error, report that instead.
|
||||
*/
|
||||
if (TLScontext->ffail_type) {
|
||||
msg_info("certificate verification failed for %s: "
|
||||
"external policy failure (%s)",
|
||||
TLScontext->namaddr, TLScontext->ffail_type);
|
||||
#ifdef USE_TLSRPT
|
||||
if (tlsrpt) {
|
||||
tlsrpt_failure_t failure_type;
|
||||
|
||||
if ((failure_type = convert_tlsrpt_policy_failure(TLScontext->ffail_type)) < 0)
|
||||
msg_panic("tls_log_verify_error: unexpected failure_reason: %s",
|
||||
TLScontext->ffail_type);
|
||||
trw_report_failure(tlsrpt, failure_type,
|
||||
/* additional_info= */ (char *) 0,
|
||||
/* failure_reason= */ (char *) 0);
|
||||
}
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Specific causes for verification failure.
|
||||
*/
|
||||
@ -218,10 +258,22 @@ void tls_log_verify_error(TLS_SESS_STATE *TLScontext)
|
||||
*/
|
||||
msg_info("certificate verification failed for %s: "
|
||||
"not trusted by local or TLSA policy", TLScontext->namaddr);
|
||||
#ifdef USE_TLSRPT
|
||||
if (tlsrpt)
|
||||
trw_report_failure(tlsrpt, TLSRPT_CERTIFICATE_NOT_TRUSTED,
|
||||
/* additional_info= */ (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_info= */ (char *) 0,
|
||||
CERT_ERROR_TO_STRING(err));
|
||||
#endif
|
||||
break;
|
||||
case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY:
|
||||
case X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN:
|
||||
@ -237,25 +289,55 @@ void tls_log_verify_error(TLS_SESS_STATE *TLScontext)
|
||||
strcpy(buf, "<unknown>");
|
||||
msg_info("certificate verification failed for %s: untrusted issuer %s",
|
||||
TLScontext->namaddr, printable(buf, '?'));
|
||||
#ifdef USE_TLSRPT
|
||||
if (tlsrpt)
|
||||
trw_report_failure(tlsrpt, TLSRPT_VALIDATION_FAILURE,
|
||||
/* additional_info= */ (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_info= */ (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_info= */ (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_info= */ (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_info= */ (char *) 0,
|
||||
CERT_ERROR_TO_STRING(err));
|
||||
#endif
|
||||
break;
|
||||
default:
|
||||
msg_info("%s certificate verification failed for %s: num=%d:%s",
|
||||
@ -263,6 +345,9 @@ void tls_log_verify_error(TLS_SESS_STATE *TLScontext)
|
||||
X509_verify_cert_error_string(err));
|
||||
break;
|
||||
}
|
||||
#ifdef USE_TLSRPT
|
||||
vstring_free(err_vstr);
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifndef DONT_GRIPE
|
||||
|
698
postfix/src/tls/tlsrpt_wrapper.c
Normal file
698
postfix/src/tls/tlsrpt_wrapper.c
Normal file
@ -0,0 +1,698 @@
|
||||
/*++
|
||||
/* NAME
|
||||
/* tlsrpt_wrapper 3
|
||||
/* SUMMARY
|
||||
/* TLSRPT support for the SMTP and TLS protocol engines
|
||||
/* 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_info,
|
||||
/* 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 */
|
||||
/* POSTFIX ARCHITECTURE, BOTTOM-UP VIEW
|
||||
/* .ad
|
||||
/* .fi
|
||||
/* This module encapsulates TLSRPT support for Postfix's
|
||||
/* multi-process and multi-layer architecture. The text that follows
|
||||
/* explains the purpose of this software layer.
|
||||
/*
|
||||
/* First, 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.
|
||||
/*
|
||||
/* Second, some TLS errors are detected in the SMTP protocol
|
||||
/* engine (example: a remote SMTP server does not announce STARTTLS
|
||||
/* support), while other TLS errors are detected in the TLS protocol
|
||||
/* engine (example: certificate verification error).
|
||||
/*
|
||||
/* Third, the Postfix TLS protocol engine may be located in a
|
||||
/* different process than the SMTP protocol engine. And even if the
|
||||
/* two are located in the same process, the TLS protocol engine knows
|
||||
/* nothing about SMTP. Hence, there needs to be an abstraction that
|
||||
/* isolates the TLS protocol engine from the SMTP-specific details
|
||||
/* of TLSRPT.
|
||||
/*
|
||||
/* Fourth, Postfix has a pipelined and layered architecture where
|
||||
/* each process (or architectural layer) handles a problem as it
|
||||
/* runs into it, instead of reporting problem details back to its
|
||||
/* pipeline predecessor (or back to a higher architectural layer).
|
||||
/* TLSRPT_WRAPPER IMPLEMENTATION
|
||||
/* .ad
|
||||
/* .fi
|
||||
/* At a high level, the SMTP protocol engine encapsulates SMTP
|
||||
/* session and TLS policy information in an opaque TLSRPT_WRAPPER
|
||||
/* object, and passes that object to the TLS protocol engine. The
|
||||
/* TLS protocol engine can invoke TLSRPT_WRAPPER methods to report a
|
||||
/* TLS error through the sys4.de TLSRPT client library. In a similar
|
||||
/* manner, the SMTP protocol engine can invoke TLSRPT_WRAPPER object
|
||||
/* methods to report a TLS error or success.
|
||||
/*
|
||||
/* At a low level, 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 local IPC in a tlsproxy(8) process.
|
||||
/*
|
||||
/* The TLS protocol engine may report a TLS error by invoking
|
||||
/* TLSRPT_WRAPPER methods, 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 (for example an error that resulted in
|
||||
/* a successful TLS handshake with a downgraded TLS security level).
|
||||
/*
|
||||
/* The Postfix SMTP protocol engine reports success or failure
|
||||
/* by invoking TLSRPT_WRAPPER methods, depending on whether all
|
||||
/* matching requirements were satisfied. The SMTP protocol engine
|
||||
/* does not report success or failure by invoking TLSRPT_WRAPPER
|
||||
/* methods if the TLS protocol engine already reported a failure.
|
||||
/* TLSRPT_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,
|
||||
/* but this not affect email deliveries.
|
||||
/* .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 resets 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 (may be null)
|
||||
/* policies[].policy.policy-string[]. Ignored if the tls_policy_type
|
||||
/* value is TLSRPT_NO_POLICY_FOUND.
|
||||
/* .IP tls_policy_domain (may be null)
|
||||
/* 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_info (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 warning when information is missing.
|
||||
/* Such warnings will not affect the operation of 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->mx_host_patterns, 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 ((snd_mta_addr || rcv_mta_name || rcv_mta_addr)
|
||||
&& ((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 (rcv_mta_ehlo && ((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);
|
||||
}
|
||||
|
||||
/*
|
||||
* Report a tlsrpt library internal error.
|
||||
*/
|
||||
else if (tlsrpt_error_code_is_internal(libtlsrpt_errorcode)) {
|
||||
msg_warn("Could not report TLS handshake result to tlsrpt library:"
|
||||
" %s (error %d)", tlsrpt_strerror(libtlsrpt_errorcode),
|
||||
libtlsrpt_errorcode);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Report a libc error. Do not report success if errno was zero. When
|
||||
* debug logging is enabled, also log some library-internal info.
|
||||
*/
|
||||
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);
|
||||
if (msg_verbose)
|
||||
msg_warn("Error location in tlsrpt library: %s (error %d)",
|
||||
tlsrpt_strerror(libtlsrpt_errorcode),
|
||||
libtlsrpt_errorcode);
|
||||
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[] = {
|
||||
"starttls_not_supported", TLSRPT_STARTTLS_NOT_SUPPORTED,
|
||||
"certificate_host_mismatch", TLSRPT_CERTIFICATE_HOST_MISMATCH,
|
||||
"certificate_not_trusted", TLSRPT_CERTIFICATE_NOT_TRUSTED,
|
||||
"certificate_expired", TLSRPT_CERTIFICATE_EXPIRED,
|
||||
"validation_failure", TLSRPT_VALIDATION_FAILURE,
|
||||
"sts_policy_fetch_error", TLSRPT_STS_POLICY_FETCH_ERROR,
|
||||
"sts_policy_invalid", TLSRPT_STS_POLICY_INVALID,
|
||||
"sts_webpki_invalid", TLSRPT_STS_WEBPKI_INVALID,
|
||||
"tlsa_invalid", TLSRPT_TLSA_INVALID,
|
||||
"dnssec_invalid", TLSRPT_DNSSEC_INVALID,
|
||||
"dane_required", TLSRPT_DANE_REQUIRED,
|
||||
"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_info,
|
||||
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;
|
||||
|
||||
/* Give the local admin a clue. */
|
||||
msg_info("TLSRPT: status=failure, domain=%s, receiving_mx=%s[%s],"
|
||||
" failure_type=%s%s%s",
|
||||
trw->rpt_policy_domain, trw->rcv_mta_name, trw->rcv_mta_addr,
|
||||
trw_failure_type_to_string(failure_type),
|
||||
failure_reason ? ", failure_reason=" : "",
|
||||
failure_reason ? failure_reason : "");
|
||||
|
||||
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_info,
|
||||
/* 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;
|
||||
|
||||
/* Give the local admin a clue. */
|
||||
msg_info("TLSRPT: status=success, domain=%s, receiving_mx=%s[%s]",
|
||||
trw->rpt_policy_domain, trw->rcv_mta_name, trw->rcv_mta_addr);
|
||||
|
||||
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) {
|
||||
char **cpp;
|
||||
|
||||
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_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 */
|
122
postfix/src/tls/tlsrpt_wrapper.h
Normal file
122
postfix/src/tls/tlsrpt_wrapper.h
Normal file
@ -0,0 +1,122 @@
|
||||
#ifndef _TLSRPT_WRAPPER_INCLUDED_
|
||||
#define _TLSRPT_WRAPPER_INCLUDED_
|
||||
|
||||
/*++
|
||||
/* NAME
|
||||
/* tlsrpt_wrapper 3h
|
||||
/* SUMMARY
|
||||
/* TLSRPT support for the SMTP and TLS protocol engines
|
||||
/* 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_info,
|
||||
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_ */
|
@ -75,6 +75,7 @@ tlsproxy.o: ../../include/split_at.h
|
||||
tlsproxy.o: ../../include/sys_defs.h
|
||||
tlsproxy.o: ../../include/tls.h
|
||||
tlsproxy.o: ../../include/tls_proxy.h
|
||||
tlsproxy.o: ../../include/tlsrpt_wrapper.h
|
||||
tlsproxy.o: ../../include/vbuf.h
|
||||
tlsproxy.o: ../../include/vstream.h
|
||||
tlsproxy.o: ../../include/vstring.h
|
||||
|
@ -426,6 +426,7 @@
|
||||
#define TLS_INTERNAL /* XXX */
|
||||
#include <tls.h>
|
||||
#include <tls_proxy.h>
|
||||
#include <tlsrpt_wrapper.h>
|
||||
|
||||
/*
|
||||
* Application-specific.
|
||||
@ -731,6 +732,20 @@ static int tlsp_eval_tls_error(TLSP_STATE *state, int err)
|
||||
state->flags |= TLSP_FLAG_NO_MORE_CIPHERTEXT_IO;
|
||||
return (TLSP_STAT_OK);
|
||||
}
|
||||
|
||||
/*
|
||||
* Report a generic failure only if a more specific failure wasn't
|
||||
* already reported.
|
||||
*/
|
||||
#ifdef USE_TLSRPT
|
||||
if (state->client_start_props->tlsrpt
|
||||
&& (state->flags & TLSP_FLAG_DO_HANDSHAKE)
|
||||
&& state->is_server_role == 0)
|
||||
trw_report_failure(state->client_start_props->tlsrpt,
|
||||
TLSRPT_VALIDATION_FAILURE,
|
||||
/* additional_info= */ (char *) 0,
|
||||
"tls-handshake-failure");
|
||||
#endif
|
||||
tlsp_state_free(state);
|
||||
return (TLSP_STAT_ERR);
|
||||
}
|
||||
|
@ -45,7 +45,8 @@ SRCS = alldig.c allprint.c argv.c argv_split.c attr_clnt.c attr_print0.c \
|
||||
byte_mask.c known_tcp_ports.c argv_split_at.c dict_stream.c \
|
||||
sane_strtol.c hash_fnv.c ldseed.c mkmap_cdb.c mkmap_db.c mkmap_dbm.c \
|
||||
mkmap_fail.c mkmap_lmdb.c mkmap_open.c mkmap_sdbm.c inet_prefix_top.c \
|
||||
inet_addr_sizes.c quote_for_json.c
|
||||
inet_addr_sizes.c quote_for_json.c mystrerror.c \
|
||||
sane_sockaddr_to_hostaddr.c
|
||||
OBJS = alldig.o allprint.o argv.o argv_split.o attr_clnt.o attr_print0.o \
|
||||
attr_print64.o attr_print_plain.o attr_scan0.o attr_scan64.o \
|
||||
attr_scan_plain.o auto_clnt.o base64_code.o basename.o binhash.o \
|
||||
@ -92,7 +93,7 @@ OBJS = alldig.o allprint.o argv.o argv_split.o attr_clnt.o attr_print0.o \
|
||||
byte_mask.o known_tcp_ports.o argv_split_at.o dict_stream.o \
|
||||
sane_strtol.o hash_fnv.o ldseed.o mkmap_db.o mkmap_dbm.o \
|
||||
mkmap_fail.o mkmap_open.o inet_prefix_top.o inet_addr_sizes.o \
|
||||
quote_for_json.o
|
||||
quote_for_json.o mystrerror.o sane_sockaddr_to_hostaddr.o
|
||||
# MAP_OBJ is for maps that may be dynamically loaded with dynamicmaps.cf.
|
||||
# When hard-linking these, makedefs sets NON_PLUGIN_MAP_OBJ=$(MAP_OBJ),
|
||||
# otherwise it sets the PLUGIN_* macros.
|
||||
@ -2444,6 +2445,12 @@ mymalloc.o: sys_defs.h
|
||||
myrand.o: myrand.c
|
||||
myrand.o: myrand.h
|
||||
myrand.o: sys_defs.h
|
||||
mystrerror.o: check_arg.h
|
||||
mystrerror.o: mystrerror.c
|
||||
mystrerror.o: stringops.h
|
||||
mystrerror.o: sys_defs.h
|
||||
mystrerror.o: vbuf.h
|
||||
mystrerror.o: vstring.h
|
||||
mystrtok.o: check_arg.h
|
||||
mystrtok.o: msg.h
|
||||
mystrtok.o: mystrtok.c
|
||||
@ -2549,9 +2556,11 @@ printable.o: stringops.h
|
||||
printable.o: sys_defs.h
|
||||
printable.o: vbuf.h
|
||||
printable.o: vstring.h
|
||||
quote_for_json.o: check_arg.h
|
||||
quote_for_json.o: quote_for_json.c
|
||||
quote_for_json.o: stringops.h
|
||||
quote_for_json.o: sys_defs.h
|
||||
quote_for_json.o: vbuf.h
|
||||
quote_for_json.o: vstring.h
|
||||
rand_sleep.o: iostuff.h
|
||||
rand_sleep.o: msg.h
|
||||
@ -2617,6 +2626,10 @@ sane_rename.o: sane_fsops.h
|
||||
sane_rename.o: sane_rename.c
|
||||
sane_rename.o: sys_defs.h
|
||||
sane_rename.o: warn_stat.h
|
||||
sane_sockaddr_to_hostaddr.o: inet_proto.h
|
||||
sane_sockaddr_to_hostaddr.o: myaddrinfo.h
|
||||
sane_sockaddr_to_hostaddr.o: sane_sockaddr_to_hostaddr.c
|
||||
sane_sockaddr_to_hostaddr.o: sys_defs.h
|
||||
sane_socketpair.o: msg.h
|
||||
sane_socketpair.o: sane_socketpair.c
|
||||
sane_socketpair.o: sane_socketpair.h
|
||||
@ -2883,6 +2896,7 @@ vbuf.o: vbuf.h
|
||||
vbuf_print.o: check_arg.h
|
||||
vbuf_print.o: msg.h
|
||||
vbuf_print.o: mymalloc.h
|
||||
vbuf_print.o: stringops.h
|
||||
vbuf_print.o: sys_defs.h
|
||||
vbuf_print.o: vbuf.h
|
||||
vbuf_print.o: vbuf_print.c
|
||||
|
@ -31,6 +31,10 @@
|
||||
/* char *arg;
|
||||
/* ssize_t arg_len;
|
||||
/*
|
||||
/* ARGV *argv_addv(argvp, argv)
|
||||
/* ARGV *argvp;
|
||||
/* const char **argv;
|
||||
/*
|
||||
/* void argv_terminate(argvp);
|
||||
/* ARGV *argvp;
|
||||
/*
|
||||
@ -94,6 +98,10 @@
|
||||
/* 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.
|
||||
/*
|
||||
@ -144,6 +152,9 @@
|
||||
/* Google, Inc.
|
||||
/* 111 8th Avenue
|
||||
/* New York, NY 10011, USA
|
||||
/*
|
||||
/* Wietse Venema
|
||||
/* porcupine.org
|
||||
/*--*/
|
||||
|
||||
/* System libraries. */
|
||||
@ -301,6 +312,23 @@ void argv_addn(ARGV *argvp,...)
|
||||
argvp->argv[argvp->argc] = 0;
|
||||
}
|
||||
|
||||
/* argv_addv - optionally create ARGV, append string vector */
|
||||
|
||||
ARGV *argv_addv(ARGV *argvp, const char *const * argv)
|
||||
{
|
||||
const char *const * cpp;
|
||||
|
||||
if (argvp == 0) {
|
||||
for (cpp = argv; *cpp; cpp++)
|
||||
/* void */ ;
|
||||
argvp = argv_alloc(cpp - argv);
|
||||
}
|
||||
for (cpp = argv; *cpp; cpp++)
|
||||
argv_add(argvp, *cpp, (char *) 0);
|
||||
argvp->argv[argvp->argc] = 0;
|
||||
return (argvp);
|
||||
}
|
||||
|
||||
/* argv_terminate - terminate string array */
|
||||
|
||||
void argv_terminate(ARGV *argvp)
|
||||
@ -602,6 +630,23 @@ static ARGV *test_argv_join(const TEST_CASE *tp, ARGV *argvp)
|
||||
return (argvp);
|
||||
}
|
||||
|
||||
/* test_argv_addv_appends - populate result */
|
||||
|
||||
static ARGV *test_argv_addv_appends(const TEST_CASE *tp, ARGV *argvp)
|
||||
{
|
||||
argvp = argv_addv(argvp, tp->inputs);
|
||||
return (argvp);
|
||||
}
|
||||
|
||||
/* test_argv_addv_creates_appends - populate result */
|
||||
|
||||
static ARGV *test_argv_addv_creates(const TEST_CASE *tp, ARGV *argvp)
|
||||
{
|
||||
argv_free(argvp);
|
||||
argvp = argv_addv((ARGV *) 0, tp->inputs);
|
||||
return (argvp);
|
||||
}
|
||||
|
||||
/* test_argv_verify - verify result */
|
||||
|
||||
static int test_argv_verify(const TEST_CASE *tp, ARGV *argvp)
|
||||
@ -737,6 +782,14 @@ static const TEST_CASE test_cases[] = {
|
||||
{0}, 0, test_argv_join,
|
||||
0, 1, {"", 0}, ':'
|
||||
},
|
||||
{"argv_addv appends to ARGV",
|
||||
{"foo", "baz", "bar", 0}, /* ignored */ 0, test_argv_addv_appends,
|
||||
0, 3, {"foo", "baz", "bar", 0}
|
||||
},
|
||||
{"argv_addv creates ARGV",
|
||||
{"foo", "baz", "bar", 0}, /* ignored */ 0, test_argv_addv_creates,
|
||||
0, 3, {"foo", "baz", "bar", 0}
|
||||
},
|
||||
0,
|
||||
};
|
||||
|
||||
|
@ -20,7 +20,7 @@ typedef struct ARGV {
|
||||
char **argv; /* string array */
|
||||
} ARGV;
|
||||
|
||||
typedef int (*ARGV_COMPAR_FN)(const void *, const void *);
|
||||
typedef int (*ARGV_COMPAR_FN) (const void *, const void *);
|
||||
|
||||
extern ARGV *argv_alloc(ssize_t);
|
||||
extern ARGV *argv_sort(ARGV *); /* backwards compatibility */
|
||||
@ -28,6 +28,7 @@ extern ARGV *argv_qsort(ARGV *, ARGV_COMPAR_FN);
|
||||
extern ARGV *argv_uniq(ARGV *, ARGV_COMPAR_FN);
|
||||
extern void argv_add(ARGV *,...);
|
||||
extern void argv_addn(ARGV *,...);
|
||||
extern ARGV *argv_addv(ARGV *, const char *const *);
|
||||
extern void argv_terminate(ARGV *);
|
||||
extern void argv_truncate(ARGV *, ssize_t);
|
||||
extern void argv_insert_one(ARGV *, ssize_t, const char *);
|
||||
|
@ -44,6 +44,8 @@
|
||||
/* functionality.
|
||||
/* .IP HEX_ENCODE_FLAG_USE_COLON
|
||||
/* Inserts one ":" between bytes.
|
||||
/* .IP HEX_ENCODE_FLAG_APPEND
|
||||
/* Append output to the buffer.
|
||||
/* .PP
|
||||
/* hex_decode_opt() enables extended functionality as controlled
|
||||
/* with \fIflags\fR.
|
||||
@ -69,6 +71,9 @@
|
||||
/* Google, Inc.
|
||||
/* 111 8th Avenue
|
||||
/* New York, NY 10011, USA
|
||||
/*
|
||||
/* Wietse Venema
|
||||
/* porcupine.org
|
||||
/*--*/
|
||||
|
||||
/* System library. */
|
||||
@ -107,7 +112,8 @@ VSTRING *hex_encode_opt(VSTRING *result, const char *in, ssize_t len, int flags)
|
||||
int ch;
|
||||
ssize_t count;
|
||||
|
||||
VSTRING_RESET(result);
|
||||
if ((flags & HEX_ENCODE_FLAG_APPEND) == 0)
|
||||
VSTRING_RESET(result);
|
||||
for (cp = UCHAR_PTR(in), count = len; count > 0; count--, cp++) {
|
||||
ch = *cp;
|
||||
VSTRING_ADDCH(result, hex_chars[(ch >> 4) & 0xf]);
|
||||
@ -177,67 +183,121 @@ VSTRING *hex_decode_opt(VSTRING *result, const char *in, ssize_t len, int flags)
|
||||
}
|
||||
|
||||
#ifdef TEST
|
||||
#include <argv.h>
|
||||
|
||||
/*
|
||||
* Proof-of-concept test program: convert to hexadecimal and back.
|
||||
*/
|
||||
|
||||
#define STR(x) vstring_str(x)
|
||||
#define LEN(x) VSTRING_LEN(x)
|
||||
|
||||
typedef struct TEST_CASE {
|
||||
const char *label; /* identifies test case */
|
||||
VSTRING *(*func) (VSTRING *, const char *, ssize_t, int);
|
||||
const char *input; /* input string */
|
||||
ssize_t inlen; /* input size */
|
||||
int flags; /* flags */
|
||||
const char *exp_output; /* expected output or null */
|
||||
ssize_t exp_outlen; /* expected size */
|
||||
} TEST_CASE;
|
||||
|
||||
/*
|
||||
* The test cases.
|
||||
*/
|
||||
#define OUTPUT_INIT "thrash:" /* output buffer initial content */
|
||||
#define OUTPUT_INIT_SZ (sizeof(OUTPUT_INIT) - 1)
|
||||
|
||||
static const TEST_CASE test_cases[] = {
|
||||
{"hex_encode_no_options", hex_encode_opt,
|
||||
"this is a test",
|
||||
sizeof("this is a test") - 1,
|
||||
HEX_ENCODE_FLAG_NONE,
|
||||
"7468697320697320612074657374",
|
||||
sizeof("7468697320697320612074657374") - 1,
|
||||
},
|
||||
{"hex_decode_no_options", hex_decode_opt,
|
||||
"7468697320697320612074657374",
|
||||
sizeof("7468697320697320612074657374") - 1,
|
||||
HEX_DECODE_FLAG_NONE,
|
||||
"this is a test",
|
||||
sizeof("this is a test") - 1,
|
||||
},
|
||||
{"hex_decode_no_colon_allow_colon", hex_decode_opt,
|
||||
"7468697320697320612074657374",
|
||||
sizeof("7468697320697320612074657374") - 1,
|
||||
HEX_DECODE_FLAG_ALLOW_COLON,
|
||||
"this is a test",
|
||||
sizeof("this is a test") - 1,
|
||||
},
|
||||
{"hex_encode_appends", hex_encode_opt,
|
||||
"this is a test",
|
||||
sizeof("this is a test") - 1,
|
||||
HEX_ENCODE_FLAG_APPEND,
|
||||
OUTPUT_INIT "7468697320697320612074657374",
|
||||
sizeof(OUTPUT_INIT "7468697320697320612074657374") - 1,
|
||||
},
|
||||
{"hex_encode_with_colon", hex_encode_opt,
|
||||
"this is a test",
|
||||
sizeof("this is a test") - 1,
|
||||
HEX_ENCODE_FLAG_USE_COLON,
|
||||
"74:68:69:73:20:69:73:20:61:20:74:65:73:74",
|
||||
sizeof("74:68:69:73:20:69:73:20:61:20:74:65:73:74") - 1,
|
||||
},
|
||||
{"hex_encode_with_colon_and_append", hex_encode_opt,
|
||||
"this is a test",
|
||||
sizeof("this is a test") - 1,
|
||||
HEX_ENCODE_FLAG_USE_COLON | HEX_ENCODE_FLAG_APPEND,
|
||||
OUTPUT_INIT "74:68:69:73:20:69:73:20:61:20:74:65:73:74",
|
||||
sizeof(OUTPUT_INIT "74:68:69:73:20:69:73:20:61:20:74:65:73:74") - 1,
|
||||
},
|
||||
{"hex_decode_error", hex_decode_opt,
|
||||
"this is a test",
|
||||
sizeof("this is a test") - 1,
|
||||
HEX_DECODE_FLAG_ALLOW_COLON,
|
||||
0,
|
||||
0,
|
||||
},
|
||||
{0},
|
||||
};
|
||||
|
||||
int main(int unused_argc, char **unused_argv)
|
||||
{
|
||||
VSTRING *b1 = vstring_alloc(1);
|
||||
VSTRING *b2 = vstring_alloc(1);
|
||||
char *test = "this is a test";
|
||||
ARGV *argv;
|
||||
VSTRING *buf = vstring_alloc(1);
|
||||
int pass = 0;
|
||||
int fail = 0;
|
||||
const TEST_CASE *tp;
|
||||
|
||||
#define DECODE(b,x,l) { \
|
||||
if (hex_decode((b),(x),(l)) == 0) \
|
||||
msg_panic("bad hex: %s", (x)); \
|
||||
for (tp = test_cases; tp->label != 0; tp++) {
|
||||
VSTRING *out;
|
||||
int ok = 0;
|
||||
|
||||
msg_info("RUN %s", tp->label);
|
||||
vstring_memcpy(buf, OUTPUT_INIT, OUTPUT_INIT_SZ);
|
||||
out = tp->func(buf, tp->input, tp->inlen, tp->flags);
|
||||
if (out == 0 && tp->exp_output == 0) {
|
||||
ok = 1;
|
||||
} else if (out != buf) {
|
||||
msg_warn("got result '%p', want: '%p'",
|
||||
(void *) out, (void *) buf);
|
||||
} else if (LEN(out) != tp->exp_outlen) {
|
||||
msg_warn("got result length '%ld', want: '%ld'",
|
||||
(long) LEN(out), (long) tp->exp_outlen);
|
||||
} else if (memcmp(STR(out), tp->exp_output, tp->exp_outlen) != 0) {
|
||||
msg_warn("got result '%*s', want: '%*s'",
|
||||
(int) LEN(out), STR(out),
|
||||
(int) tp->exp_outlen, tp->exp_output);
|
||||
} else {
|
||||
ok = 1;
|
||||
}
|
||||
if (ok) {
|
||||
msg_info("PASS %s", tp->label);
|
||||
pass++;
|
||||
} else {
|
||||
msg_info("FAIL %s", tp->label);
|
||||
fail++;
|
||||
}
|
||||
}
|
||||
#define VERIFY(b,t) { \
|
||||
if (strcmp((b), (t)) != 0) \
|
||||
msg_panic("bad test: %s", (b)); \
|
||||
}
|
||||
|
||||
hex_encode(b1, test, strlen(test));
|
||||
DECODE(b2, STR(b1), LEN(b1));
|
||||
VERIFY(STR(b2), test);
|
||||
|
||||
hex_encode(b1, test, strlen(test));
|
||||
hex_encode(b2, STR(b1), LEN(b1));
|
||||
hex_encode(b1, STR(b2), LEN(b2));
|
||||
DECODE(b2, STR(b1), LEN(b1));
|
||||
DECODE(b1, STR(b2), LEN(b2));
|
||||
DECODE(b2, STR(b1), LEN(b1));
|
||||
VERIFY(STR(b2), test);
|
||||
|
||||
hex_encode(b1, test, strlen(test));
|
||||
hex_encode(b2, STR(b1), LEN(b1));
|
||||
hex_encode(b1, STR(b2), LEN(b2));
|
||||
hex_encode(b2, STR(b1), LEN(b1));
|
||||
hex_encode(b1, STR(b2), LEN(b2));
|
||||
DECODE(b2, STR(b1), LEN(b1));
|
||||
DECODE(b1, STR(b2), LEN(b2));
|
||||
DECODE(b2, STR(b1), LEN(b1));
|
||||
DECODE(b1, STR(b2), LEN(b2));
|
||||
DECODE(b2, STR(b1), LEN(b1));
|
||||
VERIFY(STR(b2), test);
|
||||
|
||||
hex_encode_opt(b1, test, strlen(test), HEX_ENCODE_FLAG_USE_COLON);
|
||||
argv = argv_split(STR(b1), ":");
|
||||
if (argv->argc != strlen(test))
|
||||
msg_panic("HEX_ENCODE_FLAG_USE_COLON");
|
||||
if (hex_decode_opt(b2, STR(b1), LEN(b1), HEX_DECODE_FLAG_ALLOW_COLON) == 0)
|
||||
msg_panic("HEX_DECODE_FLAG_ALLOW_COLON");
|
||||
VERIFY(STR(b2), test);
|
||||
argv_free(argv);
|
||||
|
||||
vstring_free(b1);
|
||||
vstring_free(b2);
|
||||
return (0);
|
||||
msg_info("PASS=%d FAIL=%d", pass, fail);
|
||||
return (fail > 0);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -21,6 +21,7 @@
|
||||
*/
|
||||
#define HEX_ENCODE_FLAG_NONE (0)
|
||||
#define HEX_ENCODE_FLAG_USE_COLON (1<<0)
|
||||
#define HEX_ENCODE_FLAG_APPEND (1<<1)
|
||||
|
||||
#define HEX_DECODE_FLAG_NONE (0)
|
||||
#define HEX_DECODE_FLAG_ALLOW_COLON (1<<0)
|
||||
@ -49,6 +50,9 @@ extern VSTRING *WARN_UNUSED_RESULT hex_decode_opt(VSTRING *, const char *, ssize
|
||||
/* Google, Inc.
|
||||
/* 111 8th Avenue
|
||||
/* New York, NY 10011, USA
|
||||
/*
|
||||
/* Wietse Venema
|
||||
/* porcupine.org
|
||||
/*--*/
|
||||
|
||||
#endif
|
||||
|
@ -210,6 +210,12 @@ extern void myaddrinfo_control(int,...);
|
||||
msg_fatal("sockaddr_to_hostname: %s", MAI_STRERROR(_aierr)); \
|
||||
} while (0)
|
||||
|
||||
/*
|
||||
* sane_sockaddr_to_hostaddr.c
|
||||
*/
|
||||
extern int WARN_UNUSED_RESULT sane_sockaddr_to_hostaddr(const struct sockaddr *,
|
||||
SOCKADDR_SIZE, MAI_HOSTADDR_STR *, MAI_SERVPORT_STR *, int);
|
||||
|
||||
/* LICENSE
|
||||
/* .ad
|
||||
/* .fi
|
||||
|
39
postfix/src/util/mystrerror.c
Normal file
39
postfix/src/util/mystrerror.c
Normal file
@ -0,0 +1,39 @@
|
||||
/*++
|
||||
/* NAME
|
||||
/* mystrerror 3
|
||||
/* SUMMARY
|
||||
/* convert error number to string
|
||||
/* SYNOPSIS
|
||||
/* #include <stringops.h>
|
||||
/*
|
||||
/* const char *mystrerror()
|
||||
/* int errnum)
|
||||
/* DESCRIPTION
|
||||
/* mystrerror() maps an error number to string. Unlike strerror(3)
|
||||
/* it returns "Application error" instead of "Success".
|
||||
/* LICENSE
|
||||
/* .ad
|
||||
/* .fi
|
||||
/* The Secure Mailer license must be distributed with this software.
|
||||
/* AUTHOR(S)
|
||||
/* Wietse Venema
|
||||
/* porcupine.org
|
||||
/*--*/
|
||||
|
||||
/*
|
||||
* System library.
|
||||
*/
|
||||
#include <sys_defs.h>
|
||||
#include <string.h>
|
||||
|
||||
/*
|
||||
* Utility library.
|
||||
*/
|
||||
#include <stringops.h>
|
||||
|
||||
/* mystrerror - convert error number to string */
|
||||
|
||||
const char *mystrerror(int errnum)
|
||||
{
|
||||
return (errnum ? strerror(errnum) : "Application error");
|
||||
}
|
76
postfix/src/util/sane_sockaddr_to_hostaddr.c
Normal file
76
postfix/src/util/sane_sockaddr_to_hostaddr.c
Normal file
@ -0,0 +1,76 @@
|
||||
/*++
|
||||
/* NAME
|
||||
/* sane_sockaddr_to_hostaddr 3
|
||||
/* SUMMARY
|
||||
/* Sanitize IPv4 in IPv6 address
|
||||
/* SYNOPSIS
|
||||
/* #include <myaddrinfo.h>
|
||||
/*
|
||||
/* 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)
|
||||
/* DESCRIPTION
|
||||
/* sane_sockaddr_to_hostaddr() wraps sockaddr_to_hostaddr() and
|
||||
/* converts an IPv4 in IPv6 address to IPv4 form, but only if IPv4
|
||||
/* support is available.
|
||||
/* HISTORY
|
||||
/* .ad
|
||||
/* .fi
|
||||
/* This implementation was taken from postscreen, and consolidates
|
||||
/* multiple instances of similar code across the Postfix code base.
|
||||
/* LICENSE
|
||||
/* .ad
|
||||
/* .fi
|
||||
/* The Secure Mailer license must be distributed with this software.
|
||||
/* AUTHOR(S)
|
||||
/* Wietse Venema
|
||||
/* IBM T.J. Watson Research
|
||||
/* P.O. Box 704
|
||||
/* Yorktown Heights, NY 10598, USA
|
||||
/*
|
||||
/* Wietse Venema
|
||||
/* Google, Inc.
|
||||
/* 111 8th Avenue
|
||||
/* New York, NY 10011, USA
|
||||
/*
|
||||
/* Wietse Venema
|
||||
/* porcupine.org
|
||||
/*--*/
|
||||
|
||||
/*
|
||||
* System library.
|
||||
*/
|
||||
#include <sys_defs.h>
|
||||
|
||||
/*
|
||||
* Utility library.
|
||||
*/
|
||||
#include <myaddrinfo.h>
|
||||
#include <inet_proto.h>
|
||||
|
||||
static const INET_PROTO_INFO *proto_info;
|
||||
|
||||
/* sane_sockaddr_to_hostaddr - sanitize IPV4 in IPV6 address */
|
||||
|
||||
int sane_sockaddr_to_hostaddr(const 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);
|
||||
}
|
@ -67,6 +67,7 @@ extern int strcasecmp_utf8x(int, const char *, const char *);
|
||||
extern int strncasecmp_utf8x(int, const char *, const char *, ssize_t);
|
||||
extern char *quote_for_json(VSTRING *, const char *, ssize_t);
|
||||
extern char *quote_for_json_append(VSTRING *, const char *, ssize_t);
|
||||
extern const char *mystrerror(int);
|
||||
|
||||
#define EXTPAR_FLAG_NONE (0)
|
||||
#define EXTPAR_FLAG_STRIP (1<<0) /* "{ text }" -> "text" */
|
||||
|
@ -67,6 +67,7 @@
|
||||
#include "mymalloc.h"
|
||||
#include "vbuf.h"
|
||||
#include "vstring.h"
|
||||
#include "stringops.h"
|
||||
#include "vbuf_print.h"
|
||||
|
||||
/*
|
||||
@ -290,8 +291,7 @@ VBUF *vbuf_print(VBUF *bp, const char *format, va_list ap)
|
||||
break;
|
||||
case 'm':
|
||||
/* Ignore the 'l' modifier, width and precision. */
|
||||
VBUF_STRCAT(bp, saved_errno ?
|
||||
strerror(saved_errno) : "Application error");
|
||||
VBUF_STRCAT(bp, mystrerror(saved_errno));
|
||||
break;
|
||||
case 'p':
|
||||
if (long_flag)
|
||||
|
Loading…
x
Reference in New Issue
Block a user