]> git.ipfire.org Git - thirdparty/postfix.git/commitdiff
postfix-3.11-20250906-nonprod
authorWietse Z Venema <wietse@porcupine.org>
Sat, 6 Sep 2025 05:00:00 +0000 (00:00 -0500)
committerViktor Dukhovni <ietf-dane@dukhovni.org>
Sun, 7 Sep 2025 02:02:15 +0000 (12:02 +1000)
77 files changed:
postfix/.indent.pro
postfix/HISTORY
postfix/html/bounce.8.html
postfix/html/defer.8.html
postfix/html/lmtp.8.html
postfix/html/mailq.1.html
postfix/html/newaliases.1.html
postfix/html/pipe.8.html
postfix/html/postconf.5.html
postfix/html/relocated.5.html
postfix/html/sendmail.1.html
postfix/html/smtp.8.html
postfix/html/smtpd.8.html
postfix/html/trace.8.html
postfix/makedefs
postfix/man/man1/sendmail.1
postfix/man/man5/postconf.5
postfix/man/man8/bounce.8
postfix/man/man8/pipe.8
postfix/man/man8/smtp.8
postfix/man/man8/smtpd.8
postfix/mantools/postconf2man
postfix/mantools/postlink
postfix/proto/postconf.proto
postfix/proto/stop
postfix/proto/stop.double-history
postfix/proto/stop.double-proto-html
postfix/proto/stop.spell-cc
postfix/proto/stop.spell-history
postfix/src/bounce/Makefile.in
postfix/src/bounce/bounce.c
postfix/src/bounce/bounce_notify_util.c
postfix/src/cleanup/cleanup_api.c
postfix/src/global/Makefile.in
postfix/src/global/cleanup_strflags.c
postfix/src/global/cleanup_user.h
postfix/src/global/ehlo_mask.c
postfix/src/global/ehlo_mask.h
postfix/src/global/ehlo_mask.in [deleted file]
postfix/src/global/ehlo_mask.ref [deleted file]
postfix/src/global/ehlo_mask_test.c [new file with mode: 0644]
postfix/src/global/mail_params.c
postfix/src/global/mail_params.h
postfix/src/global/post_mail.c
postfix/src/global/rec_type.h
postfix/src/local/forward.c
postfix/src/pipe/Makefile.in
postfix/src/pipe/pipe.c
postfix/src/postcat/postcat.c
postfix/src/posttls-finger/posttls-finger.c
postfix/src/sendmail/Makefile.in
postfix/src/sendmail/sendmail.c
postfix/src/showq/showq.c
postfix/src/smtp/Makefile.in
postfix/src/smtp/lmtp_params.c
postfix/src/smtp/smtp.c
postfix/src/smtp/smtp.h
postfix/src/smtp/smtp_connect.c
postfix/src/smtp/smtp_params.c
postfix/src/smtp/smtp_proto.c
postfix/src/smtp/smtp_reqtls_policy.c [new file with mode: 0644]
postfix/src/smtp/smtp_reqtls_policy.h [new file with mode: 0644]
postfix/src/smtp/smtp_reqtls_policy_test.c [new file with mode: 0644]
postfix/src/smtp/smtp_state.c
postfix/src/smtp/smtp_trouble.c
postfix/src/smtpd/smtpd.c
postfix/src/smtpd/smtpd.h
postfix/src/tls/tls.h
postfix/src/util/argv.c
postfix/src/util/argv.h
postfix/src/util/dict_debug_test.sh [changed mode: 0755->0644]
postfix/src/util/inet_addr_list.c
postfix/src/util/inet_prefix_top.c
postfix/src/util/name_mask.c
postfix/src/util/name_mask.h
postfix/src/util/name_mask.ref5
postfix/src/util/name_mask.ref6

index 9fa65a8f98523a03973139a85d187c7608d4395d..78948c7aa523f969b5de3a989806ad17a5d629ef 100644 (file)
 -TSMTP_CLI_ATTR
 -TSMTP_CMD
 -TSMTP_ITERATOR
+-TSMTP_REQTLS_POLICY
 -TSMTP_RESP
 -TSMTP_SASL_AUTH_CACHE
 -TSMTP_SESSION
index bd2c2beecc2980fc79c398edf6b5112dfda8dab2..ca33b511ea9b66f8d87b14119cfef144ed6bb9b4 100644 (file)
@@ -28932,7 +28932,7 @@ Apologies for any names omitted.
        Documentation: updated TLSRPT_README, added postfix-tlspol
        policy plugin, deprecated the policy_ttl attribute. File:
        proto/TLSRPT_README.html.
-
 20250207
 
        Performance: when a mysql: or pgsql: configuration specifies
@@ -29604,3 +29604,270 @@ Apologies for any names omitted.
        proto/postconf.proto, global/mail_params.h, smtp/lmtp_params.c,
        smtp/smtp.c, smtp/smtp.h, smtp/smtp_connect.c, smtp/smtp_params.c,
        smtp/smtp_tls_policy.c, smtp/smtp_tls_policy_test.c.
+
+       Baseline is postfix-3.11-20250906
+
+NONPROD CODE
+
+       Feature: support for the REQUIRETLS verb in SMTP. According
+       to RFC 8689, this requires TLS server certificate matching.
+       Files: cleanup/cleanup_api.c, global/cleanup_strflags.c,
+       global/post_mail.c, global/post_mail.c, global/ehlo_mask.[hc],
+       global/ehlo_mask_test.c, local/forward.c, smtpd/smtpd.c,
+       smtp/smtp_connect.c, smtp/smtp_proto.c.
+
+       Added a configuration parameter "requiretls_enable" (default:
+       yes). Files: cleanup/cleanup_api.c, global/cleanup_strflags.c,
+       global/post_mail.c, global/post_mail.c, global/ehlo_mask.[hc],
+       global/ehlo_mask_test.c, local/forward.c, smtpd/smtpd.c,
+       smtp/smtp_connect.c, smtp/smtp_proto.c.
+
+       After a certificate check fails, or a remote SMTP server
+       does not announce REQUIRETLS support, the Postfix SMTP
+       client will override the RFC 8689 5.x.x.  status and treat
+       it as a soft error, until there are no more alternate MX
+       servers to try. Files: smtp/smtp.h, smtp/smtp_proto.c,
+       smtp/smtp_trouble.c.
+
+       When a message received with REQUIRETLS is returned in a
+       delivery status notification, return the message headers
+       only, and do not request delivery with REQUIRETLS. Files:
+       bounce/bounce_notify_service.c, bounce/bounce_one_service.c,
+       bounce/bounce_trace_service.c, bounce/bounce_verp_service.c,
+       bounce/bounce_warn_service.c.
+
+       Completed: new Postfix sendmail command option "-O requiretls"
+       to request that deliveries over SMTP use the REQUIRETLS
+       extension. The option value "requiretls" is case-insensitive.
+       Files: sendmail/sendmail.c, global/rec_types.h, pickup/pickup.c.
+
+       Cleanup: new Postfix sendmail command option "-O smtputf8"
+       to request that deliveries over SMTP use the SMTPUTF8
+       extension. This reuses logic that was introduced for
+       REQUIRETLS. The option value "smtputf8" is case-insensitive.
+       Files: sendmail/sendmail.c.
+
+       Cleanup: when message delivery requires that a remote SMTP
+       server supports SMTPUTF8, try multiple MX servers before
+       returning a message as undeliverable. This reuses logic
+       that was introduced for REQUIRETLS. File: smtp/smtp_proto.c.
+
+       Completed: support in the pipe(8) daemon to propagate
+       REQUIRETLS through post-queue content filters that pass
+       filtered mail to the Postfix sendmail(1) command. This
+       involves a new a pipe(8) macro ${requiretls} that expands
+       into a suitable sendmail(1) command-line option. A more
+       secretive alternative would be to pass the info with a
+       REQUIRETLS environment variable, but that would require
+       change to the default import_environment setting. Files:
+       pipe/pipe.c, sendmail/sendmail.c.
+
+       Completed: REQUIRETLS support can be disabled in the Postfix
+       SMTP/LMTP client with "{ -o requiretls_enable = no }". This
+       is recommended for a perimeter MTA that hands off mail to
+       internal servers that may not support REQUIRETLS.
+
+       Completed: smtp_enforce_requiretls list of next-hop domains
+       (or UNIX-domain pathnames) that are ready for REQUIRETLS
+       enforcement. This may help with gradual adoption.
+
+       Completed 20250818: infrastructure that will use message
+       headers to propagate REQUIRETLS through non-Milter content
+       filters. Files: global/x_esmtp_verb.[hc],
+       global/x_esmtp_verb_test.c.
+
+       Completed 20250818: infrastructure for REQUIRETLS enforcement
+       policy (enforce, best-effort, disable) that will be indexed
+       by the TLS next-hop hostname. Files: smtp/smtp_reqtls_policy.[hc],
+       smtp/smtp_reqtls_policy_test.c.
+
+       Completed 20250818: return headers-only messages in all delivery status
+       notifications. Files: qmgr/qmgr_message.c, oqmgr/qmgr_message.c.
+
+       Completed 20250818: do not propagate REQUIRETLS when sending
+       delivery status notifications. (RFC 8689 section 5: When
+       the MAIL FROM return-path is empty, the REQUIRETLS parameter
+       SHOULD NOT cause a bounce message to be discarded even if
+       the next-hop relay does not advertise REQUIRETLS.)
+
+       Completed 20250820: enable/disable redacting delivery status
+       notifications as described in RFC 8689 section 5.
+
+       Completed 20250824: when a message needs top be delivered
+       with SMTPUTF8, bit a remote server does not support it,
+       try an alternate server. File: smtp/smtp_proto.c.
+
+       Completed 20250824: better handling of line breaks in
+       indented paragraphs in the postconf(5) conversion
+       from HTML to 'man' format. File: mantools/postconf2man.
+
+       Completed 20250824: requiretls_redact_dsn (default: yes)
+       as described in RFC 8689 section 5, to produces bounce
+       messages that don't need REQUIRETLS support on every hop
+       in the return path. Files: proto/postconf.proto,
+       global/mail_params.h, bounce/bounce.c.
+
+       Completed 20250824: smtp_requiretls_policy and
+       lmtp_requiretls_policy for responsible REQUIRETLS policy
+       enforcement. Files: proto/postconf.proto, global/mail_params.h,
+       smtp/lmtp_params.c, smtp/smtp.c, smtp/smtp_connect.c,
+       smtp/smtp.h, smtp/smtp_params.c, smtp/smtp_proto.c,
+       smtp/smtp_reqtls_policy.c, smtp/smtp_reqtls_policy.h,
+       smtp/smtp_reqtls_policy_test.c, smtp/smtp_state.c.
+
+       Completed 20250824: cleaned up some test code. Files:
+       util/inet_prefix_top.c, util/inet_addr_list.c.
+
+       Completed 20250824: When SMTPUTF8 is needed, skip servers
+       that don't support SMTPUTF8, instead of giving up immediately.
+       File: smtp/smtp_proto.c.
+
+       Completed 20250825: when a server does not announce REQUIRETLS,
+       and the Postfix SMTP or LMTP client does not enforce
+       REQUIRETLS, send "MAIL FROM ... RET=HDRS" to limit exposure.
+       file: smtp/smtp_proto.c.
+
+       Completed 20250826: renamed all the new identifiers introduced
+       for REQUIRETLS support to ...REQTLS... and ...reqtls... and
+       re-indented the code. minimize differences with pre-existing code.
+
+       Completed 20250826: support to request REQUIRETLS and
+       SMTPUTF8 on the Postfix sendmail(1) command line, plus
+       corresponding support in other programs to handle that
+       information. Files: sendmail/sendmail.c, pickup/pickup.c,
+       postcat/postcat.c., showq/showq.c.
+
+       Completed 20250827: logic to skip destinations whose TLS
+       policy level cannot satisfy the REQUIRETLS policy, or to
+       log what would fail if REQUIRETLS were fully enforced.
+       File: smtp/smtp_connect.c.
+
+       Completed 20250829: removed code that was not used; backed
+       out gratuitous changes; minimized the diffs against the
+       production release; renamed enforce_reqtls to the more
+       meaningful reqtls_level.
+
+TODO
+
+       Make it easy to find out by domain what the REQUIRETLS
+       success rates are, and what the failure modes are.
+
+       Add optional statistics logging for "REQUIRETLS sent" and
+       for "all REQUIRETLS requirements pass". But these say
+       nothing about connections that failed to establish an
+       acceptable TLS session.
+
+       Other logging: RFC 8689 prescribes enhanced status codes:
+
+       - REQUIRETLS not supported by server: 5.7.30 REQUIRETLS
+         support required
+
+       - Unable to establish TLS-protected SMTP session: 5.7.10
+         Encryption needed
+
+       These will show up in logging.
+
+       Known failure modes
+       misc problems at DNS, TCP, or SMTP level
+       misc errors with TLS policy or REQUIRETLS policy
+       smtp_connect.c:
+           TLS policy disables certificate matching
+           TLS policy disables encryption (opportunistic only)
+       smtp_proto.c.
+           STARTTLS rejected (sender requested REQUIRETLS...)
+           STARTTLS not offered (sender requested REQUIRETLS...)
+           (TLS is required, but our TLS engine is unavailable)
+           (TLS is required, but unavailable)
+           CERT not trusted|matched (sender requested REQUIRETLS...)
+
+       Revert $requiretls in pipe daemon?
+
+       Which enforcement levels can we implement?
+
+           enforce: require that the server supports REQUIRETLS,
+           and that the connection satisfies RFC XXX requirements.
+
+           no-plaintext: skip servers that don't announce STARTTLS;
+           request REQUIRETLS if the server supports REQUIRETLS,
+           otherwise deliver the message as if the sender did not
+           request REQUIRETLS.
+
+           ????/ignore/disable/none: request REQUIRETLS if the
+           server supports REQUIRETLS, otherwise deliver the message
+           as if the sender did not request REQUIRETLS.
+
+       Maybe log "server announces REQUIRETLS" if we're not
+       enforcing REQUIRETLS.
+
+       Delete $requiretls from pipe daemon?
+
+       Verify that SMTPUTF8 and REQUIRETLS flags propagate from
+       sendmail(1) and smtpd(8) through cleanup(8) and qmgr(8) to
+       delivery agents and bounce services.
+
+       Add support to propagate REQUIRETLS (Not: TLS-Required:)
+       header through cleanup to queue files.
+
+       Encapsulate the sendopts-to-cleanup-flags mapping.
+
+       Postfix sendmail -O TlsRequired option?
+
+       What REQUIRETLS expectations can we enforce when delivering
+       over a UNIX-domain channel? The SMTP/LMTP client currently
+       implements the same behavior as for TCP, except that
+       opportunistic TLS is converted into 'none'.
+
+       Document how REQUIRETLS works (or does not) with external
+       content filters.
+
+       - REQUIRETLS will not affect Milter-based content filters,
+         assuming that they don't expose message content via some
+         side channel.
+
+       - REQUIRETLS can work with smtpd_proxy_filter as long as
+         - the Postfix SMTP server passes the entire Postfix SMTP
+           client's MAIL FROM command line through the filter to
+           the Postfix SMTP server after the proxy filter,
+         - the post-filter Postfix SMTP server allows REQUIRETLS
+           in a plaintext session.
+         The Postfix proxy filter client does not need to require
+         REQUIRETLS (or SMTPUTF8) announcements in the filter's
+         EHLO response.
+
+       - REQUIRETLS can work with a local SMTP-based after-queue
+         content filters as long as
+         - the filter announces REQUIRETLS in the EHLO response
+           (this could be 'always', or copied from the after-filter
+           Postfix SMTP server's EHLO response),
+         - the filter passes the entire MAIL FROM command from the
+           before-filter Postfix SMTP client to the after-filter
+           Postfix SMTP server,
+         - the post-filter Postfix SMTP server allows MAIL FROM
+           with REQUIRETLS in a plaintext session.
+         Apart from that, the content filter does not need to
+         'know' that REQUIRETLS is active (assuming that it does
+         not leak message content through some side channel.
+
+       - REQUIRETLS can work with pipe(8)-filter-sendmail(1)
+         after-queue content filters, by specifying a pipe(8) macro
+         ${requiretls} which expands to a suitable sendmail(1)
+         command-line option. Maybe we can also make this work
+         with a REQUIRETLS environment variable (requires change
+         to the (Postfix sendmail) import_environment list.
+
+       - The Postfix LMTP client when run with the -X option will
+         not require that the LMTP server announces REQUIRETLS
+         support.
+
+       - Perimeter MTA configuration: disable REQUIRETLS (or
+         REQUIRETLS enforcement) on the inbound relay transport
+         when internal infrastructure may not be suitable for
+         REQUIRETLS enforcement.
+
+       If a message contains "TLS-Required: no", should a bounce
+       message also contain this header?
+
+       Ditto for "tls_required_enable = no" and "TLS-Required:
+       no". The header is provided by the sender, and enforcement
+       is up the Postfix SMTP client.
+
index 695478942e1e9e645d85d7b519f7551ac0117659..44f4b26087e0c681c47ec2a8c29e22dd2d35fd80 100644 (file)
@@ -172,6 +172,15 @@ BOUNCE(8)                                                            BOUNCE(8)
               Enable  support  for  the  "TLS-Required:  no"  message  header,
               defined in <a href="https://tools.ietf.org/html/rfc8689">RFC 8689</a>.
 
+       Available in Postfix 3.11 and later:
+
+       <b><a href="postconf.5.html#requiretls_redact_dsn">requiretls_redact_dsn</a> (yes)</b>
+              When sending a delivery status notification for an original mes-
+              sage received with the REQUIRETLS option, do not send the origi-
+              nal   message  body  (as  if  that  message  was  received  with
+              "RET=HDRS") and do not enforce REQUIRETLS (as  if  that  message
+              was received without REQUIRETLS).
+
 <b><a name="files">FILES</a></b>
        /var/spool/postfix/bounce/* non-delivery records
        /var/spool/postfix/defer/* non-delivery records
index 695478942e1e9e645d85d7b519f7551ac0117659..44f4b26087e0c681c47ec2a8c29e22dd2d35fd80 100644 (file)
@@ -172,6 +172,15 @@ BOUNCE(8)                                                            BOUNCE(8)
               Enable  support  for  the  "TLS-Required:  no"  message  header,
               defined in <a href="https://tools.ietf.org/html/rfc8689">RFC 8689</a>.
 
+       Available in Postfix 3.11 and later:
+
+       <b><a href="postconf.5.html#requiretls_redact_dsn">requiretls_redact_dsn</a> (yes)</b>
+              When sending a delivery status notification for an original mes-
+              sage received with the REQUIRETLS option, do not send the origi-
+              nal   message  body  (as  if  that  message  was  received  with
+              "RET=HDRS") and do not enforce REQUIRETLS (as  if  that  message
+              was received without REQUIRETLS).
+
 <b><a name="files">FILES</a></b>
        /var/spool/postfix/bounce/* non-delivery records
        /var/spool/postfix/defer/* non-delivery records
index e116f43aa938dfd020400c6db507a4bf41f389dc..c0ce2ddb3964cbf1860372195634bcb3a14fa46d 100644 (file)
@@ -174,7 +174,7 @@ SMTP(8)                                                                SMTP(8)
        <a href="https://tools.ietf.org/html/rfc6531">RFC 6531</a> (Internationalized SMTP)
        <a href="https://tools.ietf.org/html/rfc6533">RFC 6533</a> (Internationalized Delivery Status Notifications)
        <a href="https://tools.ietf.org/html/rfc7672">RFC 7672</a> (SMTP security via opportunistic DANE TLS)
-       <a href="https://tools.ietf.org/html/rfc8689">RFC 8689</a> (TLS-Required message header)
+       <a href="https://tools.ietf.org/html/rfc8689">RFC 8689</a> (SMTP REQUIRETLS extension, TLS-Required header)
 
 <b><a name="diagnostics">DIAGNOSTICS</a></b>
        Problems  and  transactions  are  logged  to <b>syslogd</b>(8) or <a href="postlogd.8.html"><b>postlogd</b>(8)</a>.
@@ -507,7 +507,7 @@ SMTP(8)                                                                SMTP(8)
               The delimiter between username and password in  sasl_passwd_maps
               lookup results.
 
-<b><a name="starttls_support_controls">STARTTLS SUPPORT CONTROLS</a></b>
+<b><a name="tls_support_controls">TLS SUPPORT CONTROLS</a></b>
        Detailed  information  about STARTTLS configuration may be found in the
        <a href="TLS_README.html">TLS_README</a> document.
 
@@ -775,7 +775,16 @@ SMTP(8)                                                                SMTP(8)
               Enable  support  for  the  "TLS-Required:  no"  message  header,
               defined in <a href="https://tools.ietf.org/html/rfc8689">RFC 8689</a>.
 
-<b><a name="obsolete_starttls_controls">OBSOLETE STARTTLS CONTROLS</a></b>
+       <b><a href="postconf.5.html#requiretls_enable">requiretls_enable</a> (yes)</b>
+              Enable  support  for  the  ESMTP  verb "REQUIRETLS" in the "MAIL
+              FROM" command.
+
+       <b><a href="postconf.5.html#smtp_requiretls_policy">smtp_requiretls_policy</a> (see 'postconf -d  <a href="postconf.5.html#smtp_requiretls_policy">smtp_requiretls_policy</a>'  out-</b>
+       <b>put)</b>
+              How the Postfix SMTP and LMTP client will enforce REQUIRETLS for
+              messages received with the REQUIRETLS option.
+
+<b><a name="obsolete_tls_controls">OBSOLETE TLS CONTROLS</a></b>
        The  following  configuration  parameters  exist for compatibility with
        Postfix versions before 2.3. Support for these will  be  removed  in  a
        future release.
index 4645b733aa92da0bd14758ceab565dabf9f18ddf..91157d8ef7f20cdd3af67313a194be62f99246ae 100644 (file)
@@ -168,7 +168,7 @@ SENDMAIL(1)                                                        SENDMAIL(1)
               Delivery   status   notification   control.   Specify  either  a
               comma-separated list with one or more of <b>failure</b> (send notifica-
               tion  when delivery fails), <b>delay</b> (send notification when deliv-
-              ery is delayed), or <b>success</b> (send notification when the  message
+              ery is delayed), or <b>success</b> (send notification after the message
               is delivered); or specify <b>never</b> (don't send any notifications at
               all).
 
@@ -177,14 +177,36 @@ SENDMAIL(1)                                                        SENDMAIL(1)
        <b>-n</b> (ignored)
               Backwards compatibility.
 
-       <b>-oA</b><i>alias</i><b>_</b><i>database</i>
-              Non-default alias database. Specify <i>pathname</i>  or  <i>type</i>:<i>pathname</i>.
-              See <a href="postalias.1.html"><b>postalias</b>(1)</a> for details.
+       <b>-O requiretls=yes</b>
+
+       <b>-O requiretls=no</b>
+              When delivering a message to an SMTP or LMTP server, the connec-
+              tion  must  use TLS with a verified server certificate, and that
+              server must support REQUIRETLS. The "requiretls" name and option
+              value are case-insensitive. REQUIRETLS enforcement is controlled
+              with    the    configuration    parameters    <a href="postconf.5.html#requiretls_enable">requiretls_enable</a>,
+              <a href="postconf.5.html#smtp_requiretls_policy">smtp_requiretls_policy</a>, and <a href="postconf.5.html#lmtp_requiretls_policy">lmtp_requiretls_policy</a>.
+
+              This feature is available in Postfix 3.11 and later.
+
+       <b>-O smtputf8=yes</b>
+
+       <b>-O smtputf8=no</b>
+              When  delivering  a  message  to  an SMTP or LMTP server, and an
+              envelope address or message  header  contains  UTF8  text,  that
+              server  must  support  SMTPUTF8.  The "smtputf8" option name and
+              value are case-insensitive.
+
+              This feature is available in Postfix 3.11 and later.
 
        <b>-O</b> <i>option=value</i> (ignored)
-              Set  the named <i>option</i> to <i>value</i>. Use the equivalent configuration
+              Set the named <i>option</i> to <i>value</i>. Use the equivalent  configuration
               parameter in <a href="postconf.5.html"><b>main.cf</b></a> instead.
 
+       <b>-oA</b><i>alias</i><b>_</b><i>database</i>
+              Non-default  alias  database. Specify <i>pathname</i> or <i>type</i>:<i>pathname</i>.
+              See <a href="postalias.1.html"><b>postalias</b>(1)</a> for details.
+
        <b>-o7</b> (ignored)
 
        <b>-o8</b> (ignored)
@@ -483,6 +505,12 @@ SENDMAIL(1)                                                        SENDMAIL(1)
               the  default  Postfix  instance,  and that are started, stopped,
               etc., together with the default Postfix instance.
 
+       Postfix 3.11 and later:
+
+       <b><a href="postconf.5.html#requiretls_enable">requiretls_enable</a> (yes)</b>
+              Enable support for the ESMTP  verb  "REQUIRETLS"  in  the  "MAIL
+              FROM" command.
+
 <b><a name="files">FILES</a></b>
        /var/spool/postfix, mail queue
        /etc/postfix, configuration files
@@ -501,7 +529,7 @@ SENDMAIL(1)                                                        SENDMAIL(1)
        syslogd(8), system logging
 
 <b><a name="readme_files">README_FILES</a></b>
-       Use "<b>postconf <a href="postconf.5.html#readme_directory">readme_directory</a></b>" or "<b>postconf <a href="postconf.5.html#html_directory">html_directory</a></b>" to  locate
+       Use  "<b>postconf <a href="postconf.5.html#readme_directory">readme_directory</a></b>" or "<b>postconf <a href="postconf.5.html#html_directory">html_directory</a></b>" to locate
        this information.
        <a href="DEBUG_README.html">DEBUG_README</a>, Postfix debugging howto
        <a href="ETRN_README.html">ETRN_README</a>, Postfix ETRN howto
index 4645b733aa92da0bd14758ceab565dabf9f18ddf..91157d8ef7f20cdd3af67313a194be62f99246ae 100644 (file)
@@ -168,7 +168,7 @@ SENDMAIL(1)                                                        SENDMAIL(1)
               Delivery   status   notification   control.   Specify  either  a
               comma-separated list with one or more of <b>failure</b> (send notifica-
               tion  when delivery fails), <b>delay</b> (send notification when deliv-
-              ery is delayed), or <b>success</b> (send notification when the  message
+              ery is delayed), or <b>success</b> (send notification after the message
               is delivered); or specify <b>never</b> (don't send any notifications at
               all).
 
@@ -177,14 +177,36 @@ SENDMAIL(1)                                                        SENDMAIL(1)
        <b>-n</b> (ignored)
               Backwards compatibility.
 
-       <b>-oA</b><i>alias</i><b>_</b><i>database</i>
-              Non-default alias database. Specify <i>pathname</i>  or  <i>type</i>:<i>pathname</i>.
-              See <a href="postalias.1.html"><b>postalias</b>(1)</a> for details.
+       <b>-O requiretls=yes</b>
+
+       <b>-O requiretls=no</b>
+              When delivering a message to an SMTP or LMTP server, the connec-
+              tion  must  use TLS with a verified server certificate, and that
+              server must support REQUIRETLS. The "requiretls" name and option
+              value are case-insensitive. REQUIRETLS enforcement is controlled
+              with    the    configuration    parameters    <a href="postconf.5.html#requiretls_enable">requiretls_enable</a>,
+              <a href="postconf.5.html#smtp_requiretls_policy">smtp_requiretls_policy</a>, and <a href="postconf.5.html#lmtp_requiretls_policy">lmtp_requiretls_policy</a>.
+
+              This feature is available in Postfix 3.11 and later.
+
+       <b>-O smtputf8=yes</b>
+
+       <b>-O smtputf8=no</b>
+              When  delivering  a  message  to  an SMTP or LMTP server, and an
+              envelope address or message  header  contains  UTF8  text,  that
+              server  must  support  SMTPUTF8.  The "smtputf8" option name and
+              value are case-insensitive.
+
+              This feature is available in Postfix 3.11 and later.
 
        <b>-O</b> <i>option=value</i> (ignored)
-              Set  the named <i>option</i> to <i>value</i>. Use the equivalent configuration
+              Set the named <i>option</i> to <i>value</i>. Use the equivalent  configuration
               parameter in <a href="postconf.5.html"><b>main.cf</b></a> instead.
 
+       <b>-oA</b><i>alias</i><b>_</b><i>database</i>
+              Non-default  alias  database. Specify <i>pathname</i> or <i>type</i>:<i>pathname</i>.
+              See <a href="postalias.1.html"><b>postalias</b>(1)</a> for details.
+
        <b>-o7</b> (ignored)
 
        <b>-o8</b> (ignored)
@@ -483,6 +505,12 @@ SENDMAIL(1)                                                        SENDMAIL(1)
               the  default  Postfix  instance,  and that are started, stopped,
               etc., together with the default Postfix instance.
 
+       Postfix 3.11 and later:
+
+       <b><a href="postconf.5.html#requiretls_enable">requiretls_enable</a> (yes)</b>
+              Enable support for the ESMTP  verb  "REQUIRETLS"  in  the  "MAIL
+              FROM" command.
+
 <b><a name="files">FILES</a></b>
        /var/spool/postfix, mail queue
        /etc/postfix, configuration files
@@ -501,7 +529,7 @@ SENDMAIL(1)                                                        SENDMAIL(1)
        syslogd(8), system logging
 
 <b><a name="readme_files">README_FILES</a></b>
-       Use "<b>postconf <a href="postconf.5.html#readme_directory">readme_directory</a></b>" or "<b>postconf <a href="postconf.5.html#html_directory">html_directory</a></b>" to  locate
+       Use  "<b>postconf <a href="postconf.5.html#readme_directory">readme_directory</a></b>" or "<b>postconf <a href="postconf.5.html#html_directory">html_directory</a></b>" to locate
        this information.
        <a href="DEBUG_README.html">DEBUG_README</a>, Postfix debugging howto
        <a href="ETRN_README.html">ETRN_README</a>, Postfix ETRN howto
index 911a740eb03e35e65b33b413b49b9b4423d015b3..2b0f82d05157a061d6dc1dbfbf02acd71e6ffcd1 100644 (file)
@@ -309,6 +309,15 @@ PIPE(8)                                                                PIPE(8)
                      This information is modified by the <b>hqu</b> flags for quoting
                      and case folding.
 
+              <b>${requiretls}</b>
+                     This  feature  is  intended for content filters that pass
+                     filtered mail to the  Postfix  <a href="sendmail.1.html">sendmail(1)</a>  command.  The
+                     macro  expands  to  the  Postfix <a href="sendmail.1.html">sendmail(1)</a> command-line
+                     option   <b>-Orequiretls=yes</b>   if   the   sender   requested
+                     REQUIRETLS, otherwise it expands to <b>-Orequiretls=no</b>.
+
+                     This feature is available as of Postfix 3.11.
+
               <b>${sasl_method}</b>
                      This macro expands to the name of the SASL authentication
                      mechanism in the  AUTH  command  when  the  Postfix  SMTP
@@ -488,6 +497,12 @@ PIPE(8)                                                                PIPE(8)
               The  email  address  form that will be used in non-debug logging
               (info, warning, etc.).
 
+       Available in Postfix 3.11 and later:
+
+       <b><a href="postconf.5.html#requiretls_enable">requiretls_enable</a> (yes)</b>
+              Enable support for the ESMTP  verb  "REQUIRETLS"  in  the  "MAIL
+              FROM" command.
+
 <b><a name="see_also">SEE ALSO</a></b>
        <a href="qmgr.8.html">qmgr(8)</a>, queue manager
        <a href="bounce.8.html">bounce(8)</a>, delivery status reports
index e3ad237024e2a185c76e5b8541055bf59df5f99a..a9e03fe25fba1cfbf35b8f1b0f9fa59916c0181f 100644 (file)
@@ -5373,6 +5373,17 @@ configuration parameter.  See there for details. </p>
 <p> This feature is available in Postfix 2.7 and later. </p>
 
 
+</DD>
+
+<DT><b><a name="lmtp_requiretls_policy">lmtp_requiretls_policy</a>
+(default: opportunistic)</b></DT><DD>
+
+<p> The LMTP-specific version of the <a href="postconf.5.html#smtp_requiretls_policy">smtp_requiretls_policy</a>
+configuration parameter. See there for details. </p>
+
+<p> This feature is available in Postfix &ge; 3.11. </p>
+
+
 </DD>
 
 <DT><b><a name="lmtp_rset_timeout">lmtp_rset_timeout</a>
@@ -10611,6 +10622,74 @@ the mail server (IMPORTING HOME DIRECTORIES IS NOT RECOMMENDED).
 </p>
 
 
+</DD>
+
+<DT><b><a name="requiretls_enable">requiretls_enable</a>
+(default: yes)</b></DT><DD>
+
+<p> Enable support for the ESMTP verb "REQUIRETLS" in the "MAIL
+FROM" command. As defined in <a href="https://tools.ietf.org/html/rfc8689">RFC 8689</a>, when a message specifies
+REQUIRETLS: </p>
+
+<ul>
+
+<li> <p> deliveries with SMTP or LMTP must use a TLS connection, </p>
+
+<li> <p> to a securely looked up MX server (e.g., DNSSEC or MTA-STS),
+</p>
+
+<li> <p> with a matched server certificate (Postfix SMTP or LMTP
+client TLS security levels "secure", "verify", "fingerprint",
+dane-only, or opportunistic "dane"), </p>
+
+<li> <p> and the server must announce "REQUIRETLS" support after
+the STARTTLS handshake. </p>
+
+</ul>
+
+<p> When delivering a message that specifies REQUIRETLS, the Postfix
+SMTP client will try one or more servers, limited by the
+<a href="postconf.5.html#smtp_mx_address_limit">smtp_mx_address_limit</a> and <a href="postconf.5.html#smtp_mx_session_limit">smtp_mx_session_limit</a> parameters, until
+it finds an MX server that satisfies the above requirements. If
+such a server is not found, the Postfix SMTP or LMTP client returns
+the message as undeliverable. </p>
+
+<p> Notes: </p>
+
+<ul>
+
+<li> <p> With the Postfix SMTP or LMTP clients, REQUIRETLS enforcement
+is controlled with <a href="postconf.5.html#smtp_requiretls_policy">smtp_requiretls_policy</a> or <a href="postconf.5.html#lmtp_requiretls_policy">lmtp_requiretls_policy</a>. It
+is initially not enforced for deliveries to local servers, including
+LMTP message stores and local content filters. </p>
+
+<li> <p> The ESMTP REQUIRETLS option overrides the "TLS-Required:
+no" message header. </p>
+
+</ul>
+
+<p> This feature is available in Postfix &ge; 3.11. </p>
+
+
+</DD>
+
+<DT><b><a name="requiretls_redact_dsn">requiretls_redact_dsn</a>
+(default: yes)</b></DT><DD>
+
+<p> When sending a delivery status notification for an original
+message received with the REQUIRETLS option, do not send the original
+message body (as if that message was received with "RET=HDRS") and
+do not enforce REQUIRETLS (as if that message was received without
+REQUIRETLS). For a detailed discussion see <a href="https://tools.ietf.org/html/rfc8689">RFC 8689</a> section 5. </p>
+
+<p> Note: the 'reverse' path for sending a delivery status notification
+may differ from the 'forward' path for receiving the original message.
+Not every hop in the reverse path may support REQUIRETLS, even
+though every hop in the forward path supported it. The setting
+"<a href="postconf.5.html#requiretls_redact_dsn">requiretls_redact_dsn</a> = no" may therefore result in the loss of a
+delivery status notification. </p>
+
+
 </DD>
 
 <DT><b><a name="reset_owner_alias">reset_owner_alias</a>
@@ -12529,6 +12608,166 @@ line. </p>
 <p> This feature is available in Postfix 2.7. </p>
 
 
+</DD>
+
+<DT><b><a name="smtp_requiretls_policy">smtp_requiretls_policy</a>
+(default: see 'postconf -d <a href="postconf.5.html#smtp_requiretls_policy">smtp_requiretls_policy</a>' output)</b></DT><DD>
+
+<p> How the Postfix SMTP and LMTP client will enforce REQUIRETLS
+for messages received with the REQUIRETLS option. Policy examples
+for SMTP and LMTP are at the end. </p>
+
+<ul>
+
+<li> <p> Specify a list of items, separated with whitespace or
+comma; continue a long line by starting the next line with whitespace.
+</p>
+
+<li> <p> Each item must be an action (see below), or a <a href="DATABASE_README.html">type:table</a>
+lookup table that must return an action (not a <a href="DATABASE_README.html">type:table</a>). </p>
+
+<li> A <a href="DATABASE_README.html">type:table</a> lookup table is searched with the next-hop
+destination, without any <i>[ ]</i>, <i>:service</i>, or <i>:port</i>.
+</p>
+
+<li> <p> The next-hop destination for TCP connections is the recipient
+domain, but this can be overruled with <a href="postconf.5.html#transport_maps">transport_maps</a>, <a href="postconf.5.html#relayhost">relayhost</a>,
+<a href="postconf.5.html#content_filter">content_filter</a>, or other routing features. The next-hop destination
+for LMTP over UNIX-domain connections is always the value of
+<a href="postconf.5.html#myhostname">myhostname</a>. </p>
+
+</ul>
+
+<p> Supported actions: </p>
+
+<dl>
+
+<dt> <b> enforce </b> </dt> <dd>  <p> Skip connections that do not
+meet <a href="https://tools.ietf.org/html/rfc8689">RFC 8689</a> section 4.2 requirements, and skip servers that don't
+announce REQUIRETLS support. Return the message as undeliverable if no
+suitable connection and server are found, and log a "REQUIRETLS
+Failure" event. </p> </dd>
+
+<dt> <b> opportunistic+starttls </b> </dt> <dd> <p> Skip servers
+that don't announce STARTTLS support. Return the message as
+undeliverable if no suitable server is found, and log a "REQUIRETLS
+Failure" event. </p> <p> Request REQUIRETLS if a server supports
+REQUIRETLS, otherwise simply deliver the message and log "REQUIRETLS
+Debug" events when a connection would not meet all <a href="https://tools.ietf.org/html/rfc8689">RFC 8689</a> section
+4.2 requirements. </p> <p> This can be appropriate for an outbound
+perimeter MTA, when forwarding messages from internal systems to
+the Internet, at a time that many domains do not publish DANE or
+MTA-STS policies. </p> </dd>
+
+<dt> <b> opportunistic </b> </dt> <dd> <p> Request REQUIRETLS if
+the server supports REQUIRETLS, otherwise simply deliver the message.
+</p> <p> This can be appropriate for an inbound perimeter MTA, when
+forwarding messages from the Internet to internal servers or content
+filters. Internal servers or content filters may not support
+REQUIRETLS, and internal connections may be secured with means other
+than DANE or STS. </p> </dd>
+
+<dt> <b> disable </b> </dt> <dd> <p> Disable REQUIRETLS support.
+This may be used as a last-resort workaround when a server announces
+REQUIRETLS support, but the support is inoperable. </p></dd>
+
+</dl>
+
+<p> Notes: </p>
+
+<ul>
+
+<li> <p> Postfix appends an implicit <b>opportunistic+starttls</b>
+action after the end of each policy. </p>
+
+<li> <p> To match any name below the domain "example.com" specify
+a table entry with the storage key ".example.com" in <a href="DATABASE_README.html">type:table</a>
+lookup tables that need an exact match. This is appropriate, for
+example, with <a href="DATABASE_README.html#types">hash</a>:, <a href="DATABASE_README.html#types">btree</a>: or <a href="lmdb_table.5.html">lmdb</a>:. </p>
+
+<li> <p> Do not specify a match pattern for ".domain" with <a href="regexp_table.5.html">regexp</a>:,
+<a href="pcre_table.5.html">pcre</a>:, <a href="socketmap_table.html">socketmap</a>:, or <a href="tcp_table.5.html">tcp</a>:, as <a href="postconf.5.html#smtp_requiretls_policy">smtp_requiretls_policy</a> will
+not query those tables with that form. </p>
+
+</ul>
+
+<p> SMTP client examples: </p>
+
+<ul>
+
+<li> <p> The default SMTP client REQUIRETLS policy: when a sender
+requests REQUIRETLS, require that external servers support STARTTLS,
+and request REQUIRETLS if an internal or external server supports
+REQUIRETLS. </p>
+<pre>
+/etc/postfix/<a href="postconf.5.html">main.cf</a>:
+    <a href="postconf.5.html#smtp_tls_security_level">smtp_tls_security_level</a> = may
+    <a href="postconf.5.html#smtp_tls_policy_maps">smtp_tls_policy_maps</a> = ...dane/sts plugin...
+    <a href="postconf.5.html#smtp_requiretls_policy">smtp_requiretls_policy</a> =
+        <a href="DATABASE_README.html#types">inline</a>:{
+            {.$<a href="postconf.5.html#mydomain">mydomain</a> = opportunistic}
+            {localhost = opportunistic} }
+        opportunistic+starttls
+</pre>
+
+<li> <p> As above, with external destinations listed in a separate
+file for easier maintenance. </p>
+<pre>
+/etc/postfix/<a href="postconf.5.html">main.cf</a>:
+    <a href="postconf.5.html#smtp_tls_security_level">smtp_tls_security_level</a> = may
+    <a href="postconf.5.html#smtp_tls_policy_maps">smtp_tls_policy_maps</a> = ...dane/sts plugin...
+    <a href="postconf.5.html#smtp_requiretls_policy">smtp_requiretls_policy</a> =
+        <a href="DATABASE_README.html#types">inline</a>:{
+            {.$<a href="postconf.5.html#mydomain">mydomain</a> = opportunistic}
+            {localhost = opportunistic} }
+        <a href="DATABASE_README.html#types">hash</a>:/etc/postfix/requiretls-per-site
+        opportunistic+starttls
+</pre>
+<pre>
+/etc/postfix/requiretls-per-site:
+    one.example         enforce
+    two.example         enforce
+    three.example       opportunistic
+    ...
+</pre>
+
+<li> <p> Distant future: when a sender requests REQUIRETLS, enforce
+all REQUIRETLS requirements for all external destinations. </p>
+<pre>
+/etc/postfix/<a href="postconf.5.html">main.cf</a>:
+    <a href="postconf.5.html#smtp_tls_secure_cert_match">smtp_tls_secure_cert_match</a> = nexthop, dot-nexthop
+    <a href="postconf.5.html#smtp_tls_policy_maps">smtp_tls_policy_maps</a> = ...dane/sts plugin...
+    <a href="postconf.5.html#smtp_requiretls_policy">smtp_requiretls_policy</a> =
+        <a href="DATABASE_README.html#types">inline</a>:{
+            {.$<a href="postconf.5.html#mydomain">mydomain</a> = opportunistic}
+            {localhost = opportunistic} }
+        enforce
+</pre>
+
+</ul>
+
+<p>
+LMTP client examples:
+</p>
+
+<ul>
+
+<li> <p> The default LMTP client REQUIRETLS policy: when a sender
+requests REQUIRETLS, request REQUIRETLS if the server supports
+REQUIRETLS, otherwise deliver the message as if the sender did not
+request REQUIRETLS. Note: with deliveries over a UNIX-domain socket,
+the next-hop destination for <a href="postconf.5.html#lmtp_requiretls_policy">lmtp_requiretls_policy</a> lookups will
+be the <a href="postconf.5.html#myhostname">myhostname</a> parameter value. </p>
+<pre>
+/etc/postfix/<a href="postconf.5.html">main.cf</a>:
+    <a href="postconf.5.html#lmtp_requiretls_policy">lmtp_requiretls_policy</a> = opportunistic
+</pre>
+
+</ul>
+
+<p> This feature is available in Postfix &ge; 3.11. </p>
+
+
 </DD>
 
 <DT><b><a name="smtp_rset_timeout">smtp_rset_timeout</a>
@@ -20876,6 +21115,9 @@ If a message contains a "TLS-Required: no" header, then Postfix
 will add that header to a delivery status notification for that
 message. </p>
 
+<p> Note: the ESMTP REQUIRETLS option overrides the "TLS-Required:
+no" message header.  </p>
+
 <p> This feature is available in Postfix &ge; 3.10. </p>
 
 
index 600ee757c462ebd6c10f8d3331e733229a83e008..a6397fe62b8c867e026cc11b678c3928c2e8072f 100644 (file)
@@ -5,7 +5,7 @@
 <link rel='stylesheet' type='text/css' href='postfix-doc.css'>
 <title> Postfix manual - relocated(5) </title>
 </head> <body> <pre>
-<i>RELOCATED</i>(5)                  File Formats Manual                 <i>RELOCATED</i>(5)
+RELOCATED(5)                                                      RELOCATED(5)
 
 <b><a name="name">NAME</a></b>
        relocated - Postfix relocated table format
 
        Normally, the <a href="relocated.5.html"><b>relocated</b>(5)</a> table is  specified  as  a  text  file  that
        serves as input to the <a href="postmap.1.html"><b>postmap</b>(1)</a> command.  The result, an indexed file
-       in <b>dbm</b> or <b>db</b> format, is used for fast searching by the mail system. Ex-
-       ecute  the  command  "<b>postmap /etc/postfix/relocated</b>" to rebuild an in-
-       dexed file after changing the corresponding relocated table.
+       in <b>dbm</b> or <b>db</b> format, is used for fast searching  by  the  mail  system.
+       Execute  the  command  "<b>postmap  /etc/postfix/relocated</b>"  to rebuild an
+       indexed file after changing the corresponding relocated table.
 
        When the table is provided via other means such as NIS,  LDAP  or  SQL,
        the same lookups are done as for ordinary indexed files.
 
        Alternatively,  the  table  can be provided as a regular-expression map
-       where patterns are given as regular expressions, or lookups can be  di-
-       rected  to a TCP-based server. In those case, the lookups are done in a
-       slightly different way as described below under "REGULAR EXPRESSION TA-
-       BLES" or "TCP-BASED TABLES".
+       where patterns are given as regular  expressions,  or  lookups  can  be
+       directed  to a TCP-based server. In those case, the lookups are done in
+       a slightly different way as described below under  "REGULAR  EXPRESSION
+       TABLES" or "TCP-BASED TABLES".
 
        Table lookups are case insensitive.
 
 <b><a name="case_folding">CASE FOLDING</a></b>
-       The search string is folded to lowercase before database lookup. As  of
-       Postfix  2.3,  the search string is not case folded with database types
-       such as <a href="regexp_table.5.html">regexp</a>: or <a href="pcre_table.5.html">pcre</a>: whose lookup fields can match both  upper  and
+       The  search string is folded to lowercase before database lookup. As of
+       Postfix 2.3, the search string is not case folded with  database  types
+       such  as  <a href="regexp_table.5.html">regexp</a>: or <a href="pcre_table.5.html">pcre</a>: whose lookup fields can match both upper and
        lower case.
 
 <b><a name="table_format">TABLE FORMAT</a></b>
                    <i>pattern      new</i><b>_</b><i>location</i>
 
               Where <i>new</i><b>_</b><i>location</i> specifies  contact  information  such  as  an
-              email address, or perhaps a street address or telephone number.
+              email  address, or perhaps a street address or telephone number.
 
-       <b>o</b>      Postfix  3.11  and  later  can optionally disable the hard-coded
-              prefix. Specify "<a href="postconf.5.html#relocated_prefix_enable">relocated_prefix_enable</a> = no" in  <a href="postconf.5.html">main.cf</a>,  and
-              specify  <a href="postconf.5.html#relocated_maps">relocated_maps</a> entries with your own <a href="https://tools.ietf.org/html/rfc3463">RFC 3463</a>-compliant
+       <b>o</b>      Postfix 3.11 and later can  optionally  disable  the  hard-coded
+              prefix.  Specify  "<a href="postconf.5.html#relocated_prefix_enable">relocated_prefix_enable</a> = no" in <a href="postconf.5.html">main.cf</a>, and
+              specify <a href="postconf.5.html#relocated_maps">relocated_maps</a> entries with your own <a href="https://tools.ietf.org/html/rfc3463">RFC  3463</a>-compliant
               enhanced status code and text, for example:
 
                    <i>pattern</i>      5.2.0 Mailbox is unavailable
                    <i>pattern</i>      5.2.1 Mailbox is disabled
 
-       <b>o</b>      Empty lines and whitespace-only lines are ignored, as are  lines
+       <b>o</b>      Empty  lines and whitespace-only lines are ignored, as are lines
               whose first non-whitespace character is a `#'.
 
-       <b>o</b>      A  logical  line  starts  with  non-whitespace text. A line that
+       <b>o</b>      A logical line starts with  non-whitespace  text.  A  line  that
               starts with whitespace continues a logical line.
 
 <b><a name="table_search_order">TABLE SEARCH ORDER</a></b>
-       With lookups from indexed files such as DB or DBM,  or  from  networked
-       tables  such  as  NIS,  LDAP or SQL, patterns are tried in the order as
+       With  lookups  from  indexed files such as DB or DBM, or from networked
+       tables such as NIS, LDAP or SQL, patterns are tried  in  the  order  as
        listed below:
 
        <i>user</i>@<i>domain</i>
-              Matches <i>user</i>@<i>domain</i>. This form has  precedence  over  all  other
+              Matches  <i>user</i>@<i>domain</i>.  This  form  has precedence over all other
               forms.
 
        <i>user</i>   Matches <i>user</i>@<i>site</i> when <i>site</i> is $<b><a href="postconf.5.html#myorigin">myorigin</a></b>, when <i>site</i> is listed in
 
 <b><a name="address_extension">ADDRESS EXTENSION</a></b>
        When a mail address localpart contains the optional recipient delimiter
-       (e.g.,  <i>user+foo</i>@<i>domain</i>),  the  lookup  order becomes: <i>user+foo</i>@<i>domain</i>,
+       (e.g., <i>user+foo</i>@<i>domain</i>), the  lookup  order  becomes:  <i>user+foo</i>@<i>domain</i>,
        <i>user</i>@<i>domain</i>, <i>user+foo</i>, <i>user</i>, and @<i>domain</i>.
 
 <b><a name="regular_expression_tables">REGULAR EXPRESSION TABLES</a></b>
-       This section describes how the table lookups change when the  table  is
-       given  in  the form of regular expressions or when lookups are directed
-       to a TCP-based server. For a description of regular  expression  lookup
-       table  syntax,  see <a href="regexp_table.5.html"><b>regexp_table</b>(5)</a> or <a href="pcre_table.5.html"><b>pcre_table</b>(5)</a>. For a description
+       This  section  describes how the table lookups change when the table is
+       given in the form of regular expressions or when lookups  are  directed
+       to  a  TCP-based server. For a description of regular expression lookup
+       table syntax, see <a href="regexp_table.5.html"><b>regexp_table</b>(5)</a> or <a href="pcre_table.5.html"><b>pcre_table</b>(5)</a>. For  a  description
        of the TCP client/server table lookup protocol, see <a href="tcp_table.5.html"><b>tcp_table</b>(5)</a>.  This
        feature is available in Postfix 2.5 and later.
 
-       Each pattern is a regular expression that is applied to the entire  ad-
-       dress  being looked up. Thus, <i>user@domain</i> mail addresses are not broken
-       up into their <i>user</i> and <i>@domain</i> constituent parts, nor is <i>user+foo</i>  bro-
-       ken up into <i>user</i> and <i>foo</i>.
+       Each pattern is a regular expression that  is  applied  to  the  entire
+       address  being looked up. Thus, <i>user@domain</i> mail addresses are not bro-
+       ken up into their <i>user</i> and <i>@domain</i> constituent parts, nor  is  <i>user+foo</i>
+       broken up into <i>user</i> and <i>foo</i>.
 
        Patterns  are  applied  in the order as specified in the table, until a
        pattern is found that matches the search string.
        The table format does not understand quoting conventions.
 
 <b><a name="configuration_parameters">CONFIGURATION PARAMETERS</a></b>
-       The following <a href="postconf.5.html"><b>main.cf</b></a> parameters are especially relevant.  The text be-
-       low provides only a parameter summary. See <a href="postconf.5.html"><b>postconf</b>(5)</a> for more details
-       including examples.
+       The  following  <a href="postconf.5.html"><b>main.cf</b></a>  parameters  are especially relevant.  The text
+       below provides only a  parameter  summary.  See  <a href="postconf.5.html"><b>postconf</b>(5)</a>  for  more
+       details including examples.
 
        <b><a href="postconf.5.html#relocated_maps">relocated_maps</a> (empty)</b>
               Optional lookup tables with new contact information for users or
        Available with Postfix version 3.11 and later:
 
        <b><a href="postconf.5.html#relocated_prefix_enable">relocated_prefix_enable</a> (yes)</b>
-              Prepend  the  prefix  "<b>5.1.6  User  has  moved to</b> " to all relo-
+              Prepend the prefix "<b>5.1.6 User has  moved  to</b>  "  to  all  relo-
               cated_maps lookup results.
 
        Other parameters of interest:
 
        <b><a href="postconf.5.html#inet_interfaces">inet_interfaces</a> (all)</b>
-              The local network interface addresses that this mail system  re-
-              ceives mail on.
+              The  local  network  interface  addresses  that this mail system
+              receives mail on.
 
        <b><a href="postconf.5.html#mydestination">mydestination</a> ($<a href="postconf.5.html#myhostname">myhostname</a>, localhost.$<a href="postconf.5.html#mydomain">mydomain</a>, localhost)</b>
-              The  list of domains that are delivered via the $<a href="postconf.5.html#local_transport">local_transport</a>
+              The list of domains that are delivered via the  $<a href="postconf.5.html#local_transport">local_transport</a>
               mail delivery transport.
 
        <b><a href="postconf.5.html#myorigin">myorigin</a> ($<a href="postconf.5.html#myhostname">myhostname</a>)</b>
-              The domain name that locally-posted mail appears to  come  from,
+              The  domain  name that locally-posted mail appears to come from,
               and that locally posted mail is delivered to.
 
        <b><a href="postconf.5.html#proxy_interfaces">proxy_interfaces</a> (empty)</b>
-              The remote network interface addresses that this mail system re-
-              ceives  mail on by way of a proxy or network address translation
-              unit.
+              The remote network interface addresses  that  this  mail  system
+              receives  mail  on by way of a proxy or network address transla-
+              tion unit.
 
 <b><a name="see_also">SEE ALSO</a></b>
        <a href="trivial-rewrite.8.html">trivial-rewrite(8)</a>, address resolver
        111 8th Avenue
        New York, NY 10011, USA
 
-                                                                  <i>RELOCATED</i>(5)
+                                                                  RELOCATED(5)
 </pre> </body> </html>
index 4645b733aa92da0bd14758ceab565dabf9f18ddf..91157d8ef7f20cdd3af67313a194be62f99246ae 100644 (file)
@@ -168,7 +168,7 @@ SENDMAIL(1)                                                        SENDMAIL(1)
               Delivery   status   notification   control.   Specify  either  a
               comma-separated list with one or more of <b>failure</b> (send notifica-
               tion  when delivery fails), <b>delay</b> (send notification when deliv-
-              ery is delayed), or <b>success</b> (send notification when the  message
+              ery is delayed), or <b>success</b> (send notification after the message
               is delivered); or specify <b>never</b> (don't send any notifications at
               all).
 
@@ -177,14 +177,36 @@ SENDMAIL(1)                                                        SENDMAIL(1)
        <b>-n</b> (ignored)
               Backwards compatibility.
 
-       <b>-oA</b><i>alias</i><b>_</b><i>database</i>
-              Non-default alias database. Specify <i>pathname</i>  or  <i>type</i>:<i>pathname</i>.
-              See <a href="postalias.1.html"><b>postalias</b>(1)</a> for details.
+       <b>-O requiretls=yes</b>
+
+       <b>-O requiretls=no</b>
+              When delivering a message to an SMTP or LMTP server, the connec-
+              tion  must  use TLS with a verified server certificate, and that
+              server must support REQUIRETLS. The "requiretls" name and option
+              value are case-insensitive. REQUIRETLS enforcement is controlled
+              with    the    configuration    parameters    <a href="postconf.5.html#requiretls_enable">requiretls_enable</a>,
+              <a href="postconf.5.html#smtp_requiretls_policy">smtp_requiretls_policy</a>, and <a href="postconf.5.html#lmtp_requiretls_policy">lmtp_requiretls_policy</a>.
+
+              This feature is available in Postfix 3.11 and later.
+
+       <b>-O smtputf8=yes</b>
+
+       <b>-O smtputf8=no</b>
+              When  delivering  a  message  to  an SMTP or LMTP server, and an
+              envelope address or message  header  contains  UTF8  text,  that
+              server  must  support  SMTPUTF8.  The "smtputf8" option name and
+              value are case-insensitive.
+
+              This feature is available in Postfix 3.11 and later.
 
        <b>-O</b> <i>option=value</i> (ignored)
-              Set  the named <i>option</i> to <i>value</i>. Use the equivalent configuration
+              Set the named <i>option</i> to <i>value</i>. Use the equivalent  configuration
               parameter in <a href="postconf.5.html"><b>main.cf</b></a> instead.
 
+       <b>-oA</b><i>alias</i><b>_</b><i>database</i>
+              Non-default  alias  database. Specify <i>pathname</i> or <i>type</i>:<i>pathname</i>.
+              See <a href="postalias.1.html"><b>postalias</b>(1)</a> for details.
+
        <b>-o7</b> (ignored)
 
        <b>-o8</b> (ignored)
@@ -483,6 +505,12 @@ SENDMAIL(1)                                                        SENDMAIL(1)
               the  default  Postfix  instance,  and that are started, stopped,
               etc., together with the default Postfix instance.
 
+       Postfix 3.11 and later:
+
+       <b><a href="postconf.5.html#requiretls_enable">requiretls_enable</a> (yes)</b>
+              Enable support for the ESMTP  verb  "REQUIRETLS"  in  the  "MAIL
+              FROM" command.
+
 <b><a name="files">FILES</a></b>
        /var/spool/postfix, mail queue
        /etc/postfix, configuration files
@@ -501,7 +529,7 @@ SENDMAIL(1)                                                        SENDMAIL(1)
        syslogd(8), system logging
 
 <b><a name="readme_files">README_FILES</a></b>
-       Use "<b>postconf <a href="postconf.5.html#readme_directory">readme_directory</a></b>" or "<b>postconf <a href="postconf.5.html#html_directory">html_directory</a></b>" to  locate
+       Use  "<b>postconf <a href="postconf.5.html#readme_directory">readme_directory</a></b>" or "<b>postconf <a href="postconf.5.html#html_directory">html_directory</a></b>" to locate
        this information.
        <a href="DEBUG_README.html">DEBUG_README</a>, Postfix debugging howto
        <a href="ETRN_README.html">ETRN_README</a>, Postfix ETRN howto
index e116f43aa938dfd020400c6db507a4bf41f389dc..c0ce2ddb3964cbf1860372195634bcb3a14fa46d 100644 (file)
@@ -174,7 +174,7 @@ SMTP(8)                                                                SMTP(8)
        <a href="https://tools.ietf.org/html/rfc6531">RFC 6531</a> (Internationalized SMTP)
        <a href="https://tools.ietf.org/html/rfc6533">RFC 6533</a> (Internationalized Delivery Status Notifications)
        <a href="https://tools.ietf.org/html/rfc7672">RFC 7672</a> (SMTP security via opportunistic DANE TLS)
-       <a href="https://tools.ietf.org/html/rfc8689">RFC 8689</a> (TLS-Required message header)
+       <a href="https://tools.ietf.org/html/rfc8689">RFC 8689</a> (SMTP REQUIRETLS extension, TLS-Required header)
 
 <b><a name="diagnostics">DIAGNOSTICS</a></b>
        Problems  and  transactions  are  logged  to <b>syslogd</b>(8) or <a href="postlogd.8.html"><b>postlogd</b>(8)</a>.
@@ -507,7 +507,7 @@ SMTP(8)                                                                SMTP(8)
               The delimiter between username and password in  sasl_passwd_maps
               lookup results.
 
-<b><a name="starttls_support_controls">STARTTLS SUPPORT CONTROLS</a></b>
+<b><a name="tls_support_controls">TLS SUPPORT CONTROLS</a></b>
        Detailed  information  about STARTTLS configuration may be found in the
        <a href="TLS_README.html">TLS_README</a> document.
 
@@ -775,7 +775,16 @@ SMTP(8)                                                                SMTP(8)
               Enable  support  for  the  "TLS-Required:  no"  message  header,
               defined in <a href="https://tools.ietf.org/html/rfc8689">RFC 8689</a>.
 
-<b><a name="obsolete_starttls_controls">OBSOLETE STARTTLS CONTROLS</a></b>
+       <b><a href="postconf.5.html#requiretls_enable">requiretls_enable</a> (yes)</b>
+              Enable  support  for  the  ESMTP  verb "REQUIRETLS" in the "MAIL
+              FROM" command.
+
+       <b><a href="postconf.5.html#smtp_requiretls_policy">smtp_requiretls_policy</a> (see 'postconf -d  <a href="postconf.5.html#smtp_requiretls_policy">smtp_requiretls_policy</a>'  out-</b>
+       <b>put)</b>
+              How the Postfix SMTP and LMTP client will enforce REQUIRETLS for
+              messages received with the REQUIRETLS option.
+
+<b><a name="obsolete_tls_controls">OBSOLETE TLS CONTROLS</a></b>
        The  following  configuration  parameters  exist for compatibility with
        Postfix versions before 2.3. Support for these will  be  removed  in  a
        future release.
index 8465bbf2529157c6c7e8a9c0a7726116aa46448c..5f8fcfa2c99dfccb42ca204d698e3bfbccdff773 100644 (file)
@@ -62,6 +62,7 @@ SMTPD(8)                                                              SMTPD(8)
        <a href="https://tools.ietf.org/html/rfc6531">RFC 6531</a> (Internationalized SMTP)
        <a href="https://tools.ietf.org/html/rfc6533">RFC 6533</a> (Internationalized Delivery Status Notifications)
        <a href="https://tools.ietf.org/html/rfc7505">RFC 7505</a> ("Null MX" No Service Resource Record)
+       <a href="https://tools.ietf.org/html/rfc8689">RFC 8689</a> (SMTP REQUIRETLS extension)
 
 <b><a name="diagnostics">DIAGNOSTICS</a></b>
        Problems and transactions are logged to <b>syslogd</b>(8) or <a href="postlogd.8.html"><b>postlogd</b>(8)</a>.
@@ -430,7 +431,7 @@ SMTPD(8)                                                              SMTPD(8)
               If  non-empty,  a  filter  for the SASL mechanism names that the
               Postfix SMTP server will announce in the EHLO response.
 
-<b><a name="starttls_support_controls">STARTTLS SUPPORT CONTROLS</a></b>
+<b><a name="tls_support_controls">TLS SUPPORT CONTROLS</a></b>
        Detailed information about STARTTLS configuration may be found  in  the
        <a href="TLS_README.html">TLS_README</a> document.
 
@@ -655,109 +656,115 @@ SMTPD(8)                                                              SMTPD(8)
               instead of an X.509 certificate, when asking  for  or  requiring
               client authentication.
 
-<b><a name="obsolete_starttls_controls">OBSOLETE STARTTLS CONTROLS</a></b>
-       The  following  configuration  parameters  exist for compatibility with
-       Postfix versions before 2.3. Support for these will  be  removed  in  a
+       Available in Postfix version 3.10 and later:
+
+       <b><a href="postconf.5.html#requiretls_enable">requiretls_enable</a> (yes)</b>
+              Enable  support  for  the  ESMTP  verb "REQUIRETLS" in the "MAIL
+              FROM" command.
+
+<b><a name="obsolete_tls_controls">OBSOLETE TLS CONTROLS</a></b>
+       The following configuration parameters  exist  for  compatibility  with
+       Postfix  versions  before  2.3.  Support for these will be removed in a
        future release.
 
        <b><a href="postconf.5.html#smtpd_use_tls">smtpd_use_tls</a> (no)</b>
-              Opportunistic  TLS:  announce  STARTTLS  support  to remote SMTP
+              Opportunistic TLS: announce  STARTTLS  support  to  remote  SMTP
               clients, but do not require that clients use TLS encryption.
 
        <b><a href="postconf.5.html#smtpd_enforce_tls">smtpd_enforce_tls</a> (no)</b>
               Mandatory TLS: announce STARTTLS support to remote SMTP clients,
-              and  reject  all  plaintext commands except HELO, EHLO, XCLIENT,
+              and reject all plaintext commands except  HELO,  EHLO,  XCLIENT,
               STARTTLS, NOOP, QUIT, and (Postfix &gt;= 3.9) HELP.
 
        <b><a href="postconf.5.html#smtpd_tls_cipherlist">smtpd_tls_cipherlist</a> (empty)</b>
-              Obsolete Postfix &lt; 2.3 control for the Postfix SMTP  server  TLS
+              Obsolete  Postfix  &lt; 2.3 control for the Postfix SMTP server TLS
               cipher list.
 
 <b><a name="smtputf8_controls">SMTPUTF8 CONTROLS</a></b>
        Preliminary SMTPUTF8 support is introduced with Postfix 3.0.
 
        <b><a href="postconf.5.html#smtputf8_enable">smtputf8_enable</a> (yes)</b>
-              Enable  preliminary SMTPUTF8 support for the protocols described
+              Enable preliminary SMTPUTF8 support for the protocols  described
               in <a href="https://tools.ietf.org/html/rfc6531">RFC 6531</a>, <a href="https://tools.ietf.org/html/rfc6532">RFC 6532</a>, and <a href="https://tools.ietf.org/html/rfc6533">RFC 6533</a>.
 
        <b><a href="postconf.5.html#strict_smtputf8">strict_smtputf8</a> (no)</b>
               Enable stricter enforcement of the SMTPUTF8 protocol.
 
        <b><a href="postconf.5.html#smtputf8_autodetect_classes">smtputf8_autodetect_classes</a> (sendmail, verify)</b>
-              Detect that a message requires SMTPUTF8 support for  the  speci-
+              Detect  that  a message requires SMTPUTF8 support for the speci-
               fied mail origin classes.
 
        Available in Postfix version 3.2 and later:
 
        <b><a href="postconf.5.html#enable_idna2003_compatibility">enable_idna2003_compatibility</a> (no)</b>
-              Enable   'transitional'   compatibility   between  IDNA2003  and
-              IDNA2008, when converting UTF-8 domain names to/from  the  ASCII
+              Enable  'transitional'  compatibility   between   IDNA2003   and
+              IDNA2008,  when  converting UTF-8 domain names to/from the ASCII
               form that is used for DNS lookups.
 
 <b><a name="verp_support_controls">VERP SUPPORT CONTROLS</a></b>
-       With  VERP  style delivery, each recipient of a message receives a cus-
-       tomized copy of the message with his/her own recipient address  encoded
+       With VERP style delivery, each recipient of a message receives  a  cus-
+       tomized  copy of the message with his/her own recipient address encoded
        in the envelope sender address.  The <a href="VERP_README.html">VERP_README</a> file describes config-
-       uration and operation details of Postfix support for variable  envelope
-       return  path addresses.  VERP style delivery is requested with the SMTP
-       XVERP command or with the "sendmail  -V"  command-line  option  and  is
+       uration  and operation details of Postfix support for variable envelope
+       return path addresses.  VERP style delivery is requested with the  SMTP
+       XVERP  command  or  with  the  "sendmail -V" command-line option and is
        available in Postfix version 1.1 and later.
 
        <b><a href="postconf.5.html#default_verp_delimiters">default_verp_delimiters</a> (+=)</b>
               The two default VERP delimiter characters.
 
        <b><a href="postconf.5.html#verp_delimiter_filter">verp_delimiter_filter</a> (-=+)</b>
-              The  characters  Postfix accepts as VERP delimiter characters on
+              The characters Postfix accepts as VERP delimiter  characters  on
               the Postfix <a href="sendmail.1.html"><b>sendmail</b>(1)</a> command line and in SMTP commands.
 
        Available in Postfix version 1.1 and 2.0:
 
        <b><a href="postconf.5.html#authorized_verp_clients">authorized_verp_clients</a> ($<a href="postconf.5.html#mynetworks">mynetworks</a>)</b>
-              What remote SMTP clients are allowed to specify the  XVERP  com-
+              What  remote  SMTP clients are allowed to specify the XVERP com-
               mand.
 
        Available in Postfix version 2.1 and later:
 
        <b><a href="postconf.5.html#smtpd_authorized_verp_clients">smtpd_authorized_verp_clients</a> ($<a href="postconf.5.html#authorized_verp_clients">authorized_verp_clients</a>)</b>
-              What  remote  SMTP clients are allowed to specify the XVERP com-
+              What remote SMTP clients are allowed to specify the  XVERP  com-
               mand.
 
 <b><a name="trouble_shooting_controls">TROUBLE SHOOTING CONTROLS</a></b>
-       The <a href="DEBUG_README.html">DEBUG_README</a> document describes how to debug parts of  the  Postfix
-       mail  system.  The  methods  vary from making the software log a lot of
+       The  <a href="DEBUG_README.html">DEBUG_README</a>  document describes how to debug parts of the Postfix
+       mail system. The methods vary from making the software  log  a  lot  of
        detail, to running some daemon processes under control of a call tracer
        or debugger.
 
        <b><a href="postconf.5.html#debug_peer_level">debug_peer_level</a> (2)</b>
-              The  increment  in verbose logging level when a nexthop destina-
-              tion, remote client or server name or network address matches  a
+              The increment in verbose logging level when a  nexthop  destina-
+              tion,  remote client or server name or network address matches a
               pattern given with the <a href="postconf.5.html#debug_peer_list">debug_peer_list</a> parameter.
 
        <b><a href="postconf.5.html#debug_peer_list">debug_peer_list</a> (empty)</b>
-              Optional  list  of  nexthop destination, remote client or server
-              name or network address patterns that,  if  matched,  cause  the
-              verbose  logging  level  to  increase by the amount specified in
+              Optional list of nexthop destination, remote  client  or  server
+              name  or  network  address  patterns that, if matched, cause the
+              verbose logging level to increase by  the  amount  specified  in
               $<a href="postconf.5.html#debug_peer_level">debug_peer_level</a>.
 
        <b><a href="postconf.5.html#error_notice_recipient">error_notice_recipient</a> (postmaster)</b>
-              The recipient of postmaster notifications  about  mail  delivery
+              The  recipient  of  postmaster notifications about mail delivery
               problems that are caused by policy, resource, software or proto-
               col errors.
 
        <b><a href="postconf.5.html#internal_mail_filter_classes">internal_mail_filter_classes</a> (empty)</b>
-              What  categories  of  Postfix-generated  mail  are  subject   to
-              before-queue    content    inspection    by   <a href="postconf.5.html#non_smtpd_milters">non_smtpd_milters</a>,
+              What   categories  of  Postfix-generated  mail  are  subject  to
+              before-queue   content    inspection    by    <a href="postconf.5.html#non_smtpd_milters">non_smtpd_milters</a>,
               <a href="postconf.5.html#header_checks">header_checks</a> and <a href="postconf.5.html#body_checks">body_checks</a>.
 
        <b><a href="postconf.5.html#notify_classes">notify_classes</a> (resource, software)</b>
               The list of error classes that are reported to the postmaster.
 
        <b><a href="postconf.5.html#smtpd_reject_footer">smtpd_reject_footer</a> (empty)</b>
-              Optional information that is appended after  each  Postfix  SMTP
+              Optional  information  that  is appended after each Postfix SMTP
               server 4XX or 5XX response.
 
        <b><a href="postconf.5.html#soft_bounce">soft_bounce</a> (no)</b>
-              Safety  net to keep mail queued that would otherwise be returned
+              Safety net to keep mail queued that would otherwise be  returned
               to the sender.
 
        Available in Postfix version 2.1 and later:
@@ -768,49 +775,49 @@ SMTPD(8)                                                              SMTPD(8)
        Available in Postfix version 2.10 and later:
 
        <b><a href="postconf.5.html#smtpd_log_access_permit_actions">smtpd_log_access_permit_actions</a> (empty)</b>
-              Enable  logging  of  the  named  "permit" actions in SMTP server
-              access lists (by default, the SMTP server logs "reject"  actions
+              Enable logging of the named  "permit"  actions  in  SMTP  server
+              access  lists (by default, the SMTP server logs "reject" actions
               but not "permit" actions).
 
 <b><a name="known_versus_unknown_recipient_controls">KNOWN VERSUS UNKNOWN RECIPIENT CONTROLS</a></b>
-       As  of  Postfix  version  2.0, the SMTP server rejects mail for unknown
+       As of Postfix version 2.0, the SMTP server  rejects  mail  for  unknown
        recipients. This prevents the mail queue from clogging up with undeliv-
-       erable  MAILER-DAEMON messages. Additional information on this topic is
+       erable MAILER-DAEMON messages. Additional information on this topic  is
        in the <a href="LOCAL_RECIPIENT_README.html">LOCAL_RECIPIENT_README</a> and <a href="ADDRESS_CLASS_README.html">ADDRESS_CLASS_README</a> documents.
 
        <b><a href="postconf.5.html#show_user_unknown_table_name">show_user_unknown_table_name</a> (yes)</b>
-              Display the name of the recipient table in  the  "User  unknown"
+              Display  the  name  of the recipient table in the "User unknown"
               responses.
 
        <b><a href="postconf.5.html#canonical_maps">canonical_maps</a> (empty)</b>
-              Optional  address  mapping lookup tables for message headers and
+              Optional address mapping lookup tables for message  headers  and
               envelopes.
 
        <b><a href="postconf.5.html#recipient_canonical_maps">recipient_canonical_maps</a> (empty)</b>
-              Optional address mapping lookup tables for envelope  and  header
+              Optional  address  mapping lookup tables for envelope and header
               recipient addresses.
 
        <b><a href="postconf.5.html#sender_canonical_maps">sender_canonical_maps</a> (empty)</b>
-              Optional  address  mapping lookup tables for envelope and header
+              Optional address mapping lookup tables for envelope  and  header
               sender addresses.
 
        Parameters concerning known/unknown local recipients:
 
        <b><a href="postconf.5.html#mydestination">mydestination</a> ($<a href="postconf.5.html#myhostname">myhostname</a>, localhost.$<a href="postconf.5.html#mydomain">mydomain</a>, localhost)</b>
-              The list of domains that are delivered via the  $<a href="postconf.5.html#local_transport">local_transport</a>
+              The  list of domains that are delivered via the $<a href="postconf.5.html#local_transport">local_transport</a>
               mail delivery transport.
 
        <b><a href="postconf.5.html#inet_interfaces">inet_interfaces</a> (all)</b>
-              The  local  network  interface  addresses  that this mail system
+              The local network interface  addresses  that  this  mail  system
               receives mail on.
 
        <b><a href="postconf.5.html#proxy_interfaces">proxy_interfaces</a> (empty)</b>
-              The remote network interface addresses  that  this  mail  system
-              receives  mail  on by way of a proxy or network address transla-
+              The  remote  network  interface  addresses that this mail system
+              receives mail on by way of a proxy or network  address  transla-
               tion unit.
 
        <b><a href="postconf.5.html#inet_protocols">inet_protocols</a> (see 'postconf -d' output)</b>
-              The Internet protocols Postfix will attempt to use  when  making
+              The  Internet  protocols Postfix will attempt to use when making
               or accepting connections.
 
        <b><a href="postconf.5.html#local_recipient_maps">local_recipient_maps</a> (<a href="proxymap.8.html">proxy</a>:unix:passwd.byname $<a href="postconf.5.html#alias_maps">alias_maps</a>)</b>
@@ -819,61 +826,61 @@ SMTPD(8)                                                              SMTPD(8)
 
        <b><a href="postconf.5.html#unknown_local_recipient_reject_code">unknown_local_recipient_reject_code</a> (550)</b>
               The numerical Postfix SMTP server response code when a recipient
-              address  is local, and $<a href="postconf.5.html#local_recipient_maps">local_recipient_maps</a> specifies a list of
+              address is local, and $<a href="postconf.5.html#local_recipient_maps">local_recipient_maps</a> specifies a list  of
               lookup tables that does not match the recipient.
 
        Parameters concerning known/unknown recipients of relay destinations:
 
        <b><a href="postconf.5.html#relay_domains">relay_domains</a> (Postfix</b> &gt;<b>= 3.0: empty, Postfix</b> &lt; <b>3.0: $<a href="postconf.5.html#mydestination">mydestination</a>)</b>
-              What destination domains (and subdomains  thereof)  this  system
+              What  destination  domains  (and subdomains thereof) this system
               will relay mail to.
 
        <b><a href="postconf.5.html#relay_recipient_maps">relay_recipient_maps</a> (empty)</b>
-              Optional  lookup  tables with all valid addresses in the domains
+              Optional lookup tables with all valid addresses in  the  domains
               that match $<a href="postconf.5.html#relay_domains">relay_domains</a>.
 
        <b><a href="postconf.5.html#unknown_relay_recipient_reject_code">unknown_relay_recipient_reject_code</a> (550)</b>
-              The numerical Postfix SMTP server reply code  when  a  recipient
-              address  matches $<a href="postconf.5.html#relay_domains">relay_domains</a>, and <a href="postconf.5.html#relay_recipient_maps">relay_recipient_maps</a> speci-
-              fies a list of lookup tables that does not match  the  recipient
+              The  numerical  Postfix  SMTP server reply code when a recipient
+              address matches $<a href="postconf.5.html#relay_domains">relay_domains</a>, and <a href="postconf.5.html#relay_recipient_maps">relay_recipient_maps</a>  speci-
+              fies  a  list of lookup tables that does not match the recipient
               address.
 
-       Parameters   concerning   known/unknown  recipients  in  virtual  alias
+       Parameters  concerning  known/unknown  recipients  in   virtual   alias
        domains:
 
        <b><a href="postconf.5.html#virtual_alias_domains">virtual_alias_domains</a> ($<a href="postconf.5.html#virtual_alias_maps">virtual_alias_maps</a>)</b>
-              Postfix is the final destination for the specified list of  vir-
+              Postfix  is the final destination for the specified list of vir-
               tual alias domains, that is, domains for which all addresses are
               aliased to addresses in other local or remote domains.
 
        <b><a href="postconf.5.html#virtual_alias_maps">virtual_alias_maps</a> ($<a href="postconf.5.html#virtual_maps">virtual_maps</a>)</b>
               Optional lookup tables that are often searched with a full email
-              address  (including  domain)  and  that apply to all recipients:
-              <a href="local.8.html"><b>local</b>(8)</a>, virtual, and remote; this is  unlike  <a href="postconf.5.html#alias_maps">alias_maps</a>  that
-              are  only  searched  with an email address localpart (no domain)
+              address (including domain) and that  apply  to  all  recipients:
+              <a href="local.8.html"><b>local</b>(8)</a>,  virtual,  and  remote; this is unlike <a href="postconf.5.html#alias_maps">alias_maps</a> that
+              are only searched with an email address  localpart  (no  domain)
               and that apply only to <a href="local.8.html"><b>local</b>(8)</a> recipients.
 
        <b><a href="postconf.5.html#unknown_virtual_alias_reject_code">unknown_virtual_alias_reject_code</a> (550)</b>
-              The Postfix SMTP server reply  code  when  a  recipient  address
-              matches  $<a href="postconf.5.html#virtual_alias_domains">virtual_alias_domains</a>,  and $<a href="postconf.5.html#virtual_alias_maps">virtual_alias_maps</a> speci-
-              fies a list of lookup tables that does not match  the  recipient
+              The  Postfix  SMTP  server  reply  code when a recipient address
+              matches $<a href="postconf.5.html#virtual_alias_domains">virtual_alias_domains</a>, and  $<a href="postconf.5.html#virtual_alias_maps">virtual_alias_maps</a>  speci-
+              fies  a  list of lookup tables that does not match the recipient
               address.
 
        Parameters  concerning  known/unknown  recipients  in  virtual  mailbox
        domains:
 
        <b><a href="postconf.5.html#virtual_mailbox_domains">virtual_mailbox_domains</a> ($<a href="postconf.5.html#virtual_mailbox_maps">virtual_mailbox_maps</a>)</b>
-              Postfix is the final  destination  for  the  specified  list  of
-              domains;  mail  is  delivered  via  the  $<a href="postconf.5.html#virtual_transport">virtual_transport</a> mail
+              Postfix  is  the  final  destination  for  the specified list of
+              domains; mail  is  delivered  via  the  $<a href="postconf.5.html#virtual_transport">virtual_transport</a>  mail
               delivery transport.
 
        <b><a href="postconf.5.html#virtual_mailbox_maps">virtual_mailbox_maps</a> (empty)</b>
-              Optional lookup tables with all valid addresses in  the  domains
+              Optional  lookup  tables with all valid addresses in the domains
               that match $<a href="postconf.5.html#virtual_mailbox_domains">virtual_mailbox_domains</a>.
 
        <b><a href="postconf.5.html#unknown_virtual_mailbox_reject_code">unknown_virtual_mailbox_reject_code</a> (550)</b>
-              The  Postfix  SMTP  server  reply  code when a recipient address
-              matches  $<a href="postconf.5.html#virtual_mailbox_domains">virtual_mailbox_domains</a>,   and   $<a href="postconf.5.html#virtual_mailbox_maps">virtual_mailbox_maps</a>
+              The Postfix SMTP server reply  code  when  a  recipient  address
+              matches   $<a href="postconf.5.html#virtual_mailbox_domains">virtual_mailbox_domains</a>,   and  $<a href="postconf.5.html#virtual_mailbox_maps">virtual_mailbox_maps</a>
               specifies a list of lookup tables that does not match the recip-
               ient address.
 
@@ -882,7 +889,7 @@ SMTPD(8)                                                              SMTPD(8)
        control client request rates.
 
        <b><a href="postconf.5.html#line_length_limit">line_length_limit</a> (2048)</b>
-              Upon  input,  long  lines  are chopped up into pieces of at most
+              Upon input, long lines are chopped up into  pieces  of  at  most
               this length; upon delivery, long lines are reconstructed.
 
        <b><a href="postconf.5.html#queue_minfree">queue_minfree</a> (0)</b>
@@ -890,62 +897,62 @@ SMTPD(8)                                                              SMTPD(8)
               tem that is needed to receive mail.
 
        <b><a href="postconf.5.html#message_size_limit">message_size_limit</a> (10240000)</b>
-              The  maximal  size  in  bytes  of  a message, including envelope
+              The maximal size in  bytes  of  a  message,  including  envelope
               information.
 
        <b><a href="postconf.5.html#smtpd_recipient_limit">smtpd_recipient_limit</a> (1000)</b>
-              The maximal number of recipients that the  Postfix  SMTP  server
+              The  maximal  number  of recipients that the Postfix SMTP server
               accepts per message delivery request.
 
        <b><a href="postconf.5.html#smtpd_timeout">smtpd_timeout</a> (normal: 300s, <a href="STRESS_README.html">overload</a>: 10s)</b>
-              When  the  Postfix  SMTP  server  wants  to  send an SMTP server
-              response, how long the Postfix SMTP  server  will  wait  for  an
-              underlying  network  write  operation  to complete; and when the
-              Postfix SMTP server Postfix wants  to  receive  an  SMTP  client
-              request,  how  long  the  Postfix  SMTP  server will wait for an
+              When the Postfix SMTP  server  wants  to  send  an  SMTP  server
+              response,  how  long  the  Postfix  SMTP server will wait for an
+              underlying network write operation to  complete;  and  when  the
+              Postfix  SMTP  server  Postfix  wants  to receive an SMTP client
+              request, how long the Postfix  SMTP  server  will  wait  for  an
               underlying network read operation to complete.
 
        <b><a href="postconf.5.html#smtpd_history_flush_threshold">smtpd_history_flush_threshold</a> (100)</b>
-              The maximal number of lines in the Postfix SMTP  server  command
-              history  before it is flushed upon receipt of EHLO, RSET, or end
+              The  maximal  number of lines in the Postfix SMTP server command
+              history before it is flushed upon receipt of EHLO, RSET, or  end
               of DATA.
 
        Available in Postfix version 2.3 and later:
 
        <b><a href="postconf.5.html#smtpd_peername_lookup">smtpd_peername_lookup</a> (yes)</b>
-              Attempt to look up the remote SMTP client hostname,  and  verify
+              Attempt  to  look up the remote SMTP client hostname, and verify
               that the name matches the client IP address.
 
        The per SMTP client connection count and request rate limits are imple-
-       mented in co-operation with the <a href="anvil.8.html"><b>anvil</b>(8)</a> service, and are available  in
+       mented  in co-operation with the <a href="anvil.8.html"><b>anvil</b>(8)</a> service, and are available in
        Postfix version 2.2 and later.
 
        <b><a href="postconf.5.html#smtpd_client_connection_count_limit">smtpd_client_connection_count_limit</a> (50)</b>
-              How  many simultaneous connections any client is allowed to make
+              How many simultaneous connections any client is allowed to  make
               to this service.
 
        <b><a href="postconf.5.html#smtpd_client_connection_rate_limit">smtpd_client_connection_rate_limit</a> (0)</b>
-              The maximal number of connection attempts any client is  allowed
+              The  maximal number of connection attempts any client is allowed
               to make to this service per time unit.
 
        <b><a href="postconf.5.html#smtpd_client_message_rate_limit">smtpd_client_message_rate_limit</a> (0)</b>
-              The  maximal number of message delivery requests that any client
-              is allowed to make to this service per time unit, regardless  of
+              The maximal number of message delivery requests that any  client
+              is  allowed to make to this service per time unit, regardless of
               whether or not Postfix actually accepts those messages.
 
        <b><a href="postconf.5.html#smtpd_client_recipient_rate_limit">smtpd_client_recipient_rate_limit</a> (0)</b>
-              The  maximal  number  of  recipient addresses that any client is
-              allowed to send to this service per  time  unit,  regardless  of
+              The maximal number of recipient addresses  that  any  client  is
+              allowed  to  send  to  this service per time unit, regardless of
               whether or not Postfix actually accepts those recipients.
 
        <b><a href="postconf.5.html#smtpd_client_event_limit_exceptions">smtpd_client_event_limit_exceptions</a> ($<a href="postconf.5.html#mynetworks">mynetworks</a>)</b>
-              Clients  that  are excluded from smtpd_client_*_count/rate_limit
+              Clients that are excluded  from  smtpd_client_*_count/rate_limit
               restrictions.
 
        Available in Postfix version 2.3 and later:
 
        <b><a href="postconf.5.html#smtpd_client_new_tls_session_rate_limit">smtpd_client_new_tls_session_rate_limit</a> (0)</b>
-              The maximal number of new (i.e., uncached) TLS sessions  that  a
+              The  maximal  number of new (i.e., uncached) TLS sessions that a
               remote SMTP client is allowed to negotiate with this service per
               time unit.
 
@@ -953,29 +960,29 @@ SMTPD(8)                                                              SMTPD(8)
 
        <b><a href="postconf.5.html#smtpd_per_record_deadline">smtpd_per_record_deadline</a> (normal: no, <a href="STRESS_README.html">overload</a>: yes)</b>
               Change  the  behavior  of  the  <a href="postconf.5.html#smtpd_timeout">smtpd_timeout</a>  and  <a href="postconf.5.html#smtpd_starttls_timeout">smtpd_start</a>-
-              <a href="postconf.5.html#smtpd_starttls_timeout">tls_timeout</a>  time  limits,  from  a time limit per read or write
-              system call, to a time limit  to  send  or  receive  a  complete
-              record  (an  SMTP command line, SMTP response line, SMTP message
+              <a href="postconf.5.html#smtpd_starttls_timeout">tls_timeout</a> time limits, from a time limit  per  read  or  write
+              system  call,  to  a  time  limit  to send or receive a complete
+              record (an SMTP command line, SMTP response line,  SMTP  message
               content line, or TLS protocol message).
 
        Available in Postfix version 3.1 and later:
 
        <b><a href="postconf.5.html#smtpd_client_auth_rate_limit">smtpd_client_auth_rate_limit</a> (0)</b>
-              The maximal number of AUTH commands that any client  is  allowed
-              to  send to this service per time unit, regardless of whether or
+              The  maximal  number of AUTH commands that any client is allowed
+              to send to this service per time unit, regardless of whether  or
               not Postfix actually accepts those commands.
 
        Available in Postfix version 3.7 and later:
 
        <b><a href="postconf.5.html#smtpd_per_request_deadline">smtpd_per_request_deadline</a> (normal: no, <a href="STRESS_README.html">overload</a>: yes)</b>
               Change  the  behavior  of  the  <a href="postconf.5.html#smtpd_timeout">smtpd_timeout</a>  and  <a href="postconf.5.html#smtpd_starttls_timeout">smtpd_start</a>-
-              <a href="postconf.5.html#smtpd_starttls_timeout">tls_timeout</a>  time limits, from a time limit per plaintext or TLS
-              read or write call, to a combined time  limit  for  receiving  a
-              complete  SMTP request and for sending a complete SMTP response.
+              <a href="postconf.5.html#smtpd_starttls_timeout">tls_timeout</a> time limits, from a time limit per plaintext or  TLS
+              read  or  write  call,  to a combined time limit for receiving a
+              complete SMTP request and for sending a complete SMTP  response.
 
        <b><a href="postconf.5.html#smtpd_min_data_rate">smtpd_min_data_rate</a> (500)</b>
-              The minimum plaintext data transfer  rate  in  bytes/second  for
-              DATA   and  BDAT  requests,  when  deadlines  are  enabled  with
+              The  minimum  plaintext  data  transfer rate in bytes/second for
+              DATA  and  BDAT  requests,  when  deadlines  are  enabled   with
               <a href="postconf.5.html#smtpd_per_request_deadline">smtpd_per_request_deadline</a>.
 
        <b><a href="postconf.5.html#header_from_format">header_from_format</a> (standard)</b>
@@ -984,27 +991,27 @@ SMTPD(8)                                                              SMTPD(8)
        Available in Postfix version 3.8 and later:
 
        <b><a href="postconf.5.html#smtpd_client_ipv4_prefix_length">smtpd_client_ipv4_prefix_length</a> (32)</b>
-              Aggregate smtpd_client_*_count and  smtpd_client_*_rate  statis-
+              Aggregate  smtpd_client_*_count  and smtpd_client_*_rate statis-
               tics by IPv4 network blocks with the specified network prefix.
 
        <b><a href="postconf.5.html#smtpd_client_ipv6_prefix_length">smtpd_client_ipv6_prefix_length</a> (84)</b>
-              Aggregate  smtpd_client_*_count  and smtpd_client_*_rate statis-
+              Aggregate smtpd_client_*_count and  smtpd_client_*_rate  statis-
               tics by IPv6 network blocks with the specified network prefix.
 
        Available in Postfix 3.9, 3.8.1, 3.7.6, 3.6.10, 3.5.20 and later:
 
        <b><a href="postconf.5.html#smtpd_forbid_unauth_pipelining">smtpd_forbid_unauth_pipelining</a> (Postfix</b> &gt;<b>= 3.9: yes)</b>
-              Disconnect remote SMTP clients that violate <a href="https://tools.ietf.org/html/rfc2920">RFC 2920</a>  (or  5321)
+              Disconnect  remote  SMTP clients that violate <a href="https://tools.ietf.org/html/rfc2920">RFC 2920</a> (or 5321)
               command pipelining constraints.
 
        Available in Postfix 3.9, 3.8.4, 3.7.9, 3.6.13, 3.5.23 and later:
 
        <b><a href="postconf.5.html#smtpd_forbid_bare_newline">smtpd_forbid_bare_newline</a> (Postfix</b> &gt;<b>= 3.9: normalize)</b>
-              Reject  or  restrict input lines from an SMTP client that end in
+              Reject or restrict input lines from an SMTP client that  end  in
               &lt;LF&gt; instead of the standard &lt;CR&gt;&lt;LF&gt;.
 
        <b><a href="postconf.5.html#smtpd_forbid_bare_newline_exclusions">smtpd_forbid_bare_newline_exclusions</a> ($<a href="postconf.5.html#mynetworks">mynetworks</a>)</b>
-              Exclude the  specified  clients  from  <a href="postconf.5.html#smtpd_forbid_bare_newline">smtpd_forbid_bare_newline</a>
+              Exclude  the  specified  clients  from <a href="postconf.5.html#smtpd_forbid_bare_newline">smtpd_forbid_bare_newline</a>
               enforcement.
 
        Available in Postfix 3.9, 3.8.5, 3.7.10, 3.6.14, 3.5.24 and later:
@@ -1014,55 +1021,55 @@ SMTPD(8)                                                              SMTPD(8)
               request with "<a href="postconf.5.html#smtpd_forbid_bare_newline">smtpd_forbid_bare_newline</a> = reject".
 
 <b><a name="tarpit_controls">TARPIT CONTROLS</a></b>
-       When a remote SMTP client makes errors, the  Postfix  SMTP  server  can
-       insert  delays  before  responding. This can help to slow down run-away
-       software.  The behavior is controlled by an error counter  that  counts
+       When  a  remote  SMTP  client makes errors, the Postfix SMTP server can
+       insert delays before responding. This can help to  slow  down  run-away
+       software.   The  behavior is controlled by an error counter that counts
        the number of errors within an SMTP session that a client makes without
        delivering mail.
 
        <b><a href="postconf.5.html#smtpd_error_sleep_time">smtpd_error_sleep_time</a> (1s)</b>
-              With Postfix version 2.1 and later:  the  SMTP  server  response
-              delay  after a client has made more than $<a href="postconf.5.html#smtpd_soft_error_limit">smtpd_soft_error_limit</a>
-              errors, and fewer than $<a href="postconf.5.html#smtpd_hard_error_limit">smtpd_hard_error_limit</a>  errors,  without
+              With  Postfix  version  2.1  and later: the SMTP server response
+              delay after a client has made more than  $<a href="postconf.5.html#smtpd_soft_error_limit">smtpd_soft_error_limit</a>
+              errors,  and  fewer than $<a href="postconf.5.html#smtpd_hard_error_limit">smtpd_hard_error_limit</a> errors, without
               delivering mail.
 
        <b><a href="postconf.5.html#smtpd_soft_error_limit">smtpd_soft_error_limit</a> (10)</b>
-              The  number  of  errors  a remote SMTP client is allowed to make
-              without delivering mail before the  Postfix  SMTP  server  slows
+              The number of errors a remote SMTP client  is  allowed  to  make
+              without  delivering  mail  before  the Postfix SMTP server slows
               down all its responses.
 
        <b><a href="postconf.5.html#smtpd_hard_error_limit">smtpd_hard_error_limit</a> (normal: 20, <a href="STRESS_README.html">overload</a>: 1)</b>
-              The  maximal number of errors a remote SMTP client is allowed to
+              The maximal number of errors a remote SMTP client is allowed  to
               make without delivering mail.
 
        <b><a href="postconf.5.html#smtpd_junk_command_limit">smtpd_junk_command_limit</a> (normal: 100, <a href="STRESS_README.html">overload</a>: 1)</b>
-              The number of junk commands (NOOP, VRFY, ETRN or  RSET)  that  a
-              remote  SMTP  client  can  send  before  the Postfix SMTP server
+              The  number  of  junk commands (NOOP, VRFY, ETRN or RSET) that a
+              remote SMTP client can  send  before  the  Postfix  SMTP  server
               starts to increment the error counter with each junk command.
 
        Available in Postfix version 2.1 and later:
 
        <b><a href="postconf.5.html#smtpd_recipient_overshoot_limit">smtpd_recipient_overshoot_limit</a> (1000)</b>
-              The number of recipients that a remote SMTP client can  send  in
+              The  number  of recipients that a remote SMTP client can send in
               excess  of  the  limit  specified  with  $<a href="postconf.5.html#smtpd_recipient_limit">smtpd_recipient_limit</a>,
-              before the Postfix SMTP server increments the per-session  error
+              before  the Postfix SMTP server increments the per-session error
               count for each excess recipient.
 
 <b><a name="access_policy_delegation_controls">ACCESS POLICY DELEGATION CONTROLS</a></b>
-       As  of version 2.1, Postfix can be configured to delegate access policy
-       decisions to an external server that runs  outside  Postfix.   See  the
+       As of version 2.1, Postfix can be configured to delegate access  policy
+       decisions  to  an  external  server that runs outside Postfix.  See the
        file <a href="SMTPD_POLICY_README.html">SMTPD_POLICY_README</a> for more information.
 
        <b><a href="postconf.5.html#smtpd_policy_service_max_idle">smtpd_policy_service_max_idle</a> (300s)</b>
-              The  time after which an idle SMTPD policy service connection is
+              The time after which an idle SMTPD policy service connection  is
               closed.
 
        <b><a href="postconf.5.html#smtpd_policy_service_max_ttl">smtpd_policy_service_max_ttl</a> (1000s)</b>
-              The time after which an active SMTPD policy  service  connection
+              The  time  after which an active SMTPD policy service connection
               is closed.
 
        <b><a href="postconf.5.html#smtpd_policy_service_timeout">smtpd_policy_service_timeout</a> (100s)</b>
-              The  time limit for connecting to, writing to, or receiving from
+              The time limit for connecting to, writing to, or receiving  from
               a delegated SMTPD policy server.
 
        Available in Postfix version 3.0 and later:
@@ -1072,81 +1079,81 @@ SMTPD(8)                                                              SMTPD(8)
               The default action when an SMTPD policy service request fails.
 
        <b><a href="postconf.5.html#smtpd_policy_service_request_limit">smtpd_policy_service_request_limit</a> (0)</b>
-              The maximal number of requests per SMTPD policy service  connec-
+              The  maximal number of requests per SMTPD policy service connec-
               tion, or zero (no limit).
 
        <b><a href="postconf.5.html#smtpd_policy_service_try_limit">smtpd_policy_service_try_limit</a> (2)</b>
-              The  maximal  number of attempts to send an SMTPD policy service
+              The maximal number of attempts to send an SMTPD  policy  service
               request before giving up.
 
        <b><a href="postconf.5.html#smtpd_policy_service_retry_delay">smtpd_policy_service_retry_delay</a> (1s)</b>
-              The delay between attempts to resend a failed SMTPD policy  ser-
+              The  delay between attempts to resend a failed SMTPD policy ser-
               vice request.
 
        Available in Postfix version 3.1 and later:
 
        <b><a href="postconf.5.html#smtpd_policy_service_policy_context">smtpd_policy_service_policy_context</a> (empty)</b>
-              Optional  information  that the Postfix SMTP server specifies in
-              the "policy_context"  attribute  of  a  policy  service  request
-              (originally,  to  share the same service endpoint among multiple
+              Optional information that the Postfix SMTP server  specifies  in
+              the  "policy_context"  attribute  of  a  policy  service request
+              (originally, to share the same service endpoint  among  multiple
               <a href="postconf.5.html#check_policy_service">check_policy_service</a> clients).
 
 <b><a name="access_controls">ACCESS CONTROLS</a></b>
-       The <a href="SMTPD_ACCESS_README.html">SMTPD_ACCESS_README</a> document gives an introduction to all the  SMTP
+       The  <a href="SMTPD_ACCESS_README.html">SMTPD_ACCESS_README</a> document gives an introduction to all the SMTP
        server access control features.
 
        <b><a href="postconf.5.html#smtpd_delay_reject">smtpd_delay_reject</a> (yes)</b>
-              Wait    until    the   RCPT   TO   command   before   evaluating
+              Wait   until   the   RCPT   TO   command    before    evaluating
               $<a href="postconf.5.html#smtpd_client_restrictions">smtpd_client_restrictions</a>,     $<a href="postconf.5.html#smtpd_helo_restrictions">smtpd_helo_restrictions</a>     and
               $<a href="postconf.5.html#smtpd_sender_restrictions">smtpd_sender_restrictions</a>,  or  wait  until  the  ETRN  command
-              before      evaluating      $<a href="postconf.5.html#smtpd_client_restrictions">smtpd_client_restrictions</a>       and
+              before       evaluating      $<a href="postconf.5.html#smtpd_client_restrictions">smtpd_client_restrictions</a>      and
               $<a href="postconf.5.html#smtpd_helo_restrictions">smtpd_helo_restrictions</a>.
 
        <b><a href="postconf.5.html#parent_domain_matches_subdomains">parent_domain_matches_subdomains</a> (see 'postconf -d' output)</b>
-              A  list of Postfix features where the pattern "example.com" also
-              matches subdomains  of  example.com,  instead  of  requiring  an
+              A list of Postfix features where the pattern "example.com"  also
+              matches  subdomains  of  example.com,  instead  of  requiring an
               explicit ".example.com" pattern.
 
        <b><a href="postconf.5.html#smtpd_client_restrictions">smtpd_client_restrictions</a> (empty)</b>
-              Optional  restrictions  that  the Postfix SMTP server applies in
+              Optional restrictions that the Postfix SMTP  server  applies  in
               the context of a client connection request.
 
        <b><a href="postconf.5.html#smtpd_helo_required">smtpd_helo_required</a> (no)</b>
-              Require that a remote SMTP client  introduces  itself  with  the
-              HELO  or  EHLO  command before sending the MAIL command or other
+              Require  that  a  remote  SMTP client introduces itself with the
+              HELO or EHLO command before sending the MAIL  command  or  other
               commands that require EHLO negotiation.
 
        <b><a href="postconf.5.html#smtpd_helo_restrictions">smtpd_helo_restrictions</a> (empty)</b>
-              Optional restrictions that the Postfix SMTP  server  applies  in
+              Optional  restrictions  that  the Postfix SMTP server applies in
               the context of a client HELO command.
 
        <b><a href="postconf.5.html#smtpd_sender_restrictions">smtpd_sender_restrictions</a> (empty)</b>
-              Optional  restrictions  that  the Postfix SMTP server applies in
+              Optional restrictions that the Postfix SMTP  server  applies  in
               the context of a client MAIL FROM command.
 
        <b><a href="postconf.5.html#smtpd_recipient_restrictions">smtpd_recipient_restrictions</a> (see 'postconf -d' output)</b>
-              Optional restrictions that the Postfix SMTP  server  applies  in
-              the    context    of   a   client   RCPT   TO   command,   after
+              Optional  restrictions  that  the Postfix SMTP server applies in
+              the   context   of   a   client   RCPT   TO    command,    after
               <a href="postconf.5.html#smtpd_relay_restrictions">smtpd_relay_restrictions</a>.
 
        <b><a href="postconf.5.html#smtpd_etrn_restrictions">smtpd_etrn_restrictions</a> (empty)</b>
-              Optional restrictions that the Postfix SMTP  server  applies  in
+              Optional  restrictions  that  the Postfix SMTP server applies in
               the context of a client ETRN command.
 
        <b><a href="postconf.5.html#allow_untrusted_routing">allow_untrusted_routing</a> (no)</b>
-              Forward       mail       with      sender-specified      routing
-              (user[@%!]remote[@%!]site) from untrusted  clients  to  destina-
+              Forward      mail      with       sender-specified       routing
+              (user[@%!]remote[@%!]site)  from  untrusted  clients to destina-
               tions matching $<a href="postconf.5.html#relay_domains">relay_domains</a>.
 
        <b><a href="postconf.5.html#smtpd_restriction_classes">smtpd_restriction_classes</a> (empty)</b>
               User-defined aliases for groups of access restrictions.
 
        <b><a href="postconf.5.html#smtpd_null_access_lookup_key">smtpd_null_access_lookup_key</a> (</b>&lt;&gt;<b>)</b>
-              The  lookup  key  to be used in SMTP <a href="access.5.html"><b>access</b>(5)</a> tables instead of
+              The lookup key to be used in SMTP <a href="access.5.html"><b>access</b>(5)</a>  tables  instead  of
               the null sender address.
 
        <b><a href="postconf.5.html#permit_mx_backup_networks">permit_mx_backup_networks</a> (empty)</b>
-              Restrict the use of the <a href="postconf.5.html#permit_mx_backup">permit_mx_backup</a> SMTP access feature  to
+              Restrict  the use of the <a href="postconf.5.html#permit_mx_backup">permit_mx_backup</a> SMTP access feature to
               only domains whose primary MX hosts match the listed networks.
 
        Available in Postfix version 2.0 and later:
@@ -1156,19 +1163,19 @@ SMTPD(8)                                                              SMTPD(8)
               applies in the context of the SMTP DATA command.
 
        <b><a href="postconf.5.html#smtpd_expansion_filter">smtpd_expansion_filter</a> (see 'postconf -d' output)</b>
-              What characters are allowed in $name  expansions  of  RBL  reply
+              What  characters  are  allowed  in $name expansions of RBL reply
               templates.
 
        Available in Postfix version 2.1 and later:
 
        <b><a href="postconf.5.html#smtpd_reject_unlisted_sender">smtpd_reject_unlisted_sender</a> (no)</b>
-              Request  that  the Postfix SMTP server rejects mail from unknown
-              sender addresses, even when no  explicit  <a href="postconf.5.html#reject_unlisted_sender">reject_unlisted_sender</a>
+              Request that the Postfix SMTP server rejects mail  from  unknown
+              sender  addresses,  even when no explicit <a href="postconf.5.html#reject_unlisted_sender">reject_unlisted_sender</a>
               access restriction is specified.
 
        <b><a href="postconf.5.html#smtpd_reject_unlisted_recipient">smtpd_reject_unlisted_recipient</a> (yes)</b>
-              Request  that  the  Postfix SMTP server rejects mail for unknown
-              recipient     addresses,     even     when      no      explicit
+              Request that the Postfix SMTP server rejects  mail  for  unknown
+              recipient      addresses,      even     when     no     explicit
               <a href="postconf.5.html#reject_unlisted_recipient">reject_unlisted_recipient</a> access restriction is specified.
 
        Available in Postfix version 2.2 and later:
@@ -1182,17 +1189,17 @@ SMTPD(8)                                                              SMTPD(8)
        <b><a href="postconf.5.html#smtpd_relay_restrictions">smtpd_relay_restrictions</a> (<a href="postconf.5.html#permit_mynetworks">permit_mynetworks</a>, <a href="postconf.5.html#permit_sasl_authenticated">permit_sasl_authenticated</a>,</b>
        <b><a href="postconf.5.html#defer_unauth_destination">defer_unauth_destination</a>)</b>
               Access restrictions for mail relay control that the Postfix SMTP
-              server  applies  in  the  context of the RCPT TO command, before
+              server applies in the context of the  RCPT  TO  command,  before
               <a href="postconf.5.html#smtpd_recipient_restrictions">smtpd_recipient_restrictions</a>.
 
 <b><a name="sender_and_recipient_address_verification_controls">SENDER AND RECIPIENT ADDRESS VERIFICATION CONTROLS</a></b>
-       Postfix version 2.1 introduces sender and recipient  address  verifica-
+       Postfix  version  2.1 introduces sender and recipient address verifica-
        tion.  This feature is implemented by sending probe email messages that
        are  not  actually  delivered.   This  feature  is  requested  via  the
-       <a href="postconf.5.html#reject_unverified_sender">reject_unverified_sender</a>    and    <a href="postconf.5.html#reject_unverified_recipient">reject_unverified_recipient</a>   access
-       restrictions.  The status of verification probes is maintained  by  the
-       <a href="verify.8.html"><b>verify</b>(8)</a>  server.  See the file <a href="ADDRESS_VERIFICATION_README.html">ADDRESS_VERIFICATION_README</a> for infor-
-       mation about how to configure and operate the Postfix  sender/recipient
+       <a href="postconf.5.html#reject_unverified_sender">reject_unverified_sender</a>   and    <a href="postconf.5.html#reject_unverified_recipient">reject_unverified_recipient</a>    access
+       restrictions.   The  status of verification probes is maintained by the
+       <a href="verify.8.html"><b>verify</b>(8)</a> server.  See the file <a href="ADDRESS_VERIFICATION_README.html">ADDRESS_VERIFICATION_README</a> for  infor-
+       mation  about how to configure and operate the Postfix sender/recipient
        address verification service.
 
        <b><a href="postconf.5.html#address_verify_poll_count">address_verify_poll_count</a> (normal: 3, <a href="STRESS_README.html">overload</a>: 1)</b>
@@ -1204,7 +1211,7 @@ SMTPD(8)                                                              SMTPD(8)
               fication request in progress.
 
        <b><a href="postconf.5.html#address_verify_sender">address_verify_sender</a> ($<a href="postconf.5.html#double_bounce_sender">double_bounce_sender</a>)</b>
-              The  sender address to use in address verification probes; prior
+              The sender address to use in address verification probes;  prior
               to Postfix 2.5 the default was "postmaster".
 
        <b><a href="postconf.5.html#unverified_sender_reject_code">unverified_sender_reject_code</a> (450)</b>
@@ -1212,18 +1219,18 @@ SMTPD(8)                                                              SMTPD(8)
               address is rejected by the <a href="postconf.5.html#reject_unverified_sender">reject_unverified_sender</a> restriction.
 
        <b><a href="postconf.5.html#unverified_recipient_reject_code">unverified_recipient_reject_code</a> (450)</b>
-              The numerical Postfix SMTP  server  response  when  a  recipient
-              address  is rejected by the <a href="postconf.5.html#reject_unverified_recipient">reject_unverified_recipient</a> restric-
+              The  numerical  Postfix  SMTP  server  response when a recipient
+              address is rejected by the <a href="postconf.5.html#reject_unverified_recipient">reject_unverified_recipient</a>  restric-
               tion.
 
        Available in Postfix version 2.6 and later:
 
        <b><a href="postconf.5.html#unverified_sender_defer_code">unverified_sender_defer_code</a> (450)</b>
-              The numerical Postfix SMTP server response code  when  a  sender
+              The  numerical  Postfix  SMTP server response code when a sender
               address probe fails due to a temporary error condition.
 
        <b><a href="postconf.5.html#unverified_recipient_defer_code">unverified_recipient_defer_code</a> (450)</b>
-              The  numerical  Postfix  SMTP  server  response when a recipient
+              The numerical Postfix SMTP  server  response  when  a  recipient
               address probe fails due to a temporary error condition.
 
        <b><a href="postconf.5.html#unverified_sender_reject_reason">unverified_sender_reject_reason</a> (empty)</b>
@@ -1235,17 +1242,17 @@ SMTPD(8)                                                              SMTPD(8)
               <a href="postconf.5.html#reject_unverified_recipient">reject_unverified_recipient</a>.
 
        <b><a href="postconf.5.html#unverified_sender_tempfail_action">unverified_sender_tempfail_action</a> ($<a href="postconf.5.html#reject_tempfail_action">reject_tempfail_action</a>)</b>
-              The Postfix SMTP server's action  when  <a href="postconf.5.html#reject_unverified_sender">reject_unverified_sender</a>
+              The  Postfix  SMTP server's action when <a href="postconf.5.html#reject_unverified_sender">reject_unverified_sender</a>
               fails due to a temporary error condition.
 
        <b><a href="postconf.5.html#unverified_recipient_tempfail_action">unverified_recipient_tempfail_action</a> ($<a href="postconf.5.html#reject_tempfail_action">reject_tempfail_action</a>)</b>
-              The  Postfix SMTP server's action when <a href="postconf.5.html#reject_unverified_recipient">reject_unverified_recipi</a>-
+              The Postfix SMTP server's action when  <a href="postconf.5.html#reject_unverified_recipient">reject_unverified_recipi</a>-
               <a href="postconf.5.html#reject_unverified_recipient">ent</a> fails due to a temporary error condition.
 
        Available with Postfix 2.9 and later:
 
        <b><a href="postconf.5.html#address_verify_sender_ttl">address_verify_sender_ttl</a> (0s)</b>
-              The time  between  changes  in  the  time-dependent  portion  of
+              The  time  between  changes  in  the  time-dependent  portion of
               address verification probe sender addresses.
 
 <b><a name="access_control_responses">ACCESS CONTROL RESPONSES</a></b>
@@ -1257,36 +1264,36 @@ SMTPD(8)                                                              SMTPD(8)
               map "reject" action.
 
        <b><a href="postconf.5.html#defer_code">defer_code</a> (450)</b>
-              The  numerical  Postfix  SMTP server response code when a remote
+              The numerical Postfix SMTP server response code  when  a  remote
               SMTP client request is rejected by the "defer" restriction.
 
        <b><a href="postconf.5.html#invalid_hostname_reject_code">invalid_hostname_reject_code</a> (501)</b>
-              The numerical Postfix SMTP server response code when the  client
-              HELO   or   EHLO   command   parameter   is   rejected   by  the
+              The  numerical Postfix SMTP server response code when the client
+              HELO  or   EHLO   command   parameter   is   rejected   by   the
               <a href="postconf.5.html#reject_invalid_helo_hostname">reject_invalid_helo_hostname</a> restriction.
 
        <b><a href="postconf.5.html#maps_rbl_reject_code">maps_rbl_reject_code</a> (554)</b>
-              The numerical Postfix SMTP server response code  when  a  remote
-              SMTP   client  request  is  blocked  by  the  <a href="postconf.5.html#reject_rbl_client">reject_rbl_client</a>,
+              The  numerical  Postfix  SMTP server response code when a remote
+              SMTP  client  request  is  blocked  by  the   <a href="postconf.5.html#reject_rbl_client">reject_rbl_client</a>,
               <a href="postconf.5.html#reject_rhsbl_client">reject_rhsbl_client</a>,                <a href="postconf.5.html#reject_rhsbl_reverse_client">reject_rhsbl_reverse_client</a>,
               <a href="postconf.5.html#reject_rhsbl_sender">reject_rhsbl_sender</a> or <a href="postconf.5.html#reject_rhsbl_recipient">reject_rhsbl_recipient</a> restriction.
 
        <b><a href="postconf.5.html#non_fqdn_reject_code">non_fqdn_reject_code</a> (504)</b>
-              The  numerical  Postfix  SMTP  server  reply  code when a client
-              request  is  rejected  by   the   <a href="postconf.5.html#reject_non_fqdn_helo_hostname">reject_non_fqdn_helo_hostname</a>,
+              The numerical Postfix SMTP  server  reply  code  when  a  client
+              request   is   rejected  by  the  <a href="postconf.5.html#reject_non_fqdn_helo_hostname">reject_non_fqdn_helo_hostname</a>,
               <a href="postconf.5.html#reject_non_fqdn_sender">reject_non_fqdn_sender</a> or <a href="postconf.5.html#reject_non_fqdn_recipient">reject_non_fqdn_recipient</a> restriction.
 
        <b><a href="postconf.5.html#plaintext_reject_code">plaintext_reject_code</a> (450)</b>
-              The numerical Postfix SMTP server response code when  a  request
+              The  numerical  Postfix SMTP server response code when a request
               is rejected by the <b><a href="postconf.5.html#reject_plaintext_session">reject_plaintext_session</a></b> restriction.
 
        <b><a href="postconf.5.html#reject_code">reject_code</a> (554)</b>
-              The  numerical  Postfix  SMTP server response code when a remote
+              The numerical Postfix SMTP server response code  when  a  remote
               SMTP client request is rejected by the "reject" restriction.
 
        <b><a href="postconf.5.html#relay_domains_reject_code">relay_domains_reject_code</a> (554)</b>
-              The numerical Postfix SMTP server response code  when  a  client
-              request  is  rejected by the <a href="postconf.5.html#reject_unauth_destination">reject_unauth_destination</a> recipient
+              The  numerical  Postfix  SMTP server response code when a client
+              request is rejected by the  <a href="postconf.5.html#reject_unauth_destination">reject_unauth_destination</a>  recipient
               restriction.
 
        <b><a href="postconf.5.html#unknown_address_reject_code">unknown_address_reject_code</a> (450)</b>
@@ -1294,24 +1301,24 @@ SMTPD(8)                                                              SMTPD(8)
               a sender or recipient address because its domain is unknown.
 
        <b><a href="postconf.5.html#unknown_client_reject_code">unknown_client_reject_code</a> (450)</b>
-              The  numerical  Postfix  SMTP server response code when a client
-              without valid address  &lt;=&gt;  name  mapping  is  rejected  by  the
+              The numerical Postfix SMTP server response code  when  a  client
+              without  valid  address  &lt;=&gt;  name  mapping  is  rejected by the
               <a href="postconf.5.html#reject_unknown_client_hostname">reject_unknown_client_hostname</a> restriction.
 
        <b><a href="postconf.5.html#unknown_hostname_reject_code">unknown_hostname_reject_code</a> (450)</b>
-              The  numerical  Postfix SMTP server response code when the host-
-              name specified with the HELO or EHLO command is rejected by  the
+              The numerical Postfix SMTP server response code when  the  host-
+              name  specified with the HELO or EHLO command is rejected by the
               <a href="postconf.5.html#reject_unknown_helo_hostname">reject_unknown_helo_hostname</a> restriction.
 
        Available in Postfix version 2.0 and later:
 
        <b><a href="postconf.5.html#default_rbl_reply">default_rbl_reply</a> (see 'postconf -d' output)</b>
-              The  default Postfix SMTP server response template for a request
+              The default Postfix SMTP server response template for a  request
               that is rejected by an RBL-based restriction.
 
        <b><a href="postconf.5.html#multi_recipient_bounce_reject_code">multi_recipient_bounce_reject_code</a> (550)</b>
-              The numerical Postfix SMTP server response code  when  a  remote
-              SMTP  client  request  is  blocked  by  the <a href="postconf.5.html#reject_multi_recipient_bounce">reject_multi_recipi</a>-
+              The  numerical  Postfix  SMTP server response code when a remote
+              SMTP client  request  is  blocked  by  the  <a href="postconf.5.html#reject_multi_recipient_bounce">reject_multi_recipi</a>-
               <a href="postconf.5.html#reject_multi_recipient_bounce">ent_bounce</a> restriction.
 
        <b><a href="postconf.5.html#rbl_reply_maps">rbl_reply_maps</a> (empty)</b>
@@ -1321,52 +1328,52 @@ SMTPD(8)                                                              SMTPD(8)
 
        <b><a href="postconf.5.html#access_map_defer_code">access_map_defer_code</a> (450)</b>
               The numerical Postfix SMTP server response code for an <a href="access.5.html"><b>access</b>(5)</a>
-              map    "defer"    action,    including    "<a href="postconf.5.html#defer_if_permit">defer_if_permit</a>"   or
+              map   "defer"    action,    including    "<a href="postconf.5.html#defer_if_permit">defer_if_permit</a>"    or
               "<a href="postconf.5.html#defer_if_reject">defer_if_reject</a>".
 
        <b><a href="postconf.5.html#reject_tempfail_action">reject_tempfail_action</a> (<a href="postconf.5.html#defer_if_permit">defer_if_permit</a>)</b>
-              The Postfix SMTP server's action when a reject-type  restriction
+              The  Postfix SMTP server's action when a reject-type restriction
               fails due to a temporary error condition.
 
        <b><a href="postconf.5.html#unknown_helo_hostname_tempfail_action">unknown_helo_hostname_tempfail_action</a> ($<a href="postconf.5.html#reject_tempfail_action">reject_tempfail_action</a>)</b>
-              The  Postfix SMTP server's action when <a href="postconf.5.html#reject_unknown_helo_hostname">reject_unknown_helo_host</a>-
+              The Postfix SMTP server's action when  <a href="postconf.5.html#reject_unknown_helo_hostname">reject_unknown_helo_host</a>-
               <a href="postconf.5.html#reject_unknown_helo_hostname">name</a> fails due to a temporary error condition.
 
        <b><a href="postconf.5.html#unknown_address_tempfail_action">unknown_address_tempfail_action</a> ($<a href="postconf.5.html#reject_tempfail_action">reject_tempfail_action</a>)</b>
-              The      Postfix      SMTP      server's       action       when
-              <a href="postconf.5.html#reject_unknown_sender_domain">reject_unknown_sender_domain</a>  or <a href="postconf.5.html#reject_unknown_recipient_domain">reject_unknown_recipient_domain</a>
+              The       Postfix       SMTP      server's      action      when
+              <a href="postconf.5.html#reject_unknown_sender_domain">reject_unknown_sender_domain</a> or  <a href="postconf.5.html#reject_unknown_recipient_domain">reject_unknown_recipient_domain</a>
               fail due to a temporary error condition.
 
 <b><a name="miscellaneous_controls">MISCELLANEOUS CONTROLS</a></b>
        <b><a href="postconf.5.html#config_directory">config_directory</a> (see 'postconf -d' output)</b>
-              The default location of the Postfix <a href="postconf.5.html">main.cf</a> and  <a href="master.5.html">master.cf</a>  con-
+              The  default  location of the Postfix <a href="postconf.5.html">main.cf</a> and <a href="master.5.html">master.cf</a> con-
               figuration files.
 
        <b><a href="postconf.5.html#daemon_timeout">daemon_timeout</a> (18000s)</b>
-              How  much  time  a  Postfix  daemon process may take to handle a
+              How much time a Postfix daemon process  may  take  to  handle  a
               request before it is terminated by a built-in watchdog timer.
 
        <b><a href="postconf.5.html#command_directory">command_directory</a> (see 'postconf -d' output)</b>
               The location of all postfix administrative commands.
 
        <b><a href="postconf.5.html#double_bounce_sender">double_bounce_sender</a> (double-bounce)</b>
-              The sender address of postmaster notifications that  are  gener-
+              The  sender  address of postmaster notifications that are gener-
               ated by the mail system.
 
        <b><a href="postconf.5.html#ipc_timeout">ipc_timeout</a> (3600s)</b>
-              The  time  limit  for  sending  or receiving information over an
+              The time limit for sending  or  receiving  information  over  an
               internal communication channel.
 
        <b><a href="postconf.5.html#mail_name">mail_name</a> (Postfix)</b>
-              The mail system name that is displayed in Received: headers,  in
+              The  mail system name that is displayed in Received: headers, in
               the SMTP greeting banner, and in bounced mail.
 
        <b><a href="postconf.5.html#mail_owner">mail_owner</a> (postfix)</b>
-              The  UNIX  system  account  that owns the Postfix queue and most
+              The UNIX system account that owns the  Postfix  queue  and  most
               Postfix daemon processes.
 
        <b><a href="postconf.5.html#max_idle">max_idle</a> (100s)</b>
-              The maximum amount of time that an idle Postfix  daemon  process
+              The  maximum  amount of time that an idle Postfix daemon process
               waits for an incoming connection before terminating voluntarily.
 
        <b><a href="postconf.5.html#max_use">max_use</a> (100)</b>
@@ -1377,11 +1384,11 @@ SMTPD(8)                                                              SMTPD(8)
               The internet hostname of this mail system.
 
        <b><a href="postconf.5.html#mynetworks">mynetworks</a> (see 'postconf -d' output)</b>
-              The  list of "trusted" remote SMTP clients that have more privi-
+              The list of "trusted" remote SMTP clients that have more  privi-
               leges than "strangers".
 
        <b><a href="postconf.5.html#myorigin">myorigin</a> ($<a href="postconf.5.html#myhostname">myhostname</a>)</b>
-              The domain name that locally-posted mail appears to  come  from,
+              The  domain  name that locally-posted mail appears to come from,
               and that locally posted mail is delivered to.
 
        <b><a href="postconf.5.html#process_id">process_id</a> (read-only)</b>
@@ -1394,24 +1401,24 @@ SMTPD(8)                                                              SMTPD(8)
               The location of the Postfix top-level queue directory.
 
        <b><a href="postconf.5.html#recipient_delimiter">recipient_delimiter</a> (empty)</b>
-              The  set of characters that can separate an email address local-
+              The set of characters that can separate an email address  local-
               part, user name, or a .forward file name from its extension.
 
        <b><a href="postconf.5.html#smtpd_banner">smtpd_banner</a> ($<a href="postconf.5.html#myhostname">myhostname</a> ESMTP $<a href="postconf.5.html#mail_name">mail_name</a>)</b>
-              The text that follows the 220 status code in the  SMTP  greeting
+              The  text  that follows the 220 status code in the SMTP greeting
               banner.
 
        <b><a href="postconf.5.html#syslog_facility">syslog_facility</a> (mail)</b>
               The syslog facility of Postfix logging.
 
        <b><a href="postconf.5.html#syslog_name">syslog_name</a> (see 'postconf -d' output)</b>
-              A  prefix  that  is  prepended  to  the  process  name in syslog
+              A prefix that  is  prepended  to  the  process  name  in  syslog
               records, so that, for example, "smtpd" becomes "prefix/smtpd".
 
        Available in Postfix version 2.2 and later:
 
        <b><a href="postconf.5.html#smtpd_forbidden_commands">smtpd_forbidden_commands</a> (CONNECT GET POST <a href="regexp_table.5.html">regexp</a>:{{/^[^A-Z]/ Bogus}})</b>
-              List of commands that cause the Postfix SMTP server  to  immedi-
+              List  of  commands that cause the Postfix SMTP server to immedi-
               ately terminate the session with a 221 code.
 
        Available in Postfix version 2.5 and later:
@@ -1428,20 +1435,20 @@ SMTPD(8)                                                              SMTPD(8)
        Available in Postfix 3.4 and later:
 
        <b><a href="postconf.5.html#smtpd_reject_footer_maps">smtpd_reject_footer_maps</a> (empty)</b>
-              Lookup tables, indexed by the complete Postfix SMTP  server  4xx
+              Lookup  tables,  indexed by the complete Postfix SMTP server 4xx
               or 5xx response, with reject footer templates.
 
        Available in Postfix 3.10 and later:
 
        <b><a href="postconf.5.html#smtpd_hide_client_session">smtpd_hide_client_session</a> (no)</b>
-              Do  not  include  SMTP client session information in the Postfix
+              Do not include SMTP client session information  in  the  Postfix
               SMTP server's Received: message header.
 
        Available in Postfix version 3.11 and later:
 
        <b><a href="postconf.5.html#smtpd_reject_filter_maps">smtpd_reject_filter_maps</a> (empty)</b>
-              An optional filter that can replace a reject response  from  the
-              Postfix  SMTP  server  itself,  or  from  a program that replies
+              An  optional  filter that can replace a reject response from the
+              Postfix SMTP server itself,  or  from  a  program  that  replies
               through the Postfix SMTP server.
 
 <b><a name="see_also">SEE ALSO</a></b>
index 695478942e1e9e645d85d7b519f7551ac0117659..44f4b26087e0c681c47ec2a8c29e22dd2d35fd80 100644 (file)
@@ -172,6 +172,15 @@ BOUNCE(8)                                                            BOUNCE(8)
               Enable  support  for  the  "TLS-Required:  no"  message  header,
               defined in <a href="https://tools.ietf.org/html/rfc8689">RFC 8689</a>.
 
+       Available in Postfix 3.11 and later:
+
+       <b><a href="postconf.5.html#requiretls_redact_dsn">requiretls_redact_dsn</a> (yes)</b>
+              When sending a delivery status notification for an original mes-
+              sage received with the REQUIRETLS option, do not send the origi-
+              nal   message  body  (as  if  that  message  was  received  with
+              "RET=HDRS") and do not enforce REQUIRETLS (as  if  that  message
+              was received without REQUIRETLS).
+
 <b><a name="files">FILES</a></b>
        /var/spool/postfix/bounce/* non-delivery records
        /var/spool/postfix/defer/* non-delivery records
index 9bd730281776e0ed633f46078a2c6d57e76e7a0d..5d2a2557181b21976d1ff682cfa0dea89a47b2d4 100644 (file)
@@ -979,7 +979,7 @@ CCARGS="$CCARGS -DSNAPSHOT"
 
 # Non-production: needs thorough testing, or major changes are still
 # needed before the code stabilizes.
-#CCARGS="$CCARGS -DNONPROD"
+CCARGS="$CCARGS -DNONPROD"
 
 # Workaround: prepend Postfix include files before other include files.
 CCARGS="-I. -I../../include $CCARGS"
index e3bc7a639eb5dd456f94b31ee2b4f8ad87237d18..a3193cf75060c1a3c2412c4f8d7332d011d0fe90 100644 (file)
@@ -158,19 +158,36 @@ Delivery status notification control. Specify either a
 comma\-separated list with one or more of \fBfailure\fR (send
 notification when delivery fails), \fBdelay\fR (send
 notification when delivery is delayed), or \fBsuccess\fR
-(send notification when the message is delivered); or specify
+(send notification after the message is delivered); or specify
 \fBnever\fR (don't send any notifications at all).
 
 This feature is available in Postfix 2.3 and later.
 .IP "\fB\-n\fR (ignored)"
 Backwards compatibility.
-.IP "\fB\-oA\fIalias_database\fR"
-Non\-default alias database. Specify \fIpathname\fR or
-\fItype\fR:\fIpathname\fR. See \fBpostalias\fR(1) for
-details.
+.IP "\fB\-O requiretls=yes\fR"
+.IP "\fB\-O requiretls=no\fR"
+When delivering a message to an SMTP or LMTP server, the
+connection must use TLS with a verified server certificate,
+and that server must support REQUIRETLS. The "requiretls" name
+and option value are case\-insensitive. REQUIRETLS enforcement
+is controlled with the configuration parameters requiretls_enable,
+smtp_requiretls_policy, and lmtp_requiretls_policy.
+
+This feature is available in Postfix 3.11 and later.
+.IP "\fB\-O smtputf8=yes\fR"
+.IP "\fB\-O smtputf8=no\fR"
+When delivering a message to an SMTP or LMTP server, and an
+envelope address or message header contains UTF8 text, that server
+must support SMTPUTF8. The "smtputf8" option name and value
+are case\-insensitive.
+
+This feature is available in Postfix 3.11 and later.
 .IP "\fB\-O \fIoption=value\fR (ignored)"
 Set the named \fIoption\fR to \fIvalue\fR. Use the equivalent
 configuration parameter in \fBmain.cf\fR instead.
+.IP "\fB\-oA\fIalias_database\fR"
+Non\-default alias database. Specify \fIpathname\fR or
+\fItype\fR:\fIpathname\fR. See \fBpostalias\fR(1) for details.
 .IP "\fB\-o7\fR (ignored)"
 .IP "\fB\-o8\fR (ignored)"
 To send 8\-bit or binary content, use an appropriate MIME encapsulation
@@ -462,6 +479,11 @@ these directories belong to additional Postfix instances that share
 the Postfix executable files and documentation with the default
 Postfix instance, and that are started, stopped, etc., together
 with the default Postfix instance.
+.PP
+Postfix 3.11 and later:
+.IP "\fBrequiretls_enable (yes)\fR"
+Enable support for the ESMTP verb "REQUIRETLS" in the "MAIL
+FROM" command.
 .SH "FILES"
 .na
 .nf
index 31bfc03755078761107f0ad57f8295b865ad2a14..e38135a80dd4aef6e1f5a896e26a73129a04b45c 100644 (file)
@@ -3302,6 +3302,11 @@ The LMTP\-specific version of the smtp_reply_filter
 configuration parameter.  See there for details.
 .PP
 This feature is available in Postfix 2.7 and later.
+.SH lmtp_requiretls_policy (default: opportunistic)
+The LMTP\-specific version of the smtp_requiretls_policy
+configuration parameter. See there for details.
+.PP
+This feature is available in Postfix >= 3.11.
 .SH lmtp_rset_timeout (default: 20s)
 The Postfix LMTP client time limit for sending the RSET command,
 and for receiving the remote LMTP server response. The LMTP client
@@ -6607,6 +6612,55 @@ Require that a \fBlocal\fR(8) recipient's home directory exists
 before mail delivery is attempted. By default this test is disabled.
 It can be useful for environments that import home directories to
 the mail server (IMPORTING HOME DIRECTORIES IS NOT RECOMMENDED).
+.SH requiretls_enable (default: yes)
+Enable support for the ESMTP verb "REQUIRETLS" in the "MAIL
+FROM" command. As defined in RFC 8689, when a message specifies
+REQUIRETLS:
+.IP \(bu
+deliveries with SMTP or LMTP must use a TLS connection,
+.IP \(bu
+to a securely looked up MX server (e.g., DNSSEC or MTA\-STS),
+.IP \(bu
+with a matched server certificate (Postfix SMTP or LMTP
+client TLS security levels "secure", "verify", "fingerprint",
+dane\-only, or opportunistic "dane"),
+.IP \(bu
+and the server must announce "REQUIRETLS" support after
+the STARTTLS handshake.
+.br
+.PP
+When delivering a message that specifies REQUIRETLS, the Postfix
+SMTP client will try one or more servers, limited by the
+smtp_mx_address_limit and smtp_mx_session_limit parameters, until
+it finds an MX server that satisfies the above requirements. If
+such a server is not found, the Postfix SMTP or LMTP client returns
+the message as undeliverable.
+.PP
+Notes:
+.IP \(bu
+With the Postfix SMTP or LMTP clients, REQUIRETLS enforcement
+is controlled with smtp_requiretls_policy or lmtp_requiretls_policy. It
+is initially not enforced for deliveries to local servers, including
+LMTP message stores and local content filters.
+.IP \(bu
+The ESMTP REQUIRETLS option overrides the "TLS\-Required:
+no" message header.
+.br
+.PP
+This feature is available in Postfix >= 3.11.
+.SH requiretls_redact_dsn (default: yes)
+When sending a delivery status notification for an original
+message received with the REQUIRETLS option, do not send the original
+message body (as if that message was received with "RET=HDRS") and
+do not enforce REQUIRETLS (as if that message was received without
+REQUIRETLS). For a detailed discussion see RFC 8689 section 5.
+.PP
+Note: the 'reverse' path for sending a delivery status notification
+may differ from the 'forward' path for receiving the original message.
+Not every hop in the reverse path may support REQUIRETLS, even
+though every hop in the forward path supported it. The setting
+"requiretls_redact_dsn = no" may therefore result in the loss of a
+delivery status notification.
 .SH reset_owner_alias (default: no)
 Reset the \fBlocal\fR(8) delivery agent's idea of the owner\-alias
 attribute, when delivering mail to a child alias that does not have
@@ -7917,6 +7971,153 @@ Examples:
 .ad
 .PP
 This feature is available in Postfix 2.7.
+.SH smtp_requiretls_policy (default: see 'postconf \-d smtp_requiretls_policy' output)
+How the Postfix SMTP and LMTP client will enforce REQUIRETLS
+for messages received with the REQUIRETLS option. Policy examples
+for SMTP and LMTP are at the end.
+.IP \(bu
+Specify a list of items, separated with whitespace or
+comma; continue a long line by starting the next line with whitespace.
+.IP \(bu
+Each item must be an action (see below), or a type:table
+lookup table that must return an action (not a type:table).
+.IP \(bu
+A type:table lookup table is searched with the next\-hop
+destination, without any \fI[ ]\fR, \fI:service\fR, or \fI:port\fR.
+.IP \(bu
+The next\-hop destination for TCP connections is the recipient
+domain, but this can be overruled with transport_maps, relayhost,
+content_filter, or other routing features. The next\-hop destination
+for LMTP over UNIX\-domain connections is always the value of
+myhostname.
+.br
+.PP
+Supported actions:
+.IP "\fB enforce \fR"
+Skip connections that do not
+meet RFC 8689 section 4.2 requirements, and skip servers that don't
+announce REQUIRETLS support. Return the message as undeliverable if no
+suitable connection and server are found, and log a "REQUIRETLS
+Failure" event.
+.br
+.IP "\fB opportunistic+starttls \fR"
+Skip servers
+that don't announce STARTTLS support. Return the message as
+undeliverable if no suitable server is found, and log a "REQUIRETLS
+Failure" event.
+.sp
+Request REQUIRETLS if a server supports
+REQUIRETLS, otherwise simply deliver the message and log "REQUIRETLS
+Debug" events when a connection would not meet all RFC 8689 section
+4.2 requirements.
+.sp
+This can be appropriate for an outbound
+perimeter MTA, when forwarding messages from internal systems to
+the Internet, at a time that many domains do not publish DANE or
+MTA\-STS policies.
+.br
+.IP "\fB opportunistic \fR"
+Request REQUIRETLS if
+the server supports REQUIRETLS, otherwise simply deliver the message.
+.sp
+This can be appropriate for an inbound perimeter MTA, when
+forwarding messages from the Internet to internal servers or content
+filters. Internal servers or content filters may not support
+REQUIRETLS, and internal connections may be secured with means other
+than DANE or STS.
+.br
+.IP "\fB disable \fR"
+Disable REQUIRETLS support.
+This may be used as a last\-resort workaround when a server announces
+REQUIRETLS support, but the support is inoperable.
+.br
+.br
+.PP
+Notes:
+.IP \(bu
+Postfix appends an implicit \fBopportunistic+starttls\fR
+action after the end of each policy.
+.IP \(bu
+To match any name below the domain "example.com" specify
+a table entry with the storage key ".example.com" in type:table
+lookup tables that need an exact match. This is appropriate, for
+example, with hash:, btree: or lmdb:.
+.IP \(bu
+Do not specify a match pattern for ".domain" with regexp:,
+pcre:, socketmap:, or tcp:, as smtp_requiretls_policy will
+not query those tables with that form.
+.br
+.PP
+SMTP client examples:
+.IP \(bu
+The default SMTP client REQUIRETLS policy: when a sender
+requests REQUIRETLS, require that external servers support STARTTLS,
+and request REQUIRETLS if an internal or external server supports
+REQUIRETLS.
+.sp
+/etc/postfix/main.cf:
+    smtp_tls_security_level = may
+    smtp_tls_policy_maps = ...dane/sts plugin...
+    smtp_requiretls_policy =
+        inline:{
+            {.$mydomain = opportunistic}
+            {localhost = opportunistic} }
+        opportunistic+starttls
+.fi
+.ad
+.IP \(bu
+As above, with external destinations listed in a separate
+file for easier maintenance.
+.sp
+/etc/postfix/main.cf:
+    smtp_tls_security_level = may
+    smtp_tls_policy_maps = ...dane/sts plugin...
+    smtp_requiretls_policy =
+        inline:{
+            {.$mydomain = opportunistic}
+            {localhost = opportunistic} }
+        hash:/etc/postfix/requiretls\-per\-site
+        opportunistic+starttls
+.sp
+/etc/postfix/requiretls\-per\-site:
+    one.example         enforce
+    two.example         enforce
+    three.example       opportunistic
+    ...
+.fi
+.ad
+.IP \(bu
+Distant future: when a sender requests REQUIRETLS, enforce
+all REQUIRETLS requirements for all external destinations.
+.sp
+/etc/postfix/main.cf:
+    smtp_tls_secure_cert_match = nexthop, dot\-nexthop
+    smtp_tls_policy_maps = ...dane/sts plugin...
+    smtp_requiretls_policy =
+        inline:{
+            {.$mydomain = opportunistic}
+            {localhost = opportunistic} }
+        enforce
+.fi
+.ad
+.br
+.PP
+LMTP client examples:
+.IP \(bu
+The default LMTP client REQUIRETLS policy: when a sender
+requests REQUIRETLS, request REQUIRETLS if the server supports
+REQUIRETLS, otherwise deliver the message as if the sender did not
+request REQUIRETLS. Note: with deliveries over a UNIX\-domain socket,
+the next\-hop destination for lmtp_requiretls_policy lookups will
+be the myhostname parameter value.
+.sp
+/etc/postfix/main.cf:
+    lmtp_requiretls_policy = opportunistic
+.fi
+.ad
+.br
+.PP
+This feature is available in Postfix >= 3.11.
 .SH smtp_rset_timeout (default: 20s)
 The Postfix SMTP client time limit for sending the RSET command,
 and for receiving the remote SMTP server response. The SMTP client
@@ -9107,8 +9308,7 @@ See the documentation of the smtp_tls_policy_maps parameter and
 TLS_README for more information about security levels.
 .PP
 Example:
-.nf
-.na
+.sp
 # Preferred syntax with Postfix >= 3.6:
 smtp_tls_mandatory_protocols = >=TLSv1.2, <=TLSv1.3
 # Legacy syntax:
@@ -9499,8 +9699,7 @@ this protocol via "!TLSv1.3" is supported since Postfix 3.4 (or patch
 releases >= 3.0.14, 3.1.10, 3.2.7 and 3.3.2).
 .PP
 Example:
-.nf
-.na
+.sp
 # Preferred syntax with Postfix >= 3.6:
 smtp_tls_protocols = >=TLSv1, <=TLSv1.3
 # Legacy syntax:
@@ -13312,10 +13511,7 @@ Example: client\-certificate access table, with sha256 fingerprints:
     smtpd_client_restrictions =
         check_ccert_access hash:/etc/postfix/access,
         reject
-.fi
-.ad
-.nf
-.na
+.sp
 /etc/postfix/access:
     # Action folded to next line...
     AF:88:7C:AD:51:95:6F:36:96:...:01:FB:2E:48:CD:AB:49:25:A2:3B
@@ -13579,8 +13775,7 @@ this protocol via "!TLSv1.3" is supported since Postfix 3.4 (or patch
 releases >= 3.0.14, 3.1.10, 3.2.7 and 3.3.2).
 .PP
 Example:
-.nf
-.na
+.sp
 # Preferred syntax with Postfix >= 3.6:
 smtpd_tls_protocols = >=TLSv1, <=TLSv1.3
 # Legacy syntax:
@@ -14599,6 +14794,9 @@ If a message contains a "TLS\-Required: no" header, then Postfix
 will add that header to a delivery status notification for that
 message.
 .PP
+Note: the ESMTP REQUIRETLS option overrides the "TLS\-Required:
+no" message header.
+.PP
 This feature is available in Postfix >= 3.10.
 .SH tls_server_sni_maps (default: empty)
 Optional lookup tables that map names received from remote SMTP
index 781eb86b2e2e0a43aa5d4b374114f40f87e914e1..2e15904ed9e85abff9e45f96ad73a64ecf59fb6d 100644 (file)
@@ -151,6 +151,14 @@ Available in Postfix 3.10 and later:
 .IP "\fBtls_required_enable (yes)\fR"
 Enable support for the "TLS\-Required: no" message header, defined
 in RFC 8689.
+.PP
+Available in Postfix 3.11 and later:
+.IP "\fBrequiretls_redact_dsn (yes)\fR"
+When sending a delivery status notification for an original
+message received with the REQUIRETLS option, do not send the original
+message body (as if that message was received with "RET=HDRS") and
+do not enforce REQUIRETLS (as if that message was received without
+REQUIRETLS).
 .SH "FILES"
 .na
 .nf
index 770a459bcfab73debc05759e636c5a0c5dcde13f..22b7fb4521fb1013ea513a59237a4024ccda7250 100644 (file)
@@ -294,6 +294,14 @@ expands to as many command\-line arguments as there are recipients.
 .sp
 This information is modified by the \fBhqu\fR flags for quoting
 and case folding.
+.IP \fB${requiretls}\fR
+This feature is intended for content filters that pass filtered
+mail to the Postfix sendmail(1) command. The macro expands to
+the Postfix sendmail(1) command\-line option \fB\-Orequiretls=yes\fR
+if the sender requested REQUIRETLS, otherwise it expands to
+\fB\-Orequiretls=no\fR.
+.sp
+This feature is available as of Postfix 3.11.
 .IP \fB${sasl_method}\fR
 This macro expands to the name of the SASL authentication
 mechanism in the AUTH command when the Postfix SMTP server
@@ -462,6 +470,11 @@ Available in Postfix 3.5 and later:
 .IP "\fBinfo_log_address_format (external)\fR"
 The email address form that will be used in non\-debug logging
 (info, warning, etc.).
+.PP
+Available in Postfix 3.11 and later:
+.IP "\fBrequiretls_enable (yes)\fR"
+Enable support for the ESMTP verb "REQUIRETLS" in the "MAIL
+FROM" command.
 .SH "SEE ALSO"
 .na
 .nf
index dde3d5c7dbf998237b28edb35a459337df53ee21..b12529b3edd883b94cb509cf57bba4bc61ff9f69 100644 (file)
@@ -190,7 +190,7 @@ RFC 5321 (SMTP protocol)
 RFC 6531 (Internationalized SMTP)
 RFC 6533 (Internationalized Delivery Status Notifications)
 RFC 7672 (SMTP security via opportunistic DANE TLS)
-RFC 8689 (TLS\-Required message header)
+RFC 8689 (SMTP REQUIRETLS extension, TLS\-Required header)
 .SH DIAGNOSTICS
 .ad
 .fi
@@ -485,7 +485,7 @@ Available in Postfix version 3.9 and later:
 .IP "\fBsmtp_sasl_password_result_delimiter (:)\fR"
 The delimiter between username and password in sasl_passwd_maps lookup
 results.
-.SH "STARTTLS SUPPORT CONTROLS"
+.SH "TLS SUPPORT CONTROLS"
 .na
 .nf
 .ad
@@ -695,7 +695,13 @@ Available in Postfix version 3.11 and later:
 .IP "\fBtls_required_enable (yes)\fR"
 Enable support for the "TLS\-Required: no" message header, defined
 in RFC 8689.
-.SH "OBSOLETE STARTTLS CONTROLS"
+.IP "\fBrequiretls_enable (yes)\fR"
+Enable support for the ESMTP verb "REQUIRETLS" in the "MAIL
+FROM" command.
+.IP "\fBsmtp_requiretls_policy (see 'postconf -d smtp_requiretls_policy' output)\fR"
+How the Postfix SMTP and LMTP client will enforce REQUIRETLS
+for messages received with the REQUIRETLS option.
+.SH "OBSOLETE TLS CONTROLS"
 .na
 .nf
 .ad
index 616a4a14af5209ef3eb8a12661703d40dfc69aef..2aa74e8d03889b51d71868840792cac4265e08f4 100644 (file)
@@ -67,6 +67,7 @@ RFC 5321 (SMTP protocol)
 RFC 6531 (Internationalized SMTP)
 RFC 6533 (Internationalized Delivery Status Notifications)
 RFC 7505 ("Null MX" No Service Resource Record)
+RFC 8689 (SMTP REQUIRETLS extension)
 .SH DIAGNOSTICS
 .ad
 .fi
@@ -402,7 +403,7 @@ Available in Postfix 3.6 and later:
 .IP "\fBsmtpd_sasl_mechanism_filter (!external, static:rest)\fR"
 If non\-empty, a filter for the SASL mechanism names that the
 Postfix SMTP server will announce in the EHLO response.
-.SH "STARTTLS SUPPORT CONTROLS"
+.SH "TLS SUPPORT CONTROLS"
 .na
 .nf
 .ad
@@ -578,7 +579,12 @@ Available in Postfix version 3.9 and later:
 Request that remote SMTP clients send an RFC7250 raw public key
 instead of an X.509 certificate, when asking for or requiring client
 authentication.
-.SH "OBSOLETE STARTTLS CONTROLS"
+.PP
+Available in Postfix version 3.10 and later:
+.IP "\fBrequiretls_enable (yes)\fR"
+Enable support for the ESMTP verb "REQUIRETLS" in the "MAIL
+FROM" command.
+.SH "OBSOLETE TLS CONTROLS"
 .na
 .nf
 .ad
index 83a0beeee6e724aeafb9a8a10c44209aa38f77ff..3c89b8abba0cee0b15086eb9f7872ce1537304b6 100755 (executable)
@@ -55,6 +55,7 @@ while(<>) {
     $block =~ s/<i>/\\fI/g;
     $block =~ s/<\/b>/\\fR/g;
     $block =~ s/<\/i>/\\fR/g;
+    $block =~ s/\s*<\/p(re)?>\s*<p(re)?>\s*/\n.sp\n/g;
     $block =~ s/^(<p(re)?>)/.PP\n\1/ if ($wantpp);
     $block =~ s/<p> */\n/g;
     $block =~ s/ *<\/p>/\n/g;
index 2b174bcacd1e57586e6a5aa70217477fd5970b12..da426545fc2b6d14893ce08f4544335f737c2d75 100755 (executable)
@@ -1191,6 +1191,10 @@ while (<>) {
     s;\bignore_srv_lookup_error\b;<a href="postconf.5.html#ignore_srv_lookup_error">$&</a>;g;
 
     s;\btls_required_enable\b;<a href="postconf.5.html#tls_required_enable">$&</a>;g;
+    s;\brequiretls_enable\b;<a href="postconf.5.html#requiretls_enable">$&</a>;g;
+    s;\bsmtp_requiretls_policy\b;<a href="postconf.5.html#smtp_requiretls_policy">$&</a>;g;
+    s;\blmtp_requiretls_policy\b;<a href="postconf.5.html#lmtp_requiretls_policy">$&</a>;g;
+    s;\brequiretls_redact_dsn\b;<a href="postconf.5.html#requiretls_redact_dsn">$&</a>;g;
     s;\bfull_name_encoding_charset\b;<a href="postconf.5.html#full_name_encoding_charset">$&</a>;g;
     s;\bsmtpd_hide_client_session\b;<a href="postconf.5.html#smtpd_hide_client_session">$&</a>;g;
 
index cbaf202ec5ba1e255f73d6610b20bf25b67a8462..a06248a7be1dec8ed0330f838125c14064e4dd88 100644 (file)
@@ -19634,12 +19634,238 @@ no enforcement of TLS policy. This disables TLS policy lookup, and
 limits the Postfix SMTP client
 TLS security level to "may", that is, do not verify remote SMTP
 server certificates, and fall back to plaintext if TLS is unavailable.
-If a message contains a "TLS-Required: no" header, then Postfix
-will add that header to a delivery status notification for that
+If a message contains a "TLS-Required: no" header, then Postfix 
+will add that header to a delivery status notification for that 
 message. </p>
 
+<p> Note: the ESMTP REQUIRETLS option overrides the "TLS-Required:
+no" message header.  </p>
+
 <p> This feature is available in Postfix &ge; 3.10. </p>
 
+%PARAM requiretls_enable yes
+
+<p> Enable support for the ESMTP verb "REQUIRETLS" in the "MAIL
+FROM" command. As defined in RFC 8689, when a message specifies
+REQUIRETLS: </p>
+
+<ul>
+
+<li> <p> deliveries with SMTP or LMTP must use a TLS connection, </p>
+
+<li> <p> to a securely looked up MX server (e.g., DNSSEC or MTA-STS),
+</p>
+
+<li> <p> with a matched server certificate (Postfix SMTP or LMTP
+client TLS security levels "secure", "verify", "fingerprint",
+dane-only, or opportunistic "dane"), </p>
+
+<li> <p> and the server must announce "REQUIRETLS" support after
+the STARTTLS handshake. </p>
+
+</ul>
+
+<p> When delivering a message that specifies REQUIRETLS, the Postfix
+SMTP client will try one or more servers, limited by the
+smtp_mx_address_limit and smtp_mx_session_limit parameters, until
+it finds an MX server that satisfies the above requirements. If
+such a server is not found, the Postfix SMTP or LMTP client returns
+the message as undeliverable. </p>
+
+<p> Notes: </p>
+
+<ul>
+
+<li> <p> With the Postfix SMTP or LMTP clients, REQUIRETLS enforcement
+is controlled with smtp_requiretls_policy or lmtp_requiretls_policy. It
+is initially not enforced for deliveries to local servers, including
+LMTP message stores and local content filters. </p>
+
+<li> <p> The ESMTP REQUIRETLS option overrides the "TLS-Required:
+no" message header. </p>
+
+</ul>
+
+<p> This feature is available in Postfix &ge; 3.11. </p>
+
+%PARAM requiretls_redact_dsn yes
+
+<p> When sending a delivery status notification for an original
+message received with the REQUIRETLS option, do not send the original
+message body (as if that message was received with "RET=HDRS") and
+do not enforce REQUIRETLS (as if that message was received without
+REQUIRETLS). For a detailed discussion see RFC 8689 section 5. </p>
+
+<p> Note: the 'reverse' path for sending a delivery status notification
+may differ from the 'forward' path for receiving the original message. 
+Not every hop in the reverse path may support REQUIRETLS, even
+though every hop in the forward path supported it. The setting
+"requiretls_redact_dsn = no" may therefore result in the loss of a
+delivery status notification. </p>
+
+%PARAM smtp_requiretls_policy see 'postconf -d smtp_requiretls_policy' output
+
+<p> How the Postfix SMTP and LMTP client will enforce REQUIRETLS
+for messages received with the REQUIRETLS option. Policy examples
+for SMTP and LMTP are at the end. </p>
+
+<ul>
+
+<li> <p> Specify a list of items, separated with whitespace or
+comma; continue a long line by starting the next line with whitespace.
+</p>
+
+<li> <p> Each item must be an action (see below), or a type:table
+lookup table that must return an action (not a type:table). </p>
+
+<li> A type:table lookup table is searched with the next-hop
+destination, without any <i>[ ]</i>, <i>:service</i>, or <i>:port</i>.
+</p>
+
+<li> <p> The next-hop destination for TCP connections is the recipient
+domain, but this can be overruled with transport_maps, relayhost,
+content_filter, or other routing features. The next-hop destination
+for LMTP over UNIX-domain connections is always the value of
+myhostname. </p>
+
+</ul>
+
+<p> Supported actions: </p>
+
+<dl>
+
+<dt> <b> enforce </b> </dt> <dd>  <p> Skip connections that do not
+meet RFC 8689 section 4.2 requirements, and skip servers that don't
+announce REQUIRETLS support. Return the message as undeliverable if no
+suitable connection and server are found, and log a "REQUIRETLS
+Failure" event. </p> </dd>
+
+<dt> <b> opportunistic+starttls </b> </dt> <dd> <p> Skip servers
+that don't announce STARTTLS support. Return the message as
+undeliverable if no suitable server is found, and log a "REQUIRETLS
+Failure" event. </p> <p> Request REQUIRETLS if a server supports
+REQUIRETLS, otherwise simply deliver the message and log "REQUIRETLS
+Debug" events when a connection would not meet all RFC 8689 section
+4.2 requirements. </p> <p> This can be appropriate for an outbound
+perimeter MTA, when forwarding messages from internal systems to
+the Internet, at a time that many domains do not publish DANE or
+MTA-STS policies. </p> </dd>
+
+<dt> <b> opportunistic </b> </dt> <dd> <p> Request REQUIRETLS if
+the server supports REQUIRETLS, otherwise simply deliver the message.
+</p> <p> This can be appropriate for an inbound perimeter MTA, when
+forwarding messages from the Internet to internal servers or content
+filters. Internal servers or content filters may not support
+REQUIRETLS, and internal connections may be secured with means other
+than DANE or STS. </p> </dd>
+
+<dt> <b> disable </b> </dt> <dd> <p> Disable REQUIRETLS support.
+This may be used as a last-resort workaround when a server announces
+REQUIRETLS support, but the support is inoperable. </p></dd>
+
+</dl>
+
+<p> Notes: </p>
+
+<ul> 
+
+<li> <p> Postfix appends an implicit <b>opportunistic+starttls</b>
+action after the end of each policy. </p>
+
+<li> <p> To match any name below the domain "example.com" specify
+a table entry with the storage key ".example.com" in type:table
+lookup tables that need an exact match. This is appropriate, for
+example, with hash:, btree: or lmdb:. </p>
+
+<li> <p> Do not specify a match pattern for ".domain" with regexp:,
+pcre:, socketmap:, or tcp:, as smtp_requiretls_policy will
+not query those tables with that form. </p>
+
+</ul>
+
+<p> SMTP client examples: </p>
+
+<ul>
+
+<li> <p> The default SMTP client REQUIRETLS policy: when a sender
+requests REQUIRETLS, require that external servers support STARTTLS,
+and request REQUIRETLS if an internal or external server supports
+REQUIRETLS. </p>
+<pre>
+/etc/postfix/main.cf:
+    smtp_tls_security_level = may
+    smtp_tls_policy_maps = ...dane/sts plugin...
+    smtp_requiretls_policy =
+        inline:{
+            {.$mydomain = opportunistic}
+            {localhost = opportunistic} }
+       opportunistic+starttls
+</pre>
+
+<li> <p> As above, with external destinations listed in a separate
+file for easier maintenance. </p>
+<pre>
+/etc/postfix/main.cf:
+    smtp_tls_security_level = may
+    smtp_tls_policy_maps = ...dane/sts plugin...
+    smtp_requiretls_policy =
+        inline:{
+            {.$mydomain = opportunistic}
+            {localhost = opportunistic} }
+       hash:/etc/postfix/requiretls-per-site
+       opportunistic+starttls
+</pre>
+<pre>
+/etc/postfix/requiretls-per-site:
+    one.example        enforce
+    two.example        enforce
+    three.example      opportunistic
+    ...
+</pre>
+
+<li> <p> Distant future: when a sender requests REQUIRETLS, enforce
+all REQUIRETLS requirements for all external destinations. </p>
+<pre>
+/etc/postfix/main.cf:
+    smtp_tls_secure_cert_match = nexthop, dot-nexthop
+    smtp_tls_policy_maps = ...dane/sts plugin...
+    smtp_requiretls_policy =
+        inline:{
+            {.$mydomain = opportunistic}
+            {localhost = opportunistic} }
+        enforce
+</pre>
+
+</ul>
+
+<p>
+LMTP client examples:
+</p>
+
+<ul>
+
+<li> <p> The default LMTP client REQUIRETLS policy: when a sender
+requests REQUIRETLS, request REQUIRETLS if the server supports
+REQUIRETLS, otherwise deliver the message as if the sender did not
+request REQUIRETLS. Note: with deliveries over a UNIX-domain socket,
+the next-hop destination for lmtp_requiretls_policy lookups will
+be the myhostname parameter value. </p>
+<pre>
+/etc/postfix/main.cf:
+    lmtp_requiretls_policy = opportunistic
+</pre>
+
+</ul>
+
+<p> This feature is available in Postfix &ge; 3.11. </p>
+
+%PARAM lmtp_requiretls_policy opportunistic
+
+<p> The LMTP-specific version of the smtp_requiretls_policy
+configuration parameter. See there for details. </p>
+
+<p> This feature is available in Postfix &ge; 3.11. </p>
+
 %PARAM smtpd_hide_client_session no
 
 <p> Do not include SMTP client session information in the Postfix
index 3b3c4b93fb3a27dd5558ebd8c6e8b0be80653094..a18a1c0e4335cd08f1ab8cc11dcf1be5ea5269e7 100644 (file)
@@ -1664,6 +1664,9 @@ REQUIRETLS
 RequireTLS
 requiretls
 sendopts
+TODO
+Onoop
+Orequiretls
 tz
 GID
 SIGKILL
@@ -1685,3 +1688,4 @@ PRELOAD
 rhansen
 XDG
 crosstalk
+HDRS
index 78427bde68dc131162acaf657195547648f5017c..f22598cebbf0e57f127d1862c1a0b0ca0d0036d3 100644 (file)
@@ -159,10 +159,17 @@ proto  proto socketmap_table
  qmgr qmgr_deliver c qmgr qmgr_message c qmqpd qmqpd c 
  smtp smtp_proto c smtpd smtpd c verify verify c 
  operations Files cleanup cleanup h cleanup cleanup_message c 
- proto postconf proto pipe pipe c 
+ global ehlo_mask_test c local forward c smtpd smtpd c 
+ more alternate MX servers to try Files smtp smtp h 
+ Files sendmail sendmail c global rec_types h 
+ Files sendmail sendmail c 
+ Files sendmail sendmail c global rec_types h pickup pickup c 
+ pipe pipe c sendmail sendmail c 
+ smtp smtp c smtp smtp_proto c 
  bounce bounce c bounce bounce_notify_util c cleanup cleanup c 
  cleanup cleanup_message c smtp smtp c smtp smtp_connect c 
  Documentation edited for clarity Files pipe pipe c 
+ servers to try Files smtp smtp h smtp smtp_proto c 
  global mail_params h smtpd smtpd c 
  global mail_params h proto postconf proto smtp smtp c 
  proto postconf proto proto TLS_README html 
@@ -196,3 +203,8 @@ proto  proto COMPATIBILITY_README html
  request Reported by John Doe File tlsproxy tlsproxy c 
  smtpd smtpd c smtpd smtpd_chat c global mail_params h 
  Files Makefile in smtp smtp h smtp smtp_connect c 
+ global mail_params h bounce bounce c 
+ smtp lmtp_params c smtp smtp c smtp smtp_connect c 
+ smtp smtp h smtp smtp_params c smtp smtp_proto c 
+ information Files sendmail sendmail c pickup pickup c 
+ postcat postcat c showq showq c 
index bed72b65e968902d6064b0397b054993237382f8..f0dd67d2c3fef2b32b41c7b065490aef412475ec 100644 (file)
@@ -365,3 +365,4 @@ Postfix  Postfix legacy TLS Support
  TLSv1 2 with cipher ECDHE RSA AES256 GCM SHA384 256 256 bits 
  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
 enhanced status code and text format 45 number number text 
+opportunistic  opportunistic starttls
index 4313fb9d7d821416580685d5d6a0812e019d7e64..02b3d46b4eb3609f85e275d5fa746ffd37038bb6 100644 (file)
@@ -1865,8 +1865,12 @@ DIGEST
 OSSL
 ossl
 deduplicates
+crosstalk
 intmax
 lflag
 REPLYCODE
 PTEST
 finalizer
+REQTLS
+reqtls
+Esmtp
index 9019565366fb60cd71305e23817f0719a2b350ea..a212f6b487b39c327a2c4e4678cc9f0f88a39cc6 100644 (file)
@@ -100,6 +100,7 @@ Roessner
 bitflags
 Schulze
 tlspol
+TlsRequired
 Gueven
 Oemer
 Kozmenko
index 469db866ae547a343456a0d8dcfe5035c4a9bcf3..49f86500239234eb828e55b420ff52f19f8794c7 100644 (file)
@@ -182,6 +182,7 @@ bounce.o: ../../include/deliver_request.h
 bounce.o: ../../include/dsb_scan.h
 bounce.o: ../../include/dsn.h
 bounce.o: ../../include/dsn_buf.h
+bounce.o: ../../include/dsn_mask.h
 bounce.o: ../../include/hfrom_format.h
 bounce.o: ../../include/htable.h
 bounce.o: ../../include/iostuff.h
@@ -199,6 +200,7 @@ bounce.o: ../../include/mymalloc.h
 bounce.o: ../../include/nvtable.h
 bounce.o: ../../include/rcpt_buf.h
 bounce.o: ../../include/recipient_list.h
+bounce.o: ../../include/sendopts.h
 bounce.o: ../../include/stringops.h
 bounce.o: ../../include/sys_defs.h
 bounce.o: ../../include/vbuf.h
index 04f51553baffc8824a818d588835402630552b10..969db53389885b4593042c0354aa63373940d1cc 100644 (file)
 /* .IP "\fBtls_required_enable (yes)\fR"
 /*     Enable support for the "TLS-Required: no" message header, defined
 /*     in RFC 8689.
+/* .PP
+/*     Available in Postfix 3.11 and later:
+/* .IP "\fBrequiretls_redact_dsn (yes)\fR"
+/*     When sending a delivery status notification for an original
+/*     message received with the REQUIRETLS option, do not send the original
+/*     message body (as if that message was received with "RET=HDRS") and
+/*     do not enforce REQUIRETLS (as if that message was received without
+/*     REQUIRETLS).
 /* FILES
 /*     /var/spool/postfix/bounce/* non-delivery records
 /*     /var/spool/postfix/defer/* non-delivery records
 #include <rcpt_buf.h>
 #include <dsb_scan.h>
 #include <hfrom_format.h>
+#include <sendopts.h>
+#include <dsn_mask.h>
 
 /* Single-threaded server skeleton. */
 
@@ -218,6 +228,7 @@ char   *var_delay_rcpt;
 char   *var_bounce_tmpl;
 bool    var_threaded_bounce;
 char   *var_hfrom_format;              /* header_from_format */
+int     var_reqtls_redact_dsn;
 
  /*
   * We're single threaded, so we can avoid some memory allocation overhead.
@@ -312,6 +323,27 @@ static int bounce_append_proto(char *service_name, VSTREAM *client)
                                  &rcpt_buf->rcpt, &dsn_buf->dsn));
 }
 
+/* edit_notification_properties - bounce message filter */
+
+static void edit_notification_properties(int *sendopts, int *dsn_ret)
+{
+
+    /*
+     * If REQUIRETLS is requested, do not propagate "TLS-Required: no". See
+     * also down-stream code in bounce_header().
+     */
+    if (*sendopts & SOPT_REQUIRETLS_ESMTP)
+       *sendopts &= ~SOPT_REQUIRETLS_HEADER;
+
+    /*
+     * Redact delivery status notification for REQUIRETLS message.
+     */
+    if (var_reqtls_redact_dsn && (*sendopts & SOPT_REQUIRETLS_ESMTP)) {
+       *sendopts &= ~SOPT_REQUIRETLS_ESMTP;
+       *dsn_ret = DSN_RET_HDRS;
+    }
+}
+
 /* bounce_notify_proto - bounce_notify server protocol */
 
 static int bounce_notify_proto(char *service_name, VSTREAM *client,
@@ -368,6 +400,12 @@ static int bounce_notify_proto(char *service_name, VSTREAM *client,
     if (flags & BOUNCE_FLAG_CLEAN)
        bounce_cleanup_register(service_name, STR(queue_id));
 
+    /*
+     * Handle REQUIRETLS etc. matters.
+     */
+    if (var_reqtls_enable && (sendopts & SOPT_REQUIRETLS_ALL))
+       edit_notification_properties(&sendopts, &dsn_ret);
+
     /*
      * Execute the request.
      */
@@ -436,6 +474,12 @@ static int bounce_verp_proto(char *service_name, VSTREAM *client)
     if (flags & BOUNCE_FLAG_CLEAN)
        bounce_cleanup_register(service_name, STR(queue_id));
 
+    /*
+     * Handle REQUIRETLS etc. matters.
+     */
+    if (var_reqtls_enable && (sendopts & SOPT_REQUIRETLS_ALL))
+       edit_notification_properties(&sendopts, &dsn_ret);
+
     /*
      * Execute the request. Fall back to traditional notification if a bounce
      * was returned as undeliverable, because we don't want to VERPify those.
@@ -528,6 +572,12 @@ static int bounce_one_proto(char *service_name, VSTREAM *client)
                 rcpt_buf->dsn_notify, STR(dsn_buf->status),
                 STR(dsn_buf->action), STR(dsn_buf->reason));
 
+    /*
+     * Handle REQUIRETLS etc. matters.
+     */
+    if (var_reqtls_enable && (sendopts & SOPT_REQUIRETLS_ALL))
+       edit_notification_properties(&sendopts, &dsn_ret);
+
     /*
      * Execute the request.
      */
@@ -698,6 +748,7 @@ int     main(int argc, char **argv)
     };
     static const CONFIG_NBOOL_TABLE nbool_table[] = {
        VAR_THREADED_BOUNCE, DEF_THREADED_BOUNCE, &var_threaded_bounce,
+       VAR_REQTLS_REDACT_DSN, DEF_REQTLS_REDACT_DSN, &var_reqtls_redact_dsn,
        0,
     };
 
index f089e4c045d3b5bdfcc32be11463c691a4f8cf00..38112f8adedda1851fc9366ffc7e08d778428f92 100644 (file)
@@ -534,7 +534,8 @@ int     bounce_header(VSTREAM *bounce, BOUNCE_INFO *bounce_info,
     }
 
     /*
-     * Trade confidentiality against availability.
+     * Trade confidentiality against availability. See also up-stream code in
+     * edit_notification_properties().
      */
     if (var_tls_required_enable
        && (bounce_info->sendopts & SOPT_REQUIRETLS_HEADER) != 0)
index 6a0c6dac0af72b44724c80c82ba70c984b0c96df..87066e54e2beea6f218a39aedd361783599ff7f3 100644 (file)
@@ -80,6 +80,8 @@
 /* .IP CLEANUP_FLAG_AUTOUTF8
 /*     Autodetection: request SMTPUTF8 support if the message
 /*     contains an UTF8 message header, sender, or recipient.
+/* .IP CLEANUP_FLAG_REQTLS
+/*     The sender requested REQUIRETLS (RFC 8689) enforcement.
 /* DIAGNOSTICS
 /*     Problems and transactions are logged to \fBsyslogd\fR(8)
 /*     or \fBpostlogd\fR(8).
@@ -208,9 +210,15 @@ void    cleanup_control(CLEANUP_STATE *state, int flags)
     } else {
        state->err_mask = ~0;
     }
+
+    /*
+     * Propagate requests that are specified at the envelope level. This may
+     * be augmented later with information derived from message content.
+     */
     if (state->flags & CLEANUP_FLAG_SMTPUTF8)
        state->sendopts |= SMTPUTF8_FLAG_REQUESTED;
-    /* TODO(wietse) REQUIRETLS. */
+    if (state->flags & CLEANUP_FLAG_REQTLS)
+       state->sendopts |= SOPT_REQUIRETLS_ESMTP;
     if (msg_verbose)
        msg_info("server flags = %s", cleanup_strflags(state->flags));
 }
index dfc28b6319097f62023a506ddec648e7900eeb48..cc7086cfa95b69eec75574c4095c712df17cc62e 100644 (file)
@@ -124,14 +124,14 @@ TESTPROG= domain_list dot_lockfile mail_addr_crunch mail_addr_find \
        off_cvt quote_822_local rec2stream recdump resolve_clnt \
        resolve_local rewrite_clnt stream2rec string_list tok822_parse \
        quote_821_local mail_conf_time mime_state strip_addr \
-       verify_clnt xtext anvil_clnt scache ehlo_mask \
+       verify_clnt xtext anvil_clnt scache ehlo_mask_test \
        valid_mailhost_addr own_inet_addr header_body_checks \
        data_redirect addr_match_list safe_ultostr verify_sender_addr \
        mail_version mail_dict server_acl uxtext mail_parm_split \
        fold_addr smtp_reply_footer mail_addr_map normalize_mailhost_addr \
        haproxy_srvr_test map_search delivered_hdr login_sender_match \
        compat_level config_known_tcp_ports hfrom_format rfc2047_code \
-       ascii_header_text sendopts_test dict_sqlite_test
+       ascii_header_text sendopts_test dict_sqlite_test esmtp_verb_test
 
 LIBS   = ../../lib/lib$(LIB_PREFIX)util$(LIB_SUFFIX)
 LIB_DIR        = ../../lib
@@ -336,7 +336,7 @@ anvil_clnt: $(LIB) $(LIBS)
 scache: scache.c $(LIB) $(LIBS)
        $(CC) $(CFLAGS) -DTEST -o $@ $@.c $(LIB) $(LIBS) $(SYSLIBS)
 
-ehlo_mask: ehlo_mask.c $(LIB) $(LIBS)
+ehlo_mask_test: ehlo_mask_test.c $(LIB) $(LIBS)
        $(CC) $(CFLAGS) -DTEST -o $@ $@.c $(LIB) $(LIBS) $(SYSLIBS)
 
 valid_mailhost_addr: valid_mailhost_addr.c $(LIB) $(LIBS)
@@ -416,7 +416,7 @@ config_known_tcp_ports: config_known_tcp_ports.c $(LIB) $(LIBS)
        $(CC) $(CFLAGS) -DTEST -o $@ $@.c $(LIB) $(LIBS) $(SYSLIBS)
 
 tests: tok822_test mime_tests strip_addr_test tok822_limit_test \
-       xtext_test scache_multi_test ehlo_mask_test \
+       xtext_test scache_multi_test test_ehlo_mask \
        namadr_list_test mail_conf_time_test header_body_checks_tests \
        mail_version_test server_acl_test resolve_local_test maps_test \
        safe_ultostr_test mail_parm_split_test fold_addr_test \
@@ -616,10 +616,8 @@ scache_multi_test: scache scache_multi.in scache_multi.ref
        diff scache_multi.ref scache_multi.tmp
        rm -f scache_multi.tmp
 
-ehlo_mask_test: ehlo_mask ehlo_mask.in ehlo_mask.ref
-       $(SHLIB_ENV) $(VALGRIND) ./ehlo_mask <ehlo_mask.in >ehlo_mask.tmp
-       diff ehlo_mask.ref ehlo_mask.tmp
-       rm -f ehlo_mask.tmp
+test_ehlo_mask: ehlo_mask_test
+       $(SHLIB_ENV) $(VALGRIND) ./ehlo_mask_test
 
 namadr_list_test: namadr_list namadr_list.in namadr_list.ref
        -$(SHLIB_ENV) sh namadr_list.in >namadr_list.tmp 2>&1
@@ -808,7 +806,7 @@ tidy:       clean
 
 depend: $(MAKES)
        (sed '1,/^# do not edit/!d' Makefile.in; \
-       set -e; for i in [a-z][a-z0-9]*.c; do \
+       set -e; for i in [a-z][a-z0-9_]*.c; do \
            $(CC) -E $(DEFS) $(INCL) $$i | grep -v '[<>]' | sed -n -e '/^# *1 *"\([^"]*\)".*/{' \
            -e 's//'`echo $$i|sed 's/c$$/o/'`': \1/' \
            -e 's/o: \.\//o: /' -e p -e '}' ; \
@@ -1481,6 +1479,16 @@ ehlo_mask.o: ../../include/vbuf.h
 ehlo_mask.o: ../../include/vstring.h
 ehlo_mask.o: ehlo_mask.c
 ehlo_mask.o: ehlo_mask.h
+ehlo_mask_test.o: ../../include/check_arg.h
+ehlo_mask_test.o: ../../include/msg.h
+ehlo_mask_test.o: ../../include/msg_vstream.h
+ehlo_mask_test.o: ../../include/stringops.h
+ehlo_mask_test.o: ../../include/sys_defs.h
+ehlo_mask_test.o: ../../include/vbuf.h
+ehlo_mask_test.o: ../../include/vstream.h
+ehlo_mask_test.o: ../../include/vstring.h
+ehlo_mask_test.o: ehlo_mask.h
+ehlo_mask_test.o: ehlo_mask_test.c
 ext_prop.o: ../../include/check_arg.h
 ext_prop.o: ../../include/name_mask.h
 ext_prop.o: ../../include/sys_defs.h
index d281c446245cb9b0e0c524ae286e362515287eca..afcf47317033bbed49f602641422854d0ef07d4f 100644 (file)
@@ -55,6 +55,7 @@ static struct cleanup_flag_map cleanup_flag_map[] = {
     CLEANUP_FLAG_SMTP_REPLY, "enable_smtp_reply",
     CLEANUP_FLAG_SMTPUTF8, "smtputf8_requested",
     CLEANUP_FLAG_AUTOUTF8, "smtputf8_autodetect",
+    CLEANUP_FLAG_REQTLS, "requiretls_requested",
 };
 
 /* cleanup_strflags - map flags code to printable string */
index 0b1985b7076704bec30ccf82c15963bfc9323b10..6d7c03ada36a5316bc4768dff8bbaea21b321fa1 100644 (file)
@@ -25,6 +25,7 @@
 #define CLEANUP_FLAG_SMTP_REPLY        (1<<7)  /* Enable SMTP reply */
 #define CLEANUP_FLAG_SMTPUTF8  (1<<8)  /* SMTPUTF8 requested */
 #define CLEANUP_FLAG_AUTOUTF8  (1<<9)  /* Autodetect SMTPUTF8 */
+#define CLEANUP_FLAG_REQTLS    (1<<10) /* REQUIRETLS requested */
 
 #define CLEANUP_FLAG_FILTER_ALL        (CLEANUP_FLAG_FILTER | CLEANUP_FLAG_MILTER)
 
index df905e13f01de72c9c970944e74e530e3d4446da..adf8f0ca7962a0db4b24d9edef3a6f814a51aaaf 100644 (file)
@@ -20,6 +20,7 @@
 /*     #define EHLO_MASK_DSN           (1<<11)
 /*     #define EHLO_MASK_SMTPUTF8      (1<<12)
 /*     #define EHLO_MASK_CHUNKING      (1<<13)
+/*     #define EHLO_MASK_REQTLS        (1<<14)
 /*     #define EHLO_MASK_SILENT        (1<<15)
 /*
 /*     int     ehlo_mask(keyword_list)
   * The lookup table.
   */
 static const NAME_MASK ehlo_mask_table[] = {
-    "8BITMIME", EHLO_MASK_8BITMIME,
-    "AUTH", EHLO_MASK_AUTH,
-    "ETRN", EHLO_MASK_ETRN,
-    "PIPELINING", EHLO_MASK_PIPELINING,
-    "SIZE", EHLO_MASK_SIZE,
-    "VERP", EHLO_MASK_VERP,
-    "VRFY", EHLO_MASK_VRFY,
-    "XCLIENT", EHLO_MASK_XCLIENT,
-    "XFORWARD", EHLO_MASK_XFORWARD,
-    "STARTTLS", EHLO_MASK_STARTTLS,
-    "ENHANCEDSTATUSCODES", EHLO_MASK_ENHANCEDSTATUSCODES,
-    "DSN", EHLO_MASK_DSN,
-    "EHLO_MASK_SMTPUTF8", EHLO_MASK_SMTPUTF8,
-    "SMTPUTF8", EHLO_MASK_SMTPUTF8,
-    "CHUNKING", EHLO_MASK_CHUNKING,
-    "SILENT-DISCARD", EHLO_MASK_SILENT,        /* XXX In-band signaling */
+    EHLO_VERB_8BITMIME, EHLO_MASK_8BITMIME,
+    EHLO_VERB_AUTH, EHLO_MASK_AUTH,
+    EHLO_VERB_ETRN, EHLO_MASK_ETRN,
+    EHLO_VERB_PIPELINING, EHLO_MASK_PIPELINING,
+    EHLO_VERB_SIZE, EHLO_MASK_SIZE,
+    EHLO_VERB_VERP, EHLO_MASK_VERP,
+    EHLO_VERB_VRFY, EHLO_MASK_VRFY,
+    EHLO_VERB_XCLIENT, EHLO_MASK_XCLIENT,
+    EHLO_VERB_XFORWARD, EHLO_MASK_XFORWARD,
+    EHLO_VERB_STARTTLS, EHLO_MASK_STARTTLS,
+    EHLO_VERB_ENHANCEDSTATUSCODES, EHLO_MASK_ENHANCEDSTATUSCODES,
+    EHLO_VERB_DSN, EHLO_MASK_DSN,
+    EHLO_VERB_SMTPUTF8, EHLO_MASK_SMTPUTF8,
+    EHLO_VERB_CHUNKING, EHLO_MASK_CHUNKING,
+    EHLO_VERB_REQTLS, EHLO_MASK_REQTLS,
+    EHLO_VERB_SILENT, EHLO_MASK_SILENT,
     0,
 };
 
@@ -114,32 +115,3 @@ const char *str_ehlo_mask(int mask_bits)
      */
     return (str_name_mask("ehlo bitmask", ehlo_mask_table, mask_bits));
 }
-
-#ifdef TEST
-
- /*
-  * Stand-alone test program.
-  */
-#include <stdlib.h>
-#include <vstream.h>
-#include <vstring.h>
-#include <vstring_vstream.h>
-
-int     main(int unused_argc, char **unused_argv)
-{
-    int     mask_bits;
-    VSTRING *buf = vstring_alloc(1);
-    const char *mask_string;
-
-    while (vstring_get_nonl(buf, VSTREAM_IN) != VSTREAM_EOF) {
-       mask_bits = ehlo_mask(vstring_str(buf));
-       mask_string = str_ehlo_mask(mask_bits);
-       vstream_printf("%s -> 0x%x -> %s\n", vstring_str(buf), mask_bits,
-                      mask_string);
-       vstream_fflush(VSTREAM_OUT);
-    }
-    vstring_free(buf);
-    exit(0);
-}
-
-#endif
index 9a318970d11c8ae2116caea9422b5c8f297caa06..c8d1fae19b039bd4afd0a2f6fe55ce3bbb2af93a 100644 (file)
@@ -12,7 +12,7 @@
 /* .nf
 
  /*
-  * External interface.
+  * Bit flags.
   */
 #define EHLO_MASK_8BITMIME     (1<<0)  /* start of first byte */
 #define EHLO_MASK_PIPELINING   (1<<1)
 #define EHLO_MASK_DSN          (1<<11)
 #define EHLO_MASK_SMTPUTF8     (1<<12)
 #define EHLO_MASK_CHUNKING     (1<<13)
-#define EHLO_MASK_SILENT       (1<<15)
+#define EHLO_MASK_REQTLS       (1<<14)
+#define EHLO_MASK_SILENT       (1<<15) /* in-band signaling */
 
+ /*
+  * ESMTP verbs.
+  */
+#define EHLO_VERB_8BITMIME     "8BITMIME"
+#define EHLO_VERB_PIPELINING   "PIPELINING"
+#define EHLO_VERB_SIZE                 "SIZE"
+#define EHLO_VERB_VRFY                 "VRFY"
+#define EHLO_VERB_ETRN                 "ETRN"
+#define EHLO_VERB_AUTH                 "AUTH"
+#define EHLO_VERB_VERP                 "VERP"
+#define EHLO_VERB_STARTTLS     "STARTTLS"
+#define EHLO_VERB_XCLIENT      "XCLIENT"
+#define EHLO_VERB_XFORWARD     "XFORWARD"
+#define EHLO_VERB_ENHANCEDSTATUSCODES  "ENHANCEDSTATUSCODES"
+#define EHLO_VERB_DSN          "DSN"
+#define EHLO_VERB_SMTPUTF8     "SMTPUTF8"
+#define EHLO_VERB_CHUNKING     "CHUNKING"
+#define EHLO_VERB_REQTLS       "REQUIRETLS"
+#define EHLO_VERB_SILENT       "SILENT-DISCARD"        /* in-band signaling */
+
+ /*
+  * Functions.
+  */
 extern int ehlo_mask(const char *);
 extern const char *str_ehlo_mask(int);
 
diff --git a/postfix/src/global/ehlo_mask.in b/postfix/src/global/ehlo_mask.in
deleted file mode 100644 (file)
index 50fc248..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-starttls, 8bitmime, verp, etrn, etrn
-foobar, auth, pipelining, size, vrfy
-xclient, xforward
diff --git a/postfix/src/global/ehlo_mask.ref b/postfix/src/global/ehlo_mask.ref
deleted file mode 100644 (file)
index e865ab6..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-starttls, 8bitmime, verp, etrn, etrn -> 0xd1 -> 8BITMIME ETRN VERP STARTTLS
-foobar, auth, pipelining, size, vrfy -> 0x2e -> AUTH PIPELINING SIZE VRFY
-xclient, xforward -> 0x300 -> XCLIENT XFORWARD
diff --git a/postfix/src/global/ehlo_mask_test.c b/postfix/src/global/ehlo_mask_test.c
new file mode 100644 (file)
index 0000000..fd0c2c8
--- /dev/null
@@ -0,0 +1,150 @@
+ /*
+  * System library.
+  */
+#include <sys_defs.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stringops.h>
+
+ /*
+  * Utility library.
+  */
+#include <msg.h>
+#include <msg_vstream.h>
+#include <vstream.h>
+#include <vstring.h>
+
+ /*
+  * Global library.
+  */
+#include <ehlo_mask.h>
+
+ /*
+  * Tests and test cases.
+  */
+typedef struct TEST_CASE {
+    const char *label;                 /* identifies test case */
+    const char *raw;
+    int     mask;
+    const char *text;
+} TEST_CASE;
+
+ /*
+  * Verify that each verb has its unique bit mask, and vice versa.
+  */
+static const TEST_CASE test_cases[] = {
+    {"8BITMIME",
+       EHLO_VERB_8BITMIME,
+       EHLO_MASK_8BITMIME,
+       "8BITMIME"
+    },
+    {"8bitmime",
+       "8bitmime",
+       EHLO_MASK_8BITMIME,
+       "8BITMIME"
+    },
+    {"PIPELINING",
+       EHLO_VERB_PIPELINING,
+       EHLO_MASK_PIPELINING,
+       "PIPELINING"
+    },
+    {"SIZE",
+       EHLO_VERB_SIZE,
+       EHLO_MASK_SIZE,
+       "SIZE"
+    },
+    {"VRFY",
+       EHLO_VERB_VRFY,
+       EHLO_MASK_VRFY,
+       "VRFY"
+    },
+    {"ETRN",
+       EHLO_VERB_ETRN,
+       EHLO_MASK_ETRN,
+       "ETRN"
+    },
+    {"AUTH",
+       EHLO_VERB_AUTH,
+       EHLO_MASK_AUTH,
+       "AUTH"
+    },
+    {"VERP",
+       EHLO_VERB_VERP,
+       EHLO_MASK_VERP,
+       "VERP"
+    },
+    {"STARTTLS",
+       EHLO_VERB_STARTTLS,
+       EHLO_MASK_STARTTLS,
+       "STARTTLS"
+    },
+    {"XCLIENT",
+       EHLO_VERB_XCLIENT,
+       EHLO_MASK_XCLIENT,
+       "XCLIENT"
+    },
+    {"ENHANCEDSTATUSCODES",
+       EHLO_VERB_ENHANCEDSTATUSCODES,
+       EHLO_MASK_ENHANCEDSTATUSCODES,
+       "ENHANCEDSTATUSCODES"
+    },
+    {"DSN",
+       EHLO_VERB_DSN,
+       EHLO_MASK_DSN,
+       "DSN"
+    },
+    {"SMTPUTF8",
+       EHLO_VERB_SMTPUTF8,
+       EHLO_MASK_SMTPUTF8,
+       "SMTPUTF8"
+    },
+    {"CHUNKING",
+       EHLO_VERB_CHUNKING,
+       EHLO_MASK_CHUNKING,
+       "CHUNKING"
+    },
+    {"REQUIRETLS",
+       EHLO_VERB_REQTLS,
+       EHLO_MASK_REQTLS,
+       "REQUIRETLS"
+    },
+    {"SILENT",
+       EHLO_VERB_SILENT,
+       EHLO_MASK_SILENT,
+       "SILENT-DISCARD"
+    },
+    {0},
+};
+
+int     main(int argc, char **argv)
+{
+    const TEST_CASE *tp;
+    int     pass = 0;
+    int     fail = 0;
+    const char *got_text;
+    int     got_mask;
+
+    msg_vstream_init(sane_basename((VSTRING *) 0, argv[0]), VSTREAM_ERR);
+
+    /*
+     * Verify the mapping in both directions.
+     */
+    for (tp = test_cases; tp->label != 0; tp++) {
+       msg_info("RUN  %s", tp->label);
+       if ((got_mask = ehlo_mask(tp->raw)) != tp->mask) {
+           msg_warn("got mask '0x%x', want: '0x%x'", got_mask, tp->mask);
+           fail++;
+           msg_info("FAIL %s", tp->label);
+       } else if ((got_text = str_ehlo_mask(tp->mask)),
+                  strcmp(got_text, tp->text) != 0) {
+           msg_warn("got text '%s', want: '%s'", got_text, tp->text);
+           fail++;
+           msg_info("FAIL %s", tp->label);
+       } else {
+           msg_info("PASS %s", tp->label);
+           pass++;
+       }
+    }
+    msg_info("PASS=%d FAIL=%d", pass, fail);
+    exit(fail != 0);
+}
index a0da78d1aadab5bed58586c76f3afaf3fa72345b..a26839586b845a9aa16d0f2de36d476cc6bef929 100644 (file)
 /*     int     var_smtputf8_enable;
 /*     int     var_strict_smtputf8;
 /*     char    *var_smtputf8_autoclass;
+/*     int     var_reqtls_enable;
 /*     int     var_tls_required_enable;
 /*     int     var_idna2003_compat;
 /*     char    *var_compatibility_level;
@@ -370,6 +371,7 @@ char   *var_dsn_filter;
 int     var_smtputf8_enable;
 int     var_strict_smtputf8;
 char   *var_smtputf8_autoclass;
+int     var_reqtls_enable;
 int     var_tls_required_enable;
 int     var_idna2003_compat;
 char   *var_compatibility_level;
@@ -793,6 +795,7 @@ void    mail_params_init()
        VAR_SMTPUTF8_ENABLE, DEF_SMTPUTF8_ENABLE, &var_smtputf8_enable,
        VAR_IDNA2003_COMPAT, DEF_IDNA2003_COMPAT, &var_idna2003_compat,
        VAR_RESPECTFUL_LOGGING, DEF_RESPECTFUL_LOGGING, &var_respectful_logging,
+       VAR_REQTLS_ENABLE, DEF_REQTLS_ENABLE, &var_reqtls_enable,
        VAR_TLSREQUIRED_ENABLE, DEF_TLSREQUIRED_ENABLE, &var_tls_required_enable,
        0,
     };
index 28a879f1c9159e989de3237aae9890716e11da7e..6ca72325761d03b864bbf72e5610049318a443da 100644 (file)
@@ -4409,6 +4409,21 @@ extern int var_idna2003_compat;
 #define DEF_TLSREQUIRED_ENABLE         "yes"
 extern int var_tls_required_enable;
 
+#define VAR_REQTLS_ENABLE              "requiretls_enable"
+#define DEF_REQTLS_ENABLE              "yes"
+extern int var_reqtls_enable;
+
+#define VAR_SMTP_REQTLS_POLICY         "smtp_requiretls_policy"
+#define DEF_SMTP_REQTLS_POLICY         "inline:{{.$mydomain=opportunistic}, {localhost=opportunistic}}, opportunistic+starttls"
+extern char *var_smtp_reqtls_policy;
+
+#define VAR_LMTP_REQTLS_POLICY         "lmtp_requiretls_policy"
+#define DEF_LMTP_REQTLS_POLICY         "opportunistic"
+
+#define VAR_REQTLS_REDACT_DSN          "requiretls_redact_dsn"
+#define DEF_REQTLS_REDACT_DSN          "yes"
+extern int var_reqtls_redact_dsn;
+
  /*
   * Workaround for future incompatibility. Our implementation of RFC 2308
   * negative reply caching relies on the promise that res_query() and
index 1a41dfd6cfbdd63ad1d8dfc7e86e01c00a02fabf..f787acc8f4ca24ecc74ab5cb05a721a3c75f4369 100644 (file)
 /* .IP trace_flags
 /*     Message tracing flags as specified in \fB<deliver_request.h>\fR.
 /* .IP sendopts
-/*     Flags defined in <sendopts.h>. This ignores flags based on
-/*     message header content, or envelope email addresses.
+/*     Flags defined in <sendopts.h>. This ignores SMTPUTF8 flags for
+/*     UTF8 detected in message headers or envelope email addresses,
+/*     and the flag for detected "TLS-Required: no".
 /* .IP queue_id
 /*     Null pointer, or pointer to buffer that receives the queue
 /*     ID of the new message.
@@ -225,8 +226,8 @@ static void post_mail_init(VSTREAM *stream, const char *sender,
     int     cleanup_flags =
     int_filt_flags(source_class) | CLEANUP_FLAG_MASK_INTERNAL
     | smtputf8_autodetect(source_class)
+    | ((sendopts & SOPT_REQUIRETLS_ESMTP) ? CLEANUP_FLAG_REQTLS : 0)
     | ((sendopts & SMTPUTF8_FLAG_REQUESTED) ? CLEANUP_FLAG_SMTPUTF8 : 0);
-    /* TODO(wietse) REQUIRETLS. */
 
     GETTIMEOFDAY(&now);
     date = mail_date(now.tv_sec);
index 32d939b9b7b52c280fa45d4e532f70679baa1369..9452c003fdccdc393bb32c16bc969369bcc8d1f6 100644 (file)
  /*
   * The subset of inputs that the postdrop command allows.
   */
-#define REC_TYPE_POST_ENVELOPE "MFSRVAin"
+#define REC_TYPE_POST_ENVELOPE "MCFSRVAin"
 #define REC_TYPE_POST_CONTENT  "XLN"
 #define REC_TYPE_POST_EXTRACT  "EAR"
 
index 7e553ffa33f9380e71985f77dfc9ea3149f808b5..8e7b1807da6db910fa63d94abfd5e3697569979c 100644 (file)
@@ -163,9 +163,10 @@ static FORWARD_INFO *forward_open(DELIVER_REQUEST *request, const char *sender)
 #define FORWARD_CLEANUP_FLAGS \
        (CLEANUP_FLAG_BOUNCE | CLEANUP_FLAG_MASK_INTERNAL \
        | smtputf8_autodetect(MAIL_SRC_MASK_FORWARD) \
+       | ((request->sendopts & SOPT_REQUIRETLS_ESMTP) ? \
+       CLEANUP_FLAG_REQTLS : 0) \
        | ((request->sendopts & SMTPUTF8_FLAG_REQUESTED) ? \
        CLEANUP_FLAG_SMTPUTF8 : 0))
-       /* TODO(wietse) REQUIRETLS. */
 
     attr_print(cleanup, ATTR_FLAG_NONE,
               SEND_ATTR_INT(MAIL_ATTR_FLAGS, FORWARD_CLEANUP_FLAGS),
index f2a6822473f591b3e8f0027d77f7be86ba7fdac8..0199223605cd4b62769854c796dc682c23482daf 100644 (file)
@@ -83,6 +83,7 @@ pipe.o: ../../include/pipe_command.h
 pipe.o: ../../include/quote_822_local.h
 pipe.o: ../../include/quote_flags.h
 pipe.o: ../../include/recipient_list.h
+pipe.o: ../../include/sendopts.h
 pipe.o: ../../include/sent.h
 pipe.o: ../../include/set_eugid.h
 pipe.o: ../../include/split_addr.h
index 58ff5e0e76494df96bfec8f958bbdb0301837c27..feb35f2520e22d5e90c269d6bdc8669fea1c0767 100644 (file)
 /* .sp
 /*     This information is modified by the \fBhqu\fR flags for quoting
 /*     and case folding.
+/* .IP \fB${requiretls}\fR
+/*     This feature is intended for content filters that pass filtered
+/*     mail to the Postfix sendmail(1) command. The macro expands to
+/*     the Postfix sendmail(1) command-line option \fB-Orequiretls=yes\fR
+/*     if the sender requested REQUIRETLS, otherwise it expands to
+/*     \fB-Orequiretls=no\fR.
+/* .sp
+/*     This feature is available as of Postfix 3.11.
 /* .IP \fB${sasl_method}\fR
 /*     This macro expands to the name of the SASL authentication
 /*     mechanism in the AUTH command when the Postfix SMTP server
 /* .IP "\fBinfo_log_address_format (external)\fR"
 /*     The email address form that will be used in non-debug logging
 /*     (info, warning, etc.).
+/* .PP
+/*     Available in Postfix 3.11 and later:
+/* .IP "\fBrequiretls_enable (yes)\fR"
+/*     Enable support for the ESMTP verb "REQUIRETLS" in the "MAIL
+/*     FROM" command.
 /* SEE ALSO
 /*     qmgr(8), queue manager
 /*     bounce(8), delivery status reports
 #include <delivered_hdr.h>
 #include <fold_addr.h>
 #include <mail_parm_split.h>
+#include <sendopts.h>
 
 /* Single server skeleton. */
 
 #define PIPE_DICT_SASL_SENDER  "sasl_sender"   /* key */
 #define PIPE_DICT_QUEUE_ID     "queue_id"      /* key */
 #define PIPE_DICT_ENVID                "envid" /* key */
+#define PIPE_DICT_REQTLS       "requiretls"    /* key */
 
  /*
   * Flags used to pass back the type of special parameter found by
@@ -659,6 +674,7 @@ static int parse_callback(int type, VSTRING *buf, void *context)
        PIPE_DICT_SASL_SENDER, 0,
        PIPE_DICT_QUEUE_ID, 0,
        PIPE_DICT_ENVID, 0,
+       PIPE_DICT_REQTLS, 0,
        0, 0,
     };
     struct cmd_flags *p;
@@ -1290,6 +1306,10 @@ static int deliver_message(DELIVER_REQUEST *request, char *service, char **argv)
                request->queue_id);
     dict_update(PIPE_DICT_TABLE, PIPE_DICT_ENVID,
                request->dsn_envid);
+    dict_update(PIPE_DICT_TABLE, PIPE_DICT_REQTLS,
+               (request->sendopts & SOPT_REQUIRETLS_ESMTP)
+               && var_reqtls_enable ? "-Orequiretls=yes" :
+               "-Orequiretls=no");
     vstring_free(buf);
 
     if ((expanded_argv = expand_argv(service, attr.command,
index 44c0ce6baafa095391a82e61ad8adcbde4f5a3cc..91cdec1e13e1554f721af38811619e5ef76bb414 100644 (file)
@@ -348,6 +348,10 @@ static void postcat(VSTREAM *fp, VSTRING *buffer, int flags)
            /* Optional output (here before we update the state machine). */
            if (do_print)
                PRINT_RECORD(flags, offset, rec_type, STR(buffer));
+           /* Postfix 3.11 maildrop files may have preliminary SIZE record. */
+           if (strncmp(VSTREAM_PATH(fp), MAIL_QUEUE_MAILDROP "/",
+                       sizeof(MAIL_QUEUE_MAILDROP)) == 0)
+               continue;
            /* Read the message size/offset for the state machine optimizer. */
            if (data_size >= 0 || data_offset >= 0) {
                msg_warn("file contains multiple size records");
index 38c2eae31232cbce9370141b640a2998a3af9de5..83fa8532b79b77bc6911b4380e13a99a5536398f 100644 (file)
@@ -784,7 +784,7 @@ static int starttls(STATE *state)
 
     cipher_exclusions = vstring_alloc(10);
     ADD_EXCLUDE(cipher_exclusions, DEF_SMTP_TLS_EXCL_CIPH);
-    if (TLS_REQUIRED(state->level))
+    if (TLS_REQUIRED_BY_SECURITY_LEVEL(state->level))
        ADD_EXCLUDE(cipher_exclusions, DEF_SMTP_TLS_MAND_EXCL);
 
     /*
index 192faf82e274539109f575fd082b6bf709b737ee..d8e0f05609473ab89a3b7ccc17a793673c71294a 100644 (file)
@@ -86,6 +86,7 @@ sendmail.o: ../../include/recipient_list.h
 sendmail.o: ../../include/record.h
 sendmail.o: ../../include/resolve_clnt.h
 sendmail.o: ../../include/safe.h
+sendmail.o: ../../include/sendopts.h
 sendmail.o: ../../include/set_ugid.h
 sendmail.o: ../../include/split_at.h
 sendmail.o: ../../include/stringops.h
index df052c5b0e701e41fc15460d78409b610433314b..82c3b8b5633888313b65dd6d267b6ce9be4af7e9 100644 (file)
 /*     comma-separated list with one or more of \fBfailure\fR (send
 /*     notification when delivery fails), \fBdelay\fR (send
 /*     notification when delivery is delayed), or \fBsuccess\fR
-/*     (send notification when the message is delivered); or specify
+/*     (send notification after the message is delivered); or specify
 /*     \fBnever\fR (don't send any notifications at all).
 /*
 /*     This feature is available in Postfix 2.3 and later.
 /* .IP "\fB-n\fR (ignored)"
 /*     Backwards compatibility.
-/* .IP "\fB-oA\fIalias_database\fR"
-/*     Non-default alias database. Specify \fIpathname\fR or
-/*     \fItype\fR:\fIpathname\fR. See \fBpostalias\fR(1) for
-/*     details.
+/* .IP "\fB-O requiretls=yes\fR"
+/* .IP "\fB-O requiretls=no\fR"
+/*     When delivering a message to an SMTP or LMTP server, the
+/*     connection must use TLS with a verified server certificate,
+/*     and that server must support REQUIRETLS. The "requiretls" name
+/*     and option value are case-insensitive. REQUIRETLS enforcement
+/*     is controlled with the configuration parameters requiretls_enable,
+/*     smtp_requiretls_policy, and lmtp_requiretls_policy.
+/*
+/*     This feature is available in Postfix 3.11 and later.
+/* .IP "\fB-O smtputf8=yes\fR"
+/* .IP "\fB-O smtputf8=no\fR"
+/*     When delivering a message to an SMTP or LMTP server, and an
+/*     envelope address or message header contains UTF8 text, that server
+/*     must support SMTPUTF8. The "smtputf8" option name and value
+/*     are case-insensitive.
+/*
+/*     This feature is available in Postfix 3.11 and later.
 /* .IP "\fB-O \fIoption=value\fR (ignored)"
 /*     Set the named \fIoption\fR to \fIvalue\fR. Use the equivalent
 /*     configuration parameter in \fBmain.cf\fR instead.
+/* .IP "\fB-oA\fIalias_database\fR"
+/*     Non-default alias database. Specify \fIpathname\fR or
+/*     \fItype\fR:\fIpathname\fR. See \fBpostalias\fR(1) for details.
 /* .IP "\fB-o7\fR (ignored)"
 /* .IP "\fB-o8\fR (ignored)"
 /*     To send 8-bit or binary content, use an appropriate MIME encapsulation
 /*     the Postfix executable files and documentation with the default
 /*     Postfix instance, and that are started, stopped, etc., together
 /*     with the default Postfix instance.
+/* .PP
+/*     Postfix 3.11 and later:
+/* .IP "\fBrequiretls_enable (yes)\fR"
+/*     Enable support for the ESMTP verb "REQUIRETLS" in the "MAIL
+/*     FROM" command.
 /* FILES
 /*     /var/spool/postfix, mail queue
 /*     /etc/postfix, configuration files
 #include <user_acl.h>
 #include <dsn_mask.h>
 #include <mail_parm_split.h>
+#include <sendopts.h>
 
 /* Application-specific. */
 
@@ -589,6 +612,11 @@ static const CONFIG_STR_TABLE str_table[] = {
     0,
 };
 
+ /*
+  * Sender options.
+  */
+static int sm_sendopts;
+
  /*
   * Silly little macros (SLMs).
   */
@@ -788,6 +816,14 @@ static void enqueue(const int flags, const char *encoding,
      * With "sendmail -N", instead of a per-message NOTIFY record we store one
      * per recipient so that we can simplify the implementation somewhat.
      */
+    if (sm_sendopts)
+       rec_fprintf(dst, REC_TYPE_SIZE, REC_TYPE_SIZE_FORMAT,
+                   (REC_TYPE_SIZE_CAST1) ~ 0,  /* message segment size */
+                   (REC_TYPE_SIZE_CAST2) ~ 0,  /* content offset */
+                   (REC_TYPE_SIZE_CAST3) ~ 0,  /* recipient count */
+                   (REC_TYPE_SIZE_CAST4) ~ 0,  /* qmgr options */
+                   (REC_TYPE_SIZE_CAST5) ~ 0,  /* content length */
+                   (REC_TYPE_SIZE_CAST6) sm_sendopts);
     if (dsn_envid)
        rec_fprintf(dst, REC_TYPE_ATTR, "%s=%s",
                    MAIL_ATTR_DSN_ENVID, dsn_envid);
@@ -1054,6 +1090,7 @@ int     main(int argc, char **argv)
     int     saved_optind;
     ARGV   *import_env;
     char   *alias_map_from_args = 0;
+    const char *oval;
 
     /*
      * Fingerprint executables and core dumps.
@@ -1251,7 +1288,40 @@ int     main(int argc, char **argv)
            break;
        case 'N':
            if ((dsn_notify = dsn_notify_mask(optarg)) == 0)
-               msg_warn("bad -N option value -- ignored");
+               msg_warn("bad -N option value: '%s' -- ignored", optarg);
+           break;
+       case 'O':
+           if ((oval = optarg + strcspn(optarg, "="))[0] != 0)
+               oval += 1;
+           if (strncasecmp(optarg, "REQUIRETLS=", oval - optarg) == 0) {
+               if (var_reqtls_enable == 0) {
+                   msg_warn("Ignoring option '-O %s, because the "
+                            "configuration is '%s = %s'", optarg,
+                            VAR_REQTLS_ENABLE, CONFIG_BOOL_NO);
+                   continue;
+               } else if (strcasecmp(oval, CONFIG_BOOL_YES) == 0) {
+                   sm_sendopts |= SOPT_REQUIRETLS_ESMTP;
+                   continue;
+               } else if (strcasecmp(oval, CONFIG_BOOL_NO) == 0) {
+                   sm_sendopts &= ~SOPT_REQUIRETLS_ESMTP;
+                   continue;
+               }
+               msg_warn("bad -O option: '%s' -- ignored", optarg);
+           } else if (strncasecmp(optarg, "SMTPUTF8=", oval - optarg) == 0) {
+               if (var_smtputf8_enable == 0) {
+                   msg_warn("'-O %s' was requested, but the "
+                            "configuration is '%s = %s'", optarg,
+                            VAR_SMTPUTF8_ENABLE, CONFIG_BOOL_NO);
+                   continue;
+               } else if (strcasecmp(oval, CONFIG_BOOL_YES) == 0) {
+                   sm_sendopts |= SOPT_SMTPUTF8_REQUESTED;
+                   continue;
+               } else if (strcasecmp(oval, CONFIG_BOOL_NO) == 0) {
+                   sm_sendopts &= ~SOPT_SMTPUTF8_REQUESTED;
+                   continue;
+               }
+               msg_warn("bad -O option: '%s' -- ignored", optarg);
+           }
            break;
        case 'R':
            if ((dsn_ret = dsn_ret_code(optarg)) == 0)
index 80e1e89e2ee8335bc86c3f971b0548f8e6a3d16d..ed5f6bf510c638180aeca2fc37ee7cb8e903ad6f 100644 (file)
@@ -213,7 +213,8 @@ static void showq_report(VSTREAM *client, char *queue, char *id,
                arrival_time = atol(start);
            break;
        case REC_TYPE_SIZE:
-           if (msg_size_ok == 0) {
+           /* Maildrop files may have a preliminary SIZE record. */
+           if (msg_size_ok == 0 && strcmp(queue, MAIL_QUEUE_MAILDROP) != 0) {
                msg_size_ok = (start[strspn(start, "0123456789 ")] == 0
                               && (msg_size = atol(start)) >= 0);
                if (msg_size_ok == 0) {
index 25002c658d5ec83d6d58e2a09c53ba31ad85cc63..1e0be5237c89d7979b3216a77b7cc9264c84b4f2 100644 (file)
@@ -2,16 +2,19 @@ SHELL = /bin/sh
 SRCS   = smtp.c smtp_connect.c smtp_proto.c smtp_chat.c smtp_session.c \
        smtp_addr.c smtp_trouble.c smtp_state.c smtp_rcpt.c smtp_tls_policy.c \
        smtp_sasl_proto.c smtp_sasl_glue.c smtp_reuse.c smtp_map11.c \
-       smtp_sasl_auth_cache.c smtp_key.c smtp_misc.c smtp_tlsrpt.c
+       smtp_sasl_auth_cache.c smtp_key.c smtp_misc.c smtp_tlsrpt.c \
+       smtp_reqtls_policy.c
 OBJS   = smtp.o smtp_connect.o smtp_proto.o smtp_chat.o smtp_session.o \
        smtp_addr.o smtp_trouble.o smtp_state.o smtp_rcpt.o smtp_tls_policy.o \
        smtp_sasl_proto.o smtp_sasl_glue.o smtp_reuse.o smtp_map11.o \
-       smtp_sasl_auth_cache.o smtp_key.o smtp_misc.o smtp_tlsrpt.o
-HDRS   = smtp.h smtp_sasl.h smtp_addr.h smtp_reuse.h smtp_sasl_auth_cache.h
-TESTSRC        = smtp_policy_test.c
+       smtp_sasl_auth_cache.o smtp_key.o smtp_misc.o smtp_tlsrpt.o \
+       smtp_reqtls_policy.o
+HDRS   = smtp.h smtp_sasl.h smtp_addr.h smtp_reuse.h smtp_sasl_auth_cache.h \
+       smtp_reqtls_policy.h
+TESTSRC        = smtp_tls_policy_test.c smtp_reqtls_policy_test.c
 DEFS   = -I. -I$(INC_DIR) -D$(SYSTYPE)
 CFLAGS = $(DEBUG) $(OPT) $(DEFS)
-TESTPROG= smtp_unalias smtp_map11 smtp_tls_policy_test
+TESTPROG= smtp_unalias smtp_map11 smtp_tls_policy_test smtp_reqtls_policy_test
 PROG   = smtp
 INC_DIR        = ../../include
 LIBS   = ../../lib/lib$(LIB_PREFIX)master$(LIB_SUFFIX) \
@@ -33,7 +36,7 @@ Makefile: Makefile.in
 
 test:  $(TESTPROG)
 
-tests: smtp_map11_test test_smtp_tls_policy
+tests: smtp_map11_test test_smtp_tls_policy test_smtp_reqtls_policy
 
 root_tests:
 
@@ -64,6 +67,12 @@ smtp_map11_test: smtp_map11 smtp_map11.ref
        diff smtp_map11.ref smtp_map11.tmp
        rm -f smtp_map11.tmp
 
+smtp_reqtls_policy_test: smtp_reqtls_policy_test.c smtp_reqtls_policy.o
+       $(CC) $(CFLAGS) -o $@ $@.c smtp_reqtls_policy.o $(LIBS) $(SYSLIBS)
+
+test_smtp_reqtls_policy: smtp_reqtls_policy_test
+       $(SHLIB_ENV) $(VALGRIND) ./smtp_reqtls_policy_test
+
 SMTP_POLICY_TEST_OBJ = smtp_tls_policy_test.o smtp_tls_policy.o smtp_state.o smtp_key.o
 
 smtp_tls_policy_test: $(SMTP_POLICY_TEST_OBJ) $(LIBS)
@@ -136,6 +145,7 @@ smtp.o: lmtp_params.c
 smtp.o: smtp.c
 smtp.o: smtp.h
 smtp.o: smtp_params.c
+smtp.o: smtp_reqtls_policy.h
 smtp.o: smtp_sasl.h
 smtp_addr.o: ../../include/argv.h
 smtp_addr.o: ../../include/attr.h
@@ -181,6 +191,7 @@ smtp_addr.o: ../../include/vstring.h
 smtp_addr.o: smtp.h
 smtp_addr.o: smtp_addr.c
 smtp_addr.o: smtp_addr.h
+smtp_addr.o: smtp_reqtls_policy.h
 smtp_chat.o: ../../include/argv.h
 smtp_chat.o: ../../include/attr.h
 smtp_chat.o: ../../include/check_arg.h
@@ -232,6 +243,7 @@ smtp_chat.o: ../../include/vstream.h
 smtp_chat.o: ../../include/vstring.h
 smtp_chat.o: smtp.h
 smtp_chat.o: smtp_chat.c
+smtp_chat.o: smtp_reqtls_policy.h
 smtp_connect.o: ../../include/argv.h
 smtp_connect.o: ../../include/attr.h
 smtp_connect.o: ../../include/check_arg.h
@@ -286,6 +298,7 @@ smtp_connect.o: ../../include/vstring.h
 smtp_connect.o: smtp.h
 smtp_connect.o: smtp_addr.h
 smtp_connect.o: smtp_connect.c
+smtp_connect.o: smtp_reqtls_policy.h
 smtp_connect.o: smtp_reuse.h
 smtp_key.o: ../../include/argv.h
 smtp_key.o: ../../include/attr.h
@@ -326,6 +339,7 @@ smtp_key.o: ../../include/vstream.h
 smtp_key.o: ../../include/vstring.h
 smtp_key.o: smtp.h
 smtp_key.o: smtp_key.c
+smtp_key.o: smtp_reqtls_policy.h
 smtp_map11.o: ../../include/argv.h
 smtp_map11.o: ../../include/attr.h
 smtp_map11.o: ../../include/check_arg.h
@@ -367,6 +381,7 @@ smtp_map11.o: ../../include/vstream.h
 smtp_map11.o: ../../include/vstring.h
 smtp_map11.o: smtp.h
 smtp_map11.o: smtp_map11.c
+smtp_map11.o: smtp_reqtls_policy.h
 smtp_misc.o: ../../include/argv.h
 smtp_misc.o: ../../include/attr.h
 smtp_misc.o: ../../include/check_arg.h
@@ -408,6 +423,7 @@ smtp_misc.o: ../../include/vstream.h
 smtp_misc.o: ../../include/vstring.h
 smtp_misc.o: smtp.h
 smtp_misc.o: smtp_misc.c
+smtp_misc.o: smtp_reqtls_policy.h
 smtp_params.o: smtp_params.c
 smtp_proto.o: ../../include/argv.h
 smtp_proto.o: ../../include/attr.h
@@ -435,7 +451,6 @@ smtp_proto.o: ../../include/mail_queue.h
 smtp_proto.o: ../../include/maps.h
 smtp_proto.o: ../../include/mark_corrupt.h
 smtp_proto.o: ../../include/match_list.h
-smtp_proto.o: ../../include/match_parent_style.h
 smtp_proto.o: ../../include/mime_state.h
 smtp_proto.o: ../../include/msg.h
 smtp_proto.o: ../../include/msg_stats.h
@@ -474,6 +489,7 @@ smtp_proto.o: ../../include/vstring_vstream.h
 smtp_proto.o: ../../include/xtext.h
 smtp_proto.o: smtp.h
 smtp_proto.o: smtp_proto.c
+smtp_proto.o: smtp_reqtls_policy.h
 smtp_proto.o: smtp_sasl.h
 smtp_rcpt.o: ../../include/argv.h
 smtp_rcpt.o: ../../include/attr.h
@@ -518,6 +534,32 @@ smtp_rcpt.o: ../../include/vstream.h
 smtp_rcpt.o: ../../include/vstring.h
 smtp_rcpt.o: smtp.h
 smtp_rcpt.o: smtp_rcpt.c
+smtp_rcpt.o: smtp_reqtls_policy.h
+smtp_reqtls_policy.o: ../../include/argv.h
+smtp_reqtls_policy.o: ../../include/check_arg.h
+smtp_reqtls_policy.o: ../../include/dict.h
+smtp_reqtls_policy.o: ../../include/mail_params.h
+smtp_reqtls_policy.o: ../../include/msg.h
+smtp_reqtls_policy.o: ../../include/myflock.h
+smtp_reqtls_policy.o: ../../include/mymalloc.h
+smtp_reqtls_policy.o: ../../include/stringops.h
+smtp_reqtls_policy.o: ../../include/sys_defs.h
+smtp_reqtls_policy.o: ../../include/vbuf.h
+smtp_reqtls_policy.o: ../../include/vstream.h
+smtp_reqtls_policy.o: ../../include/vstring.h
+smtp_reqtls_policy.o: smtp_reqtls_policy.c
+smtp_reqtls_policy.o: smtp_reqtls_policy.h
+smtp_reqtls_policy_test.o: ../../include/argv.h
+smtp_reqtls_policy_test.o: ../../include/check_arg.h
+smtp_reqtls_policy_test.o: ../../include/msg.h
+smtp_reqtls_policy_test.o: ../../include/msg_vstream.h
+smtp_reqtls_policy_test.o: ../../include/stringops.h
+smtp_reqtls_policy_test.o: ../../include/sys_defs.h
+smtp_reqtls_policy_test.o: ../../include/vbuf.h
+smtp_reqtls_policy_test.o: ../../include/vstream.h
+smtp_reqtls_policy_test.o: ../../include/vstring.h
+smtp_reqtls_policy_test.o: smtp_reqtls_policy.h
+smtp_reqtls_policy_test.o: smtp_reqtls_policy_test.c
 smtp_reuse.o: ../../include/argv.h
 smtp_reuse.o: ../../include/attr.h
 smtp_reuse.o: ../../include/check_arg.h
@@ -556,6 +598,7 @@ smtp_reuse.o: ../../include/vbuf.h
 smtp_reuse.o: ../../include/vstream.h
 smtp_reuse.o: ../../include/vstring.h
 smtp_reuse.o: smtp.h
+smtp_reuse.o: smtp_reqtls_policy.h
 smtp_reuse.o: smtp_reuse.c
 smtp_reuse.o: smtp_reuse.h
 smtp_sasl_auth_cache.o: ../../include/argv.h
@@ -599,6 +642,7 @@ smtp_sasl_auth_cache.o: ../../include/vbuf.h
 smtp_sasl_auth_cache.o: ../../include/vstream.h
 smtp_sasl_auth_cache.o: ../../include/vstring.h
 smtp_sasl_auth_cache.o: smtp.h
+smtp_sasl_auth_cache.o: smtp_reqtls_policy.h
 smtp_sasl_auth_cache.o: smtp_sasl_auth_cache.c
 smtp_sasl_auth_cache.o: smtp_sasl_auth_cache.h
 smtp_sasl_glue.o: ../../include/argv.h
@@ -644,6 +688,7 @@ smtp_sasl_glue.o: ../../include/vstream.h
 smtp_sasl_glue.o: ../../include/vstring.h
 smtp_sasl_glue.o: ../../include/xsasl.h
 smtp_sasl_glue.o: smtp.h
+smtp_sasl_glue.o: smtp_reqtls_policy.h
 smtp_sasl_glue.o: smtp_sasl.h
 smtp_sasl_glue.o: smtp_sasl_auth_cache.h
 smtp_sasl_glue.o: smtp_sasl_glue.c
@@ -686,6 +731,7 @@ smtp_sasl_proto.o: ../../include/vbuf.h
 smtp_sasl_proto.o: ../../include/vstream.h
 smtp_sasl_proto.o: ../../include/vstring.h
 smtp_sasl_proto.o: smtp.h
+smtp_sasl_proto.o: smtp_reqtls_policy.h
 smtp_sasl_proto.o: smtp_sasl.h
 smtp_sasl_proto.o: smtp_sasl_proto.c
 smtp_session.o: ../../include/argv.h
@@ -727,6 +773,7 @@ smtp_session.o: ../../include/vbuf.h
 smtp_session.o: ../../include/vstream.h
 smtp_session.o: ../../include/vstring.h
 smtp_session.o: smtp.h
+smtp_session.o: smtp_reqtls_policy.h
 smtp_session.o: smtp_sasl.h
 smtp_session.o: smtp_session.c
 smtp_state.o: ../../include/argv.h
@@ -768,6 +815,7 @@ smtp_state.o: ../../include/vbuf.h
 smtp_state.o: ../../include/vstream.h
 smtp_state.o: ../../include/vstring.h
 smtp_state.o: smtp.h
+smtp_state.o: smtp_reqtls_policy.h
 smtp_state.o: smtp_sasl.h
 smtp_state.o: smtp_state.c
 smtp_tls_policy.o: ../../include/argv.h
@@ -814,6 +862,7 @@ smtp_tls_policy.o: ../../include/vbuf.h
 smtp_tls_policy.o: ../../include/vstream.h
 smtp_tls_policy.o: ../../include/vstring.h
 smtp_tls_policy.o: smtp.h
+smtp_tls_policy.o: smtp_reqtls_policy.h
 smtp_tls_policy.o: smtp_tls_policy.c
 smtp_tls_policy_test.o: ../../include/argv.h
 smtp_tls_policy_test.o: ../../include/attr.h
@@ -896,6 +945,7 @@ 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_reqtls_policy.h
 smtp_tlsrpt.o: smtp_tlsrpt.c
 smtp_trouble.o: ../../include/argv.h
 smtp_trouble.o: ../../include/attr.h
@@ -940,6 +990,7 @@ smtp_trouble.o: ../../include/vbuf.h
 smtp_trouble.o: ../../include/vstream.h
 smtp_trouble.o: ../../include/vstring.h
 smtp_trouble.o: smtp.h
+smtp_trouble.o: smtp_reqtls_policy.h
 smtp_trouble.o: smtp_sasl.h
 smtp_trouble.o: smtp_trouble.c
 smtp_unalias.o: ../../include/argv.h
@@ -978,4 +1029,5 @@ smtp_unalias.o: ../../include/vbuf.h
 smtp_unalias.o: ../../include/vstream.h
 smtp_unalias.o: ../../include/vstring.h
 smtp_unalias.o: smtp.h
+smtp_unalias.o: smtp_reqtls_policy.h
 smtp_unalias.o: smtp_unalias.c
index 963081b5438f411bc27f48a07df4ed30e651d665..9240370918c7cc786f5f3941f7bed1a857cf3fa1 100644 (file)
@@ -68,6 +68,7 @@
        VAR_HFROM_FORMAT, DEF_HFROM_FORMAT, &var_hfrom_format, 1, 0,
        VAR_USE_SRV_LOOKUP, DEF_USE_SRV_LOOKUP, &var_use_srv_lookup, 0, 0,
        VAR_LMTP_TLSRPT_SOCKNAME, DEF_LMTP_TLSRPT_SOCKNAME, &var_smtp_tlsrpt_sockname, 0, 0,
+       VAR_LMTP_REQTLS_POLICY, DEF_LMTP_REQTLS_POLICY, &var_smtp_reqtls_policy, 0, 0,
        0,
     };
     static const CONFIG_TIME_TABLE lmtp_time_table[] = {
index beb46033c95a36dfa7cd7cc51aa39116d87e213d..1b8d5bc392725d3b666f71af652012375458e64f 100644 (file)
 /*     RFC 6531 (Internationalized SMTP)
 /*     RFC 6533 (Internationalized Delivery Status Notifications)
 /*     RFC 7672 (SMTP security via opportunistic DANE TLS)
-/*     RFC 8689 (TLS-Required message header)
+/*     RFC 8689 (SMTP REQUIRETLS extension, TLS-Required header)
 /* DIAGNOSTICS
 /*     Problems and transactions are logged to \fBsyslogd\fR(8)
 /*     or \fBpostlogd\fR(8).
 /* .IP "\fBsmtp_sasl_password_result_delimiter (:)\fR"
 /*     The delimiter between username and password in sasl_passwd_maps lookup
 /*     results.
-/* STARTTLS SUPPORT CONTROLS
+/* TLS SUPPORT CONTROLS
 /* .ad
 /* .fi
 /*     Detailed information about STARTTLS configuration may be found
 /* .IP "\fBtls_required_enable (yes)\fR"
 /*     Enable support for the "TLS-Required: no" message header, defined
 /*     in RFC 8689.
-/* OBSOLETE STARTTLS CONTROLS
+/* .IP "\fBrequiretls_enable (yes)\fR"
+/*     Enable support for the ESMTP verb "REQUIRETLS" in the "MAIL
+/*     FROM" command.
+/* .IP "\fBsmtp_requiretls_policy (see 'postconf -d smtp_requiretls_policy' output)\fR"
+/*     How the Postfix SMTP and LMTP client will enforce REQUIRETLS
+/*     for messages received with the REQUIRETLS option.
+/* OBSOLETE TLS CONTROLS
 /* .ad
 /* .fi
 /*     The following configuration parameters exist for compatibility
@@ -1173,6 +1179,7 @@ bool    var_allow_srv_fallback;
 bool    var_smtp_tlsrpt_enable;
 char   *var_smtp_tlsrpt_sockname;
 bool    var_smtp_tlsrpt_skip_reused_hs;
+char   *var_smtp_reqtls_policy;
 
  /* Special handling of 535 AUTH errors. */
 char   *var_smtp_sasl_auth_cache_name;
@@ -1200,6 +1207,7 @@ HBC_CHECKS *smtp_body_checks;             /* limited body checks */
 SMTP_CLI_ATTR smtp_cli_attr;           /* parsed command-line */
 int     smtp_hfrom_format;             /* postmaster notifications */
 STRING_LIST *smtp_use_srv_lookup;
+SMTP_REQTLS_POLICY *smtp_reqtls_policy;
 
 #ifdef USE_TLS
 
@@ -1707,6 +1715,16 @@ static void pre_init(char *unused_name, char **unused_argv)
     if (*var_smtp_dns_re_filter)
        dns_rr_filter_compile(VAR_LMTP_SMTP(DNS_RE_FILTER),
                              var_smtp_dns_re_filter);
+
+    /*
+     * REQUIRETLS enforcement policy. The parser appends a default action: DO
+     * NOT skip the code below if the policy string is empty. When
+     * var_reqtls_enable != 0, smtp_reqtls_policy must also be != 0.
+     */
+    if (var_reqtls_enable)
+       smtp_reqtls_policy =
+           smtp_reqtls_policy_parse(VAR_LMTP_SMTP(REQTLS_POLICY),
+                                    var_smtp_reqtls_policy);
 }
 
 /* pre_accept - see if tables have changed */
index 28cca83a44bd2f2d564bcd26a3bdb96f3d8de7e4..8433828fcdcfaada357470c0a05d31ae4036fe9a 100644 (file)
   */
 #include <tls_proxy.h>
 
+ /*
+  * This application.
+  */
+#include <smtp_reqtls_policy.h>
+
  /*
   * Global iterator support. This is updated by the connection-management
   * loop, and contains dynamic context that appears in lookup keys for SASL
@@ -202,6 +207,7 @@ typedef struct SMTP_STATE {
 #ifdef USE_TLSRPT
     struct TLSRPT_WRAPPER *tlsrpt;
 #endif
+    int     reqtls_level;              /* from smtp_reqtls_policy */
 #endif
 
     /*
@@ -242,8 +248,10 @@ typedef struct SMTP_STATE {
 
 #ifdef USE_TLS
 #define STATE_TLS_NOT_REQUIRED(state) \
-       (var_tls_required_enable && \
-           ((state)->request->sendopts & SOPT_REQUIRETLS_HEADER))
+       (var_tls_required_enable \
+           && (var_reqtls_enable == 0 \
+               || ((state)->request->sendopts & SOPT_REQUIRETLS_ESMTP) == 0) \
+           && ((state)->request->sendopts & SOPT_REQUIRETLS_HEADER))
 #endif
 
  /*
@@ -294,6 +302,7 @@ typedef struct SMTP_STATE {
 #define SMTP_FEATURE_XFORWARD_IDENT    (1<<20)
 #define SMTP_FEATURE_SMTPUTF8          (1<<21) /* RFC 6531 */
 #define SMTP_FEATURE_FROM_PROXY                (1<<22) /* proxied connection */
+#define SMTP_FEATURE_REQTLS            (1<<23) /* RFC 8689 */
 
  /*
   * Features that passivate under the endpoint.
@@ -366,6 +375,7 @@ extern STRING_LIST *smtp_use_srv_lookup;/* services with SRV record lookup */
 
 extern TLS_APPL_STATE *smtp_tls_ctx;   /* client-side TLS engine */
 extern int smtp_tls_insecure_mx_policy;        /* DANE post insecure MX? */
+extern SMTP_REQTLS_POLICY *smtp_reqtls_policy; /* parsed list */
 
 #endif
 
@@ -548,6 +558,7 @@ extern HBC_CALL_BACKS smtp_hbc_callbacks[];
 #define PLAINTEXT_FALLBACK_OK_AFTER_STARTTLS_FAILURE \
        (session->tls_context == 0 \
            && state->tls->level == TLS_LEV_MAY \
+           && !TLS_REQUIRED_BY_REQTLS_POLICY(state->reqtls_level) \
            && (TRACE_REQ_ONLY || PREACTIVE_DELAY >= var_min_backoff_time) \
            && !HAVE_SASL_CREDENTIALS)
 
@@ -555,6 +566,7 @@ extern HBC_CALL_BACKS smtp_hbc_callbacks[];
        (session->tls_context != 0 \
            && SMTP_RCPT_LEFT(state) > SMTP_RCPT_MARK_COUNT(state) \
            && state->tls->level == TLS_LEV_MAY \
+           && !TLS_REQUIRED_BY_REQTLS_POLICY(state->reqtls_level) \
            && (TRACE_REQ_ONLY || PREACTIVE_DELAY >= var_min_backoff_time) \
            && !HAVE_SASL_CREDENTIALS)
 
@@ -645,8 +657,9 @@ extern void smtp_rcpt_done(SMTP_STATE *, SMTP_RESP *, RECIPIENT *);
  /*
   * smtp_trouble.c
   */
-#define SMTP_THROTTLE  1
-#define SMTP_NOTHROTTLE        0
+#define SMTP_MISC_FAIL_NONE            0
+#define SMTP_MISC_FAIL_THROTTLE                (1<<0)
+#define SMTP_MISC_FAIL_SOFT_NON_FINAL  (1<<1)
 extern int smtp_sess_fail(SMTP_STATE *);
 extern int PRINTFLIKE(5, 6) smtp_misc_fail(SMTP_STATE *, int, const char *,
                                             SMTP_RESP *, const char *,...);
@@ -656,9 +669,9 @@ extern void PRINTFLIKE(5, 6) smtp_rcpt_fail(SMTP_STATE *, RECIPIENT *,
 extern int smtp_stream_except(SMTP_STATE *, int, const char *);
 
 #define smtp_site_fail(state, mta, resp, ...) \
-       smtp_misc_fail((state), SMTP_THROTTLE, (mta), (resp), __VA_ARGS__)
+    smtp_misc_fail((state), SMTP_MISC_FAIL_THROTTLE, (mta), (resp), __VA_ARGS__)
 #define smtp_mesg_fail(state, mta, resp, ...) \
-       smtp_misc_fail((state), SMTP_NOTHROTTLE, (mta), (resp), __VA_ARGS__)
+    smtp_misc_fail((state), SMTP_MISC_FAIL_NONE, (mta), (resp), __VA_ARGS__)
 
  /*
   * smtp_unalias.c
index 7a93e638c661e57bc82314f53ee822fce406f287..ded52ab4acf09cb9afd4df903d11c8e5343df4a9 100644 (file)
@@ -515,19 +515,51 @@ static int smtp_get_effective_tls_level(DSN_BUF *why, SMTP_STATE *state)
     }
 
     /*
-     * If the sender requires verified TLS, the TLS level must enforce a
-     * server certificate match.
+     * Skip this destination if its TLS policy cannot satisfy the REQUIRETLS
+     * policy for this destination (REQUIRETLS Failure).
+     * 
+     * Otherwise, log what would fail if REQUIRETLS was fully enforced
+     * (REQUIRETLS Debug).
+     * 
+     * Finally, skip this destination if its REQUIRETLS policy is bad.
      */
-#if 0
-    else if ((state->request->sendopts & SOPT_REQUIRETLS_ESMTP)) {
+    switch (state->reqtls_level) {
+    case SMTP_REQTLS_POLICY_ACT_ENFORCE:
        if (TLS_MUST_MATCH(tls->level) == 0) {
-           dsb_simple(why, "5.7.10", "Sender requires verified TLS, "
-                      " but my configured TLS security level is '%s %s'",
-                      var_mail_name, str_tls_level(tls->level));
+           dsb_simple(why, "5.7.10", "REQUIRETLS Failure: sender "
+                      "requested REQUIRETLS, but my configured TLS "
+                      "security level '%s' disables certificate "
+                      "matching. The last attempted server was %s",
+                      str_tls_level(tls->level), STR(iter->host));
            return (0);
        }
+       break;
+    case SMTP_REQTLS_POLICY_ACT_OPP_TLS:
+       if (tls->level == TLS_LEV_NONE) {
+           dsb_simple(why, "5.7.10", "REQUIRETLS Failure: sender "
+                      "requested REQUIRETLS, but my configured TLS "
+                      "security level '%s' disables encryption. The "
+                      "last attempted server was %s",
+                      str_tls_level(tls->level), STR(iter->host));
+           return (0);
+       } else if (TLS_MUST_MATCH(tls->level) == 0) {
+           msg_info("%s: REQUIRETLS Debug: sender requested "
+                    "REQUIRETLS, but my configured TLS security "
+                    "level '%s' disables certificate matching. "
+                    "The last attempted server was %s",
+                    state->request->queue_id,
+                    str_tls_level(tls->level), STR(iter->host));
+       }
+       break;
+    case SMTP_REQTLS_POLICY_ACT_OPPORTUNISTIC:
+    case SMTP_REQTLS_POLICY_ACT_DISABLE:
+       break;
+    default:
+       dsb_simple(why, "4.7.10", "REQUIRETLS Failure: policy "
+                  "configuration error. The last attempted "
+                  "server was %s", STR(iter->host));
+       return (0);
     }
-#endif
 
     /*
      * Success.
@@ -564,6 +596,19 @@ static void smtp_connect_local(SMTP_STATE *state, const char *path)
     if (state->misc_flags & SMTP_MISC_FLAG_CONN_CACHE_MASK)
        SET_SCACHE_REQUEST_NEXTHOP(state, path);
 
+    /*
+     * REQUIRETLS policy selection is based on the same TLS net-hop name as
+     * with certificate matching. When var_reqtls_enable != 0,
+     * smtp_reqtls_policy must also be != 0.
+     */
+#ifdef USE_TLS
+    if (STATE_REQTLS_IS_REQUESTED(var_reqtls_enable, state))
+       state->reqtls_level =
+           smtp_reqtls_policy_eval(smtp_reqtls_policy, var_myhostname);
+    else
+       state->reqtls_level = SMTP_REQTLS_POLICY_ACT_DISABLE;
+#endif
+
     /*
      * Here we ensure that the iter->addr member refers to a copy of the
      * UNIX-domain pathname, so that smtp_save_session() will cache the
@@ -974,6 +1019,19 @@ static void smtp_connect_inet(SMTP_STATE *state, const char *nexthop,
            state->tlsrpt = 0;
 #endif                                         /* USE_TLSRPT */
 
+       /*
+        * REQUIRETLS policy selection is based on the same TLS net-hop name
+        * as with certificate matching. When var_reqtls_enable != 0,
+        * smtp_reqtls_policy must also be != 0.
+        */
+#ifdef USE_TLS
+       if (STATE_REQTLS_IS_REQUESTED(var_reqtls_enable, state))
+           state->reqtls_level =
+               smtp_reqtls_policy_eval(smtp_reqtls_policy, domain);
+       else
+           state->reqtls_level = SMTP_REQTLS_POLICY_ACT_DISABLE;
+#endif
+
        /*
         * Resolve an SMTP or LMTP server. Skip MX or SRV lookups when a
         * quoted domain is specified or when DNS lookups are disabled.
index 8569cb9f58ae8571d8e9b34cfabc29e5883283a1..898689e418b4d2014cfc404c980356124a16d17a 100644 (file)
@@ -69,6 +69,7 @@
        VAR_HFROM_FORMAT, DEF_HFROM_FORMAT, &var_hfrom_format, 1, 0,
        VAR_USE_SRV_LOOKUP, DEF_USE_SRV_LOOKUP, &var_use_srv_lookup, 0, 0,
        VAR_SMTP_TLSRPT_SOCKNAME, DEF_SMTP_TLSRPT_SOCKNAME, &var_smtp_tlsrpt_sockname, 0, 0,
+       VAR_SMTP_REQTLS_POLICY, DEF_SMTP_REQTLS_POLICY, &var_smtp_reqtls_policy, 0, 0,
        0,
     };
     static const CONFIG_TIME_TABLE smtp_time_table[] = {
index b8968637819ed93ea397d7a8e5a3dd7985b75a9e..992763eeb2594612be08bb7b0f80cf3dcdae15ef 100644 (file)
 #include <mail_addr_map.h>
 #include <ext_prop.h>
 #include <namadr_list.h>
-#include <match_parent_style.h>
 #include <lex_822.h>
 #include <dsn_mask.h>
 #include <xtext.h>
@@ -604,6 +603,10 @@ int     smtp_helo(SMTP_STATE *state)
                    /* Ignored later if we already sent STARTTLS. */
                    if ((discard_mask & EHLO_MASK_STARTTLS) == 0)
                        session->features |= SMTP_FEATURE_STARTTLS;
+               } else if (strcasecmp(word, "REQUIRETLS") == 0) {
+                   if ((discard_mask & EHLO_MASK_REQTLS) == 0
+                       && (state->misc_flags & SMTP_MISC_FLAG_IN_STARTTLS))
+                       session->features |= SMTP_FEATURE_REQTLS;
 #endif
 #ifdef USE_SASL_AUTH
                } else if (var_smtp_sasl_enable
@@ -658,14 +661,18 @@ int     smtp_helo(SMTP_STATE *state)
      * SMTPUTF8.
      * 
      * Fix 20140706: moved this before negotiating TLS, AUTH, and so on.
+     * 
+     * Fix 20250824: try multiple servers before giving up.
      */
     if ((session->features & SMTP_FEATURE_SMTPUTF8) == 0
        && DELIVERY_REQUIRES_SMTPUTF8)
-       return (smtp_mesg_fail(state, DSN_BY_LOCAL_MTA,
+       return (smtp_misc_fail(state, SMTP_MISC_FAIL_SOFT_NON_FINAL,
+                              DSN_BY_LOCAL_MTA,
                               SMTP_RESP_FAKE(&fake, "5.6.7"),
-                              "SMTPUTF8 is required, "
-                              "but was not offered by host %s",
-                              session->namaddr));
+                              "message requires SMTPUTF8, but no "
+                              "server was found that supports "
+                              "SMTPUTF8. The last attempted server "
+                              "was %s", session->namaddr));
 
     /*
      * Fix 20140706: don't do silly things when the remote server announces
@@ -679,6 +686,34 @@ int     smtp_helo(SMTP_STATE *state)
        session->features |= SMTP_FEATURE_8BITMIME;
     }
 
+    /*
+     * Require that the server announces REQUIRETLS when the sender requested
+     * REQUIRETLS. Return the message as undeliverable only when there are no
+     * more alternative MX hosts. With opportunistic REQUIRETLS, only log
+     * that the server does not offer REQUIRETLS.
+     */
+#ifdef USE_TLS
+    if (TLS_REQUIRED_BY_REQTLS_POLICY(state->reqtls_level)
+       && (state->misc_flags & SMTP_MISC_FLAG_IN_STARTTLS) != 0
+       && (session->features & SMTP_FEATURE_REQTLS) == 0) {
+       switch (state->reqtls_level) {
+       case SMTP_REQTLS_POLICY_ACT_ENFORCE:
+           return (smtp_misc_fail(state, SMTP_MISC_FAIL_SOFT_NON_FINAL,
+                                  DSN_BY_LOCAL_MTA,
+                                  SMTP_RESP_FAKE(&fake, "5.7.30"),
+                                  "REQUIRETLS Failure: sender "
+                                  "requested REQUIRETLS, but no "
+                                  "server was found that supports "
+                                  "REQUIRETLS. The last attempted "
+                                  "server was %s", session->namaddr));
+       default:
+           msg_info("%s: REQUIRETLS Debug: sender requested REQUIRETLS, "
+                    "but REQUIRETLS support was not offered by host "
+                    "%s", request->queue_id, session->namaddr);
+       }
+    }
+#endif
+
     /*
      * We use SMTP command pipelining if the server said it supported it.
      * Since we use blocking I/O, RFC 2197 says that we should inspect the
@@ -811,9 +846,14 @@ int     smtp_helo(SMTP_STATE *state)
            /*
             * Give up if we must use TLS but the server rejects STARTTLS
             * although support for it was announced in the EHLO response.
+            * 
+            * When the sender requested REQUIRETLS, and the REQUIRETLS policy
+            * requires TLS, return the message as undeliverable only when
+            * there are no more alternative MX hosts.
             */
            session->features &= ~SMTP_FEATURE_STARTTLS;
-           if (TLS_REQUIRED(state->tls->level)) {
+           if (TLS_REQUIRED_BY_SECURITY_LEVEL(state->tls->level)
+               || TLS_REQUIRED_BY_REQTLS_POLICY(state->reqtls_level)) {
 #ifdef USE_TLSRPT
                if (state->tlsrpt)
                    trw_report_failure(state->tlsrpt,
@@ -821,6 +861,16 @@ int     smtp_helo(SMTP_STATE *state)
                                        /* additional_info= */ (char *) 0,
                                        /* failure_reason= */ (char *) 0);
 #endif
+               if (TLS_REQUIRED_BY_REQTLS_POLICY(state->reqtls_level))
+                   return (smtp_misc_fail(state, SMTP_MISC_FAIL_SOFT_NON_FINAL,
+                                          DSN_BY_LOCAL_MTA,
+                                          SMTP_RESP_FAKE(&fake, "5.7.10"),
+                                          "REQUIRETLS Failure: "
+                                          "sender requested REQUIRETLS, "
+                                          "but host %s refused to "
+                                          "start TLS: %s", session->namaddr,
+                                          translit(resp->str, "\n", " ")));
+               /* TLS_REQUIRED_BY_SECURITY_LEVEL */
                return (smtp_site_fail(state, STR(iter->host), resp,
                    "TLS is required, but host %s refused to start TLS: %s",
                                       session->namaddr,
@@ -835,8 +885,13 @@ int     smtp_helo(SMTP_STATE *state)
         * 200412 Be sure to provide the default clause at the bottom of this
         * block. When TLS is required we must never, ever, end up in
         * plain-text mode.
+        * 
+        * When the sender requested REQUIRETLS, and the REQUIRETLS policy
+        * requires TLS, return the message as undeliverable only when there
+        * are no more alternative MX hosts.
         */
-       if (TLS_REQUIRED(state->tls->level)) {
+       if (TLS_REQUIRED_BY_SECURITY_LEVEL(state->tls->level)
+           || TLS_REQUIRED_BY_REQTLS_POLICY(state->reqtls_level)) {
            if (!(session->features & SMTP_FEATURE_STARTTLS)) {
 #ifdef USE_TLSRPT
                if (state->tlsrpt)
@@ -845,6 +900,16 @@ int     smtp_helo(SMTP_STATE *state)
                                        /* additional_info= */ (char *) 0,
                                        /* failure_reason= */ (char *) 0);
 #endif
+               if (TLS_REQUIRED_BY_REQTLS_POLICY(state->reqtls_level))
+                   return (smtp_misc_fail(state, SMTP_MISC_FAIL_SOFT_NON_FINAL,
+                                          DSN_BY_LOCAL_MTA,
+                                          SMTP_RESP_FAKE(&fake, "5.7.30"),
+                                          "REQUIRETLS Failure: "
+                                          "sender requested REQUIRETLS, "
+                                          "but TLS service was not "
+                                          "offered by host %s",
+                                          session->namaddr));
+               /* TLS_REQUIRED_BY_SECURITY_LEVEL */
                return (smtp_site_fail(state, DSN_BY_LOCAL_MTA,
                                       SMTP_RESP_FAKE(&fake, "4.7.4"),
                          "TLS is required, but was not offered by host %s",
@@ -879,6 +944,7 @@ static int smtp_start_tls(SMTP_STATE *state)
 {
     SMTP_SESSION *session = state->session;
     SMTP_ITERATOR *iter = state->iterator;
+    DELIVER_REQUEST *request = state->request;
     TLS_CLIENT_START_PROPS start_props;
     VSTRING *serverid;
     SMTP_RESP fake;
@@ -1146,7 +1212,7 @@ static int smtp_start_tls(SMTP_STATE *state)
        if (PLAINTEXT_FALLBACK_OK_AFTER_STARTTLS_FAILURE)
            RETRY_AS_PLAINTEXT;
        return (smtp_misc_fail(state, state->tls->level == TLS_LEV_MAY ?
-                              SMTP_NOTHROTTLE : SMTP_THROTTLE,
+                              SMTP_MISC_FAIL_NONE : SMTP_MISC_FAIL_THROTTLE,
                               DSN_BY_LOCAL_MTA,
                               SMTP_RESP_FAKE(&fake, "4.7.5"),
                               "Cannot start TLS: handshake failure"));
@@ -1169,8 +1235,10 @@ static int smtp_start_tls(SMTP_STATE *state)
      * fall back to "encrypt", updating the tls_context level accordingly, so
      * 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)) {
+           int     trusted = TLS_CERT_IS_TRUSTED(session->tls_context);
+
 #ifdef USE_TLSRPT
 
            /*
@@ -1178,27 +1246,41 @@ static int smtp_start_tls(SMTP_STATE *state)
             * 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);
-               }
+               (void) trw_report_failure(state->tlsrpt, trusted ?
+                                         TLSRPT_CERTIFICATE_HOST_MISMATCH :
+                                         TLSRPT_CERTIFICATE_NOT_TRUSTED,
+                                          /* additional_info= */ (char *) 0,
+                                          /* failure_reason= */ (char *) 0);
            }
 #endif
+
+           /*
+            * When the sender requested REQUIRETLS, and REQUIRETLS is
+            * enforced, return the message as undeliverable only when there
+            * are no more alternative MX hosts.
+            */
+           if (TLS_REQUIRED_BY_REQTLS_POLICY(state->reqtls_level))
+               return (smtp_misc_fail(state, SMTP_MISC_FAIL_SOFT_NON_FINAL,
+                                      DSN_BY_LOCAL_MTA,
+                                      SMTP_RESP_FAKE(&fake, "5.7.10"),
+                                      "REQUIRETLS Failure: sender "
+                                      "requested REQUIRETLS, but "
+                                      "no %s server certificate was "
+                                      "found. The last attempted "
+                                      "server was %s", trusted ?
+                                      "matching" : "trusted",
+                                      session->namaddr));
            return (smtp_site_fail(state, DSN_BY_LOCAL_MTA,
                                   SMTP_RESP_FAKE(&fake, "4.7.5"),
                                   "Server certificate not verified"));
+       } else {
+           /* TODO(wietse) record that this attempt satisfies REQUIRETLS. */
        }
+    }
 
     /*
      * Create a TLSRPT 'success' event only if the TLS engine has not created
-     * TLSRPT event. For example, The TLS engine will create a TLSRPT
+     * 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".
@@ -1669,7 +1751,7 @@ static int smtp_loop(SMTP_STATE *state, NOCLOBBER int send_state,
             * and some as null; historically, pickup(8) does not send any of
             * these, and the queue manager presets absent fields to "not
             * available" except for the rewrite context which is preset to
-            * local by way of migration aid.  These definitions need to be
+            * local by way of migration aid. These definitions need to be
             * centralized for maintainability.
             */
 #ifndef CAN_FORWARD_CLIENT_NAME
@@ -1764,7 +1846,12 @@ static int smtp_loop(SMTP_STATE *state, NOCLOBBER int send_state,
                    vstring_sprintf_append(next_command, " ENVID=");
                    xtext_quote_append(next_command, request->dsn_envid, "+=");
                }
-               if (request->dsn_ret)
+               /* Fix 20250825: limit content exposure in bounce. */
+               if (state->reqtls_level > SMTP_REQTLS_POLICY_ACT_DISABLE
+                   && (session->features & SMTP_FEATURE_REQTLS) == 0)
+                   vstring_sprintf_append(next_command, " RET=%s",
+                                          dsn_ret_str(DSN_RET_HDRS));
+               else if (request->dsn_ret)
                    vstring_sprintf_append(next_command, " RET=%s",
                                           dsn_ret_str(request->dsn_ret));
            }
@@ -1781,7 +1868,24 @@ static int smtp_loop(SMTP_STATE *state, NOCLOBBER int send_state,
            if ((session->features & SMTP_FEATURE_SMTPUTF8) != 0
                && (request->sendopts & SMTPUTF8_FLAG_REQUESTED) != 0)
                vstring_strcat(next_command, " SMTPUTF8");
-           /* TODO(wietse) REQUIRETLS. */
+
+           /*
+            * Request REQUIRETLS when the remote SMTP server supports
+            * REQUIRETLS and the sender requested REQUIRETLS.
+            */
+#ifdef USE_TLS
+           if (state->reqtls_level > SMTP_REQTLS_POLICY_ACT_DISABLE) {
+               if ((session->features & SMTP_FEATURE_REQTLS) != 0) {
+                   vstring_strcat(next_command, " REQUIRETLS");
+                   /* TODO(wietse) record that REQUIRETLS is active. */
+               } else if (state->reqtls_level
+                          == SMTP_REQTLS_POLICY_ACT_ENFORCE) {
+                   msg_panic("Can't happen: must enforce REQUIRETLS, but "
+                             "host %s did not announce REQUIRETLS support",
+                             session->namaddr);
+               }
+           }
+#endif
 
            /*
             * We authenticate the local MTA only, but not the sender.
diff --git a/postfix/src/smtp/smtp_reqtls_policy.c b/postfix/src/smtp/smtp_reqtls_policy.c
new file mode 100644 (file)
index 0000000..75b87b8
--- /dev/null
@@ -0,0 +1,207 @@
+/*++
+/* NAME
+/*     smtp_reqtls_policy 3
+/* SUMMARY
+/*     requiretls next-hop policy
+/* SYNOPSIS
+/*     #include <smtp_reqtls_policy.h>
+/*
+/*     SMTP_REQTLS_POLICY *smtp_reqtls_policy_parse(
+/*     const char *origin,
+/*     const char *extern_policy)
+/*
+/*     int     smtp_reqtls_policy_eval(
+/*     SMTP_REQTLS_POLICY *intern_policy,
+/*     const char *nexthop_name)
+/*
+/*     void    smtp_reqtls_policy_free(
+/*     SMTP_REQTLS_POLICY *intern_policy)
+/* DESCRIPTION
+/*     This module determines the REQUIRETLS enforcement level for
+/*     connections to a next-hop destination.
+/*
+/*     smtp_reqtls_policy_parse() converts a policy from human-readable
+/*     form to internal form. It should be called as part of
+/*     before-chroot initialization. A policy is a list of elements
+/*     that will be matched in the specified order. A policy element must
+/*     be an atom ("enforce", "opportunistic+starttls", "opportunistic",
+/*     "error") or a type:table. A table lookup result must be an
+/*     atom, not a type:table. To match a parent domain name with a
+/*     table that wants and exact match, specify an explicit '.' before
+/*     the parent domain name.
+/*
+/*     smtp_reqtls_policy_eval() evaluates an internal-form
+/*     policy for the specified next-hop destination. The
+/*     result is SMTP_REQTLS_POLICY_ACT_ENFORCE (enforce),
+/*     SMTP_REQTLS_POLICY_ACT_OPP_TLS (opportunistic+starttls),
+/*     SMTP_REQTLS_POLICY_ACT_OPPORTUNISTIC (opportunistic),
+/*     SMTP_REQTLS_POLICY_ACT_DISABLE, or SMTP_REQTLS_POLICY_ACT_ERROR
+/*     (unknown command or database access error).
+/*
+/*     smtp_reqtls_policy_free() destroys an internal-form policy.
+/*
+/*     Arguments:
+/* .IP origin
+/*     The configuration parameter name for the policy from main.cf.
+/*     This is used for error reporting only.
+/* .IP extern_policy
+/*     External policy representation.
+/* .IP intern_policy
+/*     Internal policy representation.
+/* .IP nexthop_name
+/*     Next-hop destination without [ ], :service,  or :port.
+/* HISTORY
+/*     This as derived from the Postfix server_policy(3) module.
+/* 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>
+
+#ifdef STRCASECMP_IN_STRINGS_H
+#include <strings.h>
+#endif
+
+ /*
+  * Utility library.
+  */
+#include <msg.h>
+#include <mymalloc.h>
+#include <stringops.h>
+#include <dict.h>
+
+ /*
+  * Global library.
+  */
+#include <mail_params.h>
+
+ /*
+  * Application-specific.
+  */
+#include <smtp_reqtls_policy.h>
+
+/* smtp_reqtls_policy_parse - parse policy */
+
+SMTP_REQTLS_POLICY *smtp_reqtls_policy_parse(const char *origin,
+                                                 const char *extern_policy)
+{
+    char   *saved_policy = mystrdup(extern_policy);
+    SMTP_REQTLS_POLICY *intern_policy = argv_alloc(1);
+    char   *bp = saved_policy;
+    char   *item;
+
+#define STREQ(x,y) (strcasecmp((x), (y)) == 0)
+
+    /*
+     * Keep it simple, and prepend the origin to the actual policy.
+     */
+    argv_add(intern_policy, origin, (char *) 0);
+
+    /*
+     * Nested tables are not allowed. Tables are opened before entering the
+     * chroot jail, while policies are evaluated after entering the chroot
+     * jail.
+     */
+    while ((item = mystrtokq(&bp, CHARS_COMMA_SP, CHARS_BRACE)) != 0) {
+       if (strchr(item, ':') != 0) {
+           if (strchr(origin, ':') != 0) {
+               msg_warn("table %s: nested lookup result \"%s\" is not allowed"
+                        " -- ignoring remainder of policy",
+                        origin, item);
+               argv_add(intern_policy, SMTP_REQTLS_POLICY_NAME_ERROR, (char *) 0);
+               break;
+           } else {
+               item = dict_open(item, O_RDONLY, DICT_FLAG_LOCK
+                                | DICT_FLAG_FOLD_FIX
+                                | DICT_FLAG_UTF8_REQUEST)->reg_name;
+           }
+       }
+       argv_add(intern_policy, item, (char *) 0);
+    }
+    argv_terminate(intern_policy);
+
+    /*
+     * Cleanup.
+     */
+    myfree(saved_policy);
+    return (intern_policy);
+}
+
+/* smtp_reqtls_policy_eval - evaluate policy */
+
+int     smtp_reqtls_policy_eval(SMTP_REQTLS_POLICY *intern_policy,
+                                       const char *nexthop_name)
+{
+    const char *myname = "smtp_reqtls_policy_eval";
+    char  **cpp;
+    DICT   *dict;
+    SMTP_REQTLS_POLICY *argv;
+    const char *item;
+    const char *dict_val;
+    int     ret;
+    const char *name;
+    const char *next;
+    const char *origin;
+
+    origin = intern_policy->argv[0];
+    for (cpp = intern_policy->argv + 1; (item = *cpp) != 0; cpp++) {
+       if (msg_verbose)
+           msg_info("origin=%s name=%s item=%s", origin, nexthop_name, item);
+       if (STREQ(item, SMTP_REQTLS_POLICY_NAME_OPP_TLS)) {
+           return (SMTP_REQTLS_POLICY_ACT_OPP_TLS);
+       } else if (STREQ(item, SMTP_REQTLS_POLICY_NAME_ENFORCE)) {
+           return (SMTP_REQTLS_POLICY_ACT_ENFORCE);
+       } else if (STREQ(item, SMTP_REQTLS_POLICY_NAME_OPPORTUNISTIC)) {
+           return (SMTP_REQTLS_POLICY_ACT_OPPORTUNISTIC);
+       } else if (STREQ(item, SMTP_REQTLS_POLICY_NAME_DISABLE)) {
+           return (SMTP_REQTLS_POLICY_ACT_DISABLE);
+       } else if (strchr(item, ':') != 0) {
+           if ((dict = dict_handle(item)) == 0)
+               msg_panic("%s: unexpected dictionary: %s", myname, item);
+           for (name = nexthop_name; name != 0; name = next) {
+               if ((dict_val = dict_get(dict, name)) != 0) {
+                   /* Simple atom. Avoid four malloc() and free() calls. */
+                   if (dict_val[strcspn(dict_val, ":" CHARS_COMMA_SP)] == 0) {
+                       ARGV_FAKE2_BEGIN(fake_argv, item, dict_val);
+                       ret = smtp_reqtls_policy_eval(&fake_argv, name);
+                       ARGV_FAKE_END;
+                   }
+                   /* Composite or dictionary. */
+                   else {
+                       argv = smtp_reqtls_policy_parse(item, dict_val);
+                       ret = smtp_reqtls_policy_eval(argv, name);
+                       argv_free(argv);
+                   }
+                   return (ret);
+               } else if (dict->error != 0) {
+                   msg_warn("%s: %s:%s: table lookup error -- ignoring the "
+                            "remainder of this policy", origin, dict->type,
+                            dict->name);
+                   return (SMTP_REQTLS_POLICY_ACT_ERROR);
+               }
+               /* Look up .parent if the table wants an exact match. */
+               if ((dict->flags & DICT_FLAG_FIXED) == 0)
+                   break;
+               next = strchr(name + 1, '.');
+           }
+       } else if (STREQ(item, SMTP_REQTLS_POLICY_NAME_ERROR)) {
+           return (SMTP_REQTLS_POLICY_ACT_ERROR);
+       } else {
+           msg_warn("%s: unknown policy action: '%s' -- ignoring the "
+                    "remainder of this policy", origin, item);
+           return (SMTP_REQTLS_POLICY_ACT_ERROR);
+       }
+    }
+    if (msg_verbose)
+       msg_info("origin=%s name=%s - no match", origin, nexthop_name);
+    return (SMTP_REQTLS_POLICY_ACT_OPP_TLS);
+}
diff --git a/postfix/src/smtp/smtp_reqtls_policy.h b/postfix/src/smtp/smtp_reqtls_policy.h
new file mode 100644 (file)
index 0000000..35af244
--- /dev/null
@@ -0,0 +1,58 @@
+#ifndef _SMTP_REQTLS_POLICY_INCLUDED_
+#define _SMTP_REQTLS_POLICY_INCLUDED_
+
+/*++
+/* NAME
+/*     smtp_reqtls_policy 3h
+/* SUMMARY
+/*     requiretls per-mx policy
+/* SYNOPSIS
+/*     #include <smtp_reqtls_policy.h>
+/* DESCRIPTION
+/* .nf
+
+ /*
+  * Utility library.
+  */
+#include <argv.h>
+
+ /*
+  * External interface.
+  */
+typedef ARGV SMTP_REQTLS_POLICY;
+
+#define smtp_reqtls_policy_free argv_free
+extern SMTP_REQTLS_POLICY *smtp_reqtls_policy_parse(const char *, const char *);
+extern int smtp_reqtls_policy_eval(SMTP_REQTLS_POLICY *, const char *);
+
+#define SMTP_REQTLS_POLICY_NAME_ENFORCE                "enforce"
+#define SMTP_REQTLS_POLICY_NAME_OPP_TLS                "opportunistic+starttls"
+#define SMTP_REQTLS_POLICY_NAME_OPPORTUNISTIC  "opportunistic"
+#define SMTP_REQTLS_POLICY_NAME_DISABLE                "disable"
+#define SMTP_REQTLS_POLICY_NAME_ERROR          "error"
+
+#define SMTP_REQTLS_POLICY_ACT_ENFORCE         3
+#define SMTP_REQTLS_POLICY_ACT_OPP_TLS         2
+#define SMTP_REQTLS_POLICY_ACT_OPPORTUNISTIC   1
+#define SMTP_REQTLS_POLICY_ACT_DISABLE         0
+#define SMTP_REQTLS_POLICY_ACT_ERROR           (-1)
+
+#define STATE_REQTLS_IS_REQUESTED(var, state) \
+       SENDOPTS_REQTLS_IS_REQUESTED((var), (state)->request->sendopts)
+
+#define SENDOPTS_REQTLS_IS_REQUESTED(var, sendopts) \
+       ((var) && (sendopts) & SOPT_REQUIRETLS_ESMTP)
+
+#define TLS_REQUIRED_BY_REQTLS_POLICY(reqtls_level) \
+       ((reqtls_level) >= SMTP_REQTLS_POLICY_ACT_OPP_TLS)
+
+/* LICENSE
+/* .ad
+/* .fi
+/*     The Secure Mailer license must be distributed with this software.
+/* AUTHOR(S)
+/*     Wietse Venema
+/*     porcupine.org
+/*--*/
+
+#endif
diff --git a/postfix/src/smtp/smtp_reqtls_policy_test.c b/postfix/src/smtp/smtp_reqtls_policy_test.c
new file mode 100644 (file)
index 0000000..04b9d81
--- /dev/null
@@ -0,0 +1,263 @@
+ /*
+  * System library.
+  */
+#include <sys_defs.h>
+#include <stdlib.h>
+
+ /*
+  * Utility library.
+  */
+#include <msg.h>
+#include <msg_vstream.h>
+#include <stringops.h>
+
+ /*
+  * Application-specific.
+  */
+#include <smtp_reqtls_policy.h>
+
+ /*
+  * Tests and test cases.
+  */
+struct QUERY_REPLY {
+    const char *query;
+    int     reply;
+};
+
+typedef struct TEST_CASE {
+    const char *label;
+    int     (*action) (const struct TEST_CASE *);
+} TEST_CASE;
+
+static int non_regexp_policy_no_error(const TEST_CASE *tp)
+{
+    const char *ext_policy = "inline:{"
+    "{.example = disable},"
+    "{.foo.example = enforce},"
+    "{bar.foo.example = opportunistic+starttls}},"
+    "opportunistic";
+    const struct QUERY_REPLY qr[] = {
+       {"foo.example", SMTP_REQTLS_POLICY_ACT_DISABLE},
+       {"x.foo.example", SMTP_REQTLS_POLICY_ACT_ENFORCE},
+       {"bar.foo.example", SMTP_REQTLS_POLICY_ACT_OPP_TLS},
+       {"other", SMTP_REQTLS_POLICY_ACT_OPPORTUNISTIC},
+       {0},
+    };
+    SMTP_REQTLS_POLICY *int_policy;
+    const struct QUERY_REPLY *qp;
+    const char test_origin[] = "test";
+    int     got;
+    int     errors = 0;
+
+    int_policy = smtp_reqtls_policy_parse(test_origin, ext_policy);
+    for (qp = qr; qp->query; qp++) {
+       got = smtp_reqtls_policy_eval(int_policy, qp->query);
+       if (got != qp->reply) {
+           msg_warn("got result '%d', want: '%d'", got, qp->reply);
+           errors++;
+       }
+    }
+    smtp_reqtls_policy_free(int_policy);
+    return (errors == 0);
+}
+
+static int non_regexp_policy_error_at_end(const TEST_CASE *tp)
+{
+    const char *ext_policy = "inline:{"
+    "{.foo.example = enforce},"
+    "{bar.foo.example = opportunistic+starttls}},"
+    "nonsense";
+    const struct QUERY_REPLY qr[] = {
+       {"x.foo.example", SMTP_REQTLS_POLICY_ACT_ENFORCE},
+       {"bar.foo.example", SMTP_REQTLS_POLICY_ACT_OPP_TLS},
+       {"other", SMTP_REQTLS_POLICY_ACT_ERROR},
+       {0},
+    };
+    SMTP_REQTLS_POLICY *int_policy;
+    const struct QUERY_REPLY *qp;
+    const char test_origin[] = "test";
+    int     got;
+    int     errors = 0;
+
+    int_policy = smtp_reqtls_policy_parse(test_origin, ext_policy);
+    for (qp = qr; qp->query; qp++) {
+       got = smtp_reqtls_policy_eval(int_policy, qp->query);
+       if (got != qp->reply) {
+           msg_warn("got result '%d', want: '%d'", got, qp->reply);
+           errors++;
+       }
+    }
+    smtp_reqtls_policy_free(int_policy);
+    return (errors == 0);
+}
+
+static int non_regexp_policy_error_at_start(const TEST_CASE *tp)
+{
+    const char *ext_policy = "nonsense,inline:{"
+    "{.foo.example = enforce},"
+    "{bar.foo.example = debug}},"
+    "nonsense";
+    const struct QUERY_REPLY qr[] = {
+       {"x.foo.example", SMTP_REQTLS_POLICY_ACT_ERROR},
+       {"bar.foo.example", SMTP_REQTLS_POLICY_ACT_ERROR},
+       {"other", SMTP_REQTLS_POLICY_ACT_ERROR},
+       {0},
+    };
+    SMTP_REQTLS_POLICY *int_policy;
+    const struct QUERY_REPLY *qp;
+    const char test_origin[] = "test";
+    int     got;
+    int     errors = 0;
+
+    int_policy = smtp_reqtls_policy_parse(test_origin, ext_policy);
+    for (qp = qr; qp->query; qp++) {
+       got = smtp_reqtls_policy_eval(int_policy, qp->query);
+       if (got != qp->reply) {
+           msg_warn("got result '%d', want: '%d'", got, qp->reply);
+           errors++;
+       }
+    }
+    smtp_reqtls_policy_free(int_policy);
+    return (errors == 0);
+}
+
+static int policy_table_lookup_error(const TEST_CASE *tp)
+{
+    const char *ext_policy = "fail:whatever enforce";
+    const struct QUERY_REPLY qr[] = {
+       {"x.foo.example", SMTP_REQTLS_POLICY_ACT_ERROR},
+       {"other", SMTP_REQTLS_POLICY_ACT_ERROR},
+       {0},
+    };
+    SMTP_REQTLS_POLICY *int_policy;
+    const struct QUERY_REPLY *qp;
+    const char test_origin[] = "test";
+    int     got;
+    int     errors = 0;
+
+    int_policy = smtp_reqtls_policy_parse(test_origin, ext_policy);
+    for (qp = qr; qp->query; qp++) {
+       got = smtp_reqtls_policy_eval(int_policy, qp->query);
+       if (got != qp->reply) {
+           msg_warn("got result '%d', want: '%d'", got, qp->reply);
+           errors++;
+       }
+    }
+    smtp_reqtls_policy_free(int_policy);
+    return (errors == 0);
+}
+
+static int regexp_table_no_error(const TEST_CASE *tp)
+{
+    const char *ext_policy = "regexp:{{/^foo\\.example$/ enforce}}, opportunistic";
+    const struct QUERY_REPLY qr[] = {
+       {"foo.example", SMTP_REQTLS_POLICY_ACT_ENFORCE},
+       {"x.foo.example", SMTP_REQTLS_POLICY_ACT_OPPORTUNISTIC},
+       {"bar.example", SMTP_REQTLS_POLICY_ACT_OPPORTUNISTIC},
+       {"other", SMTP_REQTLS_POLICY_ACT_OPPORTUNISTIC},
+       {0},
+    };
+    SMTP_REQTLS_POLICY *int_policy;
+    const struct QUERY_REPLY *qp;
+    const char test_origin[] = "test";
+    int     got;
+    int     errors = 0;
+
+    int_policy = smtp_reqtls_policy_parse(test_origin, ext_policy);
+    for (qp = qr; qp->query; qp++) {
+       got = smtp_reqtls_policy_eval(int_policy, qp->query);
+       if (got != qp->reply) {
+           msg_warn("got result '%d', want: '%d'", got, qp->reply);
+           errors++;
+       }
+    }
+    smtp_reqtls_policy_free(int_policy);
+    return (errors == 0);
+}
+
+static int default_is_best_effort(const TEST_CASE *tp)
+{
+    const char *ext_policy = "regexp:{{/^foo\\.example$/ enforce}}";
+    const struct QUERY_REPLY qr[] = {
+       {"foo.example", SMTP_REQTLS_POLICY_ACT_ENFORCE},
+       {"x.foo.example", SMTP_REQTLS_POLICY_ACT_OPP_TLS},
+       {"bar.example", SMTP_REQTLS_POLICY_ACT_OPP_TLS},
+       {"other", SMTP_REQTLS_POLICY_ACT_OPP_TLS},
+       {0},
+    };
+    SMTP_REQTLS_POLICY *int_policy;
+    const struct QUERY_REPLY *qp;
+    const char test_origin[] = "test";
+    int     got;
+    int     errors = 0;
+
+    int_policy = smtp_reqtls_policy_parse(test_origin, ext_policy);
+    for (qp = qr; qp->query; qp++) {
+       got = smtp_reqtls_policy_eval(int_policy, qp->query);
+       if (got != qp->reply) {
+           msg_warn("got result '%d', want: '%d'", got, qp->reply);
+           errors++;
+       }
+    }
+    smtp_reqtls_policy_free(int_policy);
+    return (errors == 0);
+}
+
+static int disallow_nested_table(const TEST_CASE *tp)
+{
+    const char *ext_policy = "inline:{{foo.example = hash:/no/where}}";
+    const struct QUERY_REPLY qr[] = {
+       {"foo.example", SMTP_REQTLS_POLICY_ACT_ERROR},
+       {"x.foo.example", SMTP_REQTLS_POLICY_ACT_OPP_TLS},
+       {0},
+    };
+    SMTP_REQTLS_POLICY *int_policy;
+    const struct QUERY_REPLY *qp;
+    const char test_origin[] = "test";
+    int     got;
+    int     errors = 0;
+
+    int_policy = smtp_reqtls_policy_parse(test_origin, ext_policy);
+    for (qp = qr; qp->query; qp++) {
+       got = smtp_reqtls_policy_eval(int_policy, qp->query);
+       if (got != qp->reply) {
+           msg_warn("got result '%d', want: '%d'", got, qp->reply);
+           errors++;
+       }
+    }
+    smtp_reqtls_policy_free(int_policy);
+    return (errors == 0);
+}
+
+static TEST_CASE test_cases[] = {
+    "non_regexp_policy_no_error", non_regexp_policy_no_error,
+    "non_regexp_policy_error_at_end", non_regexp_policy_error_at_end,
+    "non_regexp_policy_error_at_start", non_regexp_policy_error_at_start,
+    "policy_table_lookup_error", policy_table_lookup_error,
+    "regexp_table_no_error", regexp_table_no_error,
+    "default_is_best_effort", default_is_best_effort,
+    "disallow_nested_table", disallow_nested_table,
+    0,
+};
+
+int     main(int argc, char **argv)
+{
+    const TEST_CASE *tp;
+    int     pass = 0;
+    int     fail = 0;
+
+    msg_vstream_init(sane_basename((VSTRING *) 0, argv[0]), VSTREAM_ERR);
+
+    for (tp = test_cases; tp->label != 0; tp++) {
+       msg_info("RUN  %s", tp->label);
+       if (tp->action(tp) == 0) {
+           fail++;
+           msg_info("FAIL %s", tp->label);
+       } else {
+           msg_info("PASS %s", tp->label);
+           pass++;
+       }
+    }
+    msg_info("PASS=%d FAIL=%d", pass, fail);
+    exit(fail != 0);
+}
index ec8cc2df39bddcf5206f317f68904b61101cf4e7..30c3bbbf6796ebb145b1deca4414f2dd72755832 100644 (file)
@@ -82,6 +82,9 @@ SMTP_STATE *smtp_state_alloc(void)
     state->iterator->saved_dest = vstring_alloc(100);
 #ifdef USE_TLSRPT
     state->tlsrpt = 0;
+#endif
+#ifdef USE_TLS
+    state->reqtls_level = SMTP_REQTLS_POLICY_ACT_DISABLE;
 #endif
     if (var_smtp_cache_conn) {
        state->dest_label = vstring_alloc(10);
index 60880df6a657a2dd18bac23c2ed14ca8e5733d3c..dd87f2979dcbc1cf132813255b34bab8aba8ed51 100644 (file)
@@ -33,9 +33,9 @@
 /*     int     exception;
 /*     const char *description;
 /* AUXILIARY FUNCTIONS
-/*     int     smtp_misc_fail(state, throttle, mta_name, resp, format, ...)
+/*     int     smtp_misc_fail(state, flags, mta_name, resp, format, ...)
 /*     SMTP_STATE *state;
-/*     int     throttle;
+/*     int     flags;
 /*     const char *mta_name;
 /*     SMTP_RESP *resp;
 /*     const char *format;
 /*
 /*     smtp_misc_fail() provides a more detailed interface than
 /*     smtp_site_fail() and smtp_mesg_fail(), which are convenience
-/*     wrappers around smtp_misc_fail(). The throttle argument
-/*     is either SMTP_THROTTLE or SMTP_NOTHROTTLE; it is used only
-/*     in the "soft error, final server" policy, and determines
-/*     whether a destination will be marked as problematic.
+/*     wrappers around smtp_misc_fail(). See the flags argument below.
 /*
 /*     smtp_rcpt_fail() handles the case where a recipient is not
 /*     accepted by the server for reasons other than that the server
 /*     Arguments:
 /* .IP state
 /*     SMTP client state per delivery request.
+/* .IP flags
+/*     Either SMTP_MISC_FAIL_NONE or the bitwise OR of
+/*     SMTP_MISC_FAIL_THROTTLE (mark the destination as problematic)
+/*     and/or SMTP_MISC_FAIL_SOFT_NON_FINAL (if the server was not
+/*     the last one to try, treat a hard error as a soft error).
 /* .IP resp
 /*     Server response including reply code and text.
 /* .IP recipient
@@ -210,7 +212,7 @@ static void smtp_check_code(SMTP_SESSION *session, int code)
 
 /* smtp_bulk_fail - skip, defer or bounce recipients, maybe throttle queue */
 
-static int smtp_bulk_fail(SMTP_STATE *state, int throttle_queue)
+static int smtp_bulk_fail(SMTP_STATE *state, int flags)
 {
     DELIVER_REQUEST *request = state->request;
     SMTP_SESSION *session = state->session;
@@ -220,8 +222,21 @@ static int smtp_bulk_fail(SMTP_STATE *state, int throttle_queue)
     int     aggregate_status;
     int     soft_error = (STR(why->status)[0] == '4');
     int     soft_bounce_error = (STR(why->status)[0] == '5' && var_soft_bounce);
+    int     throttle_queue = (flags & SMTP_MISC_FAIL_THROTTLE);
     int     nrcpt;
 
+    /*
+     * Sanity check.
+     */
+    if ((flags & SMTP_MISC_FAIL_SOFT_NON_FINAL) != 0) {
+       if (soft_error) {
+           msg_warn("smtp_bulk_fail: ignoring SMTP_MISC_FAIL_SOFT_NON_FINAL "
+                   "for a soft error");
+       } else {
+           soft_error = (state->misc_flags & SMTP_MISC_FLAG_FINAL_SERVER) == 0;
+       }
+    }
+
     /*
      * Don't defer the recipients just yet when this error qualifies them for
      * delivery to a backup server. Just log something informative to show
@@ -302,7 +317,7 @@ int     smtp_sess_fail(SMTP_STATE *state)
      * because this error information is collected by a routine that
      * terminates BEFORE the error is reported.
      */
-    return (smtp_bulk_fail(state, SMTP_THROTTLE));
+    return (smtp_bulk_fail(state, SMTP_MISC_FAIL_THROTTLE));
 }
 
 /* vsmtp_fill_dsn - fill in temporary DSN structure */
@@ -342,7 +357,7 @@ static void vsmtp_fill_dsn(SMTP_STATE *state, const char *mta_name,
 
 /* smtp_misc_fail - maybe throttle queue; skip/defer/bounce all recipients */
 
-int     smtp_misc_fail(SMTP_STATE *state, int throttle, const char *mta_name,
+int     smtp_misc_fail(SMTP_STATE *state, int flags, const char *mta_name,
                               SMTP_RESP *resp, const char *format,...)
 {
     va_list ap;
@@ -360,7 +375,7 @@ int     smtp_misc_fail(SMTP_STATE *state, int throttle, const char *mta_name,
     /*
      * Skip, defer or bounce recipients, and throttle this queue.
      */
-    return (smtp_bulk_fail(state, throttle));
+    return (smtp_bulk_fail(state, flags));
 }
 
 /* smtp_rcpt_fail - skip, defer, or bounce recipient */
@@ -472,5 +487,5 @@ int     smtp_stream_except(SMTP_STATE *state, int code, const char *description)
      * falling back to plaintext, because RETRY_AS_PLAINTEXT clears the
      * FINAL_SERVER flag.
      */
-    return (smtp_bulk_fail(state, SMTP_THROTTLE));
+    return (smtp_bulk_fail(state, SMTP_MISC_FAIL_THROTTLE));
 }
index 66a032eee184fa50cb7d0d9a05cdc070127f888f..6289fd9c480fc30dfd3854d8b81bec1c59951a8b 100644 (file)
@@ -57,6 +57,7 @@
 /*     RFC 6531 (Internationalized SMTP)
 /*     RFC 6533 (Internationalized Delivery Status Notifications)
 /*     RFC 7505 ("Null MX" No Service Resource Record)
+/*     RFC 8689 (SMTP REQUIRETLS extension)
 /* DIAGNOSTICS
 /*     Problems and transactions are logged to \fBsyslogd\fR(8)
 /*     or \fBpostlogd\fR(8).
 /* .IP "\fBsmtpd_sasl_mechanism_filter (!external, static:rest)\fR"
 /*     If non-empty, a filter for the SASL mechanism names that the
 /*     Postfix SMTP server will announce in the EHLO response.
-/* STARTTLS SUPPORT CONTROLS
+/* TLS SUPPORT CONTROLS
 /* .ad
 /* .fi
 /*     Detailed information about STARTTLS configuration may be
 /*     Request that remote SMTP clients send an RFC7250 raw public key
 /*     instead of an X.509 certificate, when asking for or requiring client
 /*     authentication.
-/* OBSOLETE STARTTLS CONTROLS
+/* .PP
+/*     Available in Postfix version 3.10 and later:
+/* .IP "\fBrequiretls_enable (yes)\fR"
+/*     Enable support for the ESMTP verb "REQUIRETLS" in the "MAIL
+/*     FROM" command.
+/* OBSOLETE TLS CONTROLS
 /* .ad
 /* .fi
 /*     The following configuration parameters exist for compatibility
@@ -2112,6 +2118,11 @@ static int ehlo_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *argv)
        EHLO_APPEND(state, "SMTPUTF8");
     if ((discard_mask & EHLO_MASK_CHUNKING) == 0)
        EHLO_APPEND(state, "CHUNKING");
+#ifdef USE_TLS
+    if (var_reqtls_enable && (discard_mask & EHLO_MASK_REQTLS) == 0
+       && state->tls_context != 0)
+       EHLO_APPEND(state, "REQUIRETLS");
+#endif
 
     /*
      * Send the reply.
@@ -2226,7 +2237,8 @@ static int mail_open_stream(SMTPD_STATE *state)
            cleanup_flags |= CLEANUP_FLAG_SMTPUTF8;
        else
            cleanup_flags |= smtputf8_autodetect(MAIL_SRC_MASK_SMTPD);
-       /* TODO(wietse) REQUIRETLS. */
+       if (state->flags & SMTPD_FLAG_REQTLS)
+           cleanup_flags |= CLEANUP_FLAG_REQTLS;
        state->dest = mail_stream_service(MAIL_CLASS_PUBLIC,
                                          var_cleanup_service);
        if (state->dest == 0
@@ -2686,6 +2698,13 @@ static int mail_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *argv)
                   && (state->ehlo_discard_mask & EHLO_MASK_SMTPUTF8) == 0
                   && strcasecmp(arg, "SMTPUTF8") == 0) {       /* RFC 6531 */
             /* Already processed early. */ ;
+#ifdef USE_TLS
+       } else if (var_reqtls_enable
+                  && state->tls_context != 0
+                  && (state->ehlo_discard_mask & EHLO_MASK_REQTLS) == 0
+                  && strcasecmp(arg, "REQUIRETLS") == 0) {     /* RFC 8689 */
+           state->flags |= SMTPD_FLAG_REQTLS;
+#endif
 #ifdef USE_SASL_AUTH
        } else if (strncasecmp(arg, "AUTH=", 5) == 0) {
            if ((err = smtpd_sasl_mail_opt(state, arg + 5)) != 0) {
index c049194e2c31d99647b071a98107e7dae602664d..3c9a452f09d8d352de35de63e3c2fd11535e6bc8 100644 (file)
@@ -209,6 +209,7 @@ typedef struct {
 #define SMTPD_FLAG_AUTH_USED      (1<<2)       /* don't reuse SASL state */
 #define SMTPD_FLAG_SMTPUTF8       (1<<3)       /* RFC 6531/2 transaction */
 #define SMTPD_FLAG_NEED_MILTER_ABORT (1<<4)    /* undo milter_mail_event() */
+#define SMTPD_FLAG_REQTLS         (1<<5)       /* RFC 8689 */
 
 #define SMTPD_NOTE_BARE_LF        (1<<0)       /* saw at least one bare LF */
 
index c54f39656051c49153455e706c45424fe8099287..8162bdc2977fdfdbe1897b21d4791938d3079b31 100644 (file)
@@ -50,7 +50,8 @@
 #define TLS_LEV_VERIFY         7       /* certificate verified */
 #define TLS_LEV_SECURE         8       /* "secure" verification */
 
-#define TLS_REQUIRED(l)                ((l) > TLS_LEV_MAY)
+#define TLS_REQUIRED_BY_SECURITY_LEVEL(l) \
+                               ((l) > TLS_LEV_MAY)
 #define TLS_MUST_MATCH(l)      ((l) > TLS_LEV_ENCRYPT)
 #define TLS_MUST_PKIX(l)       ((l) >= TLS_LEV_VERIFY)
 #define TLS_OPPORTUNISTIC(l)   ((l) == TLS_LEV_MAY || (l) == TLS_LEV_DANE)
index 555a35ef9e3ae5bc17e0d03d9cf0c8c793bf397a..a91b33bfb9371b375676e56bf088300d639468b3 100644 (file)
 /*     void    ARGV_FAKE_BEGIN(argv, arg)
 /*     const char *arg;
 /*
+/*     void    ARGV_FAKE2_BEGIN(argv, arg1, arg2)
+/*     const char *arg1;
+/*     const char *arg2;
+/*
 /*     void    ARGV_FAKE_END
 /* DESCRIPTION
 /*     The functions in this module manipulate arrays of string
 /*     implementation allocates no heap memory and creates no copy
 /*     of the second argument.  ARGV_FAKE_END closes the statement
 /*     block and thereby releases storage.
+/*
+/*     ARGV_FAKE2_BEGIN/END provide the same functionality for a pair
+/*     of strings.
 /* SEE ALSO
 /*     msg(3) diagnostics interface
 /* DIAGNOSTICS
index 1c479069644e827e227925a5962addca10307095..7331d398056f0787c59c7a4a3db77ee31a605279 100644 (file)
@@ -58,6 +58,15 @@ extern ARGV *argv_split_at_append(ARGV *, const char *, int);
        fake_argv.argv = __fake_argv_args__; \
        fake_argv.argc = fake_argv.len = 1;
 
+#define ARGV_FAKE2_BEGIN(fake_argv, arg1, arg2) { \
+       ARGV fake_argv; \
+       char *__fake_argv_args__[3]; \
+       __fake_argv_args__[0] = (char *) (arg1); \
+       __fake_argv_args__[1] = (char *) (arg2); \
+       __fake_argv_args__[2] = 0; \
+       fake_argv.argv = __fake_argv_args__; \
+       fake_argv.argc = fake_argv.len = 2;
+
 #define ARGV_FAKE_END  }
 
 #define ARGV_END       ((char *) 0)
old mode 100755 (executable)
new mode 100644 (file)
index e579b1760c148db5dcf8ca5b12f9250cd3ae0f8d..d5f55634366fe5d28786510105731cc094724af1 100644 (file)
@@ -167,9 +167,8 @@ static void inet_addr_list_print(INET_ADDR_LIST *list)
 int     main(int argc, char **argv)
 {
     INET_ADDR_LIST list;
-    INET_PROTO_INFO *proto_info;
 
-    proto_info = inet_proto_init(argv[0], INET_PROTO_NAME_ALL);
+    inet_proto_init(argv[0], INET_PROTO_NAME_ALL);
     inet_addr_list_init(&list);
     while (--argc && *++argv)
        if (inet_addr_host(&list, *argv) == 0)
index f35d5f01dbc1a13d407b82cf46833e767e7de24d..0b6fc35604c6c353bbaa810a369fa031c9ac5e74 100644 (file)
@@ -106,6 +106,7 @@ char   *inet_prefix_top(int af, const void *src, int prefix_len)
 #include <stdlib.h>
 #include <msg_vstream.h>
 #include <name_code.h>
+#include <mymalloc.h>
 
  /*
   * TODO: add test cases for fatal and panic errors, intercept msg_fatal()
index ddd4af3008ad9e23ee6b9a0039d385623f09c179..5aaa85986814275a852819186307f07cf0b350f1 100644 (file)
 /*     int     mask;
 /*     int     flags;
 /*
+/*     const char *str_name_mask_delim_opt(
+/*     VSTRING *buf,
+/*     const char *context,
+/*     const NAME_MASK *table,
+/*     int     mask,
+/*     const char *delim,
+/*     int     flags)
+/*
 /*     const char *str_long_name_mask_opt(buf, context, table, mask, flags)
 /*     VSTRING *buf;
 /*     const char *context;
 /* .IP mask
 /*     A bit mask.
 /* .IP delim
-/*     Delimiter characters to use instead of whitespace and commas.
+/*     When converting from string to mask, the set of delimiter
+/*     characters to use instead of whitespace and commas. When
+/*     converting from mask to string, the delimiter string to use
+/*     instead what may be specified with flags.
 /* .IP flags
 /*     Bit-wise OR of one or more of the following.  Where features
 /*     would have conflicting results (e.g., FATAL versus IGNORE),
@@ -260,18 +271,17 @@ int     name_mask_delim_opt(const char *context, const NAME_MASK *table,
     return (result);
 }
 
-/* str_name_mask_opt - mask to string */
+/* str_name_mask_delim_opt - mask to string */
 
-const char *str_name_mask_opt(VSTRING *buf, const char *context,
-                                     const NAME_MASK *table,
-                                     int mask, int flags)
+const char *str_name_mask_delim_opt(VSTRING *buf, const char *context,
+                                           const NAME_MASK *table,
+                                           int mask, const char *delim,
+                                           int flags)
 {
-    const char *myname = "name_mask";
+    const char *myname = "str_name_mask";
     const NAME_MASK *np;
     ssize_t len;
     static VSTRING *my_buf = 0;
-    int     delim = (flags & NAME_MASK_COMMA ? ',' :
-                    (flags & NAME_MASK_PIPE ? '|' : ' '));
 
     if ((flags & STR_NAME_MASK_REQUIRED) == 0)
        msg_panic("%s: missing NAME_MASK_NUMBER/FATAL/RETURN/WARN/IGNORE flag",
@@ -287,7 +297,7 @@ const char *str_name_mask_opt(VSTRING *buf, const char *context,
     for (np = table; mask != 0; np++) {
        if (np->name == 0) {
            if (flags & NAME_MASK_NUMBER) {
-               vstring_sprintf_append(buf, "0x%x%c", mask, delim);
+               vstring_sprintf_append(buf, "0x%x%s", mask, delim);
            } else if (flags & NAME_MASK_FATAL) {
                msg_fatal("%s: unknown %s bit in mask: 0x%x",
                          myname, context, mask);
@@ -303,16 +313,28 @@ const char *str_name_mask_opt(VSTRING *buf, const char *context,
        }
        if (mask & np->mask) {
            mask &= ~np->mask;
-           vstring_sprintf_append(buf, "%s%c", np->name, delim);
+           vstring_sprintf_append(buf, "%s%s", np->name, delim);
        }
     }
     if ((len = VSTRING_LEN(buf)) > 0)
-       vstring_truncate(buf, len - 1);
+       vstring_truncate(buf, len - strlen(delim));
     VSTRING_TERMINATE(buf);
 
     return (STR(buf));
 }
 
+/* str_name_mask_opt - mask to string */
+
+const char *str_name_mask_opt(VSTRING *buf, const char *context,
+                                     const NAME_MASK *table,
+                                     int mask, int flags)
+{
+    const char *delim = (flags & NAME_MASK_COMMA ? "," :
+                        (flags & NAME_MASK_PIPE ? "|" : " "));
+
+    return (str_name_mask_delim_opt(buf, context, table, mask, delim, flags));
+}
+
 /* long_name_mask_delim_opt - compute mask corresponding to list of names */
 
 long    long_name_mask_delim_opt(const char *context,
index 05e45ec38ba93fb7830a19b7d3931a56ee7ca468..1e7f393ff5e6c1b855455128eb137b1f6706bf84 100644 (file)
@@ -49,9 +49,10 @@ typedef struct {
 #define name_mask(tag, table, str) \
        name_mask_opt((tag), (table), (str), NAME_MASK_DEFAULT)
 #define str_name_mask(tag, table, mask) \
-       str_name_mask_opt(((VSTRING *) 0), (tag), (table), (mask), NAME_MASK_DEFAULT)
+       str_name_mask_delim_opt(((VSTRING *) 0), (tag), (table), (mask), ", ", NAME_MASK_DEFAULT)
 
 extern int name_mask_delim_opt(const char *, const NAME_MASK *, const char *, const char *, int);
+extern const char *str_name_mask_delim_opt(VSTRING *, const char *, const NAME_MASK *, int, const char *, int);
 extern const char *str_name_mask_opt(VSTRING *, const char *, const NAME_MASK *, int, int);
 
  /*
index 68c1c3091682707191028c01bbcb4f331faaa33c..2d2fa56749a4aac0950371514b379243f52029f0 100644 (file)
@@ -6,9 +6,9 @@ unknown: warning: unknown name value "four" in "four"
 four -> 0x0 -> 
 unknown: warning: unknown name value "four" in "zero one two three four"
 zero one two three four -> 0xf -> zero one two three
-unknown: warning: name_mask: unknown mask bit in mask: 0xf0
+unknown: warning: str_name_mask: unknown mask bit in mask: 0xf0
 0xff -> 0xff -> (null)
-unknown: warning: name_mask: unknown mask bit in mask: 0xfffffff0
+unknown: warning: str_name_mask: unknown mask bit in mask: 0xfffffff0
 0xffffffff -> 0xffffffff -> (null)
 unknown: warning: unknown name value "0xffffffffffffffff" in "0xffffffffffffffff"
 0xffffffffffffffff -> 0x0 -> 
index c86a532d36220b5973dc45b533db0c19a7212f75..759ac4284f0fa8af89cc55c31b1d25be896b69b8 100644 (file)
@@ -6,9 +6,9 @@ unknown: warning: unknown name value "four" in "four"
 four -> 0x0 -> 
 unknown: warning: unknown name value "four" in "zero one two three four"
 zero one two three four -> 0xf -> zero one two three
-unknown: warning: name_mask: unknown mask bit in mask: 0xf0
+unknown: warning: str_name_mask: unknown mask bit in mask: 0xf0
 0xff -> 0xff -> zero one two three
-unknown: warning: name_mask: unknown mask bit in mask: 0xfffffff0
+unknown: warning: str_name_mask: unknown mask bit in mask: 0xfffffff0
 0xffffffff -> 0xffffffff -> zero one two three
 unknown: warning: unknown name value "0xffffffffffffffff" in "0xffffffffffffffff"
 0xffffffffffffffff -> 0x0 ->