mirror of
https://github.com/vdukhovni/postfix
synced 2025-08-22 18:07:41 +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
|
-TTEST_CASE
|
||||||
-TTLSMGR_SCACHE
|
-TTLSMGR_SCACHE
|
||||||
-TTLSP_STATE
|
-TTLSP_STATE
|
||||||
|
-TTLSRPT_WRAPPER
|
||||||
-TTLS_APPL_STATE
|
-TTLS_APPL_STATE
|
||||||
-TTLS_CERTS
|
-TTLS_CERTS
|
||||||
-TTLS_CLIENT_INIT_PROPS
|
-TTLS_CLIENT_INIT_PROPS
|
||||||
|
@ -28187,6 +28187,27 @@ Apologies for any names omitted.
|
|||||||
|
|
||||||
Typofix in comment. File: global/normalize_mailhost_addr.c.
|
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
|
20240831
|
||||||
|
|
||||||
Bugfix: require that stable releases have a three-number
|
Bugfix: require that stable releases have a three-number
|
||||||
@ -28237,7 +28258,46 @@ Apologies for any names omitted.
|
|||||||
OpenSSL 3.2) SSL_get0_group_name() function. Viktor Dukhovni.
|
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.
|
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
|
20240924
|
||||||
|
|
||||||
Misc. cleanups. Viktor Dukhovni. Files: src/tls/tls_dh.c,
|
Misc. cleanups. Viktor Dukhovni. Files: src/tls/tls_dh.c,
|
||||||
proto/postconf.proto, src/global/mail_params.h.
|
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
|
done </dev/null
|
||||||
|
|
||||||
# Some checks require a bin/postconf executable.
|
# Some checks require a bin/postconf executable.
|
||||||
pre-release-checks: typo-check missing-proxy-read-maps-check \
|
pre-release-checks: typo-check double-check missing-proxy-read-maps-check \
|
||||||
postlink-check postfix-files-check check-spell-history \
|
postlink-check postfix-files-check \
|
||||||
check-double-history check-table-proto check-see-postconf-d-output \
|
check-table-proto check-see-postconf-d-output \
|
||||||
check-snapshot-nonprod
|
check-snapshot-nonprod
|
||||||
|
|
||||||
postfix-files-check:
|
postfix-files-check:
|
||||||
@ -130,7 +130,10 @@ missing-proxy-read-maps-check:
|
|||||||
$(SHLIB_ENV) mantools/missing-proxy-read-maps | diff /dev/null -
|
$(SHLIB_ENV) mantools/missing-proxy-read-maps | diff /dev/null -
|
||||||
|
|
||||||
typo-check: spell-cc spell-install-proto-text spell-proto-html \
|
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:
|
spell-cc:
|
||||||
mantools/check-spell-cc | diff /dev/null -
|
mantools/check-spell-cc | diff /dev/null -
|
||||||
|
@ -11,6 +11,7 @@ GGeenneerraall ccoonnffiigguurraattiioonn
|
|||||||
* SASL_README: SASL Authentication
|
* SASL_README: SASL Authentication
|
||||||
* TLS_README: TLS Encryption and authentication
|
* TLS_README: TLS Encryption and authentication
|
||||||
* FORWARD_SECRECY_README: TLS Forward Secrecy
|
* FORWARD_SECRECY_README: TLS Forward Secrecy
|
||||||
|
* TLSRPT_README: TLSRPT Protocol Support
|
||||||
* IPV6_README: IP Version 6 Support
|
* IPV6_README: IP Version 6 Support
|
||||||
* SMTPUTF8_README: SMTPUTF8 Support
|
* SMTPUTF8_README: SMTPUTF8 Support
|
||||||
* MAILLOG_README: Postfix logging to file or stdout
|
* 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
|
(EPL) 2.0. Recipients can choose to take the software under the
|
||||||
license of their choice. Those who are more comfortable with the
|
license of their choice. Those who are more comfortable with the
|
||||||
IPL can continue with that license.
|
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.
|
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.
|
Add tests for Message-ID extraction in the cleanup daemon.
|
||||||
|
|
||||||
When debug logging is enabled, dict_db_open() logs a newline
|
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/STRESS_README:f:root:-:644
|
||||||
$readme_directory/TLS_LEGACY_README:f:root:-:644
|
$readme_directory/TLS_LEGACY_README:f:root:-:644
|
||||||
$readme_directory/TLS_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/TUNING_README:f:root:-:644
|
||||||
$readme_directory/ULTRIX_README:f:root:-:644
|
$readme_directory/ULTRIX_README:f:root:-:644
|
||||||
$readme_directory/UUCP_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/STRESS_README.html:f:root:-:644
|
||||||
$html_directory/TLS_LEGACY_README.html:f:root:-:644
|
$html_directory/TLS_LEGACY_README.html:f:root:-:644
|
||||||
$html_directory/TLS_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/TUNING_README.html:f:root:-:644
|
||||||
$html_directory/ULTRIX_README.html:f:root:-:644:o
|
$html_directory/ULTRIX_README.html:f:root:-:644:o
|
||||||
$html_directory/UUCP_README.html:f:root:-:644
|
$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="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="IPV6_README.html"> IP Version 6 Support </a>
|
||||||
|
|
||||||
<li> <a href="SMTPUTF8_README.html"> SMTPUTF8 Support </a>
|
<li> <a href="SMTPUTF8_README.html"> SMTPUTF8 Support </a>
|
||||||
|
@ -746,6 +746,13 @@ SMTP,(LMTP) SMTP,(LMTP)
|
|||||||
Request that remote SMTP servers send an <a href="https://tools.ietf.org/html/rfc7250">RFC7250</a> raw public key
|
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.
|
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>
|
<b>OBSOLETE STARTTLS CONTROLS</b>
|
||||||
The following configuration parameters exist for compatibility with
|
The following configuration parameters exist for compatibility with
|
||||||
Postfix versions before 2.3. Support for these will be removed in a
|
Postfix versions before 2.3. Support for these will be removed in a
|
||||||
|
@ -43,6 +43,8 @@ POSTCAT(1) POSTCAT(1)
|
|||||||
|
|
||||||
<b>-f</b> Prepend the file name to each output line.
|
<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
|
<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
|
the beginning of the message up to, but not including, the first
|
||||||
non-header line.
|
non-header line.
|
||||||
|
@ -14800,6 +14800,33 @@ Postfix versions. </p>
|
|||||||
<p> This feature is available in Postfix 3.0 and later. </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>
|
</DD>
|
||||||
|
|
||||||
<DT><b><a name="smtp_use_tls">smtp_use_tls</a>
|
<DT><b><a name="smtp_use_tls">smtp_use_tls</a>
|
||||||
|
@ -746,6 +746,13 @@ SMTP,(LMTP) SMTP,(LMTP)
|
|||||||
Request that remote SMTP servers send an <a href="https://tools.ietf.org/html/rfc7250">RFC7250</a> raw public key
|
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.
|
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>
|
<b>OBSOLETE STARTTLS CONTROLS</b>
|
||||||
The following configuration parameters exist for compatibility with
|
The following configuration parameters exist for compatibility with
|
||||||
Postfix versions before 2.3. Support for these will be removed in a
|
Postfix versions before 2.3. Support for these will be removed in a
|
||||||
|
@ -41,6 +41,8 @@ Show message envelope content.
|
|||||||
This feature is available in Postfix 2.7 and later.
|
This feature is available in Postfix 2.7 and later.
|
||||||
.IP \fB\-f\fR
|
.IP \fB\-f\fR
|
||||||
Prepend the file name to each output line.
|
Prepend the file name to each output line.
|
||||||
|
.sp
|
||||||
|
This feature is available in Postfix 3.10 and later.
|
||||||
.IP \fB\-h\fR
|
.IP \fB\-h\fR
|
||||||
Show message header content. The \fB\-h\fR option produces
|
Show message header content. The \fB\-h\fR option produces
|
||||||
output from the beginning of the message up to, but not
|
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.
|
Postfix versions.
|
||||||
.PP
|
.PP
|
||||||
This feature is available in Postfix 3.0 and later.
|
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)
|
.SH smtp_use_tls (default: no)
|
||||||
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. Beware:
|
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"
|
.IP "\fBsmtp_tls_enable_rpk (no)\fR"
|
||||||
Request that remote SMTP servers send an RFC7250 raw public key
|
Request that remote SMTP servers send an RFC7250 raw public key
|
||||||
instead of an X.509 certificate.
|
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"
|
.SH "OBSOLETE STARTTLS CONTROLS"
|
||||||
.na
|
.na
|
||||||
.nf
|
.nf
|
||||||
|
@ -6,9 +6,23 @@ postfix-[0-9]*.[0-9]*.[0-9]*)
|
|||||||
test -f conf/makedefs.out || {
|
test -f conf/makedefs.out || {
|
||||||
echo "Error: no conf/makedefs.out" 1>&2; exit 1; }
|
echo "Error: no conf/makedefs.out" 1>&2; exit 1; }
|
||||||
grep 'CCARGS.*-DSNAPSHOT' conf/makedefs.out && {
|
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 && {
|
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
|
mail_version=$(sh postfix-env.sh bin/postconf -h mail_version) || exit 1
|
||||||
test "postfix-$mail_version" = "$version" || {
|
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; }
|
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;\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;\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;\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_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_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;
|
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/STANDARD_CONFIGURATION_README.html \
|
||||||
../html/STRESS_README.html \
|
../html/STRESS_README.html \
|
||||||
../html/TLS_README.html ../html/TLS_LEGACY_README.html \
|
../html/TLS_README.html ../html/TLS_LEGACY_README.html \
|
||||||
|
../html/TLSRPT_README.html \
|
||||||
../html/TUNING_README.html \
|
../html/TUNING_README.html \
|
||||||
../html/UUCP_README.html \
|
../html/UUCP_README.html \
|
||||||
../html/VERP_README.html ../html/VIRTUAL_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/STANDARD_CONFIGURATION_README \
|
||||||
../README_FILES/STRESS_README \
|
../README_FILES/STRESS_README \
|
||||||
../README_FILES/TLS_README ../README_FILES/TLS_LEGACY_README \
|
../README_FILES/TLS_README ../README_FILES/TLS_LEGACY_README \
|
||||||
|
../README_FILES/TLSRPT_README \
|
||||||
../README_FILES/TUNING_README \
|
../README_FILES/TUNING_README \
|
||||||
../README_FILES/UUCP_README \
|
../README_FILES/UUCP_README \
|
||||||
../README_FILES/VERP_README ../README_FILES/VIRTUAL_README \
|
../README_FILES/VERP_README ../README_FILES/VIRTUAL_README \
|
||||||
@ -343,6 +345,9 @@ clobber:
|
|||||||
../html/TLS_LEGACY_README.html: TLS_LEGACY_README.html
|
../html/TLS_LEGACY_README.html: TLS_LEGACY_README.html
|
||||||
$(DETAB) $? | $(POSTLINK) >$@
|
$(DETAB) $? | $(POSTLINK) >$@
|
||||||
|
|
||||||
|
../html/TLSRPT_README.html: TLSRPT_README.html
|
||||||
|
$(DETAB) $? | $(POSTLINK) >$@
|
||||||
|
|
||||||
../README_FILES/ADDRESS_CLASS_README: ADDRESS_CLASS_README.html
|
../README_FILES/ADDRESS_CLASS_README: ADDRESS_CLASS_README.html
|
||||||
$(DETAB) $? | $(HT2READ) >$@
|
$(DETAB) $? | $(HT2READ) >$@
|
||||||
|
|
||||||
@ -529,6 +534,9 @@ clobber:
|
|||||||
../README_FILES/TLS_LEGACY_README: TLS_LEGACY_README.html
|
../README_FILES/TLS_LEGACY_README: TLS_LEGACY_README.html
|
||||||
$(DETAB) $? | $(HT2READ) >$@
|
$(DETAB) $? | $(HT2READ) >$@
|
||||||
|
|
||||||
|
../README_FILES/TLSRPT_README: TLSRPT_README.html
|
||||||
|
$(DETAB) $? | $(HT2READ) >$@
|
||||||
|
|
||||||
../README_FILES/AAAREADME: ../html/index.html $(MAKEAAA)
|
../README_FILES/AAAREADME: ../html/index.html $(MAKEAAA)
|
||||||
$(MAKEAAA) ../html/index.html | $(HT2READ) | $(DETAB) >$@
|
$(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>
|
length limit. </p>
|
||||||
|
|
||||||
<p> This feature is available in Postfix ≥ 3.9. </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
|
kex
|
||||||
keyshare
|
keyshare
|
||||||
pkg
|
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
|
address address string length
|
||||||
whether the standard End of DATA sequence CRLF CRLF is required and
|
whether the standard End of DATA sequence CRLF CRLF is required and
|
||||||
Require CRLF CRLF
|
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
|
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
|
CCARGS CCARGS DHAS_MONGODB I usr include libmongoc 1 0
|
||||||
dt dt dd 2 Also enable verbose logging in the Postfix TLS
|
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
|
ILP
|
||||||
xxfi
|
xxfi
|
||||||
optionsv
|
optionsv
|
||||||
|
rcv
|
||||||
|
snd
|
||||||
|
sts
|
||||||
|
tlsrprt
|
||||||
bdefhnoqv
|
bdefhnoqv
|
||||||
|
deduplicated
|
||||||
|
@ -379,3 +379,11 @@ Dextrous
|
|||||||
ar
|
ar
|
||||||
liveness
|
liveness
|
||||||
superset
|
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 int dns_rr_compare_pref(DNS_RR *, DNS_RR *);
|
||||||
extern DNS_RR *dns_rr_shuffle(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_remove(DNS_RR *, DNS_RR *);
|
||||||
|
extern DNS_RR *dns_rr_detach(DNS_RR *, DNS_RR *);
|
||||||
extern int var_dns_rr_list_limit;
|
extern int var_dns_rr_list_limit;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -52,6 +52,10 @@
|
|||||||
/* DNS_RR *list;
|
/* DNS_RR *list;
|
||||||
/* DNS_RR *record;
|
/* 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 *dns_srv_rr_sort(list)
|
||||||
/* DNS_RR *list;
|
/* DNS_RR *list;
|
||||||
/*
|
/*
|
||||||
@ -118,10 +122,15 @@
|
|||||||
/*
|
/*
|
||||||
/* dns_rr_shuffle() randomly permutes a list of resource records.
|
/* 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 updated list is the result value.
|
||||||
/* The record MUST be a list member.
|
/* 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
|
/* dns_srv_rr_sort() sorts a list of SRV records according to
|
||||||
/* their priority and weight as described in RFC 2782.
|
/* their priority and weight as described in RFC 2782.
|
||||||
/* LICENSE
|
/* 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_remove - remove record from list, return new list */
|
||||||
|
|
||||||
DNS_RR *dns_rr_remove(DNS_RR *list, DNS_RR *record)
|
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)
|
if (list == 0)
|
||||||
msg_panic("dns_rr_remove: record not found");
|
msg_panic("dns_rr_detach: record not found");
|
||||||
|
|
||||||
if (list == record) {
|
if (list == record) {
|
||||||
list = record->next;
|
list = record->next;
|
||||||
record->next = 0;
|
record->next = 0;
|
||||||
dns_rr_free(record);
|
|
||||||
} else {
|
} else {
|
||||||
list->next = dns_rr_remove(list->next, record);
|
list->next = dns_rr_detach(list->next, record);
|
||||||
}
|
}
|
||||||
return (list);
|
return (list);
|
||||||
}
|
}
|
||||||
|
@ -361,6 +361,93 @@ static int append_to_elem_from_list_exact_fit(void)
|
|||||||
return (eq_dns_rr_free(got, want));
|
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.
|
* 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,
|
"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(),
|
* TODO: tests for dns_rr_sort(), dns_rr_srv_sort(), dns_rr_shuffle(),
|
||||||
* dns_rr_shuffle(), etc.
|
* 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,
|
0,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -250,15 +250,12 @@ static int haproxy_srvr_parse_addr(const char *str, MAI_HOSTADDR_STR *addr,
|
|||||||
}
|
}
|
||||||
if (err == 0)
|
if (err == 0)
|
||||||
err = (hostaddr_to_sockaddr(str, (char *) 0, 0, &res)
|
err = (hostaddr_to_sockaddr(str, (char *) 0, 0, &res)
|
||||||
|| sockaddr_to_hostaddr(res->ai_addr, res->ai_addrlen,
|
|| sane_sockaddr_to_hostaddr(res->ai_addr, res->ai_addrlen,
|
||||||
addr, (MAI_SERVPORT_STR *) 0, 0));
|
addr, (MAI_SERVPORT_STR *) 0, 0));
|
||||||
if (res)
|
if (res)
|
||||||
freeaddrinfo(res);
|
freeaddrinfo(res);
|
||||||
if (err)
|
if (err)
|
||||||
return (-1);
|
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);
|
return (0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4459,6 +4459,22 @@ extern bool var_ign_srv_lookup_err;
|
|||||||
#define DEF_ALLOW_SRV_FALLBACK 0
|
#define DEF_ALLOW_SRV_FALLBACK 0
|
||||||
extern bool var_allow_srv_fallback;
|
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
|
/* LICENSE
|
||||||
/* .ad
|
/* .ad
|
||||||
/* .fi
|
/* .fi
|
||||||
@ -4473,6 +4489,9 @@ extern bool var_allow_srv_fallback;
|
|||||||
/* Google, Inc.
|
/* Google, Inc.
|
||||||
/* 111 8th Avenue
|
/* 111 8th Avenue
|
||||||
/* New York, NY 10011, USA
|
/* New York, NY 10011, USA
|
||||||
|
/*
|
||||||
|
/* Wietse Venema
|
||||||
|
/* porcupine.org
|
||||||
/*--*/
|
/*--*/
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -20,7 +20,7 @@
|
|||||||
* Patches change both the patchlevel and the release date. Snapshots have no
|
* Patches change both the patchlevel and the release date. Snapshots have no
|
||||||
* patchlevel; they change the release date only.
|
* patchlevel; they change the release date only.
|
||||||
*/
|
*/
|
||||||
#define MAIL_RELEASE_DATE "20240924"
|
#define MAIL_RELEASE_DATE "20240926"
|
||||||
#define MAIL_VERSION_NUMBER "3.10"
|
#define MAIL_VERSION_NUMBER "3.10"
|
||||||
|
|
||||||
#ifdef SNAPSHOT
|
#ifdef SNAPSHOT
|
||||||
|
@ -35,6 +35,8 @@
|
|||||||
/* This feature is available in Postfix 2.7 and later.
|
/* This feature is available in Postfix 2.7 and later.
|
||||||
/* .IP \fB-f\fR
|
/* .IP \fB-f\fR
|
||||||
/* Prepend the file name to each output line.
|
/* Prepend the file name to each output line.
|
||||||
|
/* .sp
|
||||||
|
/* This feature is available in Postfix 3.10 and later.
|
||||||
/* .IP \fB-h\fR
|
/* .IP \fB-h\fR
|
||||||
/* Show message header content. The \fB-h\fR option produces
|
/* Show message header content. The \fB-h\fR option produces
|
||||||
/* output from the beginning of the message up to, but not
|
/* output from the beginning of the message up to, but not
|
||||||
|
@ -110,25 +110,6 @@
|
|||||||
|
|
||||||
static const INET_PROTO_INFO *proto_info;
|
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 */
|
/* psc_endpt_local_lookup - look up local system connection information */
|
||||||
|
|
||||||
void psc_endpt_local_lookup(VSTREAM *smtp_client_stream,
|
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
|
* Convert the remote SMTP client address and port to printable form for
|
||||||
* logging and access control.
|
* logging and access control.
|
||||||
*/
|
*/
|
||||||
else if ((aierr = psc_sockaddr_to_hostaddr(
|
else if ((aierr = sane_sockaddr_to_hostaddr(
|
||||||
(struct sockaddr *) &addr_storage,
|
(struct sockaddr *) &addr_storage,
|
||||||
addr_storage_len, &smtp_client_addr,
|
addr_storage_len, &smtp_client_addr,
|
||||||
&smtp_client_port, SOCK_STREAM)) != 0) {
|
&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
|
* Convert the local SMTP server address and port to printable form for
|
||||||
* logging.
|
* logging.
|
||||||
*/
|
*/
|
||||||
else if ((aierr = psc_sockaddr_to_hostaddr(
|
else if ((aierr = sane_sockaddr_to_hostaddr(
|
||||||
(struct sockaddr *) &addr_storage,
|
(struct sockaddr *) &addr_storage,
|
||||||
addr_storage_len, &smtp_server_addr,
|
addr_storage_len, &smtp_server_addr,
|
||||||
&smtp_server_port, SOCK_STREAM)) != 0) {
|
&smtp_server_port, SOCK_STREAM)) != 0) {
|
||||||
|
@ -835,6 +835,8 @@ static int starttls(STATE *state)
|
|||||||
= vstring_str(cipher_exclusions),
|
= vstring_str(cipher_exclusions),
|
||||||
matchargv = state->match,
|
matchargv = state->match,
|
||||||
mdalg = state->mdalg,
|
mdalg = state->mdalg,
|
||||||
|
tlsrpt = 0,
|
||||||
|
ffail_type = 0,
|
||||||
dane = state->ddane ?
|
dane = state->ddane ?
|
||||||
state->ddane : state->dane);
|
state->ddane : state->dane);
|
||||||
|
|
||||||
@ -939,6 +941,8 @@ static int starttls(STATE *state)
|
|||||||
= vstring_str(cipher_exclusions),
|
= vstring_str(cipher_exclusions),
|
||||||
matchargv = state->match,
|
matchargv = state->match,
|
||||||
mdalg = state->mdalg,
|
mdalg = state->mdalg,
|
||||||
|
tlsrpt = 0,
|
||||||
|
ffail_type = 0,
|
||||||
dane = state->ddane ? state->ddane : state->dane);
|
dane = state->ddane ? state->ddane : state->dane);
|
||||||
} /* tlsproxy_mode */
|
} /* tlsproxy_mode */
|
||||||
vstring_free(cipher_exclusions);
|
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 \
|
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_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_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 \
|
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_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_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
|
HDRS = smtp.h smtp_sasl.h smtp_addr.h smtp_reuse.h smtp_sasl_auth_cache.h
|
||||||
TESTSRC =
|
TESTSRC =
|
||||||
DEFS = -I. -I$(INC_DIR) -D$(SYSTYPE)
|
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.h
|
||||||
smtp_connect.o: ../../include/tls_proxy.h
|
smtp_connect.o: ../../include/tls_proxy.h
|
||||||
smtp_connect.o: ../../include/tok822.h
|
smtp_connect.o: ../../include/tok822.h
|
||||||
|
smtp_connect.o: ../../include/valid_hostname.h
|
||||||
smtp_connect.o: ../../include/vbuf.h
|
smtp_connect.o: ../../include/vbuf.h
|
||||||
smtp_connect.o: ../../include/vstream.h
|
smtp_connect.o: ../../include/vstream.h
|
||||||
smtp_connect.o: ../../include/vstring.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/sys_defs.h
|
||||||
smtp_proto.o: ../../include/tls.h
|
smtp_proto.o: ../../include/tls.h
|
||||||
smtp_proto.o: ../../include/tls_proxy.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/tok822.h
|
||||||
smtp_proto.o: ../../include/uxtext.h
|
smtp_proto.o: ../../include/uxtext.h
|
||||||
smtp_proto.o: ../../include/vbuf.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/sys_defs.h
|
||||||
smtp_state.o: ../../include/tls.h
|
smtp_state.o: ../../include/tls.h
|
||||||
smtp_state.o: ../../include/tls_proxy.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/tok822.h
|
||||||
smtp_state.o: ../../include/vbuf.h
|
smtp_state.o: ../../include/vbuf.h
|
||||||
smtp_state.o: ../../include/vstream.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/nvtable.h
|
||||||
smtp_tls_policy.o: ../../include/recipient_list.h
|
smtp_tls_policy.o: ../../include/recipient_list.h
|
||||||
smtp_tls_policy.o: ../../include/resolve_clnt.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/scache.h
|
||||||
smtp_tls_policy.o: ../../include/sock_addr.h
|
smtp_tls_policy.o: ../../include/sock_addr.h
|
||||||
smtp_tls_policy.o: ../../include/string_list.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/sys_defs.h
|
||||||
smtp_tls_policy.o: ../../include/tls.h
|
smtp_tls_policy.o: ../../include/tls.h
|
||||||
smtp_tls_policy.o: ../../include/tls_proxy.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/tok822.h
|
||||||
smtp_tls_policy.o: ../../include/valid_hostname.h
|
smtp_tls_policy.o: ../../include/valid_hostname.h
|
||||||
smtp_tls_policy.o: ../../include/valid_utf8_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: ../../include/vstring.h
|
||||||
smtp_tls_policy.o: smtp.h
|
smtp_tls_policy.o: smtp.h
|
||||||
smtp_tls_policy.o: smtp_tls_policy.c
|
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/argv.h
|
||||||
smtp_trouble.o: ../../include/attr.h
|
smtp_trouble.o: ../../include/attr.h
|
||||||
smtp_trouble.o: ../../include/bounce.h
|
smtp_trouble.o: ../../include/bounce.h
|
||||||
|
@ -67,6 +67,7 @@
|
|||||||
VAR_TLSPROXY_SERVICE, DEF_TLSPROXY_SERVICE, &var_tlsproxy_service, 1, 0,
|
VAR_TLSPROXY_SERVICE, DEF_TLSPROXY_SERVICE, &var_tlsproxy_service, 1, 0,
|
||||||
VAR_HFROM_FORMAT, DEF_HFROM_FORMAT, &var_hfrom_format, 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_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,
|
0,
|
||||||
};
|
};
|
||||||
static const CONFIG_TIME_TABLE lmtp_time_table[] = {
|
static const CONFIG_TIME_TABLE lmtp_time_table[] = {
|
||||||
@ -137,5 +138,6 @@
|
|||||||
};
|
};
|
||||||
static const CONFIG_NBOOL_TABLE lmtp_nbool_table[] = {
|
static const CONFIG_NBOOL_TABLE lmtp_nbool_table[] = {
|
||||||
VAR_LMTP_REQ_DEADLINE, DEF_LMTP_REQ_DEADLINE, &var_smtp_req_deadline,
|
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,
|
0,
|
||||||
};
|
};
|
||||||
|
@ -638,6 +638,12 @@
|
|||||||
/* .IP "\fBsmtp_tls_enable_rpk (no)\fR"
|
/* .IP "\fBsmtp_tls_enable_rpk (no)\fR"
|
||||||
/* Request that remote SMTP servers send an RFC7250 raw public key
|
/* Request that remote SMTP servers send an RFC7250 raw public key
|
||||||
/* instead of an X.509 certificate.
|
/* 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
|
/* OBSOLETE STARTTLS CONTROLS
|
||||||
/* .ad
|
/* .ad
|
||||||
/* .fi
|
/* .fi
|
||||||
@ -1146,6 +1152,8 @@ int var_smtp_min_data_rate;
|
|||||||
char *var_use_srv_lookup;
|
char *var_use_srv_lookup;
|
||||||
bool var_ign_srv_lookup_err;
|
bool var_ign_srv_lookup_err;
|
||||||
bool var_allow_srv_fallback;
|
bool var_allow_srv_fallback;
|
||||||
|
bool var_smtp_tlsrpt_enable;
|
||||||
|
char *var_smtp_tlsrpt_sockname;
|
||||||
|
|
||||||
/* Special handling of 535 AUTH errors. */
|
/* Special handling of 535 AUTH errors. */
|
||||||
char *var_smtp_sasl_auth_cache_name;
|
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);
|
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_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) {
|
if (smtp_mode) {
|
||||||
smtp_tls_insecure_mx_policy =
|
smtp_tls_insecure_mx_policy =
|
||||||
tls_level_lookup(var_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 */
|
char *sni; /* Optional SNI name when not DANE */
|
||||||
int conn_reuse; /* enable connection reuse */
|
int conn_reuse; /* enable connection reuse */
|
||||||
int enable_rpk; /* Enable server->client RPK */
|
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;
|
} 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
|
* 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->sni = 0; \
|
||||||
_tls_policy_init_tmp->conn_reuse = 0; \
|
_tls_policy_init_tmp->conn_reuse = 0; \
|
||||||
_tls_policy_init_tmp->enable_rpk = 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)
|
} while (0)
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
@ -171,6 +197,9 @@ typedef struct SMTP_STATE {
|
|||||||
*/
|
*/
|
||||||
#ifdef USE_TLS
|
#ifdef USE_TLS
|
||||||
SMTP_TLS_POLICY tls[1]; /* Usage: state->tls->member */
|
SMTP_TLS_POLICY tls[1]; /* Usage: state->tls->member */
|
||||||
|
#ifdef USE_TLSRPT
|
||||||
|
struct TLSRPT_WRAPPER *tlsrpt;
|
||||||
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -757,6 +786,18 @@ extern void smtp_quote_821_address(VSTRING *, const char *);
|
|||||||
*/
|
*/
|
||||||
extern int smtp_hfrom_format;
|
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
|
/* LICENSE
|
||||||
/* .ad
|
/* .ad
|
||||||
/* .fi
|
/* .fi
|
||||||
|
@ -104,6 +104,7 @@
|
|||||||
#include <mail_error.h>
|
#include <mail_error.h>
|
||||||
#include <dsn_buf.h>
|
#include <dsn_buf.h>
|
||||||
#include <mail_addr.h>
|
#include <mail_addr.h>
|
||||||
|
#include <valid_hostname.h>
|
||||||
|
|
||||||
/* DNS library. */
|
/* 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);
|
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
|
* Resolve an SMTP or LMTP server. Skip MX or SRV lookups when a
|
||||||
* quoted domain is specified or when DNS lookups are disabled.
|
* 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;
|
session->state = state;
|
||||||
#ifdef USE_TLS
|
#ifdef USE_TLS
|
||||||
session->tls_nexthop = domain;
|
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
|
#endif
|
||||||
if (addr->pref == domain_best_pref)
|
if (addr->pref == domain_best_pref)
|
||||||
session->features |= SMTP_FEATURE_BEST_MX;
|
session->features |= SMTP_FEATURE_BEST_MX;
|
||||||
|
@ -68,6 +68,7 @@
|
|||||||
VAR_TLSPROXY_SERVICE, DEF_TLSPROXY_SERVICE, &var_tlsproxy_service, 1, 0,
|
VAR_TLSPROXY_SERVICE, DEF_TLSPROXY_SERVICE, &var_tlsproxy_service, 1, 0,
|
||||||
VAR_HFROM_FORMAT, DEF_HFROM_FORMAT, &var_hfrom_format, 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_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,
|
0,
|
||||||
};
|
};
|
||||||
static const CONFIG_TIME_TABLE smtp_time_table[] = {
|
static const CONFIG_TIME_TABLE smtp_time_table[] = {
|
||||||
@ -141,5 +142,6 @@
|
|||||||
};
|
};
|
||||||
static const CONFIG_NBOOL_TABLE smtp_nbool_table[] = {
|
static const CONFIG_NBOOL_TABLE smtp_nbool_table[] = {
|
||||||
VAR_SMTP_REQ_DEADLINE, DEF_SMTP_REQ_DEADLINE, &var_smtp_req_deadline,
|
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,
|
0,
|
||||||
};
|
};
|
||||||
|
@ -78,6 +78,9 @@
|
|||||||
/* 111 8th Avenue
|
/* 111 8th Avenue
|
||||||
/* New York, NY 10011, USA
|
/* New York, NY 10011, USA
|
||||||
/*
|
/*
|
||||||
|
/* Wietse Venema
|
||||||
|
/* porcupine.org
|
||||||
|
/*
|
||||||
/* Pipelining code in cooperation with:
|
/* Pipelining code in cooperation with:
|
||||||
/* Jon Ribbens
|
/* Jon Ribbens
|
||||||
/* Oaktree Internet Solutions Ltd.,
|
/* Oaktree Internet Solutions Ltd.,
|
||||||
@ -155,6 +158,9 @@
|
|||||||
#include <xtext.h>
|
#include <xtext.h>
|
||||||
#include <uxtext.h>
|
#include <uxtext.h>
|
||||||
#include <smtputf8.h>
|
#include <smtputf8.h>
|
||||||
|
#if defined(USE_TLS) && defined(USE_TLSRPT)
|
||||||
|
#include <tlsrpt_wrapper.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Application-specific. */
|
/* Application-specific. */
|
||||||
|
|
||||||
@ -475,6 +481,11 @@ int smtp_helo(SMTP_STATE *state)
|
|||||||
else
|
else
|
||||||
session->features &= ~SMTP_FEATURE_ESMTP;
|
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) {
|
if ((session->features & SMTP_FEATURE_ESMTP) == 0) {
|
||||||
where = "performing the HELO handshake";
|
where = "performing the HELO handshake";
|
||||||
@ -484,6 +495,10 @@ int smtp_helo(SMTP_STATE *state)
|
|||||||
"host %s refused to talk to me: %s",
|
"host %s refused to talk to me: %s",
|
||||||
session->namaddr,
|
session->namaddr,
|
||||||
translit(resp->str, "\n", " ")));
|
translit(resp->str, "\n", " ")));
|
||||||
|
#ifdef USE_TLSRPT
|
||||||
|
if (state->tlsrpt)
|
||||||
|
trw_set_ehlo_resp(state->tlsrpt, resp->str);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
where = "performing the LHLO handshake";
|
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.
|
* although support for it was announced in the EHLO response.
|
||||||
*/
|
*/
|
||||||
session->features &= ~SMTP_FEATURE_STARTTLS;
|
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,
|
return (smtp_site_fail(state, STR(iter->host), resp,
|
||||||
"TLS is required, but host %s refused to start TLS: %s",
|
"TLS is required, but host %s refused to start TLS: %s",
|
||||||
session->namaddr,
|
session->namaddr,
|
||||||
translit(resp->str, "\n", " ")));
|
translit(resp->str, "\n", " ")));
|
||||||
|
}
|
||||||
/* Else try to continue in plain-text mode. */
|
/* 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 (TLS_REQUIRED(state->tls->level)) {
|
||||||
if (!(session->features & SMTP_FEATURE_STARTTLS)) {
|
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,
|
return (smtp_site_fail(state, DSN_BY_LOCAL_MTA,
|
||||||
SMTP_RESP_FAKE(&fake, "4.7.4"),
|
SMTP_RESP_FAKE(&fake, "4.7.4"),
|
||||||
"TLS is required, but was not offered by host %s",
|
"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),
|
= vstring_str(state->tls->exclusions),
|
||||||
matchargv = state->tls->matchargv,
|
matchargv = state->tls->matchargv,
|
||||||
mdalg = var_smtp_tls_fpt_dgst,
|
mdalg = var_smtp_tls_fpt_dgst,
|
||||||
|
#ifdef USE_TLSRPT
|
||||||
|
tlsrpt = state->tlsrpt,
|
||||||
|
#else
|
||||||
|
tlsrpt = 0,
|
||||||
|
#endif
|
||||||
|
ffail_type = 0,
|
||||||
dane = state->tls->dane);
|
dane = state->tls->dane);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -1065,6 +1101,12 @@ static int smtp_start_tls(SMTP_STATE *state)
|
|||||||
= vstring_str(state->tls->exclusions),
|
= vstring_str(state->tls->exclusions),
|
||||||
matchargv = state->tls->matchargv,
|
matchargv = state->tls->matchargv,
|
||||||
mdalg = var_smtp_tls_fpt_dgst,
|
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);
|
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.
|
* we must check that here, and not state->tls->level.
|
||||||
*/
|
*/
|
||||||
if (TLS_MUST_MATCH(session->tls_context->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,
|
return (smtp_site_fail(state, DSN_BY_LOCAL_MTA,
|
||||||
SMTP_RESP_FAKE(&fake, "4.7.5"),
|
SMTP_RESP_FAKE(&fake, "4.7.5"),
|
||||||
"Server certificate not verified"));
|
"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
|
* At this point we have to re-negotiate the "EHLO" to reget the
|
||||||
|
@ -50,6 +50,13 @@
|
|||||||
#include <mail_params.h>
|
#include <mail_params.h>
|
||||||
#include <debug_peer.h>
|
#include <debug_peer.h>
|
||||||
|
|
||||||
|
/*
|
||||||
|
* TLS library.
|
||||||
|
*/
|
||||||
|
#if defined(USE_TLS) && defined(USE_TLSRPT)
|
||||||
|
#include <tlsrpt_wrapper.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Application-specific. */
|
/* Application-specific. */
|
||||||
|
|
||||||
#include "smtp.h"
|
#include "smtp.h"
|
||||||
@ -73,6 +80,9 @@ SMTP_STATE *smtp_state_alloc(void)
|
|||||||
state->iterator->host = vstring_alloc(100);
|
state->iterator->host = vstring_alloc(100);
|
||||||
state->iterator->addr = vstring_alloc(100);
|
state->iterator->addr = vstring_alloc(100);
|
||||||
state->iterator->saved_dest = vstring_alloc(100);
|
state->iterator->saved_dest = vstring_alloc(100);
|
||||||
|
#ifdef USE_TLSRPT
|
||||||
|
state->tlsrpt = 0;
|
||||||
|
#endif
|
||||||
if (var_smtp_cache_conn) {
|
if (var_smtp_cache_conn) {
|
||||||
state->dest_label = vstring_alloc(10);
|
state->dest_label = vstring_alloc(10);
|
||||||
state->dest_prop = 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->host);
|
||||||
vstring_free(state->iterator->addr);
|
vstring_free(state->iterator->addr);
|
||||||
vstring_free(state->iterator->saved_dest);
|
vstring_free(state->iterator->saved_dest);
|
||||||
|
#ifdef USE_TLSRPT
|
||||||
|
if (state->tlsrpt)
|
||||||
|
trw_free(state->tlsrpt);
|
||||||
|
#endif
|
||||||
if (state->dest_label)
|
if (state->dest_label)
|
||||||
vstring_free(state->dest_label);
|
vstring_free(state->dest_label);
|
||||||
if (state->dest_prop)
|
if (state->dest_prop)
|
||||||
|
@ -102,6 +102,7 @@
|
|||||||
#include <msg.h>
|
#include <msg.h>
|
||||||
#include <mymalloc.h>
|
#include <mymalloc.h>
|
||||||
#include <vstring.h>
|
#include <vstring.h>
|
||||||
|
#include <sane_strtol.h>
|
||||||
#include <stringops.h>
|
#include <stringops.h>
|
||||||
#include <valid_hostname.h>
|
#include <valid_hostname.h>
|
||||||
#include <valid_utf8_hostname.h>
|
#include <valid_utf8_hostname.h>
|
||||||
@ -113,6 +114,10 @@
|
|||||||
#include <maps.h>
|
#include <maps.h>
|
||||||
#include <dsn_buf.h>
|
#include <dsn_buf.h>
|
||||||
|
|
||||||
|
/* TLS library. */
|
||||||
|
|
||||||
|
#include <tlsrpt_wrapper.h>
|
||||||
|
|
||||||
/* DNS library. */
|
/* DNS library. */
|
||||||
|
|
||||||
#include <dns.h>
|
#include <dns.h>
|
||||||
@ -221,15 +226,21 @@ static void tls_policy_lookup_one(SMTP_TLS_POLICY *tls, int *site_level,
|
|||||||
{
|
{
|
||||||
const char *lookup;
|
const char *lookup;
|
||||||
char *policy;
|
char *policy;
|
||||||
char *saved_policy;
|
char *saved_policy = 0;
|
||||||
char *tok;
|
char *tok;
|
||||||
const char *err;
|
|
||||||
char *name;
|
char *name;
|
||||||
char *val;
|
char *val;
|
||||||
static VSTRING *cbuf;
|
static VSTRING *cbuf;
|
||||||
|
char *free_me = 0;
|
||||||
|
|
||||||
#undef FREE_RETURN
|
#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 { \
|
#define INVALID_RETURN(why, levelp) do { \
|
||||||
MARK_INVALID((why), (levelp)); FREE_RETURN; } while (0)
|
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);
|
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);
|
msg_warn("%s: invalid empty policy", WHERE);
|
||||||
INVALID_RETURN(tls->why, site_level);
|
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.
|
* Warn about ignored attributes when TLS is disabled.
|
||||||
*/
|
*/
|
||||||
if (*site_level < TLS_LEV_MAY) {
|
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",
|
msg_warn("%s: ignoring attribute \"%s\" with TLS disabled",
|
||||||
WHERE, tok);
|
WHERE, tok);
|
||||||
FREE_RETURN;
|
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 in attributes may have security consequences, don't ignore
|
||||||
* errors that can degrade security.
|
* errors that can degrade security.
|
||||||
*/
|
*/
|
||||||
while ((tok = mystrtok(&policy, CHARS_COMMA_SP)) != 0) {
|
while ((tok = mystrtokq(&policy, CHARS_COMMA_SP, CHARS_BRACE)) != 0) {
|
||||||
if ((err = split_nameval(tok, &name, &val)) != 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",
|
msg_warn("%s: malformed attribute/value pair \"%s\": %s",
|
||||||
WHERE, tok, err);
|
WHERE, tok, err);
|
||||||
INVALID_RETURN(tls->why, site_level);
|
INVALID_RETURN(tls->why, site_level);
|
||||||
@ -391,6 +406,7 @@ static void tls_policy_lookup_one(SMTP_TLS_POLICY *tls, int *site_level,
|
|||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
/* Last one wins. */
|
||||||
if (!strcasecmp(name, "enable_rpk")) {
|
if (!strcasecmp(name, "enable_rpk")) {
|
||||||
/* Ultimately ignored at some security levels */
|
/* Ultimately ignored at some security levels */
|
||||||
if (strcasecmp(val, "yes") == 0) {
|
if (strcasecmp(val, "yes") == 0) {
|
||||||
@ -404,10 +420,98 @@ static void tls_policy_lookup_one(SMTP_TLS_POLICY *tls, int *site_level,
|
|||||||
}
|
}
|
||||||
continue;
|
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);
|
msg_warn("%s: invalid attribute name: \"%s\"", WHERE, name);
|
||||||
INVALID_RETURN(tls->why, site_level);
|
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;
|
FREE_RETURN;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -707,6 +811,16 @@ static void policy_delete(void *item, void *unused_context)
|
|||||||
if (tls->dane)
|
if (tls->dane)
|
||||||
tls_dane_free(tls->dane);
|
tls_dane_free(tls->dane);
|
||||||
dsb_free(tls->why);
|
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);
|
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_server_init_print.c tls_proxy_server_init_scan.c \
|
||||||
tls_proxy_client_start_print.c tls_proxy_client_start_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_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 \
|
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_prng_exch.o tls_stream.o tls_bio_ops.o tls_misc.o tls_dh.o \
|
||||||
tls_verify.o tls_dane.o tls_certkey.o tls_session.o \
|
tls_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_clnt.o tls_proxy_context_print.o tls_proxy_context_scan.o \
|
||||||
tls_proxy_client_print.o tls_proxy_client_scan.o \
|
tls_proxy_client_print.o tls_proxy_client_scan.o \
|
||||||
tls_proxy_server_print.o tls_proxy_server_scan.o \
|
tls_proxy_server_print.o tls_proxy_server_scan.o \
|
||||||
tls_proxy_client_misc.o
|
tls_proxy_client_misc.o tlsrpt_wrapper.o
|
||||||
HDRS = tls.h tls_prng.h tls_scache.h tls_mgr.h tls_proxy.h
|
HDRS = tls.h tls_prng.h tls_scache.h tls_mgr.h tls_proxy.h tlsrpt_wrapper.h
|
||||||
TESTSRC =
|
TESTSRC =
|
||||||
DEFS = -I. -I$(INC_DIR) -D$(SYSTYPE)
|
DEFS = -I. -I$(INC_DIR) -D$(SYSTYPE)
|
||||||
CFLAGS = $(DEBUG) $(OPT) $(DEFS)
|
CFLAGS = $(DEBUG) $(OPT) $(DEFS)
|
||||||
@ -182,6 +182,7 @@ tls_client.o: tls.h
|
|||||||
tls_client.o: tls_client.c
|
tls_client.o: tls_client.c
|
||||||
tls_client.o: tls_mgr.h
|
tls_client.o: tls_mgr.h
|
||||||
tls_client.o: tls_scache.h
|
tls_client.o: tls_scache.h
|
||||||
|
tls_client.o: tlsrpt_wrapper.h
|
||||||
tls_dane.o: ../../include/argv.h
|
tls_dane.o: ../../include/argv.h
|
||||||
tls_dane.o: ../../include/check_arg.h
|
tls_dane.o: ../../include/check_arg.h
|
||||||
tls_dane.o: ../../include/ctable.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.h
|
||||||
tls_proxy_client_print.o: tls_proxy.h
|
tls_proxy_client_print.o: tls_proxy.h
|
||||||
tls_proxy_client_print.o: tls_proxy_client_print.c
|
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.h
|
||||||
tls_proxy_client_scan.o: ../../include/argv_attr.h
|
tls_proxy_client_scan.o: ../../include/argv_attr.h
|
||||||
tls_proxy_client_scan.o: ../../include/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.h
|
||||||
tls_proxy_client_scan.o: tls_proxy.h
|
tls_proxy_client_scan.o: tls_proxy.h
|
||||||
tls_proxy_client_scan.o: tls_proxy_client_scan.c
|
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/argv.h
|
||||||
tls_proxy_clnt.o: ../../include/attr.h
|
tls_proxy_clnt.o: ../../include/attr.h
|
||||||
tls_proxy_clnt.o: ../../include/check_arg.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: ../../include/vstring.h
|
||||||
tls_verify.o: tls.h
|
tls_verify.o: tls.h
|
||||||
tls_verify.o: tls_verify.c
|
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
|
||||||
|
@ -270,6 +270,8 @@ typedef struct {
|
|||||||
int errordepth; /* Chain depth of error cert */
|
int errordepth; /* Chain depth of error cert */
|
||||||
int errorcode; /* First error at error depth */
|
int errorcode; /* First error at error depth */
|
||||||
int must_fail; /* Failed to load trust settings */
|
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;
|
} TLS_SESS_STATE;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -502,6 +504,8 @@ typedef struct {
|
|||||||
const ARGV *matchargv; /* Cert match patterns */
|
const ARGV *matchargv; /* Cert match patterns */
|
||||||
const char *mdalg; /* default message digest algorithm */
|
const char *mdalg; /* default message digest algorithm */
|
||||||
const TLS_DANE *dane; /* DANE TLSA verification */
|
const TLS_DANE *dane; /* DANE TLSA verification */
|
||||||
|
struct TLSRPT_WRAPPER *tlsrpt; /* RFC 8460 reporting */
|
||||||
|
char *ffail_type; /* Forced verification failure */
|
||||||
} TLS_CLIENT_START_PROPS;
|
} TLS_CLIENT_START_PROPS;
|
||||||
|
|
||||||
extern TLS_APPL_STATE *tls_client_init(const TLS_CLIENT_INIT_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))
|
a6, a7, a8, a9, a10, a11, a12, a13, a14))
|
||||||
|
|
||||||
#define TLS_CLIENT_START(props, a1, a2, a3, a4, a5, a6, a7, a8, a9, \
|
#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), \
|
tls_client_start((((props)->a1), ((props)->a2), ((props)->a3), \
|
||||||
((props)->a4), ((props)->a5), ((props)->a6), ((props)->a7), \
|
((props)->a4), ((props)->a5), ((props)->a6), ((props)->a7), \
|
||||||
((props)->a8), ((props)->a9), ((props)->a10), ((props)->a11), \
|
((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), ((props)->a18), (props)))
|
((props)->a16), ((props)->a17), ((props)->a18), ((props)->a19), \
|
||||||
|
((props)->a20), (props)))
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* tls_server.c
|
* 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_peer_CN(X509 *, const TLS_SESS_STATE *);
|
||||||
extern char *tls_issuer_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 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
|
* tls_dane.c
|
||||||
|
@ -152,6 +152,9 @@
|
|||||||
/*
|
/*
|
||||||
/* Victor Duchovni
|
/* Victor Duchovni
|
||||||
/* Morgan Stanley
|
/* Morgan Stanley
|
||||||
|
/*
|
||||||
|
/* Wietse Venema
|
||||||
|
/* porcupine.org
|
||||||
/*--*/
|
/*--*/
|
||||||
|
|
||||||
/* System library. */
|
/* System library. */
|
||||||
@ -160,6 +163,7 @@
|
|||||||
|
|
||||||
#ifdef USE_TLS
|
#ifdef USE_TLS
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <tlsrpt_wrapper.h>
|
||||||
|
|
||||||
#ifdef STRCASECMP_IN_STRINGS_H
|
#ifdef STRCASECMP_IN_STRINGS_H
|
||||||
#include <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)
|
if (!TLS_CERT_IS_MATCHED(TLScontext)
|
||||||
&& (TLScontext->log_mask & TLS_LOG_UNTRUSTED)) {
|
&& (TLScontext->log_mask & TLS_LOG_UNTRUSTED)) {
|
||||||
if (TLScontext->session_reused == 0)
|
if (TLScontext->session_reused == 0)
|
||||||
tls_log_verify_error(TLScontext);
|
tls_log_verify_error(TLScontext, props->tlsrpt);
|
||||||
else
|
else
|
||||||
msg_info("%s: re-using session with untrusted peer credential, "
|
msg_info("%s: re-using session with untrusted peer credential, "
|
||||||
"look for details earlier in the log", props->namaddr);
|
"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)
|
if (!TLS_CERT_IS_MATCHED(TLScontext)
|
||||||
&& (TLScontext->log_mask & TLS_LOG_UNTRUSTED)) {
|
&& (TLScontext->log_mask & TLS_LOG_UNTRUSTED)) {
|
||||||
if (TLScontext->session_reused == 0)
|
if (TLScontext->session_reused == 0)
|
||||||
tls_log_verify_error(TLScontext);
|
tls_log_verify_error(TLScontext, props->tlsrpt);
|
||||||
else
|
else
|
||||||
msg_info("%s: re-using session with untrusted certificate, "
|
msg_info("%s: re-using session with untrusted certificate, "
|
||||||
"look for details earlier in the log", props->namaddr);
|
"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.
|
* therefore valid for use with SNI.
|
||||||
*/
|
*/
|
||||||
if (SSL_dane_enable(TLScontext->con, 0) <= 0) {
|
if (SSL_dane_enable(TLScontext->con, 0) <= 0) {
|
||||||
|
/* TLSRPT: Local resource error, don't report. */
|
||||||
msg_warn("%s: error enabling DANE-based certificate validation",
|
msg_warn("%s: error enabling DANE-based certificate validation",
|
||||||
TLScontext->namaddr);
|
TLScontext->namaddr);
|
||||||
tls_print_errors();
|
tls_print_errors();
|
||||||
@ -595,6 +600,7 @@ static int tls_auth_enable(TLS_SESS_STATE *TLScontext,
|
|||||||
case TLS_LEV_FPRINT:
|
case TLS_LEV_FPRINT:
|
||||||
/* Synthetic DANE for fingerprint security */
|
/* Synthetic DANE for fingerprint security */
|
||||||
if (SSL_dane_enable(TLScontext->con, 0) <= 0) {
|
if (SSL_dane_enable(TLScontext->con, 0) <= 0) {
|
||||||
|
/* TLSRPT: Local resource error, don't report. */
|
||||||
msg_warn("%s: error enabling fingerprint certificate validation",
|
msg_warn("%s: error enabling fingerprint certificate validation",
|
||||||
props->namaddr);
|
props->namaddr);
|
||||||
tls_print_errors();
|
tls_print_errors();
|
||||||
@ -608,6 +614,7 @@ static int tls_auth_enable(TLS_SESS_STATE *TLScontext,
|
|||||||
if (TLScontext->dane != 0 && TLScontext->dane->tlsa != 0) {
|
if (TLScontext->dane != 0 && TLScontext->dane->tlsa != 0) {
|
||||||
/* Synthetic DANE for per-destination trust-anchors */
|
/* Synthetic DANE for per-destination trust-anchors */
|
||||||
if (SSL_dane_enable(TLScontext->con, NULL) <= 0) {
|
if (SSL_dane_enable(TLScontext->con, NULL) <= 0) {
|
||||||
|
/* TLSRPT: Local resource error, don't report. */
|
||||||
msg_warn("%s: error configuring local trust anchors",
|
msg_warn("%s: error configuring local trust anchors",
|
||||||
props->namaddr);
|
props->namaddr);
|
||||||
tls_print_errors();
|
tls_print_errors();
|
||||||
@ -622,6 +629,7 @@ static int tls_auth_enable(TLS_SESS_STATE *TLScontext,
|
|||||||
|
|
||||||
if (sni) {
|
if (sni) {
|
||||||
if (strlen(sni) > TLSEXT_MAXLEN_host_name) {
|
if (strlen(sni) > TLSEXT_MAXLEN_host_name) {
|
||||||
|
/* TLSRPT: Local configuration error, don't report. */
|
||||||
msg_warn("%s: ignoring too long SNI hostname: %.100s",
|
msg_warn("%s: ignoring too long SNI hostname: %.100s",
|
||||||
props->namaddr, sni);
|
props->namaddr, sni);
|
||||||
return (0);
|
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.
|
* failed to send the SNI name, we have little choice but to abort.
|
||||||
*/
|
*/
|
||||||
if (!SSL_set_tlsext_host_name(TLScontext->con, sni)) {
|
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,
|
msg_warn("%s: error setting SNI hostname to: %s", props->namaddr,
|
||||||
sni);
|
sni);
|
||||||
return (0);
|
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);
|
protomask = tls_proto_mask_lims(props->protocols, &min_proto, &max_proto);
|
||||||
if (protomask == TLS_PROTOCOL_INVALID) {
|
if (protomask == TLS_PROTOCOL_INVALID) {
|
||||||
|
/* TLSRPT: Local configuration error, don't report. */
|
||||||
/* tls_protocol_mask() logs no warning. */
|
/* tls_protocol_mask() logs no warning. */
|
||||||
msg_warn("%s: Invalid TLS protocol list \"%s\": aborting TLS session",
|
msg_warn("%s: Invalid TLS protocol list \"%s\": aborting TLS session",
|
||||||
props->namaddr, props->protocols);
|
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;
|
TLScontext->level = props->tls_level;
|
||||||
|
|
||||||
if ((TLScontext->con = SSL_new(app_ctx->ssl_ctx)) == NULL) {
|
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()");
|
msg_warn("Could not allocate 'TLScontext->con' with SSL_new()");
|
||||||
tls_print_errors();
|
tls_print_errors();
|
||||||
tls_free_context(TLScontext);
|
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,
|
cipher_list = tls_set_ciphers(TLScontext, props->cipher_grade,
|
||||||
props->cipher_exclusions);
|
props->cipher_exclusions);
|
||||||
if (cipher_list == 0) {
|
if (cipher_list == 0) {
|
||||||
|
/* TLSRPT: Local configuration error, don't report. */
|
||||||
/* already warned */
|
/* already warned */
|
||||||
tls_free_context(TLScontext);
|
tls_free_context(TLScontext);
|
||||||
return (0);
|
return (0);
|
||||||
@ -1036,6 +1048,7 @@ TLS_SESS_STATE *tls_client_start(const TLS_CLIENT_START_PROPS *props)
|
|||||||
TLScontext->dane = props->dane;
|
TLScontext->dane = props->dane;
|
||||||
|
|
||||||
if (!SSL_set_ex_data(TLScontext->con, TLScontext_index, TLScontext)) {
|
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'");
|
msg_warn("Could not set application data for 'TLScontext->con'");
|
||||||
tls_print_errors();
|
tls_print_errors();
|
||||||
tls_free_context(TLScontext);
|
tls_free_context(TLScontext);
|
||||||
@ -1069,6 +1082,7 @@ TLS_SESS_STATE *tls_client_start(const TLS_CLIENT_START_PROPS *props)
|
|||||||
* early.
|
* early.
|
||||||
*/
|
*/
|
||||||
if (!tls_auth_enable(TLScontext, props)) {
|
if (!tls_auth_enable(TLScontext, props)) {
|
||||||
|
/* Already warned and reported TLSRPT result. */
|
||||||
tls_free_context(TLScontext);
|
tls_free_context(TLScontext);
|
||||||
return (0);
|
return (0);
|
||||||
}
|
}
|
||||||
@ -1105,6 +1119,13 @@ TLS_SESS_STATE *tls_client_start(const TLS_CLIENT_START_PROPS *props)
|
|||||||
switch (TLScontext->level) {
|
switch (TLScontext->level) {
|
||||||
case TLS_LEV_HALF_DANE:
|
case TLS_LEV_HALF_DANE:
|
||||||
case TLS_LEV_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 "
|
msg_warn("%s: all TLSA records unusable, fallback to "
|
||||||
"unauthenticated TLS", TLScontext->namaddr);
|
"unauthenticated TLS", TLScontext->namaddr);
|
||||||
must_fail = 0;
|
must_fail = 0;
|
||||||
@ -1112,13 +1133,34 @@ TLS_SESS_STATE *tls_client_start(const TLS_CLIENT_START_PROPS *props)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case TLS_LEV_FPRINT:
|
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);
|
msg_warn("%s: all fingerprints unusable", TLScontext->namaddr);
|
||||||
break;
|
break;
|
||||||
case TLS_LEV_DANE_ONLY:
|
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);
|
msg_warn("%s: all TLSA records unusable", TLScontext->namaddr);
|
||||||
break;
|
break;
|
||||||
case TLS_LEV_SECURE:
|
case TLS_LEV_SECURE:
|
||||||
case TLS_LEV_VERIFY:
|
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);
|
msg_warn("%s: all trust anchors unusable", TLScontext->namaddr);
|
||||||
break;
|
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 :
|
if (SSL_set_fd(TLScontext->con, props->stream == 0 ? props->fd :
|
||||||
vstream_fileno(props->stream)) != 1) {
|
vstream_fileno(props->stream)) != 1) {
|
||||||
|
/* TLSRPT: Local resource error, don't report. */
|
||||||
msg_info("SSL_set_fd error to %s", props->namaddr);
|
msg_info("SSL_set_fd error to %s", props->namaddr);
|
||||||
tls_print_errors();
|
tls_print_errors();
|
||||||
uncache_session(app_ctx->ssl_ctx, TLScontext);
|
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)
|
if (log_mask & TLS_LOG_TLSPKTS)
|
||||||
tls_set_bio_callback(SSL_get_rbio(TLScontext->con), tls_bio_dump_cb);
|
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
|
* If we don't trigger the handshake in the library, leave control over
|
||||||
* SSL_connect/read/write/etc with the application.
|
* 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",
|
msg_info("SSL_connect error to %s: lost connection",
|
||||||
props->namaddr);
|
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);
|
uncache_session(app_ctx->ssl_ctx, TLScontext);
|
||||||
tls_free_context(TLScontext);
|
tls_free_context(TLScontext);
|
||||||
return (0);
|
return (0);
|
||||||
@ -1360,6 +1419,19 @@ TLS_SESS_STATE *tls_client_post_connect(TLS_SESS_STATE *TLScontext,
|
|||||||
|
|
||||||
tls_int_seed();
|
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);
|
return (TLScontext);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1363,6 +1363,8 @@ TLS_SESS_STATE *tls_alloc_sess_context(int log_mask, const char *namaddr)
|
|||||||
TLScontext->errordepth = -1;
|
TLScontext->errordepth = -1;
|
||||||
TLScontext->errorcode = X509_V_OK;
|
TLScontext->errorcode = X509_V_OK;
|
||||||
TLScontext->errorcert = 0;
|
TLScontext->errorcert = 0;
|
||||||
|
TLScontext->rpt_reported = 0;
|
||||||
|
TLScontext->ffail_type = 0;
|
||||||
|
|
||||||
return (TLScontext);
|
return (TLScontext);
|
||||||
}
|
}
|
||||||
@ -1413,6 +1415,8 @@ void tls_free_context(TLS_SESS_STATE *TLScontext)
|
|||||||
myfree((void *) TLScontext->srvr_sig_dgst);
|
myfree((void *) TLScontext->srvr_sig_dgst);
|
||||||
if (TLScontext->errorcert)
|
if (TLScontext->errorcert)
|
||||||
X509_free(TLScontext->errorcert);
|
X509_free(TLScontext->errorcert);
|
||||||
|
if (TLScontext->ffail_type)
|
||||||
|
myfree(TLScontext->ffail_type);
|
||||||
|
|
||||||
myfree((void *) TLScontext);
|
myfree((void *) TLScontext);
|
||||||
}
|
}
|
||||||
|
@ -108,11 +108,12 @@ extern VSTREAM *tls_proxy_open(const char *, int, VSTREAM *, const char *,
|
|||||||
((props)->a12), ((props)->a13), ((props)->a14))
|
((props)->a12), ((props)->a13), ((props)->a14))
|
||||||
|
|
||||||
#define TLS_PROXY_CLIENT_START_PROPS(props, a1, a2, a3, a4, a5, a6, a7, a8, \
|
#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)->a1), ((props)->a2), ((props)->a3), \
|
||||||
((props)->a4), ((props)->a5), ((props)->a6), ((props)->a7), \
|
((props)->a4), ((props)->a5), ((props)->a6), ((props)->a7), \
|
||||||
((props)->a8), ((props)->a9), ((props)->a10), ((props)->a11), \
|
((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 TLS_SESS_STATE *tls_proxy_context_receive(VSTREAM *);
|
||||||
extern void tls_proxy_context_free(TLS_SESS_STATE *);
|
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_BITS "srvr_signature_bits"
|
||||||
#define TLS_ATTR_SRVR_SIG_DGST "srvr_signature_digest"
|
#define TLS_ATTR_SRVR_SIG_DGST "srvr_signature_digest"
|
||||||
#define TLS_ATTR_NAMADDR "namaddr"
|
#define TLS_ATTR_NAMADDR "namaddr"
|
||||||
|
#define TLS_ATTR_RPT_REPORTED "rpt_reported"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* TLS_SERVER_INIT_PROPS attributes.
|
* TLS_SERVER_INIT_PROPS attributes.
|
||||||
@ -255,6 +257,8 @@ extern void tls_proxy_server_start_free(TLS_SERVER_START_PROPS *);
|
|||||||
#define TLS_ATTR_MATCHARGV "matchargv"
|
#define TLS_ATTR_MATCHARGV "matchargv"
|
||||||
#define TLS_ATTR_MDALG "mdalg"
|
#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.
|
* TLS_TLSA attributes.
|
||||||
|
@ -79,6 +79,10 @@
|
|||||||
#include <tls.h>
|
#include <tls.h>
|
||||||
#include <tls_proxy.h>
|
#include <tls_proxy.h>
|
||||||
|
|
||||||
|
#ifdef USE_TLSRPT
|
||||||
|
#define TLSRPT_WRAPPER_INTERNAL
|
||||||
|
#include <tlsrpt_wrapper.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#define STR(x) vstring_str(x)
|
#define STR(x) vstring_str(x)
|
||||||
#define LEN(x) VSTRING_LEN(x)
|
#define LEN(x) VSTRING_LEN(x)
|
||||||
@ -242,6 +246,59 @@ static int tls_proxy_client_dane_print(ATTR_PRINT_COMMON_FN print_fn,
|
|||||||
return (ret);
|
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 */
|
/* tls_proxy_client_start_print - send TLS_CLIENT_START_PROPS over stream */
|
||||||
|
|
||||||
int tls_proxy_client_start_print(ATTR_PRINT_COMMON_FN print_fn,
|
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)),
|
STRING_OR_EMPTY(props->mdalg)),
|
||||||
SEND_ATTR_FUNC(tls_proxy_client_dane_print,
|
SEND_ATTR_FUNC(tls_proxy_client_dane_print,
|
||||||
(const void *) props->dane),
|
(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);
|
ATTR_TYPE_END);
|
||||||
/* Do not flush the stream. */
|
/* Do not flush the stream. */
|
||||||
if (msg_verbose)
|
if (msg_verbose)
|
||||||
|
@ -113,6 +113,10 @@
|
|||||||
#define TLS_INTERNAL
|
#define TLS_INTERNAL
|
||||||
#include <tls.h>
|
#include <tls.h>
|
||||||
#include <tls_proxy.h>
|
#include <tls_proxy.h>
|
||||||
|
#ifdef USE_TLSRPT
|
||||||
|
#define TLSRPT_WRAPPER_INTERNAL
|
||||||
|
#include <tlsrpt_wrapper.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#define STR(x) vstring_str(x)
|
#define STR(x) vstring_str(x)
|
||||||
#define LEN(x) VSTRING_LEN(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);
|
myfree((void *) props->mdalg);
|
||||||
if (props->dane)
|
if (props->dane)
|
||||||
tls_dane_free((TLS_DANE *) 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);
|
myfree((void *) props);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -419,6 +429,89 @@ static int tls_proxy_client_dane_scan(ATTR_SCAN_COMMON_FN scan_fn,
|
|||||||
return (ret);
|
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 */
|
/* 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,
|
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_grade = vstring_alloc(25);
|
||||||
VSTRING *cipher_exclusions = vstring_alloc(25);
|
VSTRING *cipher_exclusions = vstring_alloc(25);
|
||||||
VSTRING *mdalg = 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)
|
if (msg_verbose)
|
||||||
msg_info("begin tls_proxy_client_start_scan");
|
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_STR(TLS_ATTR_MDALG, mdalg),
|
||||||
RECV_ATTR_FUNC(tls_proxy_client_dane_scan,
|
RECV_ATTR_FUNC(tls_proxy_client_dane_scan,
|
||||||
&props->dane),
|
&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);
|
ATTR_TYPE_END);
|
||||||
/* Always construct a well-formed structure. */
|
/* Always construct a well-formed structure. */
|
||||||
props->nexthop = vstring_export(nexthop);
|
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_grade = vstring_export(cipher_grade);
|
||||||
props->cipher_exclusions = vstring_export(cipher_exclusions);
|
props->cipher_exclusions = vstring_export(cipher_exclusions);
|
||||||
props->mdalg = vstring_export(mdalg);
|
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) {
|
if (ret != 1) {
|
||||||
tls_proxy_client_start_free(props);
|
tls_proxy_client_start_free(props);
|
||||||
props = 0;
|
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)),
|
STRING_OR_EMPTY(tp->srvr_sig_dgst)),
|
||||||
SEND_ATTR_STR(TLS_ATTR_NAMADDR,
|
SEND_ATTR_STR(TLS_ATTR_NAMADDR,
|
||||||
STRING_OR_EMPTY(tp->namaddr)),
|
STRING_OR_EMPTY(tp->namaddr)),
|
||||||
|
SEND_ATTR_INT(TLS_ATTR_RPT_REPORTED,
|
||||||
|
tp->rpt_reported),
|
||||||
ATTR_TYPE_END);
|
ATTR_TYPE_END);
|
||||||
/* Do not flush the stream. */
|
/* Do not flush the stream. */
|
||||||
return (ret);
|
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_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_SRVR_SIG_DGST, srvr_sig_dgst),
|
||||||
RECV_ATTR_STR(TLS_ATTR_NAMADDR, namaddr),
|
RECV_ATTR_STR(TLS_ATTR_NAMADDR, namaddr),
|
||||||
|
RECV_ATTR_INT(TLS_ATTR_RPT_REPORTED,
|
||||||
|
&tls_context->rpt_reported),
|
||||||
ATTR_TYPE_END);
|
ATTR_TYPE_END);
|
||||||
/* Always construct a well-formed structure. */
|
/* Always construct a well-formed structure. */
|
||||||
tls_context->peer_CN = vstring_export(peer_CN);
|
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_curve = vstring_export(srvr_sig_curve);
|
||||||
tls_context->srvr_sig_dgst = vstring_export(srvr_sig_dgst);
|
tls_context->srvr_sig_dgst = vstring_export(srvr_sig_dgst);
|
||||||
tls_context->namaddr = vstring_export(namaddr);
|
tls_context->namaddr = vstring_export(namaddr);
|
||||||
ret = (ret == 24 ? 1 : -1);
|
ret = (ret == 25 ? 1 : -1);
|
||||||
if (ret != 1) {
|
if (ret != 1) {
|
||||||
tls_proxy_context_free(tls_context);
|
tls_proxy_context_free(tls_context);
|
||||||
tls_context = 0;
|
tls_context = 0;
|
||||||
|
@ -1035,7 +1035,7 @@ TLS_SESS_STATE *tls_server_post_accept(TLS_SESS_STATE *TLScontext)
|
|||||||
if (!TLS_CERT_IS_TRUSTED(TLScontext)
|
if (!TLS_CERT_IS_TRUSTED(TLScontext)
|
||||||
&& (TLScontext->log_mask & TLS_LOG_UNTRUSTED)) {
|
&& (TLScontext->log_mask & TLS_LOG_UNTRUSTED)) {
|
||||||
if (TLScontext->session_reused == 0)
|
if (TLScontext->session_reused == 0)
|
||||||
tls_log_verify_error(TLScontext);
|
tls_log_verify_error(TLScontext, (struct TLSRPT_WRAPPER *) 0);
|
||||||
else
|
else
|
||||||
msg_info("%s: re-using session with untrusted certificate, "
|
msg_info("%s: re-using session with untrusted certificate, "
|
||||||
"look for details earlier in the log",
|
"look for details earlier in the log",
|
||||||
|
@ -11,8 +11,9 @@
|
|||||||
/* int ok;
|
/* int ok;
|
||||||
/* X509_STORE_CTX *ctx;
|
/* X509_STORE_CTX *ctx;
|
||||||
/*
|
/*
|
||||||
/* int tls_log_verify_error(TLScontext)
|
/* int tls_log_verify_error(TLScontext, tlsrpt)
|
||||||
/* TLS_SESS_STATE *TLScontext;
|
/* TLS_SESS_STATE *TLScontext;
|
||||||
|
/* struct TLSRPT_WRAPPER *tlsrpt;
|
||||||
/*
|
/*
|
||||||
/* char *tls_peer_CN(peercert, TLScontext)
|
/* char *tls_peer_CN(peercert, TLScontext)
|
||||||
/* X509 *peercert;
|
/* X509 *peercert;
|
||||||
@ -89,6 +90,9 @@
|
|||||||
/*
|
/*
|
||||||
/* Victor Duchovni
|
/* Victor Duchovni
|
||||||
/* Morgan Stanley
|
/* Morgan Stanley
|
||||||
|
/*
|
||||||
|
/* Wietse Venema
|
||||||
|
/* porcupine.org
|
||||||
/*--*/
|
/*--*/
|
||||||
|
|
||||||
/* System library. */
|
/* System library. */
|
||||||
@ -107,6 +111,10 @@
|
|||||||
|
|
||||||
/* TLS library. */
|
/* TLS library. */
|
||||||
|
|
||||||
|
#ifdef USE_TLSRPT
|
||||||
|
#include <tlsrpt_wrapper.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#define TLS_INTERNAL
|
#define TLS_INTERNAL
|
||||||
#include <tls.h>
|
#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 */
|
/* 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];
|
char buf[CCERT_BUFSIZ];
|
||||||
int err = TLScontext->errorcode;
|
int err = TLScontext->errorcode;
|
||||||
X509 *cert = TLScontext->errorcert;
|
X509 *cert = TLScontext->errorcert;
|
||||||
int depth = TLScontext->errordepth;
|
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")
|
#define PURPOSE ((depth>0) ? "CA": TLScontext->am_server ? "client": "server")
|
||||||
|
|
||||||
if (err == X509_V_OK)
|
if (err == X509_V_OK)
|
||||||
return;
|
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.
|
* 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: "
|
msg_info("certificate verification failed for %s: "
|
||||||
"not trusted by local or TLSA policy", TLScontext->namaddr);
|
"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;
|
break;
|
||||||
case X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT:
|
case X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT:
|
||||||
msg_info("certificate verification failed for %s: "
|
msg_info("certificate verification failed for %s: "
|
||||||
"self-signed certificate", TLScontext->namaddr);
|
"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;
|
break;
|
||||||
case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY:
|
case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY:
|
||||||
case X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN:
|
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>");
|
strcpy(buf, "<unknown>");
|
||||||
msg_info("certificate verification failed for %s: untrusted issuer %s",
|
msg_info("certificate verification failed for %s: untrusted issuer %s",
|
||||||
TLScontext->namaddr, printable(buf, '?'));
|
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;
|
break;
|
||||||
case X509_V_ERR_CERT_NOT_YET_VALID:
|
case X509_V_ERR_CERT_NOT_YET_VALID:
|
||||||
case X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD:
|
case X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD:
|
||||||
msg_info("%s certificate verification failed for %s: certificate not"
|
msg_info("%s certificate verification failed for %s: certificate not"
|
||||||
" yet valid", PURPOSE, TLScontext->namaddr);
|
" 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;
|
break;
|
||||||
case X509_V_ERR_CERT_HAS_EXPIRED:
|
case X509_V_ERR_CERT_HAS_EXPIRED:
|
||||||
case X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD:
|
case X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD:
|
||||||
msg_info("%s certificate verification failed for %s: certificate has"
|
msg_info("%s certificate verification failed for %s: certificate has"
|
||||||
" expired", PURPOSE, TLScontext->namaddr);
|
" 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;
|
break;
|
||||||
case X509_V_ERR_INVALID_PURPOSE:
|
case X509_V_ERR_INVALID_PURPOSE:
|
||||||
msg_info("certificate verification failed for %s: not designated for "
|
msg_info("certificate verification failed for %s: not designated for "
|
||||||
"use as a %s certificate", TLScontext->namaddr, PURPOSE);
|
"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;
|
break;
|
||||||
case X509_V_ERR_CERT_CHAIN_TOO_LONG:
|
case X509_V_ERR_CERT_CHAIN_TOO_LONG:
|
||||||
msg_info("certificate verification failed for %s: "
|
msg_info("certificate verification failed for %s: "
|
||||||
"certificate chain longer than limit(%d)",
|
"certificate chain longer than limit(%d)",
|
||||||
TLScontext->namaddr, depth - 1);
|
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;
|
break;
|
||||||
default:
|
default:
|
||||||
msg_info("%s certificate verification failed for %s: num=%d:%s",
|
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));
|
X509_verify_cert_error_string(err));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
#ifdef USE_TLSRPT
|
||||||
|
vstring_free(err_vstr);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef DONT_GRIPE
|
#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/sys_defs.h
|
||||||
tlsproxy.o: ../../include/tls.h
|
tlsproxy.o: ../../include/tls.h
|
||||||
tlsproxy.o: ../../include/tls_proxy.h
|
tlsproxy.o: ../../include/tls_proxy.h
|
||||||
|
tlsproxy.o: ../../include/tlsrpt_wrapper.h
|
||||||
tlsproxy.o: ../../include/vbuf.h
|
tlsproxy.o: ../../include/vbuf.h
|
||||||
tlsproxy.o: ../../include/vstream.h
|
tlsproxy.o: ../../include/vstream.h
|
||||||
tlsproxy.o: ../../include/vstring.h
|
tlsproxy.o: ../../include/vstring.h
|
||||||
|
@ -426,6 +426,7 @@
|
|||||||
#define TLS_INTERNAL /* XXX */
|
#define TLS_INTERNAL /* XXX */
|
||||||
#include <tls.h>
|
#include <tls.h>
|
||||||
#include <tls_proxy.h>
|
#include <tls_proxy.h>
|
||||||
|
#include <tlsrpt_wrapper.h>
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Application-specific.
|
* 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;
|
state->flags |= TLSP_FLAG_NO_MORE_CIPHERTEXT_IO;
|
||||||
return (TLSP_STAT_OK);
|
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);
|
tlsp_state_free(state);
|
||||||
return (TLSP_STAT_ERR);
|
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 \
|
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 \
|
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 \
|
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 \
|
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_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 \
|
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 \
|
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 \
|
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 \
|
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.
|
# 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),
|
# When hard-linking these, makedefs sets NON_PLUGIN_MAP_OBJ=$(MAP_OBJ),
|
||||||
# otherwise it sets the PLUGIN_* macros.
|
# otherwise it sets the PLUGIN_* macros.
|
||||||
@ -2444,6 +2445,12 @@ mymalloc.o: sys_defs.h
|
|||||||
myrand.o: myrand.c
|
myrand.o: myrand.c
|
||||||
myrand.o: myrand.h
|
myrand.o: myrand.h
|
||||||
myrand.o: sys_defs.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: check_arg.h
|
||||||
mystrtok.o: msg.h
|
mystrtok.o: msg.h
|
||||||
mystrtok.o: mystrtok.c
|
mystrtok.o: mystrtok.c
|
||||||
@ -2549,9 +2556,11 @@ printable.o: stringops.h
|
|||||||
printable.o: sys_defs.h
|
printable.o: sys_defs.h
|
||||||
printable.o: vbuf.h
|
printable.o: vbuf.h
|
||||||
printable.o: vstring.h
|
printable.o: vstring.h
|
||||||
|
quote_for_json.o: check_arg.h
|
||||||
quote_for_json.o: quote_for_json.c
|
quote_for_json.o: quote_for_json.c
|
||||||
quote_for_json.o: stringops.h
|
quote_for_json.o: stringops.h
|
||||||
quote_for_json.o: sys_defs.h
|
quote_for_json.o: sys_defs.h
|
||||||
|
quote_for_json.o: vbuf.h
|
||||||
quote_for_json.o: vstring.h
|
quote_for_json.o: vstring.h
|
||||||
rand_sleep.o: iostuff.h
|
rand_sleep.o: iostuff.h
|
||||||
rand_sleep.o: msg.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: sane_rename.c
|
||||||
sane_rename.o: sys_defs.h
|
sane_rename.o: sys_defs.h
|
||||||
sane_rename.o: warn_stat.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: msg.h
|
||||||
sane_socketpair.o: sane_socketpair.c
|
sane_socketpair.o: sane_socketpair.c
|
||||||
sane_socketpair.o: sane_socketpair.h
|
sane_socketpair.o: sane_socketpair.h
|
||||||
@ -2883,6 +2896,7 @@ vbuf.o: vbuf.h
|
|||||||
vbuf_print.o: check_arg.h
|
vbuf_print.o: check_arg.h
|
||||||
vbuf_print.o: msg.h
|
vbuf_print.o: msg.h
|
||||||
vbuf_print.o: mymalloc.h
|
vbuf_print.o: mymalloc.h
|
||||||
|
vbuf_print.o: stringops.h
|
||||||
vbuf_print.o: sys_defs.h
|
vbuf_print.o: sys_defs.h
|
||||||
vbuf_print.o: vbuf.h
|
vbuf_print.o: vbuf.h
|
||||||
vbuf_print.o: vbuf_print.c
|
vbuf_print.o: vbuf_print.c
|
||||||
|
@ -31,6 +31,10 @@
|
|||||||
/* char *arg;
|
/* char *arg;
|
||||||
/* ssize_t arg_len;
|
/* ssize_t arg_len;
|
||||||
/*
|
/*
|
||||||
|
/* ARGV *argv_addv(argvp, argv)
|
||||||
|
/* ARGV *argvp;
|
||||||
|
/* const char **argv;
|
||||||
|
/*
|
||||||
/* void argv_terminate(argvp);
|
/* void argv_terminate(argvp);
|
||||||
/* ARGV *argvp;
|
/* ARGV *argvp;
|
||||||
/*
|
/*
|
||||||
@ -94,6 +98,10 @@
|
|||||||
/* argv_addn() is like argv_add(), but each string is followed
|
/* argv_addn() is like argv_add(), but each string is followed
|
||||||
/* by a string length argument.
|
/* 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
|
/* argv_free() releases storage for a string array, and conveniently
|
||||||
/* returns a null pointer.
|
/* returns a null pointer.
|
||||||
/*
|
/*
|
||||||
@ -144,6 +152,9 @@
|
|||||||
/* Google, Inc.
|
/* Google, Inc.
|
||||||
/* 111 8th Avenue
|
/* 111 8th Avenue
|
||||||
/* New York, NY 10011, USA
|
/* New York, NY 10011, USA
|
||||||
|
/*
|
||||||
|
/* Wietse Venema
|
||||||
|
/* porcupine.org
|
||||||
/*--*/
|
/*--*/
|
||||||
|
|
||||||
/* System libraries. */
|
/* System libraries. */
|
||||||
@ -301,6 +312,23 @@ void argv_addn(ARGV *argvp,...)
|
|||||||
argvp->argv[argvp->argc] = 0;
|
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 */
|
/* argv_terminate - terminate string array */
|
||||||
|
|
||||||
void argv_terminate(ARGV *argvp)
|
void argv_terminate(ARGV *argvp)
|
||||||
@ -602,6 +630,23 @@ static ARGV *test_argv_join(const TEST_CASE *tp, ARGV *argvp)
|
|||||||
return (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 */
|
/* test_argv_verify - verify result */
|
||||||
|
|
||||||
static int test_argv_verify(const TEST_CASE *tp, ARGV *argvp)
|
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}, 0, test_argv_join,
|
||||||
0, 1, {"", 0}, ':'
|
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,
|
0,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -28,6 +28,7 @@ extern ARGV *argv_qsort(ARGV *, ARGV_COMPAR_FN);
|
|||||||
extern ARGV *argv_uniq(ARGV *, ARGV_COMPAR_FN);
|
extern ARGV *argv_uniq(ARGV *, ARGV_COMPAR_FN);
|
||||||
extern void argv_add(ARGV *,...);
|
extern void argv_add(ARGV *,...);
|
||||||
extern void argv_addn(ARGV *,...);
|
extern void argv_addn(ARGV *,...);
|
||||||
|
extern ARGV *argv_addv(ARGV *, const char *const *);
|
||||||
extern void argv_terminate(ARGV *);
|
extern void argv_terminate(ARGV *);
|
||||||
extern void argv_truncate(ARGV *, ssize_t);
|
extern void argv_truncate(ARGV *, ssize_t);
|
||||||
extern void argv_insert_one(ARGV *, ssize_t, const char *);
|
extern void argv_insert_one(ARGV *, ssize_t, const char *);
|
||||||
|
@ -44,6 +44,8 @@
|
|||||||
/* functionality.
|
/* functionality.
|
||||||
/* .IP HEX_ENCODE_FLAG_USE_COLON
|
/* .IP HEX_ENCODE_FLAG_USE_COLON
|
||||||
/* Inserts one ":" between bytes.
|
/* Inserts one ":" between bytes.
|
||||||
|
/* .IP HEX_ENCODE_FLAG_APPEND
|
||||||
|
/* Append output to the buffer.
|
||||||
/* .PP
|
/* .PP
|
||||||
/* hex_decode_opt() enables extended functionality as controlled
|
/* hex_decode_opt() enables extended functionality as controlled
|
||||||
/* with \fIflags\fR.
|
/* with \fIflags\fR.
|
||||||
@ -69,6 +71,9 @@
|
|||||||
/* Google, Inc.
|
/* Google, Inc.
|
||||||
/* 111 8th Avenue
|
/* 111 8th Avenue
|
||||||
/* New York, NY 10011, USA
|
/* New York, NY 10011, USA
|
||||||
|
/*
|
||||||
|
/* Wietse Venema
|
||||||
|
/* porcupine.org
|
||||||
/*--*/
|
/*--*/
|
||||||
|
|
||||||
/* System library. */
|
/* System library. */
|
||||||
@ -107,6 +112,7 @@ VSTRING *hex_encode_opt(VSTRING *result, const char *in, ssize_t len, int flags)
|
|||||||
int ch;
|
int ch;
|
||||||
ssize_t count;
|
ssize_t count;
|
||||||
|
|
||||||
|
if ((flags & HEX_ENCODE_FLAG_APPEND) == 0)
|
||||||
VSTRING_RESET(result);
|
VSTRING_RESET(result);
|
||||||
for (cp = UCHAR_PTR(in), count = len; count > 0; count--, cp++) {
|
for (cp = UCHAR_PTR(in), count = len; count > 0; count--, cp++) {
|
||||||
ch = *cp;
|
ch = *cp;
|
||||||
@ -177,67 +183,121 @@ VSTRING *hex_decode_opt(VSTRING *result, const char *in, ssize_t len, int flags)
|
|||||||
}
|
}
|
||||||
|
|
||||||
#ifdef TEST
|
#ifdef TEST
|
||||||
#include <argv.h>
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Proof-of-concept test program: convert to hexadecimal and back.
|
* Proof-of-concept test program: convert to hexadecimal and back.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define STR(x) vstring_str(x)
|
#define STR(x) vstring_str(x)
|
||||||
#define LEN(x) VSTRING_LEN(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)
|
int main(int unused_argc, char **unused_argv)
|
||||||
{
|
{
|
||||||
VSTRING *b1 = vstring_alloc(1);
|
VSTRING *buf = vstring_alloc(1);
|
||||||
VSTRING *b2 = vstring_alloc(1);
|
int pass = 0;
|
||||||
char *test = "this is a test";
|
int fail = 0;
|
||||||
ARGV *argv;
|
const TEST_CASE *tp;
|
||||||
|
|
||||||
#define DECODE(b,x,l) { \
|
for (tp = test_cases; tp->label != 0; tp++) {
|
||||||
if (hex_decode((b),(x),(l)) == 0) \
|
VSTRING *out;
|
||||||
msg_panic("bad hex: %s", (x)); \
|
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;
|
||||||
}
|
}
|
||||||
#define VERIFY(b,t) { \
|
if (ok) {
|
||||||
if (strcmp((b), (t)) != 0) \
|
msg_info("PASS %s", tp->label);
|
||||||
msg_panic("bad test: %s", (b)); \
|
pass++;
|
||||||
|
} else {
|
||||||
|
msg_info("FAIL %s", tp->label);
|
||||||
|
fail++;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
hex_encode(b1, test, strlen(test));
|
msg_info("PASS=%d FAIL=%d", pass, fail);
|
||||||
DECODE(b2, STR(b1), LEN(b1));
|
return (fail > 0);
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -21,6 +21,7 @@
|
|||||||
*/
|
*/
|
||||||
#define HEX_ENCODE_FLAG_NONE (0)
|
#define HEX_ENCODE_FLAG_NONE (0)
|
||||||
#define HEX_ENCODE_FLAG_USE_COLON (1<<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_NONE (0)
|
||||||
#define HEX_DECODE_FLAG_ALLOW_COLON (1<<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.
|
/* Google, Inc.
|
||||||
/* 111 8th Avenue
|
/* 111 8th Avenue
|
||||||
/* New York, NY 10011, USA
|
/* New York, NY 10011, USA
|
||||||
|
/*
|
||||||
|
/* Wietse Venema
|
||||||
|
/* porcupine.org
|
||||||
/*--*/
|
/*--*/
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -210,6 +210,12 @@ extern void myaddrinfo_control(int,...);
|
|||||||
msg_fatal("sockaddr_to_hostname: %s", MAI_STRERROR(_aierr)); \
|
msg_fatal("sockaddr_to_hostname: %s", MAI_STRERROR(_aierr)); \
|
||||||
} while (0)
|
} 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
|
/* LICENSE
|
||||||
/* .ad
|
/* .ad
|
||||||
/* .fi
|
/* .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 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(VSTRING *, const char *, ssize_t);
|
||||||
extern char *quote_for_json_append(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_NONE (0)
|
||||||
#define EXTPAR_FLAG_STRIP (1<<0) /* "{ text }" -> "text" */
|
#define EXTPAR_FLAG_STRIP (1<<0) /* "{ text }" -> "text" */
|
||||||
|
@ -67,6 +67,7 @@
|
|||||||
#include "mymalloc.h"
|
#include "mymalloc.h"
|
||||||
#include "vbuf.h"
|
#include "vbuf.h"
|
||||||
#include "vstring.h"
|
#include "vstring.h"
|
||||||
|
#include "stringops.h"
|
||||||
#include "vbuf_print.h"
|
#include "vbuf_print.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -290,8 +291,7 @@ VBUF *vbuf_print(VBUF *bp, const char *format, va_list ap)
|
|||||||
break;
|
break;
|
||||||
case 'm':
|
case 'm':
|
||||||
/* Ignore the 'l' modifier, width and precision. */
|
/* Ignore the 'l' modifier, width and precision. */
|
||||||
VBUF_STRCAT(bp, saved_errno ?
|
VBUF_STRCAT(bp, mystrerror(saved_errno));
|
||||||
strerror(saved_errno) : "Application error");
|
|
||||||
break;
|
break;
|
||||||
case 'p':
|
case 'p':
|
||||||
if (long_flag)
|
if (long_flag)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user