2
0
mirror of https://github.com/vdukhovni/postfix synced 2025-08-22 18:07:41 +00:00

postfix-3.10-20241024

This commit is contained in:
Wietse Z Venema 2024-10-24 00:00:00 -05:00 committed by Viktor Dukhovni
parent a5b1b93841
commit c7a9de81bf
30 changed files with 668 additions and 227 deletions

View File

@ -28394,3 +28394,48 @@ Apologies for any names omitted.
util/stream_recv_fd.c, util/stream_test.c, util/stream_recv_fd.c, util/stream_test.c,
util/unix_dgram_connect.c, util/unix_dgram_listen.c, util/unix_dgram_connect.c, util/unix_dgram_listen.c,
util/vbuf.c. util/vbuf.c.
20241015
Documentation: updated the TLSRPT_README text and example
for section "Delivering TLSRPT summaries via email". File:
proto/TLSRPT_README.html.
20241021
Bugfix (defect introduced: postfix 3.0): the default master.cf
syslog_name setting for the relay service did not preserve
multi-instance information. File: conf/master.cf.
20241022
Documentation: updated the TLSRPT_README examples for
MTA-STS. File: proto/TLSRPT_README.html.
Documentation: add explicit guidance to use "postconf -x"
when checking an inline pcre or regexp table for unescaped
'$' characters. Files: mantools/postlink, proto/pcre_table,
proto/regexp_table.
Documentation: be explicit about when Postfix expands $name
in inline pcre, regexp, and cidr lookup tables. Files:
proto/cidr_table, proto/pcre_table, proto/regexp_table.
Safety: replace ASCII control characters that match isspace()
with space characters. This prevents line breaks etc. in
smtp_tls_policy attribute values that use the long form "{
name = value }". This form was introduced with Postfix 3.10
TLSRPT support. Files: smtp/smtp_tls_policy.c, util/extpar.c,
util/Makefile.in, util/normalize_ws.c, util/stringops.h.
20241023
Logging: Postfix SMTP server 'reject' logging now shows the
sasl_method, sasl_username, and sasl_sender if available.
Viktor Dukhovni. Files: smtpd/smtpd_check.c.
20241024
Documentation: in a pgsql: client configuration, the setting
"dbname" is required, but ignored when the setting "hosts"
contains an URI with a database name. File: proto/pgsql_table.

View File

@ -175,37 +175,39 @@ Notes:
DDeelliivveerriinngg TTLLSSRRPPTT ssuummmmaarriieess vviiaa eemmaaiill DDeelliivveerriinngg TTLLSSRRPPTT ssuummmmaarriieess vviiaa eemmaaiill
RFC 8460 suggests not to enforce strict TLS security when sending daily RFC 8460 Section 3 specifies that an MTA must not enforce TLS security when
success/failure summaries via email, to avoid delivery delays caused by a sending failure reports via email. However, Postfix currently has no way to
failure to enforce TLS security. Postfix currently does not have a mechanism to request that TLS enforcement will be disabled when submitting an email message.
disable TLS security enforcement when submitting an email message; this section
provides a workaround.
By design, TLSRPT is not a real-time notification system; it takes on average Options:
12 hours before a failure is reported in a daily success/failure summary. If a
TLS-related delay of a day or more is undesirable, one could set up a transport * Do nothing. When TLS security enforcement is required, a persistent
map to make TLS security optional for specific TLSRPT email notification email enforcement failure will delay the delivery of a TLSRPT summary until the
addresses. problem is addressed, or until the message expires in the mail queue. Keep
in mind that TLSRPT is not a real-time monitoring service; it takes on
average 12 hours before a failure is reported through TLSRPT.
* Exclude the sender of TLSRPT summaries from TLS enforcement. Implement the
configuration below on outbound MTA instances (replace noreply-smtp-tls-
reporting@example.com with your actual report generator's sender address):
/etc/postfix/main.cf: /etc/postfix/main.cf:
transport_maps = hash:/etc/postfix/transport # Limitation: this setting is overruled with transport_maps.
sender_dependent_default_transport_maps = inline:{
/etc/postfix/transport: { noreply-smtp-tls-reporting@example.com = allow-plaintext } }
smtp-tls-report@example.com allow-plaintext:
...
/etc/postfix/master.cf: /etc/postfix/master.cf:
# service name type private unpriv chroot wakeup maxproc # service name type private unpriv chroot wakeup maxproc
command command
allow-plaintext unix - - n - - smtp allow-plaintext unix - - n - - smtp
-o smtp_tls_security_level=may -o { smtp_tls_security_level = may }
-o smtp_tls_policy_maps=static:may -o { smtp_tls_policy_maps = static:may }
MMTTAA--SSTTSS SSuuppppoorrtt vviiaa ssmmttpp__ttllss__ppoolliiccyy__mmaappss MMTTAA--SSTTSS SSuuppppoorrtt vviiaa ssmmttpp__ttllss__ppoolliiccyy__mmaappss
Postfix supports MTA-STS though an smtp_tls_policy_maps policy plugin. Postfix Postfix supports MTA-STS though an smtp_tls_policy_maps policy plugin, which
3.10 and later expect a policy response with the usual security level and replies with a TLS security level and optional matching requirements. Postfix
matching requirements, plus any applicable name=value attributes described 3.10 and later optionally also accept the name=value attributes described
below. Specify { name = value } when a value may contain whitespace. below. Specify { name = value } when a value may contain whitespace.
Note 1: Postfix 3.10 and later will accept these attributes in an MTA-STS Note 1: Postfix 3.10 and later will accept these attributes in an MTA-STS
@ -215,8 +217,17 @@ below. Specify { name = value } when a value may contain whitespace.
Note 2: It is an error to specify these attributes for a non-STS policy. Note 2: It is an error to specify these attributes for a non-STS policy.
The examples in the table apply to the MTA-STS policy example given in https:// The examples in the table apply to the MTA-STS policy example given in RFC 8461
datatracker.ietf.org/doc/html/rfc8460#section-4.5. Section 3.2:
version: STSv1
mode: enforce
mx: mail.example.com
mx: *.example.net
mx: backupmx.example.com
max_age: 604800
A policy response may contain line breaks.
* policy_type=type * policy_type=type
@ -238,7 +249,7 @@ datatracker.ietf.org/doc/html/rfc8460#section-4.5.
Example: Example:
{ policy_string = version: STSv1 } { policy_string = mode: testing } { policy_string = version: STSv1 } { policy_string = mode: enforce }
... ...
This form ignores whitespace after the opening "{", around the "=", and This form ignores whitespace after the opening "{", around the "=", and
@ -251,7 +262,7 @@ datatracker.ietf.org/doc/html/rfc8460#section-4.5.
Example: Example:
mx_host_pattern=mx1.example.com mx_host_pattern=mx2.example.com ... mx_host_pattern=mail.example.com mx_host_pattern=*.example.net ...
* policy_failure=type * policy_failure=type

View File

@ -6,6 +6,19 @@ Wish list:
Disable -DSNAPSHOT and -DNONPROD in makedefs. Disable -DSNAPSHOT and -DNONPROD in makedefs.
Add a mail_version chek to each pluggable database client.
Add an option for a built-in JSON generator. This would
simplify TLSRPT adoption by eliminating a build-time and
run-time dependency on the libtlsrpt client library. Prior
art: this approach was previously used to implement Postfix
Milter support.
Make TLSRPT support pluggable (postfix-tlsrpt.so, like
postfix-ldap.so, postfix-mysql.so and so on). This avods a
hard install-time dependency on sys4 libtlsrpt. The sys4
code would still be a build-time dependency.
Add smtp_tlsrpt_allow_list feature (default: static:all) to limit Add smtp_tlsrpt_allow_list feature (default: static:all) to limit
the domains for which Postfix generates TLSRPT daily summaries. the domains for which Postfix generates TLSRPT daily summaries.
@ -13,6 +26,8 @@ Wish list:
Add unit tests for smtp_tlsrpt.c, tlstrpd_wrapper.c, ... Add unit tests for smtp_tlsrpt.c, tlstrpd_wrapper.c, ...
Add unit test for extpar.c
Add tests for Message-ID extraction in the cleanup daemon. Add tests for Message-ID extraction in the cleanup daemon.
When debug logging is enabled, dict_db_open() logs a newline When debug logging is enabled, dict_db_open() logs a newline

View File

@ -69,7 +69,7 @@ proxymap unix - - n - - proxymap
proxywrite unix - - n - 1 proxymap proxywrite unix - - n - 1 proxymap
smtp unix - - n - - smtp smtp unix - - n - - smtp
relay unix - - n - - smtp relay unix - - n - - smtp
-o syslog_name=postfix/$service_name -o syslog_name=${multi_instance_name?{$multi_instance_name}:{postfix}}/$service_name
# -o smtp_helo_timeout=5 -o smtp_connect_timeout=5 # -o smtp_helo_timeout=5 -o smtp_connect_timeout=5
showq unix n - n - - showq showq unix n - n - - showq
error unix - - n - - error error unix - - n - - error

View File

@ -266,44 +266,51 @@ have the details for why TLS authentication failed. </p>
<h2> <a name="delivering"> Delivering TLSRPT summaries via email</a> </h2> <h2> <a name="delivering"> Delivering TLSRPT summaries via email</a> </h2>
<p> <a href="https://tools.ietf.org/html/rfc8460">RFC 8460</a> suggests not to enforce strict TLS security when sending <p> <a href="https://datatracker.ietf.org/doc/html/rfc8460#section-3">RFC
daily success/failure summaries via email, to avoid delivery delays 8460 Section 3</a> specifies that an MTA must not enforce TLS
caused by a failure to enforce TLS security. Postfix currently does security when sending failure reports via email. However, Postfix
not have a mechanism to disable TLS security enforcement when currently has no way to request that TLS enforcement will be disabled
submitting an email message; this section provides a workaround. </p> when submitting an email message. </p>
<p> By design, TLSRPT is not a real-time notification system; it <p> Options:
takes on average 12 hours before a failure is reported in a daily
success/failure summary. If a TLS-related delay of a day or more <ul>
is undesirable, one could set up a transport map to make TLS security
optional for specific TLSRPT email notification email addresses. <li> <p> Do nothing. When TLS security enforcement is required, a
</p> persistent enforcement failure will delay the delivery of a TLSRPT
summary until the problem is addressed, or until the message expires
in the mail queue. Keep in mind that TLSRPT is not a real-time
monitoring service; it takes on average 12 hours before a failure
is reported through TLSRPT. </p>
<li> <p> Exclude the sender of TLSRPT summaries from TLS enforcement.
Implement the configuration below on outbound MTA instances (replace
noreply-smtp-tls-reporting@example.com with your actual report
generator's sender address): </p>
<blockquote>
<pre> <pre>
/etc/postfix/<a href="postconf.5.html">main.cf</a>: /etc/postfix/<a href="postconf.5.html">main.cf</a>:
<a href="postconf.5.html#transport_maps">transport_maps</a> = <a href="DATABASE_README.html#types">hash</a>:/etc/postfix/transport # Limitation: this setting is overruled with <a href="postconf.5.html#transport_maps">transport_maps</a>.
&nbsp <a href="postconf.5.html#sender_dependent_default_transport_maps">sender_dependent_default_transport_maps</a> = <a href="DATABASE_README.html#types">inline</a>:{
/etc/postfix/transport: { noreply-smtp-tls-reporting@example.com = allow-plaintext } }
smtp-tls-report@example.com allow-plaintext:
...
&nbsp &nbsp
/etc/postfix/<a href="master.5.html">master.cf</a>: /etc/postfix/<a href="master.5.html">master.cf</a>:
# service name type private unpriv chroot wakeup maxproc command # service name type private unpriv chroot wakeup maxproc command
allow-plaintext unix - - n - - smtp allow-plaintext unix - - n - - smtp
-o <a href="postconf.5.html#smtp_tls_security_level">smtp_tls_security_level</a>=may -o { <a href="postconf.5.html#smtp_tls_security_level">smtp_tls_security_level</a> = may }
-o <a href="postconf.5.html#smtp_tls_policy_maps">smtp_tls_policy_maps</a>=<a href="DATABASE_README.html#types">static</a>:may -o { <a href="postconf.5.html#smtp_tls_policy_maps">smtp_tls_policy_maps</a> = <a href="DATABASE_README.html#types">static</a>:may }
</pre> </pre>
</blockquote>
</ul>
<h2> <a name="mta-sts"> MTA-STS Support via smtp_tls_policy_maps <h2> <a name="mta-sts"> MTA-STS Support via smtp_tls_policy_maps
</a></h2> </a></h2>
<p> Postfix supports MTA-STS though an <a href="postconf.5.html#smtp_tls_policy_maps">smtp_tls_policy_maps</a> <p> Postfix supports MTA-STS though an <a href="postconf.5.html#smtp_tls_policy_maps">smtp_tls_policy_maps</a> policy
policy plugin. Postfix 3.10 and later expect a policy response with plugin, which replies with a TLS security level and optional matching
the usual security level and matching requirements, plus any requirements. Postfix 3.10 and later optionally also accept the
applicable name=value attributes described below. Specify <tt>{ name=value attributes described below. Specify <tt>{ name = value
name = value }</tt> when a value may contain whitespace. </p> }</tt> when a value may contain whitespace. </p>
<blockquote> <blockquote>
@ -319,8 +326,22 @@ policy. </p>
</blockquote> </blockquote>
<p> The examples in the table apply to the MTA-STS policy example <p> The examples in the table apply to the MTA-STS policy example
given in <a href="https://datatracker.ietf.org/doc/html/rfc8460#section-4.5">https://datatracker.ietf.org/doc/html/rfc8460#section-4.5</a>. given in <a
<p> href="https://datatracker.ietf.org/doc/html/rfc8461#section-3.2">
RFC 8461 Section 3.2</a>: </p>
<blockquote>
<pre>
version: STSv1
mode: enforce
mx: mail.example.com
mx: *.example.net
mx: backupmx.example.com
max_age: 604800
</pre>
</blockquote>
<p> A policy response may contain line breaks. </p>
<ul> <ul>
@ -347,7 +368,7 @@ in attribute values. </p>
<blockquote> <blockquote>
<pre> <pre>
{ policy_string = version: STSv1 } { policy_string = mode: testing } ... { policy_string = version: STSv1 } { policy_string = mode: enforce } ...
</pre> </pre>
</blockquote> </blockquote>
@ -363,7 +384,7 @@ in the MTA-STS policy. </p>
<blockquote> <blockquote>
<pre> <pre>
mx_host_pattern=mx1.example.com mx_host_pattern=mx2.example.com ... mx_host_pattern=mail.example.com mx_host_pattern=*.example.net ...
</pre> </pre>
</blockquote> </blockquote>
</li> </li>

View File

@ -109,8 +109,9 @@ CIDR_TABLE(5) CIDR_TABLE(5)
<a href="master.5.html">master.cf</a>: <a href="master.5.html">master.cf</a>:
<b>.. -o {</b> <i>parameter</i> <b>= .. <a href="cidr_table.5.html">cidr</a>:{ {</b> <i>rule-1</i> <b>}, {</b> <i>rule-2</i> <b>} .. } .. } ..</b> <b>.. -o {</b> <i>parameter</i> <b>= .. <a href="cidr_table.5.html">cidr</a>:{ {</b> <i>rule-1</i> <b>}, {</b> <i>rule-2</i> <b>} .. } .. } ..</b>
Postfix ignores whitespace after '{' and before '}', and writes each Postfix recursively expands any <i>$parametername</i> instances in the above
<i>rule</i> as one text line to an in-memory file: parameter value, ignores whitespace after '{' and before '}', and
writes each <i>rule</i> as one text line to an in-memory file:
in-memory file: in-memory file:
rule-1 rule-1

View File

@ -181,8 +181,9 @@ PCRE_TABLE(5) PCRE_TABLE(5)
<a href="master.5.html">master.cf</a>: <a href="master.5.html">master.cf</a>:
<b>.. -o {</b> <i>parameter</i> <b>= .. <a href="pcre_table.5.html">pcre</a>:{ {</b> <i>rule-1</i> <b>}, {</b> <i>rule-2</i> <b>} .. } .. } ..</b> <b>.. -o {</b> <i>parameter</i> <b>= .. <a href="pcre_table.5.html">pcre</a>:{ {</b> <i>rule-1</i> <b>}, {</b> <i>rule-2</i> <b>} .. } .. } ..</b>
Postfix ignores whitespace after '{' and before '}', and writes each Postfix recursively expands any <i>$parametername</i> instances in the above
<i>rule</i> as one text line to an in-memory file: parameter value, ignores whitespace after '{' and before '}', and
writes each <i>rule</i> as one text line to an in-memory file:
in-memory file: in-memory file:
rule-1 rule-1
@ -191,12 +192,29 @@ PCRE_TABLE(5) PCRE_TABLE(5)
Postfix parses the result as if it is a file in /etc/postfix. Postfix parses the result as if it is a file in /etc/postfix.
Note: if an inlined rule contains <b>$</b>, specify <b>$$</b> to keep Postfix from <b><a name="inline_specification_caveats">INLINE SPECIFICATION CAVEATS</a></b>
trying to do <i>$name</i> expansion as it evaluates a parameter value. <b>o</b> When using <i>$parametername</i> inside an inlined pattern, use
\Q<i>$parametername</i>\E to disable metacharacters such as '.' in the
<i>$parametername</i> expansion. Otherwise, the pattern may have unex-
pected matches.
Note: when using <i>$name</i> inside an inlined pattern, use \Q<i>$name</i>\E to dis- <b>o</b> When an inlined rule must contain <b>$</b>, specify <b>$$</b> to keep Postfix
able metacharacters such as '.' in the <i>$name</i> expansion. Otherwise, the from trying to do <i>$name</i> expansion as it evaluates a parameter
pattern may have unexpected matches. value. To check an inline configuration, use the "<b>postconf -x</b>"
option as shown below:
<b>o</b> When a <a href="postconf.5.html">main.cf</a> "<i>parametername = value</i>" setting contains
an inline <a href="pcre_table.5.html">pcre</a>: table, use the command "<b>postconf -x</b>
<i>parametername</i>". Verify that there are no "undefined
parameter" warnings, and that the output has the syntax
that one would use in a non-inlined Postfix <a href="pcre_table.5.html">pcre</a>: file.
<b>o</b> When a <a href="master.5.html">master.cf</a> "<b>-o {</b> <i>parametername = value</i> <b>}</b>" override
contains an inline <a href="pcre_table.5.html">pcre</a>: table, use the command "<b>postconf</b>
<b>-Px '*/*/</b><i>parametername</i><b>'</b> ". Verify that there are no
"undefined parameter" warnings, and that the output has
the syntax that one would use in a non-inlined Postfix
<a href="pcre_table.5.html">pcre</a>: file.
<b><a name="example_smtpd_access_map">EXAMPLE SMTPD ACCESS MAP</a></b> <b><a name="example_smtpd_access_map">EXAMPLE SMTPD ACCESS MAP</a></b>
# Protect your outgoing majordomo exploders # Protect your outgoing majordomo exploders

View File

@ -48,7 +48,7 @@ PGSQL_TABLE(5) PGSQL_TABLE(5)
<b>inet:</b><i>host:port</i> for TCP connections, where the <b>unix:</b> and <b>inet:</b> <b>inet:</b><i>host:port</i> for TCP connections, where the <b>unix:</b> and <b>inet:</b>
prefixes are accepted and ignored for backwards compatibility. prefixes are accepted and ignored for backwards compatibility.
Examples: Examples:
hosts = postgresql://username@example.com/tablename?sslmode=require hosts = postgresql://username@example.com/<i>databasename</i>?sslmode=require
hosts = inet:host1.some.domain inet:host2.some.domain:port hosts = inet:host1.some.domain inet:host2.some.domain:port
hosts = host1.some.domain host2.some.domain:port hosts = host1.some.domain host2.some.domain:port
hosts = unix:/file/name hosts = unix:/file/name
@ -71,9 +71,13 @@ PGSQL_TABLE(5) PGSQL_TABLE(5)
user = someone user = someone
password = some_password password = some_password
<b>dbname</b> The database name on the servers. Example: <b>dbname</b> (required)
The database name on the servers. Example:
dbname = customer_database dbname = customer_database
This setting is required, but ignored when a postgresql:// URI
specifies a database name.
<b>encoding</b> <b>encoding</b>
The encoding used by the database client. The default setting The encoding used by the database client. The default setting
is: is:

View File

@ -138,8 +138,9 @@ REGEXP_TABLE(5) REGEXP_TABLE(5)
<a href="master.5.html">master.cf</a>: <a href="master.5.html">master.cf</a>:
<b>.. -o {</b> <i>parameter</i> <b>= .. <a href="regexp_table.5.html">regexp</a>:{ {</b> <i>rule-1</i> <b>}, {</b> <i>rule-2</i> <b>} .. } .. } ..</b> <b>.. -o {</b> <i>parameter</i> <b>= .. <a href="regexp_table.5.html">regexp</a>:{ {</b> <i>rule-1</i> <b>}, {</b> <i>rule-2</i> <b>} .. } .. } ..</b>
Postfix ignores whitespace after '{' and before '}', and writes each Postfix recursively expands any $parametername instances in the above
<i>rule</i> as one text line to an in-memory file: parameter value, ignores whitespace after '{' and before '}', and
writes each <i>rule</i> as one text line to an in-memory file:
in-memory file: in-memory file:
rule-1 rule-1
@ -148,12 +149,30 @@ REGEXP_TABLE(5) REGEXP_TABLE(5)
Postfix parses the result as if it is a file in /etc/postfix. Postfix parses the result as if it is a file in /etc/postfix.
Note: if an inlined rule contains <b>$</b>, specify <b>$$</b> to keep Postfix from <b><a name="inline_specification_caveats">INLINE SPECIFICATION CAVEATS</a></b>
trying to do <i>$name</i> expansion as it evaluates a parameter value. <b>o</b> Avoid using <i>$parametername</i> inside an inlined <a href="regexp_table.5.html">regexp</a>: pattern.
The pattern would have unexpected matches when there are
metacharacters such as '.' in the <i>$parametername</i> expansion. To
prevent unexpected matches, use a <a href="pcre_table.5.html">pcre</a>: table, and specify
\Q<i>$parametername</i>\E.
Note: when using <i>$name</i> inside an inlined pattern, this will not disable <b>o</b> When an inlined rule must contain <b>$</b>, specify <b>$$</b> to keep Postfix
metacharacters such as '.' in the <i>$name</i> expansion. To prevent unex- from trying to do <i>$name</i> expansion as it evaluates a parameter
pected matches, use a <a href="pcre_table.5.html">pcre</a>: table, and specify \Q<i>$name</i>\E. value. To check an inline configuration, use the "<b>postconf -x</b>"
option as shown below:
<b>o</b> When a <a href="postconf.5.html">main.cf</a> "<i>parametername = value</i>" setting contains
an inline <a href="regexp_table.5.html">regexp</a>: table, use the command "<b>postconf -x</b>
<i>parametername</i>". Verify that there are no "undefined
parameter" warnings, and that the output has the syntax
that one would use in a non-inlined Postfix <a href="regexp_table.5.html">regexp</a>: file.
<b>o</b> When a <a href="master.5.html">master.cf</a> "<b>-o {</b> <i>parametername = value</i> <b>}</b>" override
contains an inline <a href="regexp_table.5.html">regexp</a>: table, use the command "<b>post-</b>
<b>conf -Px '*/*/</b><i>parametername</i><b>'</b> ". Verify that there are no
"undefined parameter" warnings, and that the output has
the syntax that one would use in a non-inlined Postfix
<a href="regexp_table.5.html">regexp</a>: file.
<b><a name="example_smtpd_access_map">EXAMPLE SMTPD ACCESS MAP</a></b> <b><a name="example_smtpd_access_map">EXAMPLE SMTPD ACCESS MAP</a></b>
# Disallow sender-specified routing. This is a must if you relay mail # Disallow sender-specified routing. This is a must if you relay mail

View File

@ -127,9 +127,10 @@ master.cf:
\fB.. \-o { \fIparameter\fR \fB= .. cidr:{ { \fIrule\-1\fB }, { \fIrule\-2\fB } .. } .. } ..\fR \fB.. \-o { \fIparameter\fR \fB= .. cidr:{ { \fIrule\-1\fB }, { \fIrule\-2\fB } .. } .. } ..\fR
.fi .fi
Postfix ignores whitespace after '{' and before '}', and Postfix recursively expands any \fI$parametername\fR instances
writes each \fIrule\fR as one text line to an in\-memory in the above parameter value, ignores whitespace after '{'
file: and before '}', and writes each \fIrule\fR as one text line to
an in\-memory file:
.nf .nf
in\-memory file: in\-memory file:

View File

@ -193,9 +193,10 @@ master.cf:
\fB.. \-o { \fIparameter\fR \fB= .. pcre:{ { \fIrule\-1\fB }, { \fIrule\-2\fB } .. } .. } ..\fR \fB.. \-o { \fIparameter\fR \fB= .. pcre:{ { \fIrule\-1\fB }, { \fIrule\-2\fB } .. } .. } ..\fR
.fi .fi
Postfix ignores whitespace after '{' and before '}', and Postfix recursively expands any \fI$parametername\fR instances
writes each \fIrule\fR as one text line to an in\-memory in the above parameter value, ignores whitespace after '{'
file: and before '}', and writes each \fIrule\fR as one text line to
an in\-memory file:
.nf .nf
in\-memory file: in\-memory file:
@ -205,15 +206,35 @@ in\-memory file:
.fi .fi
Postfix parses the result as if it is a file in /etc/postfix. Postfix parses the result as if it is a file in /etc/postfix.
.SH "INLINE SPECIFICATION CAVEATS"
Note: if an inlined rule contains \fB$\fR, specify \fB$$\fR .na
.nf
.ad
.fi
.IP \(bu
When using \fI$parametername\fR inside an inlined pattern,
use \eQ\fI$parametername\fR\eE to disable metacharacters such as
\&'.' in the \fI$parametername\fR expansion. Otherwise, the pattern
may have unexpected matches.
.IP \(bu
When an inlined rule must contain \fB$\fR, specify \fB$$\fR
to keep Postfix from trying to do \fI$name\fR expansion as to keep Postfix from trying to do \fI$name\fR expansion as
it evaluates a parameter value. it evaluates a parameter value. To check an inline configuration,
use the "\fBpostconf \-x\fR" option as shown below:
Note: when using \fI$name\fR inside an inlined pattern, use .RS
\eQ\fI$name\fR\eE to disable metacharacters such as '.' in .IP \(bu
the \fI$name\fR expansion. Otherwise, the pattern may have When a main.cf "\fIparametername = \fI value\fR" setting contains
unexpected matches. an inline pcre: table, use the command "\fBpostconf \-x
\fIparametername\fR". Verify that there are no "undefined
parameter" warnings, and that the output has the syntax that
one would use in a non\-inlined Postfix pcre: file.
.IP \(bu
When a master.cf "\fB\-o { \fIparametername = value\fB }\fR"
override contains an inline pcre: table, use the command
"\fBpostconf \-Px '*/*/\fIparametername\fB' \fR". Verify that there
are no "undefined parameter" warnings, and that the output has
the syntax that one would use in a non\-inlined Postfix pcre: file.
.RE
.SH "EXAMPLE SMTPD ACCESS MAP" .SH "EXAMPLE SMTPD ACCESS MAP"
.na .na
.nf .nf

View File

@ -62,7 +62,7 @@ connections, where the \fBunix:\fR and \fBinet:\fR prefixes
are accepted and ignored for backwards compatibility. are accepted and ignored for backwards compatibility.
Examples: Examples:
.nf .nf
hosts = postgresql://username@example.com/tablename?sslmode=require hosts = postgresql://username@example.com/\fIdatabasename\fR?sslmode=require
hosts = inet:host1.some.domain inet:host2.some.domain:port hosts = inet:host1.some.domain inet:host2.some.domain:port
hosts = host1.some.domain host2.some.domain:port hosts = host1.some.domain host2.some.domain:port
hosts = unix:/file/name hosts = unix:/file/name
@ -85,11 +85,14 @@ Example:
user = someone user = someone
password = some_password password = some_password
.fi .fi
.IP "\fBdbname\fR" .IP "\fBdbname\fR (required)"
The database name on the servers. Example: The database name on the servers. Example:
.nf .nf
dbname = customer_database dbname = customer_database
.fi .fi
.sp
This setting is required, but ignored when a postgresql://
URI specifies a database name.
.IP "\fBencoding\fR" .IP "\fBencoding\fR"
The encoding used by the database client. The default setting The encoding used by the database client. The default setting
is: is:

View File

@ -150,9 +150,10 @@ master.cf:
\fB.. \-o { \fIparameter\fR \fB= .. regexp:{ { \fIrule\-1\fB }, { \fIrule\-2\fB } .. } .. } ..\fR \fB.. \-o { \fIparameter\fR \fB= .. regexp:{ { \fIrule\-1\fB }, { \fIrule\-2\fB } .. } .. } ..\fR
.fi .fi
Postfix ignores whitespace after '{' and before '}', and Postfix recursively expands any \fi$parametername\fR instances
writes each \fIrule\fR as one text line to an in\-memory in the above parameter value, ignores whitespace after '{'
file: and before '}', and writes each \fIrule\fR as one text line to
an in\-memory file:
.nf .nf
in\-memory file: in\-memory file:
@ -162,15 +163,37 @@ in\-memory file:
.fi .fi
Postfix parses the result as if it is a file in /etc/postfix. Postfix parses the result as if it is a file in /etc/postfix.
.SH "INLINE SPECIFICATION CAVEATS"
Note: if an inlined rule contains \fB$\fR, specify \fB$$\fR .na
.nf
.ad
.fi
.IP \(bu
Avoid using \fI$parametername\fR inside an inlined regexp:
pattern. The pattern would have unexpected matches when there
are metacharacters such as '.' in the \fI$parametername\fR
expansion. To prevent unexpected matches, use a pcre: table,
and specify \eQ\fI$parametername\fR\eE.
.IP \(bu
When an inlined rule must contain \fB$\fR, specify \fB$$\fR
to keep Postfix from trying to do \fI$name\fR expansion as to keep Postfix from trying to do \fI$name\fR expansion as
it evaluates a parameter value. it evaluates a parameter value. To check an inline configuration,
use the "\fBpostconf \-x\fR" option as shown below:
Note: when using \fI$name\fR inside an inlined pattern, .RS
this will not disable metacharacters such as '.' in the .IP \(bu
\fI$name\fR expansion. To prevent unexpected matches, use When a main.cf "\fIparametername = \fI value\fR" setting
a pcre: table, and specify \eQ\fI$name\fR\eE. contains an inline regexp: table, use the command "\fBpostconf
\-x \fIparametername\fR". Verify that there are no "undefined
parameter" warnings, and that the output has the syntax that
one would use in a non\-inlined Postfix regexp: file.
.IP \(bu
When a master.cf "\fB\-o { \fIparametername = value\fB }\fR"
override contains an inline regexp: table, use the command
"\fBpostconf \-Px '*/*/\fIparametername\fB' \fR". Verify that there
are no "undefined parameter" warnings, and that the output has
the syntax that one would use in a non\-inlined Postfix regexp:
file.
.RE
.SH "EXAMPLE SMTPD ACCESS MAP" .SH "EXAMPLE SMTPD ACCESS MAP"
.na .na
.nf .nf

View File

@ -1267,7 +1267,7 @@ while (<>) {
s;\b(pipe[-</bB>]*\n*[ <bB>]*map):;<a href="DATABASE_README.html#types">$1<\/a>:;g; s;\b(pipe[-</bB>]*\n*[ <bB>]*map):;<a href="DATABASE_README.html#types">$1<\/a>:;g;
s/\b(proxy):/<a href="proxymap.8.html">$1<\/a>:/g; s/\b(proxy):/<a href="proxymap.8.html">$1<\/a>:/g;
s/\b(randmap):/<a href="DATABASE_README.html#types">$1<\/a>:/g; s/\b(randmap):/<a href="DATABASE_README.html#types">$1<\/a>:/g;
s/\b(regexp):/<a href="regexp_table.5.html">$1<\/a>:/g; s;\b(reg[-</bB>]*\n*[ <bB>]*exp):;<a href="regexp_table.5.html">$1<\/a>:;g;
s/\b(sdbm):/<a href="DATABASE_README.html#types">$1<\/a>:/g; s/\b(sdbm):/<a href="DATABASE_README.html#types">$1<\/a>:/g;
s/\b(socketmap):/<a href="socketmap_table.html">$1<\/a>:/g; s/\b(socketmap):/<a href="socketmap_table.html">$1<\/a>:/g;
s/\b(sqlite):/<a href="sqlite_table.5.html">$1<\/a>:/g; s/\b(sqlite):/<a href="sqlite_table.5.html">$1<\/a>:/g;

View File

@ -266,44 +266,51 @@ have the details for why TLS authentication failed. </p>
<h2> <a name="delivering"> Delivering TLSRPT summaries via email</a> </h2> <h2> <a name="delivering"> Delivering TLSRPT summaries via email</a> </h2>
<p> RFC 8460 suggests not to enforce strict TLS security when sending <p> <a href="https://datatracker.ietf.org/doc/html/rfc8460#section-3">RFC
daily success/failure summaries via email, to avoid delivery delays 8460 Section 3</a> specifies that an MTA must not enforce TLS
caused by a failure to enforce TLS security. Postfix currently does security when sending failure reports via email. However, Postfix
not have a mechanism to disable TLS security enforcement when currently has no way to request that TLS enforcement will be disabled
submitting an email message; this section provides a workaround. </p> when submitting an email message. </p>
<p> By design, TLSRPT is not a real-time notification system; it <p> Options:
takes on average 12 hours before a failure is reported in a daily
success/failure summary. If a TLS-related delay of a day or more <ul>
is undesirable, one could set up a transport map to make TLS security
optional for specific TLSRPT email notification email addresses. <li> <p> Do nothing. When TLS security enforcement is required, a
</p> persistent enforcement failure will delay the delivery of a TLSRPT
summary until the problem is addressed, or until the message expires
in the mail queue. Keep in mind that TLSRPT is not a real-time
monitoring service; it takes on average 12 hours before a failure
is reported through TLSRPT. </p>
<li> <p> Exclude the sender of TLSRPT summaries from TLS enforcement.
Implement the configuration below on outbound MTA instances (replace
noreply-smtp-tls-reporting@example.com with your actual report
generator's sender address): </p>
<blockquote>
<pre> <pre>
/etc/postfix/main.cf: /etc/postfix/main.cf:
transport_maps = hash:/etc/postfix/transport # Limitation: this setting is overruled with transport_maps.
&nbsp sender_dependent_default_transport_maps = inline:{
/etc/postfix/transport: { noreply-smtp-tls-reporting@example.com = allow-plaintext } }
smtp-tls-report@example.com allow-plaintext:
...
&nbsp &nbsp
/etc/postfix/master.cf: /etc/postfix/master.cf:
# service name type private unpriv chroot wakeup maxproc command # service name type private unpriv chroot wakeup maxproc command
allow-plaintext unix - - n - - smtp allow-plaintext unix - - n - - smtp
-o smtp_tls_security_level=may -o { smtp_tls_security_level = may }
-o smtp_tls_policy_maps=static:may -o { smtp_tls_policy_maps = static:may }
</pre> </pre>
</blockquote>
</ul>
<h2> <a name="mta-sts"> MTA-STS Support via smtp_tls_policy_maps <h2> <a name="mta-sts"> MTA-STS Support via smtp_tls_policy_maps
</a></h2> </a></h2>
<p> Postfix supports MTA-STS though an smtp_tls_policy_maps <p> Postfix supports MTA-STS though an smtp_tls_policy_maps policy
policy plugin. Postfix 3.10 and later expect a policy response with plugin, which replies with a TLS security level and optional matching
the usual security level and matching requirements, plus any requirements. Postfix 3.10 and later optionally also accept the
applicable name=value attributes described below. Specify <tt>{ name=value attributes described below. Specify <tt>{ name = value
name = value }</tt> when a value may contain whitespace. </p> }</tt> when a value may contain whitespace. </p>
<blockquote> <blockquote>
@ -319,8 +326,22 @@ policy. </p>
</blockquote> </blockquote>
<p> The examples in the table apply to the MTA-STS policy example <p> The examples in the table apply to the MTA-STS policy example
given in https://datatracker.ietf.org/doc/html/rfc8460#section-4.5. given in <a
<p> href="https://datatracker.ietf.org/doc/html/rfc8461#section-3.2">
RFC 8461 Section 3.2</a>: </p>
<blockquote>
<pre>
version: STSv1
mode: enforce
mx: mail.example.com
mx: *.example.net
mx: backupmx.example.com
max_age: 604800
</pre>
</blockquote>
<p> A policy response may contain line breaks. </p>
<ul> <ul>
@ -347,7 +368,7 @@ in attribute values. </p>
<blockquote> <blockquote>
<pre> <pre>
{ policy_string = version: STSv1 } { policy_string = mode: testing } ... { policy_string = version: STSv1 } { policy_string = mode: enforce } ...
</pre> </pre>
</blockquote> </blockquote>
@ -363,7 +384,7 @@ in the MTA-STS policy. </p>
<blockquote> <blockquote>
<pre> <pre>
mx_host_pattern=mx1.example.com mx_host_pattern=mx2.example.com ... mx_host_pattern=mail.example.com mx_host_pattern=*.example.net ...
</pre> </pre>
</blockquote> </blockquote>
</li> </li>

View File

@ -113,9 +113,10 @@
# \fB.. -o { \fIparameter\fR \fB= .. cidr:{ { \fIrule-1\fB }, { \fIrule-2\fB } .. } .. } ..\fR # \fB.. -o { \fIparameter\fR \fB= .. cidr:{ { \fIrule-1\fB }, { \fIrule-2\fB } .. } .. } ..\fR
# .fi # .fi
# #
# Postfix ignores whitespace after '{' and before '}', and # Postfix recursively expands any \fI$parametername\fR instances
# writes each \fIrule\fR as one text line to an in-memory # in the above parameter value, ignores whitespace after '{'
# file: # and before '}', and writes each \fIrule\fR as one text line to
# an in-memory file:
# #
# .nf # .nf
# in-memory file: # in-memory file:

View File

@ -177,9 +177,10 @@
# \fB.. -o { \fIparameter\fR \fB= .. pcre:{ { \fIrule-1\fB }, { \fIrule-2\fB } .. } .. } ..\fR # \fB.. -o { \fIparameter\fR \fB= .. pcre:{ { \fIrule-1\fB }, { \fIrule-2\fB } .. } .. } ..\fR
# .fi # .fi
# #
# Postfix ignores whitespace after '{' and before '}', and # Postfix recursively expands any \fI$parametername\fR instances
# writes each \fIrule\fR as one text line to an in-memory # in the above parameter value, ignores whitespace after '{'
# file: # and before '}', and writes each \fIrule\fR as one text line to
# an in-memory file:
# #
# .nf # .nf
# in-memory file: # in-memory file:
@ -189,15 +190,33 @@
# .fi # .fi
# #
# Postfix parses the result as if it is a file in /etc/postfix. # Postfix parses the result as if it is a file in /etc/postfix.
# # INLINE SPECIFICATION CAVEATS
# Note: if an inlined rule contains \fB$\fR, specify \fB$$\fR # .ad
# .fi
# .IP \(bu
# When using \fI$parametername\fR inside an inlined pattern,
# use \eQ\fI$parametername\fR\eE to disable metacharacters such as
# '.' in the \fI$parametername\fR expansion. Otherwise, the pattern
# may have unexpected matches.
# .IP \(bu
# When an inlined rule must contain \fB$\fR, specify \fB$$\fR
# to keep Postfix from trying to do \fI$name\fR expansion as # to keep Postfix from trying to do \fI$name\fR expansion as
# it evaluates a parameter value. # it evaluates a parameter value. To check an inline configuration,
# # use the "\fBpostconf -x\fR" option as shown below:
# Note: when using \fI$name\fR inside an inlined pattern, use # .RS
# \eQ\fI$name\fR\eE to disable metacharacters such as '.' in # .IP \(bu
# the \fI$name\fR expansion. Otherwise, the pattern may have # When a main.cf "\fIparametername = \fI value\fR" setting contains
# unexpected matches. # an inline pcre: table, use the command "\fBpostconf -x
# \fIparametername\fR". Verify that there are no "undefined
# parameter" warnings, and that the output has the syntax that
# one would use in a non-inlined Postfix pcre: file.
# .IP \(bu
# When a master.cf "\fB-o { \fIparametername = value\fB }\fR"
# override contains an inline pcre: table, use the command
# "\fBpostconf -Px '*/*/\fIparametername\fB' \fR". Verify that there
# are no "undefined parameter" warnings, and that the output has
# the syntax that one would use in a non-inlined Postfix pcre: file.
# .RE
# EXAMPLE SMTPD ACCESS MAP # EXAMPLE SMTPD ACCESS MAP
# # Protect your outgoing majordomo exploders # # Protect your outgoing majordomo exploders
# /^(?!owner-)(.*)-outgoing@(.*)/ 550 Use ${1}@${2} instead # /^(?!owner-)(.*)-outgoing@(.*)/ 550 Use ${1}@${2} instead

View File

@ -52,7 +52,7 @@
# are accepted and ignored for backwards compatibility. # are accepted and ignored for backwards compatibility.
# Examples: # Examples:
# .nf # .nf
# hosts = postgresql://username@example.com/tablename?sslmode=require # hosts = postgresql://username@example.com/\fIdatabasename\fR?sslmode=require
# hosts = inet:host1.some.domain inet:host2.some.domain:port # hosts = inet:host1.some.domain inet:host2.some.domain:port
# hosts = host1.some.domain host2.some.domain:port # hosts = host1.some.domain host2.some.domain:port
# hosts = unix:/file/name # hosts = unix:/file/name
@ -75,11 +75,14 @@
# user = someone # user = someone
# password = some_password # password = some_password
# .fi # .fi
# .IP "\fBdbname\fR" # .IP "\fBdbname\fR (required)"
# The database name on the servers. Example: # The database name on the servers. Example:
# .nf # .nf
# dbname = customer_database # dbname = customer_database
# .fi # .fi
# .sp
# This setting is required, but ignored when a postgresql://
# URI specifies a database name.
# .IP "\fBencoding\fR" # .IP "\fBencoding\fR"
# The encoding used by the database client. The default setting # The encoding used by the database client. The default setting
# is: # is:

View File

@ -134,9 +134,10 @@
# \fB.. -o { \fIparameter\fR \fB= .. regexp:{ { \fIrule-1\fB }, { \fIrule-2\fB } .. } .. } ..\fR # \fB.. -o { \fIparameter\fR \fB= .. regexp:{ { \fIrule-1\fB }, { \fIrule-2\fB } .. } .. } ..\fR
# .fi # .fi
# #
# Postfix ignores whitespace after '{' and before '}', and # Postfix recursively expands any \fi$parametername\fR instances
# writes each \fIrule\fR as one text line to an in-memory # in the above parameter value, ignores whitespace after '{'
# file: # and before '}', and writes each \fIrule\fR as one text line to
# an in-memory file:
# #
# .nf # .nf
# in-memory file: # in-memory file:
@ -146,15 +147,35 @@
# .fi # .fi
# #
# Postfix parses the result as if it is a file in /etc/postfix. # Postfix parses the result as if it is a file in /etc/postfix.
# # INLINE SPECIFICATION CAVEATS
# Note: if an inlined rule contains \fB$\fR, specify \fB$$\fR # .ad
# .fi
# .IP \(bu
# Avoid using \fI$parametername\fR inside an inlined regexp:
# pattern. The pattern would have unexpected matches when there
# are metacharacters such as '.' in the \fI$parametername\fR
# expansion. To prevent unexpected matches, use a pcre: table,
# and specify \eQ\fI$parametername\fR\eE.
# .IP \(bu
# When an inlined rule must contain \fB$\fR, specify \fB$$\fR
# to keep Postfix from trying to do \fI$name\fR expansion as # to keep Postfix from trying to do \fI$name\fR expansion as
# it evaluates a parameter value. # it evaluates a parameter value. To check an inline configuration,
# # use the "\fBpostconf -x\fR" option as shown below:
# Note: when using \fI$name\fR inside an inlined pattern, # .RS
# this will not disable metacharacters such as '.' in the # .IP \(bu
# \fI$name\fR expansion. To prevent unexpected matches, use # When a main.cf "\fIparametername = \fI value\fR" setting
# a pcre: table, and specify \eQ\fI$name\fR\eE. # contains an inline regexp: table, use the command "\fBpostconf
# -x \fIparametername\fR". Verify that there are no "undefined
# parameter" warnings, and that the output has the syntax that
# one would use in a non-inlined Postfix regexp: file.
# .IP \(bu
# When a master.cf "\fB-o { \fIparametername = value\fB }\fR"
# override contains an inline regexp: table, use the command
# "\fBpostconf -Px '*/*/\fIparametername\fB' \fR". Verify that there
# are no "undefined parameter" warnings, and that the output has
# the syntax that one would use in a non-inlined Postfix regexp:
# file.
# .RE
# EXAMPLE SMTPD ACCESS MAP # EXAMPLE SMTPD ACCESS MAP
# # Disallow sender-specified routing. This is a must if you relay mail # # Disallow sender-specified routing. This is a must if you relay mail
# # for other domains. # # for other domains.

View File

@ -1847,3 +1847,6 @@ sts
tlsrprt tlsrprt
bdefhnoqv bdefhnoqv
deduplicated deduplicated
WS
isspace
ws

View File

@ -85,3 +85,4 @@ pkgconf
testfiles testfiles
Antonin Antonin
Verrier Verrier
unescaped

View File

@ -387,3 +387,5 @@ Sys
Qsmtp Qsmtp
Qsts Qsts
gmail gmail
backupmx
noreply

View File

@ -20,7 +20,7 @@
* Patches change both the patchlevel and the release date. Snapshots have no * Patches change both the patchlevel and the release date. Snapshots have no
* patchlevel; they change the release date only. * patchlevel; they change the release date only.
*/ */
#define MAIL_RELEASE_DATE "20241010" #define MAIL_RELEASE_DATE "20241024"
#define MAIL_VERSION_NUMBER "3.10" #define MAIL_VERSION_NUMBER "3.10"
#ifdef SNAPSHOT #ifdef SNAPSHOT

View File

@ -285,12 +285,17 @@ static void tls_policy_lookup_one(SMTP_TLS_POLICY *tls, int *site_level,
/* /*
* Errors in attributes may have security consequences, don't ignore * Errors in attributes may have security consequences, don't ignore
* errors that can degrade security. * errors that can degrade security.
*
* Caution: normalize whitespace, to neutralize line break etc. characters
* inside the value portion of { name = value }.
*/ */
while ((tok = mystrtokq(&policy, CHARS_COMMA_SP, CHARS_BRACE)) != 0) { while ((tok = mystrtokq(&policy, CHARS_COMMA_SP, CHARS_BRACE)) != 0) {
const char *err; const char *err;
#define EXTPAR_OPT (EXTPAR_FLAG_STRIP | EXTPAR_FLAG_NORMAL_WS)
if ((tok[0] == CHARS_BRACE[0] if ((tok[0] == CHARS_BRACE[0]
&& (err = free_me = extpar(&tok, CHARS_BRACE, EXTPAR_FLAG_STRIP)) != 0) && (err = free_me = extpar(&tok, CHARS_BRACE, EXTPAR_OPT)) != 0)
|| (err = split_nameval(tok, &name, &val)) != 0) { || (err = split_nameval(tok, &name, &val)) != 0) {
msg_warn("%s: malformed attribute/value pair \"%s\": %s", msg_warn("%s: malformed attribute/value pair \"%s\": %s",
WHERE, tok, err); WHERE, tok, err);

View File

@ -2389,6 +2389,7 @@ static int mail_open_stream(SMTPD_STATE *state)
", sasl_method=", state->sasl_method), ", sasl_method=", state->sasl_method),
PRINT2_OR_NULL(state->sasl_username, PRINT2_OR_NULL(state->sasl_username,
", sasl_username=", state->sasl_username), ", sasl_username=", state->sasl_username),
/* This is safe because state->sasl_sender is xtext-encoded. */
PRINT2_OR_NULL(state->sasl_sender, PRINT2_OR_NULL(state->sasl_sender,
", sasl_sender=", state->sasl_sender), ", sasl_sender=", state->sasl_sender),
#else #else

View File

@ -1016,6 +1016,15 @@ void log_whatsup(SMTPD_STATE *state, const char *whatsup,
vstring_sprintf_append(buf, " proto=%s", state->protocol); vstring_sprintf_append(buf, " proto=%s", state->protocol);
if (state->helo_name) if (state->helo_name)
vstring_sprintf_append(buf, " helo=<%s>", state->helo_name); vstring_sprintf_append(buf, " helo=<%s>", state->helo_name);
#ifdef USE_SASL_AUTH
if (state->sasl_method)
vstring_sprintf_append(buf, " sasl_method=%s", state->sasl_method);
if (state->sasl_username)
vstring_sprintf_append(buf, " sasl_username=%s", state->sasl_username);
/* This is safe because state->sasl_sender is xtext-encoded. */
if (state->sasl_sender)
vstring_sprintf_append(buf, " sasl_sender=%s", state->sasl_sender);
#endif
msg_info("%s", STR(buf)); msg_info("%s", STR(buf));
vstring_free(buf); vstring_free(buf);
} }

View File

@ -46,7 +46,7 @@ SRCS = alldig.c allprint.c argv.c argv_split.c attr_clnt.c attr_print0.c \
sane_strtol.c hash_fnv.c ldseed.c mkmap_cdb.c mkmap_db.c mkmap_dbm.c \ sane_strtol.c hash_fnv.c ldseed.c mkmap_cdb.c mkmap_db.c mkmap_dbm.c \
mkmap_fail.c mkmap_lmdb.c mkmap_open.c mkmap_sdbm.c inet_prefix_top.c \ mkmap_fail.c mkmap_lmdb.c mkmap_open.c mkmap_sdbm.c inet_prefix_top.c \
inet_addr_sizes.c quote_for_json.c mystrerror.c \ inet_addr_sizes.c quote_for_json.c mystrerror.c \
sane_sockaddr_to_hostaddr.c sane_sockaddr_to_hostaddr.c normalize_ws.c
OBJS = alldig.o allprint.o argv.o argv_split.o attr_clnt.o attr_print0.o \ OBJS = alldig.o allprint.o argv.o argv_split.o attr_clnt.o attr_print0.o \
attr_print64.o attr_print_plain.o attr_scan0.o attr_scan64.o \ attr_print64.o attr_print_plain.o attr_scan0.o attr_scan64.o \
attr_scan_plain.o auto_clnt.o base64_code.o basename.o binhash.o \ attr_scan_plain.o auto_clnt.o base64_code.o basename.o binhash.o \
@ -93,7 +93,8 @@ OBJS = alldig.o allprint.o argv.o argv_split.o attr_clnt.o attr_print0.o \
byte_mask.o known_tcp_ports.o argv_split_at.o dict_stream.o \ byte_mask.o known_tcp_ports.o argv_split_at.o dict_stream.o \
sane_strtol.o hash_fnv.o ldseed.o mkmap_db.o mkmap_dbm.o \ sane_strtol.o hash_fnv.o ldseed.o mkmap_db.o mkmap_dbm.o \
mkmap_fail.o mkmap_open.o inet_prefix_top.o inet_addr_sizes.o \ mkmap_fail.o mkmap_open.o inet_prefix_top.o inet_addr_sizes.o \
quote_for_json.o mystrerror.o sane_sockaddr_to_hostaddr.o quote_for_json.o mystrerror.o sane_sockaddr_to_hostaddr.o \
normalize_ws.o
# MAP_OBJ is for maps that may be dynamically loaded with dynamicmaps.cf. # MAP_OBJ is for maps that may be dynamically loaded with dynamicmaps.cf.
# When hard-linking these, makedefs sets NON_PLUGIN_MAP_OBJ=$(MAP_OBJ), # When hard-linking these, makedefs sets NON_PLUGIN_MAP_OBJ=$(MAP_OBJ),
# otherwise it sets the PLUGIN_* macros. # otherwise it sets the PLUGIN_* macros.
@ -147,7 +148,8 @@ TESTPROG= dict_open dup2_pass_on_exec events exec_command fifo_open \
vstream timecmp dict_cache midna_domain casefold strcasecmp_utf8 \ vstream timecmp dict_cache midna_domain casefold strcasecmp_utf8 \
vbuf_print split_qnameval vstream msg_logger byte_mask \ vbuf_print split_qnameval vstream msg_logger byte_mask \
known_tcp_ports dict_stream find_inet binhash hash_fnv argv \ known_tcp_ports dict_stream find_inet binhash hash_fnv argv \
clean_env inet_prefix_top printable readlline quote_for_json clean_env inet_prefix_top printable readlline quote_for_json \
normalize_ws
PLUGIN_MAP_SO = $(LIB_PREFIX)pcre$(LIB_SUFFIX) $(LIB_PREFIX)lmdb$(LIB_SUFFIX) \ PLUGIN_MAP_SO = $(LIB_PREFIX)pcre$(LIB_SUFFIX) $(LIB_PREFIX)lmdb$(LIB_SUFFIX) \
$(LIB_PREFIX)cdb$(LIB_SUFFIX) $(LIB_PREFIX)sdbm$(LIB_SUFFIX) $(LIB_PREFIX)cdb$(LIB_SUFFIX) $(LIB_PREFIX)sdbm$(LIB_SUFFIX)
HTABLE_FIX = NORANDOMIZE=1 HTABLE_FIX = NORANDOMIZE=1
@ -611,6 +613,11 @@ quote_for_json: $(LIB)
$(CC) $(CFLAGS) -DTEST -o $@ $@.c $(LIB) $(SYSLIBS) $(CC) $(CFLAGS) -DTEST -o $@ $@.c $(LIB) $(SYSLIBS)
mv junk $@.o mv junk $@.o
normalize_ws: $(LIB)
mv $@.o junk
$(CC) $(CFLAGS) -DTEST -o $@ $@.c $(LIB) $(SYSLIBS)
mv junk $@.o
tests: all valid_hostname_test mac_expand_test dict_test unescape_test \ tests: all valid_hostname_test mac_expand_test dict_test unescape_test \
hex_quote_test ctable_test inet_addr_list_test base64_code_test \ hex_quote_test ctable_test inet_addr_list_test base64_code_test \
attr_scan64_test attr_scan0_test host_port_test dict_tests \ attr_scan64_test attr_scan0_test host_port_test dict_tests \
@ -621,7 +628,8 @@ tests: all valid_hostname_test mac_expand_test dict_test unescape_test \
miss_endif_regexp_test split_qnameval_test vstring_test \ miss_endif_regexp_test split_qnameval_test vstring_test \
vstream_test byte_mask_tests mystrtok_test known_tcp_ports_test \ vstream_test byte_mask_tests mystrtok_test known_tcp_ports_test \
binhash_test argv_test inet_prefix_top_test printable_test \ binhash_test argv_test inet_prefix_top_test printable_test \
valid_utf8_string_test readlline_test quote_for_json_test valid_utf8_string_test readlline_test quote_for_json_test \
normalize_ws_test
dict_tests: all dict_test \ dict_tests: all dict_test \
dict_pcre_tests dict_cidr_test dict_thash_test dict_static_test \ dict_pcre_tests dict_cidr_test dict_thash_test dict_static_test \
@ -1098,6 +1106,9 @@ inet_prefix_top_test: inet_prefix_top
quote_for_json_test: quote_for_json quote_for_json_test: quote_for_json
$(SHLIB_ENV) ${VALGRIND} ./quote_for_json $(SHLIB_ENV) ${VALGRIND} ./quote_for_json
normalize_ws_test: normalize_ws
$(SHLIB_ENV) ${VALGRIND} ./normalize_ws
depend: $(MAKES) depend: $(MAKES)
(sed '1,/^# do not edit/!d' Makefile.in; \ (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 \
@ -2495,6 +2506,16 @@ non_blocking.o: iostuff.h
non_blocking.o: msg.h non_blocking.o: msg.h
non_blocking.o: non_blocking.c non_blocking.o: non_blocking.c
non_blocking.o: sys_defs.h non_blocking.o: sys_defs.h
normalize_ws.o: check_arg.h
normalize_ws.o: msg.h
normalize_ws.o: msg_vstream.h
normalize_ws.o: mymalloc.h
normalize_ws.o: normalize_ws.c
normalize_ws.o: stringops.h
normalize_ws.o: sys_defs.h
normalize_ws.o: vbuf.h
normalize_ws.o: vstream.h
normalize_ws.o: vstring.h
nvtable.o: htable.h nvtable.o: htable.h
nvtable.o: mymalloc.h nvtable.o: mymalloc.h
nvtable.o: nvtable.c nvtable.o: nvtable.c

View File

@ -31,6 +31,10 @@
/* .IP EXTPAR_FLAG_STRIP /* .IP EXTPAR_FLAG_STRIP
/* Skip whitespace after the opening parenthesis, and trim /* Skip whitespace after the opening parenthesis, and trim
/* whitespace before the closing parenthesis. /* whitespace before the closing parenthesis.
/* .IP EXTPAR_FLAG_NORMAL_WS
/* Substitute SPACE for control characters (newline etc.) that
/* match isspace(). This neutralizes line break etc. characters in
/* the value portion of { name = value }.
/* .RE /* .RE
/* DIAGNOSTICS /* DIAGNOSTICS
/* In case of error the result value is a dynamically-allocated /* In case of error the result value is a dynamically-allocated
@ -104,6 +108,8 @@ char *extpar(char **bp, const char *parens, int flags)
while (ISSPACE(*cp)) while (ISSPACE(*cp))
cp++; cp++;
} }
if (flags & EXTPAR_FLAG_NORMAL_WS)
normalize_ws(cp);
*bp = cp; *bp = cp;
return (err); return (err);
} }

View File

@ -0,0 +1,144 @@
/*++
/* NAME
/* normalize_ws 3
/* SUMMARY
/* neutralize isspace()-matching control characters
/* SYNOPSIS
/* #include <stringops.h>
/*
/* char *normalize_ws(char *str)
/* DESCRIPTION
/* normalize_ws() takes a null-terminated string and substitutes
/* ASCII SPACE for any ASCII control characters that match
/* isspace(). This neutralizes line break etc. characters in the
/* value portion of { name = value }. The function substitutes
/* bytes in place, and returns its str argument.
/*
/* This function requires that input is encoded in ASCII or UTF-8.
/* 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 <ctype.h>
#include <string.h>
#include <stdlib.h>
/*
* Utility library.
*/
#include <msg.h>
#include <msg_vstream.h>
#include <mymalloc.h>
#include <stringops.h>
/* normalize_ws - replace isspace() members with space characters */
char *normalize_ws(char *str)
{
char *cp;
for (cp = str; *(cp += strcspn(cp, "\t\n\v\f\r")); *cp = ' ')
/* void */ ;
return (str);
}
#ifdef TEST
typedef struct TEST_CASE {
const char *label;
int (*action) (const struct TEST_CASE *);
const char *input;
const char *want;
} TEST_CASE;
#define PASS (0)
#define FAIL (1)
#define BUFLEN 2
/* if this test fails, isspace() may have changed */
static int normalizes_all_isspace_members(const TEST_CASE *unused)
{
int ch;
char input[BUFLEN];
char want[BUFLEN];
char *got;
for (ch = 0; ISASCII(ch); ch++) {
input[0] = ch;
input[1] = 0;
want[0] = ISSPACE(ch) ? ' ' : ch;
want[1] = 0;
got = normalize_ws(input);
if (got != input) {
msg_warn("got %p, want %p", got, input);
return (FAIL);
}
if (memcmp(got, want, BUFLEN) != 0) {
msg_warn("got '{0x%02x 0x%02x}', want '{0x%02x 0x%02x}",
got[0], got[1], want[0], want[1]);
return (FAIL);
}
}
return (PASS);
}
static int test_normalize_ws(const TEST_CASE *tp)
{
char *input = mystrdup(tp->input);
char *got;
got = normalize_ws(input);
if (strcmp(got, tp->want) != 0) {
msg_warn("got '%s', want '%s'", got, tp->want);
return (FAIL);
}
myfree(input);
return (PASS);
}
static const TEST_CASE test_cases[] = {
{"normalizes all isspace members", normalizes_all_isspace_members,},
{"normalizes_first", test_normalize_ws, "\tfoo", " foo",},
{"normalizes_middle", test_normalize_ws, "fo\to", "fo o",},
{"normalizes_last", test_normalize_ws, "foo\t", "foo ",},
{"normalizes_multiple", test_normalize_ws, "\tfo\to\t", " fo o ",},
{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++) {
int test_failed;
msg_info("RUN %s", tp->label);
test_failed = tp->action(tp);
if (test_failed) {
msg_info("FAIL %s", tp->label);
fail++;
} else {
msg_info("PASS %s", tp->label);
pass++;
}
}
msg_info("PASS=%d FAIL=%d", pass, fail);
exit(fail != 0);
}
#endif

View File

@ -68,10 +68,12 @@ extern int strncasecmp_utf8x(int, const char *, const char *, ssize_t);
extern char *quote_for_json(VSTRING *, const char *, ssize_t); extern char *quote_for_json(VSTRING *, const char *, ssize_t);
extern char *quote_for_json_append(VSTRING *, const char *, ssize_t); extern char *quote_for_json_append(VSTRING *, const char *, ssize_t);
extern const char *mystrerror(int); extern const char *mystrerror(int);
extern char *normalize_ws(char *);
#define EXTPAR_FLAG_NONE (0) #define EXTPAR_FLAG_NONE (0)
#define EXTPAR_FLAG_STRIP (1<<0) /* "{ text }" -> "text" */ #define EXTPAR_FLAG_STRIP (1<<0) /* "{ text }" -> "text" */
#define EXTPAR_FLAG_EXTRACT (1<<1) /* hint from caller's caller */ #define EXTPAR_FLAG_EXTRACT (1<<1) /* hint from caller's caller */
#define EXTPAR_FLAG_NORMAL_WS (1<<2) /* normalize 'isspace' members */
#define CASEF_FLAG_UTF8 (1<<0) #define CASEF_FLAG_UTF8 (1<<0)
#define CASEF_FLAG_APPEND (1<<1) #define CASEF_FLAG_APPEND (1<<1)