with similar code elsewhere. File: master/master_ent.c.
Backed out SMTP client TLS fallback due to multiple problems.
+
+20141018
+
+ Bugfix (introduced: Postfix 2.3): when a Milter inserted a
+ header ABOVE Postfix's own Received: header, Postfix would
+ expose its own Received: header to Milters (violating
+ protocol) and hide the Milter-inserted header from Milters
+ (wtf). Files: cleanup/cleanup.h, cleanup/cleanup_message.c,
+ cleanup/cleanup_state.c, milter/milter.[hc], milter/milter8.c.
+
+ Cleanup: revert the workaround that places headers inserted
+ with PREPEND actions or policy requests BELOW Postfix's own
+ Received: message header. File: smtpd/smtpd.c.
+
+20141019
+
+ Cleanup: replace dozens and dozens of ad-hoc string constants
+ with CHARS_SPACE, CHARS_COMMA_SP, and CHARS_BRACE. Files:
+ 52, too many files to mention here.
* The "example.com" destination uses DANE, but if TLSA records are not
present or are unusable, mail is deferred.
- * The "example.org" destination uses DANE if possible, but uses opportunistic
- TLS if no TLSA records are found. The "fallback" attribute (Postfix >=
- 2.12) overrides the global main.cf smtp_tls_fallback_level parameter to
- employ unauthenticated mandatory encryption if DANE authentication fails,
- after logging a warning.
+ * The "example.org" destination uses DANE if possible, but if no TLSA records
+ are found opportunistic TLS is used.
main.cf:
indexed = ${default_database_type}:${config_directory}/
tls_policy:
example.com dane-only
- # Postfix >= 2.12, per-destination smtp_tls_fallback_level override
- example.org dane fallback=encrypt
master.cf:
dane unix - - n - - smtp
obtained for the remote SMTP server, SSLv2 is automatically disabled (see
smtp_tls_mandatory_protocols), and the server certificate must match the
TLSA records. RFC 6698 (DANE) TLS authentication and DNSSEC support is
- available with Postfix 2.11 and later. The optional "fallback" attribute
- provides a per-site override of the main.cf smtp_tls_fallback_level
- parameter (Postfix >= 2.12).
+ available with Postfix 2.11 and later.
d\bda\ban\bne\be-\b-o\bon\bnl\bly\by
Mandatory DANE TLS. The TLS policy for the destination is obtained via TLSA
records in DNSSEC. If no TLSA records are found, or none are usable, no
the remote SMTP server, SSLv2 is automatically disabled (see
smtp_tls_mandatory_protocols), and the server certificate must match the
TLSA records. RFC 6698 (DANE) TLS authentication and DNSSEC support is
- available with Postfix 2.11 and later. The optional "fallback" attribute
- provides a per-site override of the main.cf smtp_tls_fallback_level
- parameter (Postfix >= 2.12).
+ available with Postfix 2.11 and later.
f\bfi\bin\bng\bge\ber\brp\bpr\bri\bin\bnt\bt
Certificate fingerprint verification. Available with Postfix 2.5 and later.
At this security level, there are no trusted certificate authorities. The
combined with a "|" delimiter in a single match attribute, or multiple
match attributes can be employed. The ":" character is not used as a
delimiter as it occurs between each pair of fingerprint (hexadecimal)
- digits. The optional "fallback" attribute provides a per-site override of
- the main.cf smtp_tls_fallback_level parameter (Postfix >= 2.12).
+ digits.
v\bve\ber\bri\bif\bfy\by
Mandatory server certificate verification. Mail is delivered only if the
TLS handshake succeeds, if the remote SMTP server certificate can be
"tafile" attribute optionally modifies trust chain verification in the same
manner as the "smtp_tls_trust_anchor_file" parameter. The "tafile"
attribute may be specified multiple times to load multiple trust-anchor
- files. The optional "fallback" attribute provides a per-site override of
- the main.cf smtp_tls_fallback_level parameter (Postfix >= 2.12).
+ files.
s\bse\bec\bcu\bur\bre\be
Secure certificate verification. Mail is delivered only if the TLS
handshake succeeds, if the remote SMTP server certificate can be validated
"match" attribute is specified). With Postfix >= 2.11 the "tafile"
attribute optionally modifies trust chain verification in the same manner
as the "smtp_tls_trust_anchor_file" parameter. The "tafile" attribute may
- be specified multiple times to load multiple trust-anchor files. The
- optional "fallback" attribute provides a per-site override of the main.cf
- smtp_tls_fallback_level parameter (Postfix >= 2.12).
+ be specified multiple times to load multiple trust-anchor files.
Notes:
* The "match" attribute is especially useful to verify TLS certificates for
smtp_tls_policy_maps = hash:/etc/postfix/tls_policy
# Postfix 2.5 and later
smtp_tls_fingerprint_digest = md5
-
/etc/postfix/tls_policy:
example.edu none
example.mil may
# Postfix 2.6 and later
example.info may protocols=!SSLv2 ciphers=medium
exclude=3DES
- # Postfix 2.12 and later override of smtp_tls_fallback_level
- fallback.example secure fallback=encrypt
N\bNo\bot\bte\be:\b: The "hostname" strategy if listed in a non-default setting of
smtp_tls_secure_cert_match or in the "match" attribute in the policy table can
<li> <p> The "example.com" destination uses DANE, but if TLSA records
are not present or are unusable, mail is deferred. </p>
-<li> <p> The "example.org" destination uses DANE if possible, but
-uses opportunistic TLS if no TLSA records are found. The
-"fallback" attribute (Postfix ≥ 2.12) overrides the global
-<a href="postconf.5.html">main.cf</a> <a href="postconf.5.html#smtp_tls_fallback_level">smtp_tls_fallback_level</a> parameter to employ unauthenticated
-mandatory encryption if DANE authentication fails, after logging a
-warning. </p>
+<li> <p> The "example.org" destination uses DANE if possible, but if no TLSA
+records are found opportunistic TLS is used. </p>
</ul>
<blockquote>
# <a href="postconf.5.html#default_transport">default_transport</a> = smtp, but some destinations are special:
#
<a href="postconf.5.html#transport_maps">transport_maps</a> = ${indexed}transport
+</pre>
+</blockquote>
+<blockquote>
+<pre>
transport:
example.com dane
example.org dane
+</pre>
+</blockquote>
+<blockquote>
+<pre>
tls_policy:
example.com dane-only
- # Postfix ≥ 2.12, per-destination <a href="postconf.5.html#smtp_tls_fallback_level">smtp_tls_fallback_level</a> override
- example.org dane fallback=encrypt
+</pre>
+</blockquote>
+<blockquote>
+<pre>
<a href="master.5.html">master.cf</a>:
dane unix - - n - - smtp
-o <a href="postconf.5.html#smtp_dns_support_level">smtp_dns_support_level</a>=dnssec
are obtained for the remote SMTP server, SSLv2 is automatically
disabled (see <a href="postconf.5.html#smtp_tls_mandatory_protocols">smtp_tls_mandatory_protocols</a>), and the server certificate
must match the TLSA records. <a href="http://tools.ietf.org/html/rfc6698">RFC 6698</a> (DANE) TLS authentication
-and DNSSEC support is available with Postfix 2.11 and later.
-The optional "fallback" attribute provides a per-site override of
-the <a href="postconf.5.html">main.cf</a> <a href="postconf.5.html#smtp_tls_fallback_level">smtp_tls_fallback_level</a> parameter (Postfix ≥ 2.12).
-</dd>
+and DNSSEC support is available with Postfix 2.11 and later. </dd>
<dt><b>dane-only</b></dt> <dd><a href="#client_tls_dane">Mandatory DANE TLS</a>.
The TLS policy for the destination is obtained via TLSA records in
obtained for the remote SMTP server, SSLv2 is automatically disabled
(see <a href="postconf.5.html#smtp_tls_mandatory_protocols">smtp_tls_mandatory_protocols</a>), and the server certificate must
match the TLSA records. <a href="http://tools.ietf.org/html/rfc6698">RFC 6698</a> (DANE) TLS authentication and
-DNSSEC support is available with Postfix 2.11 and later.
-The optional "fallback" attribute provides a per-site override of
-the <a href="postconf.5.html">main.cf</a> <a href="postconf.5.html#smtp_tls_fallback_level">smtp_tls_fallback_level</a> parameter (Postfix ≥ 2.12).
-</dd>
+DNSSEC support is available with Postfix 2.11 and later. </dd>
<dt><b>fingerprint</b></dt> <dd><a href="#client_tls_fprint">Certificate
fingerprint verification.</a> Available with Postfix 2.5 and
not checked. Instead, the optional <b>match</b> attribute, or else
the <a href="postconf.5.html">main.cf</a> <b><a href="postconf.5.html#smtp_tls_fingerprint_cert_match">smtp_tls_fingerprint_cert_match</a></b> parameter, lists
the server certificate fingerprints or public key fingerprints
-(Postfix 2.9 and later). The digest algorithm used to calculate
-fingerprints is selected by the <b><a href="postconf.5.html#smtp_tls_fingerprint_digest">smtp_tls_fingerprint_digest</a></b>
-parameter. Multiple fingerprints can be combined with a "|" delimiter
-in a single match attribute, or multiple match attributes can be
-employed. The ":" character is not used as a delimiter as it occurs
-between each pair of fingerprint (hexadecimal) digits.
-The optional "fallback" attribute provides a per-site override of
-the <a href="postconf.5.html">main.cf</a> <a href="postconf.5.html#smtp_tls_fallback_level">smtp_tls_fallback_level</a> parameter (Postfix ≥ 2.12).
-</dd>
+(Postfix 2.9 and later). The
+digest algorithm used to calculate fingerprints is selected by the
+<b><a href="postconf.5.html#smtp_tls_fingerprint_digest">smtp_tls_fingerprint_digest</a></b> parameter. Multiple fingerprints can
+be combined with a "|" delimiter in a single match attribute, or multiple
+match attributes can be employed. The ":" character is not used as a
+delimiter as it occurs between each pair of fingerprint (hexadecimal)
+digits. </dd>
<dt><b>verify</b></dt> <dd><a href="#client_tls_verify">Mandatory
server certificate verification</a>. Mail is delivered only if the
parameter value when no optional "match" attribute is specified).
With Postfix ≥ 2.11 the "tafile" attribute optionally modifies
trust chain verification in the same manner as the
-"<a href="postconf.5.html#smtp_tls_trust_anchor_file">smtp_tls_trust_anchor_file</a>" parameter. The "tafile" attribute may
-be specified multiple times to load multiple trust-anchor files.
-The optional "fallback" attribute provides a per-site override of
-the <a href="postconf.5.html">main.cf</a> <a href="postconf.5.html#smtp_tls_fallback_level">smtp_tls_fallback_level</a> parameter (Postfix ≥ 2.12).
-</dd>
+"<a href="postconf.5.html#smtp_tls_trust_anchor_file">smtp_tls_trust_anchor_file</a>" parameter. The "tafile" attribute
+may be specified multiple times to load multiple trust-anchor
+files. </dd>
<dt><b>secure</b></dt> <dd><a href="#client_tls_secure">Secure certificate
verification.</a> Mail is delivered only if the TLS handshake succeeds,
attribute optionally modifies trust chain verification in the same manner
as the "<a href="postconf.5.html#smtp_tls_trust_anchor_file">smtp_tls_trust_anchor_file</a>" parameter. The "tafile" attribute
may be specified multiple times to load multiple trust-anchor
-files.
-The optional "fallback" attribute provides a per-site override of
-the <a href="postconf.5.html">main.cf</a> <a href="postconf.5.html#smtp_tls_fallback_level">smtp_tls_fallback_level</a> parameter (Postfix ≥ 2.12).
-</dd>
+files. </dd>
</dl>
<a href="postconf.5.html#smtp_tls_policy_maps">smtp_tls_policy_maps</a> = <a href="DATABASE_README.html#types">hash</a>:/etc/postfix/tls_policy
# Postfix 2.5 and later
<a href="postconf.5.html#smtp_tls_fingerprint_digest">smtp_tls_fingerprint_digest</a> = md5
-
/etc/postfix/tls_policy:
example.edu none
example.mil may
match=3D:95:34:51:24:66:33:B9:D2:40:99:C0:C1:17:0B:D1
# Postfix 2.6 and later
example.info may protocols=!SSLv2 ciphers=medium exclude=3DES
- # Postfix 2.12 and later override of <a href="postconf.5.html#smtp_tls_fallback_level">smtp_tls_fallback_level</a>
- fallback.example secure fallback=encrypt
</pre>
</blockquote>
<b><a href="postconf.5.html#tlsmgr_service_name">tlsmgr_service_name</a> (tlsmgr)</b>
The name of the <a href="tlsmgr.8.html"><b>tlsmgr</b>(8)</a> service entry in <a href="master.5.html">master.cf</a>.
- Available in Postfix version 2.12 and later:
-
- <b><a href="postconf.5.html#smtp_tls_fallback_level">smtp_tls_fallback_level</a> (empty)</b>
- Optional fallback levels for authenticated TLS levels.
-
<b>OBSOLETE STARTTLS CONTROLS</b>
The following configuration parameters exist for compatibility with
Postfix versions before 2.3. Support for these will be removed in a
<p> This feature is available in Postfix 2.3 and later. </p>
-</DD>
-
-<DT><b><a name="lmtp_tls_fallback_level">lmtp_tls_fallback_level</a>
-(default: empty)</b></DT><DD>
-
-<p> The LMTP-specific version of the <a href="postconf.5.html#smtp_tls_fallback_level">smtp_tls_fallback_level</a>
-configuration parameter. See there for details. </p>
-
-<p> This feature is available in Postfix 2.12 and later. </p>
-
-
</DD>
<DT><b><a name="lmtp_tls_fingerprint_cert_match">lmtp_tls_fingerprint_cert_match</a>
<p> This feature is available in Postfix 2.3 and later. </p>
-</DD>
-
-<DT><b><a name="smtp_tls_fallback_level">smtp_tls_fallback_level</a>
-(default: empty)</b></DT><DD>
-
-<p> Optional fallback levels for authenticated TLS levels. Specify
-a white-space or comma-separated list of
-<b>policy_level</b>=<b>fallback_level</b> pairs. The <b>policy_level</b>
-must require authentication (one of dane, dane-only, fingerprint,
-verify, secure). The <b>fallback_level</b> must be "encrypt" or
-"may". When an authenticated connection at some desired policy
-level cannot be established, delivery will proceed at the correponding
-fallback level if possible. A warning will be logged
-indicating the fallback reason. </p>
-
-<p> The TLS <a href="TLS_README.html#client_tls_policy">policy</a> table
-can be used to specify a destination-specific fallback strategy via the
-"fallback" policy attribute. The value of the "fallback" attribute, if
-specified, must be "may", "encrypt" or "none". If not "none", this
-specifies the fallback level for the destination in question. If the
-attribute value is "none", fallback is suppressed for the destination
-even if enabled via a global setting of <a href="postconf.5.html#smtp_tls_fallback_level">smtp_tls_fallback_level</a>. </p>
-
-<p> Example: </p>
-
-<blockquote>
-<pre>
-/etc/postfix/<a href="postconf.5.html">main.cf</a>:
- # When authentication fails, log a warning and deliver anyway
- # over an unauthenticated TLS connection.
- #
- <a href="postconf.5.html#smtp_tls_fallback_level">smtp_tls_fallback_level</a> =
- dane=encrypt,
- dane-only=encrypt,
- fingerprint=encrypt,
- verify=encrypt,
- secure=encrypt
- indexed = ${<a href="postconf.5.html#default_database_type">default_database_type</a>}:${<a href="postconf.5.html#config_directory">config_directory</a>}/
- <a href="postconf.5.html#smtp_tls_policy_maps">smtp_tls_policy_maps</a> = ${indexed}tls-policy
-</pre>
-</blockquote>
-
-<blockquote>
-<pre>
-/etc/postfix/tls-policy:
- # No fallback for example.com
- example.com secure fallback=none
- # For example.net tolerate cleartext fallback
- example.net dane fallback=may
-</pre>
-</blockquote>
-
-<p> This feature is available in Postfix 2.12 and later. </p>
-
-
</DD>
<DT><b><a name="smtp_tls_fingerprint_cert_match">smtp_tls_fingerprint_cert_match</a>
<b><a href="postconf.5.html#tlsmgr_service_name">tlsmgr_service_name</a> (tlsmgr)</b>
The name of the <a href="tlsmgr.8.html"><b>tlsmgr</b>(8)</a> service entry in <a href="master.5.html">master.cf</a>.
- Available in Postfix version 2.12 and later:
-
- <b><a href="postconf.5.html#smtp_tls_fallback_level">smtp_tls_fallback_level</a> (empty)</b>
- Optional fallback levels for authenticated TLS levels.
-
<b>OBSOLETE STARTTLS CONTROLS</b>
The following configuration parameters exist for compatibility with
Postfix versions before 2.3. Support for these will be removed in a
configuration parameter. See there for details.
.PP
This feature is available in Postfix 2.3 and later.
-.SH lmtp_tls_fallback_level (default: empty)
-The LMTP-specific version of the smtp_tls_fallback_level
-configuration parameter. See there for details.
-.PP
-This feature is available in Postfix 2.12 and later.
.SH lmtp_tls_fingerprint_cert_match (default: empty)
The LMTP-specific version of the smtp_tls_fingerprint_cert_match
configuration parameter. See there for details.
key exchange with RSA authentication.
.PP
This feature is available in Postfix 2.3 and later.
-.SH smtp_tls_fallback_level (default: empty)
-Optional fallback levels for authenticated TLS levels. Specify
-a white-space or comma-separated list of
-\fBpolicy_level\fR=\fBfallback_level\fR pairs. The \fBpolicy_level\fR
-must require authentication (one of dane, dane-only, fingerprint,
-verify, secure). The \fBfallback_level\fR must be "encrypt" or
-"may". When an authenticated connection at some desired policy
-level cannot be established, delivery will proceed at the correponding
-fallback level if possible. A warning will be logged
-indicating the fallback reason.
-.PP
-The TLS policy table
-can be used to specify a destination-specific fallback strategy via the
-"fallback" policy attribute. The value of the "fallback" attribute, if
-specified, must be "may", "encrypt" or "none". If not "none", this
-specifies the fallback level for the destination in question. If the
-attribute value is "none", fallback is suppressed for the destination
-even if enabled via a global setting of smtp_tls_fallback_level.
-.PP
-Example:
-.sp
-.in +4
-.nf
-.na
-.ft C
-/etc/postfix/main.cf:
- # When authentication fails, log a warning and deliver anyway
- # over an unauthenticated TLS connection.
- #
- smtp_tls_fallback_level =
- dane=encrypt,
- dane-only=encrypt,
- fingerprint=encrypt,
- verify=encrypt,
- secure=encrypt
- indexed = ${default_database_type}:${config_directory}/
- smtp_tls_policy_maps = ${indexed}tls-policy
-.fi
-.ad
-.ft R
-.in -4
-.sp
-.in +4
-.nf
-.na
-.ft C
-/etc/postfix/tls-policy:
- # No fallback for example.com
- example.com secure fallback=none
- # For example.net tolerate cleartext fallback
- example.net dane fallback=may
-.fi
-.ad
-.ft R
-.in -4
-.PP
-This feature is available in Postfix 2.12 and later.
.SH smtp_tls_fingerprint_cert_match (default: empty)
List of acceptable remote SMTP server certificate fingerprints for
the "fingerprint" TLS security level (\fBsmtp_tls_security_level\fR =
RFC 6698 trust-anchor digest support in the Postfix TLS library.
.IP "\fBtlsmgr_service_name (tlsmgr)\fR"
The name of the \fBtlsmgr\fR(8) service entry in master.cf.
-.PP
-Available in Postfix version 2.12 and later:
-.IP "\fBsmtp_tls_fallback_level (empty)\fR"
-Optional fallback levels for authenticated TLS levels.
.SH "OBSOLETE STARTTLS CONTROLS"
.na
.nf
<li> <p> The "example.com" destination uses DANE, but if TLSA records
are not present or are unusable, mail is deferred. </p>
-<li> <p> The "example.org" destination uses DANE if possible, but
-uses opportunistic TLS if no TLSA records are found. The
-"fallback" attribute (Postfix ≥ 2.12) overrides the global
-main.cf smtp_tls_fallback_level parameter to employ unauthenticated
-mandatory encryption if DANE authentication fails, after logging a
-warning. </p>
+<li> <p> The "example.org" destination uses DANE if possible, but if no TLSA
+records are found opportunistic TLS is used. </p>
</ul>
<blockquote>
# default_transport = smtp, but some destinations are special:
#
transport_maps = ${indexed}transport
+</pre>
+</blockquote>
+<blockquote>
+<pre>
transport:
example.com dane
example.org dane
+</pre>
+</blockquote>
+<blockquote>
+<pre>
tls_policy:
example.com dane-only
- # Postfix ≥ 2.12, per-destination smtp_tls_fallback_level override
- example.org dane fallback=encrypt
+</pre>
+</blockquote>
+<blockquote>
+<pre>
master.cf:
dane unix - - n - - smtp
-o smtp_dns_support_level=dnssec
are obtained for the remote SMTP server, SSLv2 is automatically
disabled (see smtp_tls_mandatory_protocols), and the server certificate
must match the TLSA records. RFC 6698 (DANE) TLS authentication
-and DNSSEC support is available with Postfix 2.11 and later.
-The optional "fallback" attribute provides a per-site override of
-the main.cf smtp_tls_fallback_level parameter (Postfix ≥ 2.12).
-</dd>
+and DNSSEC support is available with Postfix 2.11 and later. </dd>
<dt><b>dane-only</b></dt> <dd><a href="#client_tls_dane">Mandatory DANE TLS</a>.
The TLS policy for the destination is obtained via TLSA records in
obtained for the remote SMTP server, SSLv2 is automatically disabled
(see smtp_tls_mandatory_protocols), and the server certificate must
match the TLSA records. RFC 6698 (DANE) TLS authentication and
-DNSSEC support is available with Postfix 2.11 and later.
-The optional "fallback" attribute provides a per-site override of
-the main.cf smtp_tls_fallback_level parameter (Postfix ≥ 2.12).
-</dd>
+DNSSEC support is available with Postfix 2.11 and later. </dd>
<dt><b>fingerprint</b></dt> <dd><a href="#client_tls_fprint">Certificate
fingerprint verification.</a> Available with Postfix 2.5 and
not checked. Instead, the optional <b>match</b> attribute, or else
the main.cf <b>smtp_tls_fingerprint_cert_match</b> parameter, lists
the server certificate fingerprints or public key fingerprints
-(Postfix 2.9 and later). The digest algorithm used to calculate
-fingerprints is selected by the <b>smtp_tls_fingerprint_digest</b>
-parameter. Multiple fingerprints can be combined with a "|" delimiter
-in a single match attribute, or multiple match attributes can be
-employed. The ":" character is not used as a delimiter as it occurs
-between each pair of fingerprint (hexadecimal) digits.
-The optional "fallback" attribute provides a per-site override of
-the main.cf smtp_tls_fallback_level parameter (Postfix ≥ 2.12).
-</dd>
+(Postfix 2.9 and later). The
+digest algorithm used to calculate fingerprints is selected by the
+<b>smtp_tls_fingerprint_digest</b> parameter. Multiple fingerprints can
+be combined with a "|" delimiter in a single match attribute, or multiple
+match attributes can be employed. The ":" character is not used as a
+delimiter as it occurs between each pair of fingerprint (hexadecimal)
+digits. </dd>
<dt><b>verify</b></dt> <dd><a href="#client_tls_verify">Mandatory
server certificate verification</a>. Mail is delivered only if the
parameter value when no optional "match" attribute is specified).
With Postfix ≥ 2.11 the "tafile" attribute optionally modifies
trust chain verification in the same manner as the
-"smtp_tls_trust_anchor_file" parameter. The "tafile" attribute may
-be specified multiple times to load multiple trust-anchor files.
-The optional "fallback" attribute provides a per-site override of
-the main.cf smtp_tls_fallback_level parameter (Postfix ≥ 2.12).
-</dd>
+"smtp_tls_trust_anchor_file" parameter. The "tafile" attribute
+may be specified multiple times to load multiple trust-anchor
+files. </dd>
<dt><b>secure</b></dt> <dd><a href="#client_tls_secure">Secure certificate
verification.</a> Mail is delivered only if the TLS handshake succeeds,
attribute optionally modifies trust chain verification in the same manner
as the "smtp_tls_trust_anchor_file" parameter. The "tafile" attribute
may be specified multiple times to load multiple trust-anchor
-files.
-The optional "fallback" attribute provides a per-site override of
-the main.cf smtp_tls_fallback_level parameter (Postfix ≥ 2.12).
-</dd>
+files. </dd>
</dl>
smtp_tls_policy_maps = hash:/etc/postfix/tls_policy
# Postfix 2.5 and later
smtp_tls_fingerprint_digest = md5
-
/etc/postfix/tls_policy:
example.edu none
example.mil may
match=3D:95:34:51:24:66:33:B9:D2:40:99:C0:C1:17:0B:D1
# Postfix 2.6 and later
example.info may protocols=!SSLv2 ciphers=medium exclude=3DES
- # Postfix 2.12 and later override of smtp_tls_fallback_level
- fallback.example secure fallback=encrypt
</pre>
</blockquote>
<p> This feature is available in Postfix 2.12 and later. </p>
-%PARAM smtp_tls_fallback_level
-
-<p> Optional fallback levels for authenticated TLS levels. Specify
-a white-space or comma-separated list of
-<b>policy_level</b>=<b>fallback_level</b> pairs. The <b>policy_level</b>
-must require authentication (one of dane, dane-only, fingerprint,
-verify, secure). The <b>fallback_level</b> must be "encrypt" or
-"may". When an authenticated connection at some desired policy
-level cannot be established, delivery will proceed at the correponding
-fallback level if possible. A warning will be logged
-indicating the fallback reason. </p>
-
-<p> The TLS <a href="TLS_README.html#client_tls_policy">policy</a> table
-can be used to specify a destination-specific fallback strategy via the
-"fallback" policy attribute. The value of the "fallback" attribute, if
-specified, must be "may", "encrypt" or "none". If not "none", this
-specifies the fallback level for the destination in question. If the
-attribute value is "none", fallback is suppressed for the destination
-even if enabled via a global setting of smtp_tls_fallback_level. </p>
-
-<p> Example: </p>
-
-<blockquote>
-<pre>
-/etc/postfix/main.cf:
- # When authentication fails, log a warning and deliver anyway
- # over an unauthenticated TLS connection.
- #
- smtp_tls_fallback_level =
- dane=encrypt,
- dane-only=encrypt,
- fingerprint=encrypt,
- verify=encrypt,
- secure=encrypt
- indexed = ${default_database_type}:${config_directory}/
- smtp_tls_policy_maps = ${indexed}tls-policy
-</pre>
-</blockquote>
-
-<blockquote>
-<pre>
-/etc/postfix/tls-policy:
- # No fallback for example.com
- example.com secure fallback=none
- # For example.net tolerate cleartext fallback
- example.net dane fallback=may
-</pre>
-</blockquote>
-
-<p> This feature is available in Postfix 2.12 and later. </p>
-
-%PARAM lmtp_tls_fallback_level
-
-<p> The LMTP-specific version of the smtp_tls_fallback_level
-configuration parameter. See there for details. </p>
-
-<p> This feature is available in Postfix 2.12 and later. </p>
-
%PARAM compatibility_level 0
<p> A safety net that causes Postfix to run with backwards-compatible
char *orig_rcpt; /* original recipient address */
char *return_receipt; /* return-receipt address */
char *errors_to; /* errors-to address */
+ ARGV *auto_hdrs; /* MTA's own header(s) */
int flags; /* processing options, status flags */
int qmgr_opts; /* qmgr processing options */
int errs; /* any badness experienced */
name_mask(VAR_CANON_CLASSES, rcpt_canon_class_table,
var_rcpt_canon_classes);
if (*var_masq_domains)
- cleanup_masq_domains = argv_split(var_masq_domains, " ,\t\r\n");
+ cleanup_masq_domains = argv_split(var_masq_domains, CHARS_COMMA_SP);
if (*var_header_checks)
cleanup_header_checks =
maps_create(VAR_HEADER_CHECKS, var_header_checks, DICT_FLAG_LOCK);
var_masq_exceptions = argv[1];
cleanup_masq_exceptions =
string_list_init(MATCH_FLAG_RETURN, var_masq_exceptions);
- masq_domains = argv_split(argv[2], " ,\t\r\n");
+ masq_domains = argv_split(argv[2], CHARS_COMMA_SP);
addr = vstring_alloc(1);
if (strchr(argv[3], '@') == 0)
msg_fatal("address must be in user@domain form");
if (hdr_opts && (hdr_opts->flags & HDR_OPT_MIME))
header_class = MIME_HDR_MULTIPART;
+ /* Update the Received: header count before maybe dropping headers below. */
+ if (hdr_opts && hdr_opts->type == HDR_RECEIVED)
+ state->hop_count += 1;
+
if ((state->flags & CLEANUP_FLAG_FILTER)
&& (CHECK(MIME_HDR_PRIMARY, cleanup_header_checks, VAR_HEADER_CHECKS)
|| CHECK(MIME_HDR_MULTIPART, cleanup_mimehdr_checks, VAR_MIMEHDR_CHECKS)
msg_info("%s: message-id=%s", state->queue_id, hdrval);
if (hdr_opts->type == HDR_RESENT_MESSAGE_ID)
msg_info("%s: resent-message-id=%s", state->queue_id, hdrval);
- if (hdr_opts->type == HDR_RECEIVED)
- if (++state->hop_count >= var_hopcount_limit) {
+ if (hdr_opts->type == HDR_RECEIVED) {
+ if (state->hop_count >= var_hopcount_limit) {
msg_warn("%s: message rejected: hopcount exceeded",
state->queue_id);
state->errs |= CLEANUP_STAT_HOPS;
}
+ /* Save our Received: header after maybe updating headers above. */
+ if (state->hop_count == 1)
+ argv_add(state->auto_hdrs, vstring_str(header_buf), ARGV_END);
+ }
if (CLEANUP_OUT_OK(state)) {
if (hdr_opts->flags & HDR_OPT_RR)
state->resent = "Resent-";
if (CLEANUP_OUT_OK(state) == 0)
return;
+ /*
+ * Future proofing: the Milter client's header suppression algorithm
+ * assumes that the MTA prepends its own Received: header. This
+ * assupmtion may be violated after some source-code update. The
+ * following check ensures consistency, at least for local submission.
+ */
+ if (state->hop_count < 1) {
+ msg_warn("%s: message rejected: no Received: header",
+ state->queue_id);
+ state->errs |= CLEANUP_STAT_BAD;
+ return;
+ }
+
/*
* Add a missing (Resent-)Message-Id: header. The message ID gives the
* time in GMT units, plus the local queue ID.
* filter library.
*/
if ((resp = milter_message(milters, state->handle->stream,
- state->data_offset)) != 0)
+ state->data_offset, state->auto_hdrs)) != 0)
cleanup_milter_apply(state, "END-OF-MESSAGE", resp);
/*
state->orig_rcpt = 0;
state->return_receipt = 0;
state->errors_to = 0;
+ state->auto_hdrs = argv_alloc(1);
state->flags = 0;
state->qmgr_opts = 0;
state->errs = 0;
myfree(state->return_receipt);
if (state->errors_to)
myfree(state->errors_to);
+ argv_free(state->auto_hdrs);
if (state->queue_name)
myfree(state->queue_name);
if (state->queue_id)
msg_vstream_init(argv[0], VSTREAM_ERR);
if (argc != 3)
msg_fatal("usage: %s types name", argv[0]);
- types_argv = argv_split(argv[1], ", \t\r\n");
+ types_argv = argv_split(argv[1], CHARS_COMMA_SP);
types = (unsigned *) mymalloc(sizeof(*types) * (types_argv->argc + 1));
for (i = 0; i < types_argv->argc; i++)
if ((types[i] = dns_type(types_argv->argv[i])) == 0)
/* Pointer to input string. The input is modified.
/* .IP "delimiters, parens"
/* See mystrtok(3) for description. Typical values are
-/* ", \\t\\r\\n" and "{}", respectively.
+/* CHARS_COMMA_SP and CHARS_BRACE, respectively.
/* .PP
/* The parens argument is followed by a list of (key, value)
/* argument pairs. Each key may appear only once. The list
url_list = vstring_alloc(32);
s = server_host;
- while ((h = mystrtok(&s, " \t\n\r,")) != NULL) {
+ while ((h = mystrtok(&s, CHARS_COMMA_SP)) != NULL) {
#if defined(LDAP_API_FEATURE_X_OPENLDAP)
/*
/* Order matters, first the terminal attributes: */
attr = cfg_get_str(dict_ldap->parser, "terminal_result_attribute", "", 0, 0);
- dict_ldap->result_attributes = argv_split(attr, " ,\t\r\n");
+ dict_ldap->result_attributes = argv_split(attr, CHARS_COMMA_SP);
dict_ldap->num_terminal = dict_ldap->result_attributes->argc;
myfree(attr);
/* Order matters, next the leaf-only attributes: */
attr = cfg_get_str(dict_ldap->parser, "leaf_result_attribute", "", 0, 0);
if (*attr)
- argv_split_append(dict_ldap->result_attributes, attr, " ,\t\r\n");
+ argv_split_append(dict_ldap->result_attributes, attr, CHARS_COMMA_SP);
dict_ldap->num_leaf =
dict_ldap->result_attributes->argc - dict_ldap->num_terminal;
myfree(attr);
/* Order matters, next the regular attributes: */
attr = cfg_get_str(dict_ldap->parser, "result_attribute", "maildrop", 0, 0);
if (*attr)
- argv_split_append(dict_ldap->result_attributes, attr, " ,\t\r\n");
+ argv_split_append(dict_ldap->result_attributes, attr, CHARS_COMMA_SP);
dict_ldap->num_attributes = dict_ldap->result_attributes->argc;
myfree(attr);
/* Order matters, finally the special attributes: */
attr = cfg_get_str(dict_ldap->parser, "special_result_attribute", "", 0, 0);
if (*attr)
- argv_split_append(dict_ldap->result_attributes, attr, " ,\t\r\n");
+ argv_split_append(dict_ldap->result_attributes, attr, CHARS_COMMA_SP);
myfree(attr);
/*
hosts = cfg_get_str(p, "hosts", "", 0, 0);
- dict_mysql->hosts = argv_split(hosts, " ,\t\r\n");
+ dict_mysql->hosts = argv_split(hosts, CHARS_COMMA_SP);
if (dict_mysql->hosts->argc == 0) {
argv_add(dict_mysql->hosts, "localhost", ARGV_END);
argv_terminate(dict_mysql->hosts);
hosts = cfg_get_str(p, "hosts", "", 0, 0);
- dict_pgsql->hosts = argv_split(hosts, " ,\t\r\n");
+ dict_pgsql->hosts = argv_split(hosts, CHARS_COMMA_SP);
if (dict_pgsql->hosts->argc == 0) {
argv_add(dict_pgsql->hosts, "localhost", ARGV_END);
argv_terminate(dict_pgsql->hosts);
if (split_nameval(vstring_str(buf), &name, &value) == 0
&& (strcmp(name, VAR_CONFIG_DIRS) == 0
|| strcmp(name, VAR_MULTI_CONF_DIRS) == 0)) {
- while (found == 0 && (cp = mystrtok(&value, ", \t\r\n")) != 0)
+ while (found == 0 && (cp = mystrtok(&value, CHARS_COMMA_SP)) != 0)
if (strcmp(cp, config_dir) == 0)
found = 1;
}
/*
* XXX These should be caught by a proper parameter parsing algorithm.
*/
- if (var_myorigin[strcspn(var_myorigin, ", \t\r\n")])
+ if (var_myorigin[strcspn(var_myorigin, CHARS_COMMA_SP)])
msg_fatal("%s parameter setting must not contain multiple values: %s",
VAR_MYORIGIN, var_myorigin);
- if (var_relayhost[strcspn(var_relayhost, ", \t\r\n")])
+ if (var_relayhost[strcspn(var_relayhost, CHARS_COMMA_SP)])
msg_fatal("%s parameter setting must not contain multiple values: %s",
VAR_RELAYHOST, var_relayhost);
}
if (hash_buf == 0) {
hash_buf = vstring_alloc(100);
- hash_queue_names = argv_split(var_hash_queue_names, " \t\r\n,");
+ hash_queue_names = argv_split(var_hash_queue_names, CHARS_COMMA_SP);
}
/*
* Patches change both the patchlevel and the release date. Snapshots have no
* patchlevel; they change the release date only.
*/
-#define MAIL_RELEASE_DATE "20141015"
+#define MAIL_RELEASE_DATE "20141019"
#define MAIL_VERSION_NUMBER "2.12"
#ifdef SNAPSHOT
const char *myname = "maps_create";
char *temp;
char *bufp;
- static char sep[] = " \t,\r\n";
- static char parens[] = "{}";
+ static char sep[] = CHARS_COMMA_SP;
+ static char parens[] = CHARS_BRACE;
MAPS *maps;
char *map_type_name;
VSTRING *map_type_name_flags;
ARGV *match_service_init(const char *patterns)
{
- const char *delim = " ,\t\r\n";
+ const char *delim = CHARS_COMMA_SP;
ARGV *list = argv_alloc(1);
char *saved_patterns = mystrdup(patterns);
char *bp = saved_patterns;
execvp(args.argv[0], args.argv);
msg_fatal("%s: execvp %s: %m", myname, args.argv[0]);
} else if (args.shell && *args.shell) {
- argv = argv_split(args.shell, " \t\r\n");
+ argv = argv_split(args.shell, CHARS_SPACE);
argv_add(argv, args.command, (char *) 0);
argv_terminate(argv);
execvp(argv->argv[0], argv->argv);
vstream_fileno(VSTREAM_ERR) = 1;
while (get_buffer(buf, VSTREAM_IN, interactive) != VSTREAM_EOF) {
- argv = argv_split(STR(buf), " \t\r\n");
+ argv = argv_split(STR(buf), CHARS_SPACE);
if (argv->argc > 0 && argv->argv[0][0] != '#') {
msg_verbose = verbose_level;
for (ap = actions; ap->command != 0; ap++) {
/* Application-specific. */
-#define SERVER_ACL_SEPARATORS ", \t\r\n"
-
static ADDR_MATCH_LIST *server_acl_mynetworks;
static ADDR_MATCH_LIST *server_acl_mynetworks_host;
* chroot jail, while access lists are evaluated after entering the
* chroot jail.
*/
- while ((acl = mystrtokq(&bp, SERVER_ACL_SEPARATORS, "{}")) != 0) {
+ while ((acl = mystrtokq(&bp, CHARS_COMMA_SP, CHARS_BRACE)) != 0) {
if (strchr(acl, ':') != 0) {
if (strchr(origin, ':') != 0) {
msg_warn("table %s: lookup result \"%s\" is not allowed"
msg_panic("%s: unexpected dictionary: %s", myname, acl);
if ((dict_val = dict_get(dict, client_addr)) != 0) {
/* Fake up an ARGV to avoid lots of mallocs and frees. */
- if (dict_val[strcspn(dict_val, ":" SERVER_ACL_SEPARATORS)] == 0) {
+ if (dict_val[strcspn(dict_val, ":" CHARS_COMMA_SP)] == 0) {
ARGV_FAKE_BEGIN(fake_argv, dict_val);
ret = server_acl_eval(client_addr, &fake_argv, acl);
ARGV_FAKE_END;
char *status_text;
char *cp = query;
- if ((addr = mystrtok(&cp, " \t\r\n")) == 0
- || (status_text = mystrtok(&cp, " \t\r\n")) == 0) {
+ if ((addr = mystrtok(&cp, CHARS_SPACE)) == 0
+ || (status_text = mystrtok(&cp, CHARS_SPACE)) == 0) {
msg_warn("bad request format");
return;
}
while (vstring_fgets_nonl(buffer, VSTREAM_IN)) {
cp = STR(buffer);
- if ((command = mystrtok(&cp, " \t\r\n")) == 0)
+ if ((command = mystrtok(&cp, CHARS_SPACE)) == 0)
continue;
if (strcmp(command, "query") == 0)
query(cp, buffer);
next = saved_forward_path;
lookup_status = -1;
- while ((lhs = mystrtok(&next, ", \t\r\n")) != 0) {
+ while ((lhs = mystrtok(&next, CHARS_COMMA_SP)) != 0) {
expand_status = local_expand(path, lhs, &state, &usr_attr,
var_fwd_exp_filter);
if ((expand_status & (MAC_PARSE_ERROR | MAC_PARSE_UNDEF)) == 0) {
static int master_line; /* config file line number */
static ARGV *master_disable; /* disabled service patterns */
-static char master_blanks[] = " \t\r\n";/* field delimiters */
+static char master_blanks[] = CHARS_SPACE;/* field delimiters */
/* fset_master_ent - specify configuration file pathname */
argv_add(serv->args, "-s",
vstring_str(vstring_sprintf(junk, "%d", serv->listen_fd_count)),
(char *) 0);
- while ((cp = mystrtokq(&bufp, master_blanks, "{}")) != 0) {
- if (*cp == '{' && (err = extpar(&cp, "{}", EXTPAR_FLAG_STRIP)) != 0)
+ while ((cp = mystrtokq(&bufp, master_blanks, CHARS_BRACE)) != 0) {
+ if (*cp == CHARS_BRACE[0]
+ && (err = extpar(&cp, CHARS_BRACE, EXTPAR_FLAG_STRIP)) != 0)
fatal_with_context("%s", err);
argv_add(serv->args, cp, (char *) 0);
}
/* const char *milter_other_event(milters)
/* MILTERS *milters;
/*
-/* const char *milter_message(milters, qfile, data_offset)
+/* const char *milter_message(milters, qfile, data_offset, auto_hdrs)
/* MILTERS *milters;
/* VSTREAM *qfile;
/* off_t data_offset;
+/* ARGV *auto_hdrs;
/*
/* const char *milter_abort(milters)
/* MILTERS *milters;
const char *value;
const char *name;
- while ((name = mystrtok(&cp, ", \t\r\n")) != 0) {
+ while ((name = mystrtok(&cp, CHARS_COMMA_SP)) != 0) {
if (msg_verbose)
msg_info("%s: \"%s\"", myname, name);
if ((value = milters->mac_lookup(name, milters->mac_context)) != 0) {
/* milter_message - inspect message content */
-const char *milter_message(MILTERS *milters, VSTREAM *fp, off_t data_offset)
+const char *milter_message(MILTERS *milters, VSTREAM *fp, off_t data_offset,
+ ARGV *auto_hdrs)
{
const char *resp;
MILTER *m;
for (resp = 0, m = milters->milter_list; resp == 0 && m != 0; m = m->next) {
any_eoh_macros = MILTER_MACRO_EVAL(global_eoh_macros, m, milters, eoh_macros);
any_eod_macros = MILTER_MACRO_EVAL(global_eod_macros, m, milters, eod_macros);
- resp = m->message(m, fp, data_offset, any_eoh_macros, any_eod_macros);
+ resp = m->message(m, fp, data_offset, any_eoh_macros, any_eod_macros,
+ auto_hdrs);
if (any_eoh_macros != global_eoh_macros)
argv_free(any_eoh_macros);
if (any_eod_macros != global_eod_macros)
MILTER *tail = 0;
char *name;
MILTER *milter;
- const char *sep = ", \t\r\n";
- const char *parens = "{}";
+ const char *sep = CHARS_COMMA_SP;
+ const char *parens = CHARS_BRACE;
int my_conn_timeout;
int my_cmd_timeout;
int my_msg_timeout;
my_msg_timeout = msg_timeout;
my_protocol = protocol;
my_def_action = def_action;
- if (name[0] == '{') { /* } */
+ if (name[0] == parens[0]) {
op = name;
if ((err = extpar(&op, parens, EXTPAR_FLAG_NONE)) != 0)
msg_fatal("milter service syntax error: %s", err);
const char *(*mail_event) (struct MILTER *, const char **, ARGV *);
const char *(*rcpt_event) (struct MILTER *, const char **, ARGV *);
const char *(*data_event) (struct MILTER *, ARGV *);
- const char *(*message) (struct MILTER *, VSTREAM *, off_t, ARGV *, ARGV *);
+ const char *(*message) (struct MILTER *, VSTREAM *, off_t, ARGV *, ARGV *, ARGV *);
const char *(*unknown_event) (struct MILTER *, const char *, ARGV *);
const char *(*other_event) (struct MILTER *);
void (*abort) (struct MILTER *);
extern const char *milter_mail_event(MILTERS *, const char **);
extern const char *milter_rcpt_event(MILTERS *, int, const char **);
extern const char *milter_data_event(MILTERS *);
-extern const char *milter_message(MILTERS *, VSTREAM *, off_t);
+extern const char *milter_message(MILTERS *, VSTREAM *, off_t, ARGV *);
extern const char *milter_unknown_event(MILTERS *, const char *);
extern const char *milter_other_event(MILTERS *);
extern void milter_abort(MILTERS *);
* don't want to take the risk that a future version will be more picky.
*/
cp = saved_version = mystrdup(milter->protocol);
- while ((name = mystrtok(&cp, " ,\t\r\n")) != 0) {
+ while ((name = mystrtok(&cp, CHARS_COMMA_SP)) != 0) {
int mask;
int vers;
MILTER8 *milter; /* milter client */
ARGV *eoh_macros; /* end-of-header macros */
ARGV *eod_macros; /* end-of-body macros */
+ ARGV *auto_hdrs; /* auto-generated headers */
+ int auto_done; /* good enough for now */
int first_header; /* first header */
int first_body; /* first body line */
const char *resp; /* milter application response */
MILTER8 *milter = msg_ctx->milter;
char *cp;
int skip_reply;
+ char **cpp;
+ unsigned done;
/*
* XXX Workaround: mime_state_update() may invoke multiple call-backs
* XXX Sendmail compatibility. It eats the first space (not tab) after the
* header label and ":".
*/
- if (msg_ctx->first_header) {
- msg_ctx->first_header = 0;
- return;
- }
+ for (cpp = msg_ctx->auto_hdrs->argv, done = 1; *cpp; cpp++, done <<= 1)
+ if ((msg_ctx->auto_done & done) == 0 && strcmp(*cpp, STR(buf)) == 0) {
+ msg_ctx->auto_done |= done;
+ return;
+ }
/*
* Sendmail 8 sends multi-line headers as text separated by newline.
static const char *milter8_message(MILTER *m, VSTREAM *qfile,
off_t data_offset,
ARGV *eoh_macros,
- ARGV *eod_macros)
+ ARGV *eod_macros,
+ ARGV *auto_hdrs)
{
const char *myname = "milter8_message";
MILTER8 *milter = (MILTER8 *) m;
msg_ctx.milter = milter;
msg_ctx.eoh_macros = eoh_macros;
msg_ctx.eod_macros = eod_macros;
+ msg_ctx.auto_hdrs = auto_hdrs;
+ msg_ctx.auto_done = 0;
msg_ctx.first_header = 1;
msg_ctx.first_body = 1;
msg_ctx.resp = 0;
*/
if (*var_defer_xports && (message->qflags & QMGR_FLUSH_DFXP) == 0) {
if (defer_xport_argv == 0)
- defer_xport_argv = argv_split(var_defer_xports, " \t\r\n,");
+ defer_xport_argv = argv_split(var_defer_xports, CHARS_COMMA_SP);
for (cpp = defer_xport_argv->argv; *cpp; cpp++)
if (strcmp(*cpp, STR(reply.transport)) == 0)
break;
* Naive parsing. We don't really know if this substring specifies a
* database or some other text.
*/
- while ((db_type = mystrtokq(&str_value, " ,\t\r\n", "{}")) != 0) {
+ while ((db_type = mystrtokq(&str_value, CHARS_COMMA_SP, CHARS_BRACE)) != 0) {
/*
* Skip over "proxy:" maptypes, to emulate the proxymap(8) server's
* local or global namespace.
*/
if (prefix != 0 && *prefix != '/' && *prefix != '.') {
- if (*prefix == '{') { /* } */
- if ((err = extpar(&prefix, "{}", EXTPAR_FLAG_NONE)) != 0) {
+ if (*prefix == CHARS_BRACE[0]) {
+ if ((err = extpar(&prefix, CHARS_BRACE, EXTPAR_FLAG_NONE)) != 0) {
/* XXX Encapsulate this in pcf_warn() function. */
if (local_scope)
msg_warn("%s:%s: %s",
}
/* Copy or replace start of logical line. */
else {
- vstring_strncpy(key, cp, strcspn(cp, " \t\r\n="));
+ vstring_strncpy(key, cp, strcspn(cp, CHARS_SPACE "="));
cvalue = (struct cvalue *) htable_find(table, STR(key));
if ((interesting = !!cvalue) != 0) {
if (cvalue->found++ == 1)
argv_insert_one(argv, field + 1, arg + 2);
arg[2] = 0; /* XXX argv_replace_one() */
field += 1;
- extract_field = (argv->argv[field][0] == '{');
+ extract_field = (argv->argv[field][0] == CHARS_BRACE[0]);
} else if (argv->argv[field + 1] != 0) {
/* Already in "-o" "name=value" form. */
field += 1;
- extract_field = (argv->argv[field][0] == '{');
+ extract_field = (argv->argv[field][0] == CHARS_BRACE[0]);
} else
extract_field = 0;
/* Extract text inside {}, optionally convert to name=value. */
if (extract_field) {
- pcf_extract_field(argv, field, "{}");
+ pcf_extract_field(argv, field, CHARS_BRACE);
if (argv->argv[field - 1][1] == 'o')
pcf_normalize_nameval(argv, field);
}
/* Normalize non-option arguments. */
for ( /* void */ ; argv->argv[field] != 0; field++)
/* Extract text inside {}. */
- if (argv->argv[field][0] == '{') /* } */
- pcf_extract_field(argv, field, "{}");
+ if (argv->argv[field][0] == CHARS_BRACE[0])
+ pcf_extract_field(argv, field, CHARS_BRACE);
}
/* pcf_fix_fatal - fix multiline text before release */
*
* XXX Do per-field sanity checks.
*/
- argv = argv_splitq(buf, PCF_MASTER_BLANKS, "{}");
+ argv = argv_splitq(buf, PCF_MASTER_BLANKS, CHARS_BRACE);
if (argv->argc < PCF_MASTER_MIN_FIELDS) {
argv_free(argv); /* Coverity 201311 */
return ("bad field count");
*/
if (field == PCF_MASTER_FLD_CMD) {
argv_truncate(masterp->argv, PCF_MASTER_FLD_CMD);
- argv_splitq_append(masterp->argv, new_value, PCF_MASTER_BLANKS, "{}");
+ argv_splitq_append(masterp->argv, new_value, PCF_MASTER_BLANKS, CHARS_BRACE);
pcf_normalize_daemon_args(masterp->argv);
}
*/
if ((class_list = pcf_lookup_eval(dict_name, VAR_REST_CLASSES)) != 0) {
cp = saved_class_list = mystrdup(class_list);
- while ((param_name = mystrtok(&cp, ", \t\r\n")) != 0) {
+ while ((param_name = mystrtok(&cp, CHARS_COMMA_SP)) != 0) {
if (local_scope == 0
&& htable_locate(pcf_rest_class_table, param_name) == 0)
htable_enter(pcf_rest_class_table, param_name, "");
* Run the management script.
*/
if (force_single_instance
- || argv_split(var_multi_conf_dirs, "\t\r\n, ")->argc == 0) {
+ || argv_split(var_multi_conf_dirs, CHARS_COMMA_SP)->argc == 0) {
script = concatenate(var_daemon_dir, "/postfix-script", (char *) 0);
if (optind < 1)
msg_panic("bad optind value");
if (*var_multi_wrapper == 0)
msg_fatal("multi-instance support is requested, but %s is empty",
VAR_MULTI_WRAPPER);
- my_argv = argv_split(var_multi_wrapper, " \t\r\n");
+ my_argv = argv_split(var_multi_wrapper, CHARS_SPACE);
do {
argv_add(my_argv, argv[optind], (char *) 0);
} while (argv[optind++] != 0);
* trailing whitespace from key and value.
*/
key = STR(line_buffer);
- value = key + strcspn(key, " \t\r\n");
+ value = key + strcspn(key, CHARS_SPACE);
if (*value)
*value++ = 0;
while (ISSPACE(*value))
* only comma characters. Count the actual number of elements, before we
* decide that the list is empty.
*/
- secondary_names = argv_split(var_multi_conf_dirs, "\t\n\r, ");
+ secondary_names = argv_split(var_multi_conf_dirs, CHARS_COMMA_SP);
/*
* First, the primary instance. This is synthesized out of thin air.
char *elem;
cp = saved = mystrdup(cmdlist);
- while ((elem = mystrtok(&cp, "\t\n\r, ")) != 0 && strcmp(elem, cmd) != 0)
+ while ((elem = mystrtok(&cp, CHARS_COMMA_SP)) != 0 && strcmp(elem, cmd) != 0)
/* void */ ;
myfree(saved);
return (elem != 0);
void psc_dnsbl_init(void)
{
const char *myname = "psc_dnsbl_init";
- ARGV *dnsbl_site = argv_split(var_psc_dnsbl_sites, ", \t\r\n");
+ ARGV *dnsbl_site = argv_split(var_psc_dnsbl_sites, CHARS_COMMA_SP);
char **cpp;
/*
static void super(const char **queues, int action)
{
- ARGV *hash_queue_names = argv_split(var_hash_queue_names, " \t\r\n,");
+ ARGV *hash_queue_names = argv_split(var_hash_queue_names, CHARS_COMMA_SP);
VSTRING *actual_path = vstring_alloc(10);
VSTRING *wanted_path = vstring_alloc(10);
struct stat st;
static void post_jail_init(char *service_name, char **unused_argv)
{
- const char *sep = ", \t\r\n";
- const char *parens = "{}";
+ const char *sep = CHARS_COMMA_SP;
+ const char *parens = CHARS_BRACE;
char *saved_filter;
char *bp;
char *type_name;
*/
if (*var_defer_xports && (message->qflags & QMGR_FLUSH_DFXP) == 0) {
if (defer_xport_argv == 0)
- defer_xport_argv = argv_split(var_defer_xports, " \t\r\n,");
+ defer_xport_argv = argv_split(var_defer_xports, CHARS_COMMA_SP);
for (cpp = defer_xport_argv->argv; *cpp; cpp++)
if (strcmp(*cpp, STR(reply.transport)) == 0)
break;
argv_add(ext_argv, "postalias", (char *) 0);
for (n = 0; n < msg_verbose; n++)
argv_add(ext_argv, "-v", (char *) 0);
- argv_split_append(ext_argv, var_alias_db_map, ", \t\r\n");
+ argv_split_append(ext_argv, var_alias_db_map, CHARS_COMMA_SP);
argv_terminate(ext_argv);
mail_run_replace(var_command_dir, ext_argv->argv);
/* NOTREACHED */
non_fallback_sites = sites->argc;
/* When we are lmtp(8) var_fallback_relay is null */
if (smtp_mode)
- argv_split_append(sites, var_fallback_relay, ", \t\r\n");
+ argv_split_append(sites, var_fallback_relay, CHARS_COMMA_SP);
/*
* Don't give up after a hard host lookup error until we have tried the
/*
* Sanity checks.
*/
-#define HAS_MULTIPLE_VALUES(s) ((s)[strcspn((s), ", \t\r\n")] != 0)
+#define HAS_MULTIPLE_VALUES(s) ((s)[strcspn((s), CHARS_COMMA_SP)] != 0)
if (*map == 0)
msg_panic("%s: empty SASL authentication cache name", myname);
}
saved_policy = policy = mystrdup(lookup);
- if ((tok = mystrtok(&policy, "\t\n\r ,")) == 0) {
+ if ((tok = mystrtok(&policy, CHARS_COMMA_SP)) == 0) {
msg_warn("%s: invalid empty policy", WHERE);
INVALID_RETURN(tls->why, site_level);
}
* Warn about ignored attributes when TLS is disabled.
*/
if (*site_level < TLS_LEV_MAY) {
- while ((tok = mystrtok(&policy, "\t\n\r ,")) != 0)
+ while ((tok = mystrtok(&policy, CHARS_COMMA_SP)) != 0)
msg_warn("%s: ignoring attribute \"%s\" with TLS disabled",
WHERE, tok);
FREE_RETURN;
* Errors in attributes may have security consequences, don't ignore
* errors that can degrade security.
*/
- while ((tok = mystrtok(&policy, "\t\n\r ,")) != 0) {
+ while ((tok = mystrtok(&policy, CHARS_COMMA_SP)) != 0) {
if ((err = split_nameval(tok, &name, &val)) != 0) {
msg_warn("%s: malformed attribute/value pair \"%s\": %s",
WHERE, tok, err);
char *file;
do {
- if ((file = mystrtok(&buf, "\t\n\r ,")) != 0)
+ if ((file = mystrtok(&buf, CHARS_COMMA_SP)) != 0)
ret = tls_dane_load_trustfile(dane, file);
} while (file && ret);
tls->dane = tls_dane_alloc();
if (!TLS_DANE_HASEE(tls->dane)) {
tls_dane_add_ee_digests(tls->dane, var_smtp_tls_fpt_dgst,
- var_smtp_tls_fpt_cmatch, "\t\n\r, ");
+ var_smtp_tls_fpt_cmatch, CHARS_COMMA_SP);
if (!TLS_DANE_HASEE(tls->dane)) {
msg_warn("nexthop domain %s: configured at fingerprint "
"security level, but with no fingerprints to match.",
tls->matchargv =
argv_split(tls->level == TLS_LEV_VERIFY ?
var_smtp_tls_vfy_cmatch : var_smtp_tls_sec_cmatch,
- "\t\n\r, :");
+ CHARS_COMMA_SP ":");
if (*var_smtp_tls_tafile) {
if (tls->dane == 0)
tls->dane = tls_dane_alloc();
rec_fputs(state->cleanup, REC_TYPE_MESG, "");
}
+ /*
+ * PREPEND message headers above our own Received: header.
+ */
+ if (state->prepend)
+ for (cpp = state->prepend->argv; *cpp; cpp++)
+ out_fprintf(out_stream, REC_TYPE_NORM, "%s", *cpp);
+
/*
* Suppress our own Received: header in the unlikely case that we are an
* intermediate proxy.
#endif
}
- /*
- * PREPEND message headers below our own Received: header. According
- * https://www.milter.org/developers/api/smfi_insheader, Milters see only
- * headers that have been sent by the SMTP client and those header
- * modifications by earlier filters. Based on this we allow Milters to
- * see headers added by access map or by policy service.
- */
- if (state->prepend)
- for (cpp = state->prepend->argv; *cpp; cpp++)
- out_fprintf(out_stream, REC_TYPE_NORM, "%s", *cpp);
-
smtpd_chat_reply(state, "354 End data with <CR><LF>.<CR><LF>");
state->where = SMTPD_AFTER_DATA;
#include "smtpd_resolve.h"
#include "smtpd_expand.h"
-#define RESTRICTION_SEPARATORS ", \t\r\n"
-
/*
* Eject seat in case of parsing problems.
*/
char *saved_name = 0;
const char *policy_name = 0;
char *cp;
- const char *sep = ", \t\r\n";
- const char *parens = "{}";
+ const char *sep = CHARS_COMMA_SP;
+ const char *parens = CHARS_BRACE;
char *err;
if (policy_clnt_table == 0)
link_override_table_to_variable(int_table, smtpd_policy_try_limit);
link_override_table_to_variable(str_table, smtpd_policy_def_action);
- if (*name == '{') { /* } */
+ if (*name == parens[0]) {
cp = saved_name = mystrdup(name);
if ((err = extpar(&cp, parens, EXTPAR_FLAG_NONE)) != 0)
msg_fatal("policy service syntax error: %s", cp);
#define SMTPD_CHECK_PARSE_MAPS (1<<1)
#define SMTPD_CHECK_PARSE_ALL (~0)
- while ((name = mystrtokq(&bp, RESTRICTION_SEPARATORS, "{}")) != 0) {
+ while ((name = mystrtokq(&bp, CHARS_COMMA_SP, CHARS_BRACE)) != 0) {
argv_add(argv, name, (char *) 0);
if ((flags & SMTPD_CHECK_PARSE_POLICY)
&& last && strcasecmp(last, CHECK_POLICY_SERVICE) == 0)
smtpd_rest_classes = htable_create(1);
if (*var_rest_classes) {
cp = saved_classes = mystrdup(var_rest_classes);
- while ((name = mystrtok(&cp, RESTRICTION_SEPARATORS)) != 0) {
+ while ((name = mystrtok(&cp, CHARS_COMMA_SP)) != 0) {
if ((value = mail_conf_lookup_eval(name)) == 0 || *value == 0)
msg_fatal("restriction class `%s' needs a definition", name);
/* XXX This store operation should not be case-sensitive. */
*/
#define ADDROF(x) ((char *) &(x))
- restrictions = argv_splitq(value, RESTRICTION_SEPARATORS, "{}");
+ restrictions = argv_splitq(value, CHARS_COMMA_SP, CHARS_BRACE);
memcpy(ADDROF(savebuf), ADDROF(smtpd_check_buf), sizeof(savebuf));
status = setjmp(smtpd_check_buf);
if (status != 0) {
"use \"%s domain-name\" instead",
REJECT_MAPS_RBL, var_mail_name, REJECT_RBL_CLIENT);
}
- while ((rbl_domain = mystrtok(&bp, RESTRICTION_SEPARATORS)) != 0) {
+ while ((rbl_domain = mystrtok(&bp, CHARS_COMMA_SP)) != 0) {
result = reject_rbl_addr(state, rbl_domain, state->addr,
SMTPD_NAME_CLIENT);
if (result != SMTPD_CHECK_DUNNO)
if ((owners = check_mail_addr_find(state, sender, smtpd_sender_login_maps,
STR(reply->recipient), (char **) 0)) != 0) {
cp = saved_owners = mystrdup(owners);
- while ((name = mystrtok(&cp, RESTRICTION_SEPARATORS)) != 0) {
+ while ((name = mystrtok(&cp, CHARS_COMMA_SP)) != 0) {
if (strcasecmp(state->sasl_username, name) == 0) {
found = 1;
break;
if (smtpd_rest_classes == 0)
smtpd_rest_classes = htable_create(1);
- if ((name = mystrtok(&cp, RESTRICTION_SEPARATORS)) == 0)
+ if ((name = mystrtok(&cp, CHARS_COMMA_SP)) == 0)
msg_panic("rest_class: null class name");
if ((entry = htable_locate(smtpd_rest_classes, name)) != 0)
argv_free((ARGV *) entry->value);
vstream_printf("exit %d\n", system(bp + 1));
continue;
}
- args = argv_split(bp, " \t\r\n");
+ args = argv_split(bp, CHARS_SPACE);
/*
* Recognize the command.
char *cmd;
saved_cmds = cp = mystrdup(cmds);
- while ((cmd = mystrtok(&cp, " \t\r\n,")) != 0)
+ while ((cmd = mystrtok(&cp, CHARS_COMMA_SP)) != 0)
set_cmd_flags(cmd, flags);
myfree(saved_cmds);
}
VAR_TLS_DANE_AGILITY, var_tls_dane_agility);
} else if (add_digest(fullmtype, 0)) {
save = cp = mystrdup(var_tls_dane_digests);
- while ((tok = mystrtok(&cp, "\t\n\r ,")) != 0) {
+ while ((tok = mystrtok(&cp, CHARS_COMMA_SP)) != 0) {
if ((d = add_digest(tok, ++digest_pref)) == 0) {
signalg = 0;
signmd = 0;
msg_fatal("chdir %s: %m", var_queue_dir);
while (vstring_fgets_nonl(inbuf, VSTREAM_IN)) {
- argv = argv_split(STR(inbuf), " \t\r\n");
+ argv = argv_split(STR(inbuf), CHARS_SPACE);
if (argv->argc == 0) {
argv_free(argv);
continue;
} while (0)
save = cp = mystrdup(plist);
- while ((tok = mystrtok(&cp, "\t\n\r ,:")) != 0) {
+ while ((tok = mystrtok(&cp, CHARS_COMMA_SP ":")) != 0) {
if (*tok == '!')
exclude |= code =
name_code(protocol_table, NAME_CODE_FLAG_NONE, ++tok);
/*
* Apply locally-specified exclusions.
*/
-#define CIPHER_SEP "\t\n\r ,:"
+#define CIPHER_SEP CHARS_COMMA_SP ":"
if (exclusions != 0) {
cp = save = mystrdup(exclusions);
while ((tok = mystrtok(&cp, CIPHER_SEP)) != 0) {
/*
* Split the table name into its constituent parts.
*/
- if ((len = balpar(name, "{}")) == 0 || name[len] != 0
+ if ((len = balpar(name, CHARS_BRACE)) == 0 || name[len] != 0
|| *(saved_name = mystrndup(name + 1, len - 2)) == 0)
DICT_PIPE_RETURN(dict_surrogate(DICT_TYPE_PIPE, name,
open_flags, dict_flags,
* level. The first table determines the pattern-matching flags.
*/
DICT_OWNER_AGGREGATE_INIT(aggr_owner);
- argv = argv_splitq(saved_name, ", \t\r\n", "{}");
+ argv = argv_splitq(saved_name, CHARS_COMMA_SP, CHARS_BRACE);
for (cpp = argv->argv; (dict_type_name = *cpp) != 0; cpp++) {
if (msg_verbose)
msg_info("%s: %s", myname, dict_type_name);
/*
* Split the name name into its constituent parts.
*/
- if ((len = balpar(name, "{}")) == 0 || name[len] != 0
+ if ((len = balpar(name, CHARS_BRACE)) == 0 || name[len] != 0
|| *(saved_name = mystrndup(name + 1, len - 2)) == 0)
DICT_RANDOM_RETURN(dict_surrogate(DICT_TYPE_RANDOM, name,
open_flags, dict_flags,
dict_random->dict.lookup = dict_random_lookup;
dict_random->dict.close = dict_random_close;
dict_random->dict.flags = dict_flags | DICT_FLAG_PATTERN;
- dict_random->replies = argv_splitq(saved_name, ", \t\r\n", "{}");
+ dict_random->replies = argv_splitq(saved_name, CHARS_COMMA_SP, CHARS_BRACE);
dict_random->dict.owner.status = DICT_OWNER_TRUSTED;
dict_random->dict.owner.uid = 0;
* trailing whitespace from key and value.
*/
key = STR(line_buffer);
- value = key + strcspn(key, " \t\r\n");
+ value = key + strcspn(key, CHARS_SPACE);
if (*value)
*value++ = 0;
while (ISSPACE(*value))
/*
* Split the table name into its constituent parts.
*/
- if ((len = balpar(name, "{}")) == 0 || name[len] != 0
+ if ((len = balpar(name, CHARS_BRACE)) == 0 || name[len] != 0
|| *(saved_name = mystrndup(name + 1, len - 2)) == 0)
DICT_UNION_RETURN(dict_surrogate(DICT_TYPE_UNION, name,
open_flags, dict_flags,
* level. The first table determines the pattern-matching flags.
*/
DICT_OWNER_AGGREGATE_INIT(aggr_owner);
- argv = argv_splitq(saved_name, ", \t\r\n", "{}");
+ argv = argv_splitq(saved_name, CHARS_COMMA_SP, CHARS_BRACE);
for (cpp = argv->argv; (dict_type_name = *cpp) != 0; cpp++) {
if (msg_verbose)
msg_info("%s: %s", myname, dict_type_name);
/*
* The whitespace separator set.
*/
-#define MAC_EXP_WHITESPACE " \t\r\n"
+#define MAC_EXP_WHITESPACE CHARS_SPACE
/* mac_exp_eval - evaluate binary expression */
if (VSTRING_LEN(buf) == 0)
break;
cp = vstring_str(buf);
- name = mystrtok(&cp, " \t\r\n=");
- value = mystrtok(&cp, " \t\r\n=");
+ name = mystrtok(&cp, CHARS_SPACE "=");
+ value = mystrtok(&cp, CHARS_SPACE "=");
htable_enter(table, name, value ? mystrdup(value) : 0);
}
const char *myname = "match_list_parse";
VSTRING *buf = vstring_alloc(10);
VSTREAM *fp;
- const char *delim = " ,\t\r\n";
+ const char *delim = CHARS_COMMA_SP;
char *bp = string;
char *start;
char *item;
* /filename contents are expanded in-line. To support !/filename we
* prepend the negation operator to each item from the file.
*/
- while ((start = mystrtokq(&bp, delim, "{}")) != 0) {
+ while ((start = mystrtokq(&bp, delim, CHARS_BRACE)) != 0) {
if (*start == '#') {
msg_warn("%s: comment at end of line is not supported: %s %s",
myname, start, bp);
while (vstring_fgets(vp, VSTREAM_IN) && VSTRING_LEN(vp) > 0) {
start = vstring_str(vp);
- if (strchr(start, '{') == 0) {
- while ((str = mystrtok(&start, " \t\r\n")) != 0)
+ if (strchr(start, CHARS_BRACE[0]) == 0) {
+ while ((str = mystrtok(&start, CHARS_SPACE)) != 0)
vstream_printf(">%s<\n", str);
} else {
- while ((str = mystrtokq(&start, " \t\r\n", "{}")) != 0)
+ while ((str = mystrtokq(&start, CHARS_SPACE, CHARS_BRACE)) != 0)
vstream_printf(">%s<\n", str);
}
vstream_fflush(VSTREAM_OUT);
execvp(args.argv[0], args.argv);
msg_fatal("%s: execvp %s: %m", myname, args.argv[0]);
} else if (args.shell && *args.shell) {
- argv = argv_split(args.shell, " \t\r\n");
+ argv = argv_split(args.shell, CHARS_SPACE);
argv_add(argv, args.command, (char *) 0);
argv_terminate(argv);
execvp(argv->argv[0], argv->argv);
#define EXTPAR_FLAG_STRIP (1<<0) /* "{ text }" -> "text" */
#define EXTPAR_FLAG_EXTRACT (1<<1) /* hint from caller's caller */
- /*
- * Character sets for parsing.
- */
-#define CHARS_COMMA_SP ", \t\r\n" /* list separator */
-#define CHARS_SPACE " \t\r\n" /* word separator */
-#define CHARS_BRACE "{}" /* grouping */
-
/* LICENSE
/* .ad
/* .fi
#define TOLOWER(c) (ISUPPER(c) ? tolower((unsigned char)(c)) : (c))
#define TOUPPER(c) (ISLOWER(c) ? toupper((unsigned char)(c)) : (c))
+ /*
+ * Character sets for parsing.
+ */
+#define CHARS_COMMA_SP ", \t\r\n" /* list separator */
+#define CHARS_SPACE " \t\r\n" /* word separator */
+#define CHARS_BRACE "{}" /* grouping */
+
/*
* Scaffolding. I don't want to lose messages while the program is under
* development.
execvp(args.argv[0], args.argv);
msg_fatal("%s: execvp %s: %m", myname, args.argv[0]);
} else if (args.shell && *args.shell) {
- argv = argv_split(args.shell, " \t\r\n");
+ argv = argv_split(args.shell, CHARS_SPACE);
argv_add(argv, args.command, (char *) 0);
argv_terminate(argv);
execvp(argv->argv[0], argv->argv);