2
0
mirror of https://github.com/vdukhovni/postfix synced 2025-08-30 05:38:06 +00:00

postfix-2.12-20141013

This commit is contained in:
Wietse Venema 2014-10-13 00:00:00 -05:00 committed by Viktor Dukhovni
parent 757df5bc6c
commit 783583def2
25 changed files with 324 additions and 96 deletions

View File

@ -20640,3 +20640,25 @@ Apologies for any names omitted.
./proto/postconf.proto, global/mail_params.h, smtp/lmtp_params.c, ./proto/postconf.proto, global/mail_params.h, smtp/lmtp_params.c,
smtp/smtp.c, smtp/smtp.h, smtp/smtp_connect.c, smtp/smtp_params.c, smtp/smtp.c, smtp/smtp.h, smtp/smtp_connect.c, smtp/smtp_params.c,
smtp/smtp_proto.c, smtp/smtp_tls_policy.c, smtp/smtp_trouble.c. smtp/smtp_proto.c, smtp/smtp_tls_policy.c, smtp/smtp_trouble.c.
20141012
Cleanup: missing format-string checks. Files: master/master_ent.c,
posttls-finger/posttls-finger.c, smtpd/smtpd_proxy.c.
Bugfix: the PREPEND access/policy action added headers ABOVE
Postfix's own Received: header, exposing Postfix's own
Received: header to Milters (protocol violation) and hiding
the PREPENDed header from Milters. The latter caused problems
for DMARC implementations with SPF policy plus DKIM Milter.
PREPENDed headers are now added BELOW Postfix's own Received:
header and remain visible to Milters. File: smtpd/smtpd.c.
20141013
Cleanup: configuration file line numbers in error/warning
messages could point to comment lines before or after the
problem. Files: util/readlline.[hc], master/master_ent.c,
postalias/postalias.c, postmap/postmap.c, util/dict.c,
util/dict_cidr.c, util/dict_pcre.e, util/dict_regexp.c,
util/dict_thash.c, postconf/postconf_master.c.

View File

@ -1027,8 +1027,11 @@ default. This is the recommended configuration for early adopters.
* The "example.com" destination uses DANE, but if TLSA records are not * The "example.com" destination uses DANE, but if TLSA records are not
present or are unusable, mail is deferred. present or are unusable, mail is deferred.
* The "example.org" destination uses DANE if possible, but if no TLSA records * The "example.org" destination uses DANE if possible, but uses opportunistic
are found opportunistic TLS is used. 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.
main.cf: main.cf:
indexed = ${default_database_type}:${config_directory}/ indexed = ${default_database_type}:${config_directory}/
@ -1052,6 +1055,8 @@ default. This is the recommended configuration for early adopters.
tls_policy: tls_policy:
example.com dane-only example.com dane-only
# Postfix >= 2.12, per-destination smtp_tls_fallback_level override
example.org dane fallback=encrypt
master.cf: master.cf:
dane unix - - n - - smtp dane unix - - n - - smtp
@ -1632,7 +1637,9 @@ ddaannee
obtained for the remote SMTP server, SSLv2 is automatically disabled (see obtained for the remote SMTP server, SSLv2 is automatically disabled (see
smtp_tls_mandatory_protocols), and the server certificate must match the smtp_tls_mandatory_protocols), and the server certificate must match the
TLSA records. RFC 6698 (DANE) TLS authentication and DNSSEC support is TLSA records. RFC 6698 (DANE) TLS authentication and DNSSEC support is
available with Postfix 2.11 and later. 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).
ddaannee--oonnllyy ddaannee--oonnllyy
Mandatory DANE TLS. The TLS policy for the destination is obtained via TLSA 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 records in DNSSEC. If no TLSA records are found, or none are usable, no
@ -1640,7 +1647,9 @@ ddaannee--oonnllyy
the remote SMTP server, SSLv2 is automatically disabled (see the remote SMTP server, SSLv2 is automatically disabled (see
smtp_tls_mandatory_protocols), and the server certificate must match the smtp_tls_mandatory_protocols), and the server certificate must match the
TLSA records. RFC 6698 (DANE) TLS authentication and DNSSEC support is TLSA records. RFC 6698 (DANE) TLS authentication and DNSSEC support is
available with Postfix 2.11 and later. 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).
ffiinnggeerrpprriinntt ffiinnggeerrpprriinntt
Certificate fingerprint verification. Available with Postfix 2.5 and later. Certificate fingerprint verification. Available with Postfix 2.5 and later.
At this security level, there are no trusted certificate authorities. The At this security level, there are no trusted certificate authorities. The
@ -1653,7 +1662,8 @@ ffiinnggeerrpprriinntt
combined with a "|" delimiter in a single match attribute, or multiple combined with a "|" delimiter in a single match attribute, or multiple
match attributes can be employed. The ":" character is not used as a match attributes can be employed. The ":" character is not used as a
delimiter as it occurs between each pair of fingerprint (hexadecimal) delimiter as it occurs between each pair of fingerprint (hexadecimal)
digits. digits. The optional "fallback" attribute provides a per-site override of
the main.cf smtp_tls_fallback_level parameter (Postfix >= 2.12).
vveerriiffyy vveerriiffyy
Mandatory server certificate verification. Mail is delivered only if the Mandatory server certificate verification. Mail is delivered only if the
TLS handshake succeeds, if the remote SMTP server certificate can be TLS handshake succeeds, if the remote SMTP server certificate can be
@ -1664,7 +1674,8 @@ vveerriiffyy
"tafile" attribute optionally modifies trust chain verification in the same "tafile" attribute optionally modifies trust chain verification in the same
manner as the "smtp_tls_trust_anchor_file" parameter. The "tafile" manner as the "smtp_tls_trust_anchor_file" parameter. The "tafile"
attribute may be specified multiple times to load multiple trust-anchor attribute may be specified multiple times to load multiple trust-anchor
files. files. The optional "fallback" attribute provides a per-site override of
the main.cf smtp_tls_fallback_level parameter (Postfix >= 2.12).
sseeccuurree sseeccuurree
Secure certificate verification. Mail is delivered only if the TLS Secure certificate verification. Mail is delivered only if the TLS
handshake succeeds, if the remote SMTP server certificate can be validated handshake succeeds, if the remote SMTP server certificate can be validated
@ -1674,7 +1685,9 @@ sseeccuurree
"match" attribute is specified). With Postfix >= 2.11 the "tafile" "match" attribute is specified). With Postfix >= 2.11 the "tafile"
attribute optionally modifies trust chain verification in the same manner attribute optionally modifies trust chain verification in the same manner
as the "smtp_tls_trust_anchor_file" parameter. The "tafile" attribute may as the "smtp_tls_trust_anchor_file" parameter. The "tafile" attribute may
be specified multiple times to load multiple trust-anchor files. 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).
Notes: Notes:
* The "match" attribute is especially useful to verify TLS certificates for * The "match" attribute is especially useful to verify TLS certificates for
@ -1708,6 +1721,7 @@ Example:
smtp_tls_policy_maps = hash:/etc/postfix/tls_policy smtp_tls_policy_maps = hash:/etc/postfix/tls_policy
# Postfix 2.5 and later # Postfix 2.5 and later
smtp_tls_fingerprint_digest = md5 smtp_tls_fingerprint_digest = md5
/etc/postfix/tls_policy: /etc/postfix/tls_policy:
example.edu none example.edu none
example.mil may example.mil may
@ -1723,6 +1737,8 @@ Example:
# Postfix 2.6 and later # Postfix 2.6 and later
example.info may protocols=!SSLv2 ciphers=medium example.info may protocols=!SSLv2 ciphers=medium
exclude=3DES exclude=3DES
# Postfix 2.12 and later override of smtp_tls_fallback_level
fallback.example secure fallback=encrypt
NNoottee:: The "hostname" strategy if listed in a non-default setting of NNoottee:: 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 smtp_tls_secure_cert_match or in the "match" attribute in the policy table can

View File

@ -59,6 +59,16 @@ Maintainers may also benefit from the makedefs documentation
(mantools/srctoman - makedefs | nroff -man | less) with information (mantools/srctoman - makedefs | nroff -man | less) with information
about build options that are not described in the INSTALL instructions. about build options that are not described in the INSTALL instructions.
Incompatible changes with snapshot 20141013
===========================================
Headers prepended with the access/policy PREPEND action are now
added BELOW Postfix's own Recived: header. This ensures a) that
Postfix's own Recived: header remains hidden from Milters as required
by the Milter protocol, and b) that PREPENDed headers become visible
to Milters, as expected by DMARC implementations based on SPF policy
plus DKIM milter.
Major changes with snapshot 20141011 Major changes with snapshot 20141011
==================================== ====================================
@ -73,7 +83,7 @@ Fallback to unauthenticated TLS is logged, so that downgrade attacks
are "tamper-evident". Fallback should be used only when testing, are "tamper-evident". Fallback should be used only when testing,
or temporarily when working around a known problem at a remote site. or temporarily when working around a known problem at a remote site.
Incompatible changes with snapshot 20141008 Incompatible changes with snapshot 20141009
=========================================== ===========================================
The default settings have changed for relay_domains (new: empty, The default settings have changed for relay_domains (new: empty,

View File

@ -1373,8 +1373,12 @@ for early adopters. <p>
<li> <p> The "example.com" destination uses DANE, but if TLSA records <li> <p> The "example.com" destination uses DANE, but if TLSA records
are not present or are unusable, mail is deferred. </p> are not present or are unusable, mail is deferred. </p>
<li> <p> The "example.org" destination uses DANE if possible, but if no TLSA <li> <p> The "example.org" destination uses DANE if possible, but
records are found opportunistic TLS is used. </p> uses opportunistic TLS if no TLSA records are found. The
"fallback" attribute (Postfix &ge; 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>
</ul> </ul>
<blockquote> <blockquote>
@ -1394,26 +1398,16 @@ records are found opportunistic TLS is used. </p>
# <a href="postconf.5.html#default_transport">default_transport</a> = smtp, but some destinations are special: # <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 <a href="postconf.5.html#transport_maps">transport_maps</a> = ${indexed}transport
</pre>
</blockquote>
<blockquote>
<pre>
transport: transport:
example.com dane example.com dane
example.org dane example.org dane
</pre>
</blockquote>
<blockquote>
<pre>
tls_policy: tls_policy:
example.com dane-only example.com dane-only
</pre> # Postfix &ge; 2.12, per-destination <a href="postconf.5.html#smtp_tls_fallback_level">smtp_tls_fallback_level</a> override
</blockquote> example.org dane fallback=encrypt
<blockquote>
<pre>
<a href="master.5.html">master.cf</a>: <a href="master.5.html">master.cf</a>:
dane unix - - n - - smtp dane unix - - n - - smtp
-o <a href="postconf.5.html#smtp_dns_support_level">smtp_dns_support_level</a>=dnssec -o <a href="postconf.5.html#smtp_dns_support_level">smtp_dns_support_level</a>=dnssec
@ -2146,7 +2140,10 @@ href="#client_tls_encrypt">encrypt</a>. When usable TLSA records
are obtained for the remote SMTP server, SSLv2 is automatically 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 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 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. </dd> 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 &ge; 2.12).
</dd>
<dt><b>dane-only</b></dt> <dd><a href="#client_tls_dane">Mandatory DANE TLS</a>. <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 The TLS policy for the destination is obtained via TLSA records in
@ -2155,7 +2152,10 @@ connection is made to the server. When usable TLSA records are
obtained for the remote SMTP server, SSLv2 is automatically disabled 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 (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 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. </dd> 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 &ge; 2.12).
</dd>
<dt><b>fingerprint</b></dt> <dd><a href="#client_tls_fprint">Certificate <dt><b>fingerprint</b></dt> <dd><a href="#client_tls_fprint">Certificate
fingerprint verification.</a> Available with Postfix 2.5 and fingerprint verification.</a> Available with Postfix 2.5 and
@ -2164,13 +2164,15 @@ authorities. The certificate trust chain, expiration date, ... are
not checked. Instead, the optional <b>match</b> attribute, or else 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 <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 the server certificate fingerprints or public key fingerprints
(Postfix 2.9 and later). The (Postfix 2.9 and later). The digest algorithm used to calculate
digest algorithm used to calculate fingerprints is selected by the fingerprints is selected by the <b><a href="postconf.5.html#smtp_tls_fingerprint_digest">smtp_tls_fingerprint_digest</a></b>
<b><a href="postconf.5.html#smtp_tls_fingerprint_digest">smtp_tls_fingerprint_digest</a></b> parameter. Multiple fingerprints can parameter. Multiple fingerprints can be combined with a "|" delimiter
be combined with a "|" delimiter in a single match attribute, or multiple in a single match attribute, or multiple match attributes can be
match attributes can be employed. The ":" character is not used as a employed. The ":" character is not used as a delimiter as it occurs
delimiter as it occurs between each pair of fingerprint (hexadecimal) between each pair of fingerprint (hexadecimal) digits.
digits. </dd> 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 &ge; 2.12).
</dd>
<dt><b>verify</b></dt> <dd><a href="#client_tls_verify">Mandatory <dt><b>verify</b></dt> <dd><a href="#client_tls_verify">Mandatory
server certificate verification</a>. Mail is delivered only if the server certificate verification</a>. Mail is delivered only if the
@ -2181,9 +2183,11 @@ the optional "match" attribute (or the <a href="postconf.5.html">main.cf</a> <a
parameter value when no optional "match" attribute is specified). parameter value when no optional "match" attribute is specified).
With Postfix &ge; 2.11 the "tafile" attribute optionally modifies With Postfix &ge; 2.11 the "tafile" attribute optionally modifies
trust chain verification in the same manner as the 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 "<a href="postconf.5.html#smtp_tls_trust_anchor_file">smtp_tls_trust_anchor_file</a>" parameter. The "tafile" attribute may
may be specified multiple times to load multiple trust-anchor be specified multiple times to load multiple trust-anchor files.
files. </dd> 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 &ge; 2.12).
</dd>
<dt><b>secure</b></dt> <dd><a href="#client_tls_secure">Secure certificate <dt><b>secure</b></dt> <dd><a href="#client_tls_secure">Secure certificate
verification.</a> Mail is delivered only if the TLS handshake succeeds, verification.</a> Mail is delivered only if the TLS handshake succeeds,
@ -2195,7 +2199,10 @@ server certificate name matches the optional "match" attribute (or the
attribute optionally modifies trust chain verification in the same manner 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 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 may be specified multiple times to load multiple trust-anchor
files. </dd> 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 &ge; 2.12).
</dd>
</dl> </dl>
@ -2242,6 +2249,7 @@ Example:
<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 <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 # Postfix 2.5 and later
<a href="postconf.5.html#smtp_tls_fingerprint_digest">smtp_tls_fingerprint_digest</a> = md5 <a href="postconf.5.html#smtp_tls_fingerprint_digest">smtp_tls_fingerprint_digest</a> = md5
/etc/postfix/tls_policy: /etc/postfix/tls_policy:
example.edu none example.edu none
example.mil may example.mil may
@ -2256,6 +2264,8 @@ Example:
match=3D:95:34:51:24:66:33:B9:D2:40:99:C0:C1:17:0B:D1 match=3D:95:34:51:24:66:33:B9:D2:40:99:C0:C1:17:0B:D1
# Postfix 2.6 and later # Postfix 2.6 and later
example.info may protocols=!SSLv2 ciphers=medium exclude=3DES 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> </pre>
</blockquote> </blockquote>

View File

@ -552,6 +552,11 @@ SMTP(8) SMTP(8)
<b><a href="postconf.5.html#tlsmgr_service_name">tlsmgr_service_name</a> (tlsmgr)</b> <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>. 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> <b>OBSOLETE STARTTLS CONTROLS</b>
The following configuration parameters exist for compatibility with The following configuration parameters exist for compatibility with
Postfix versions before 2.3. Support for these will be removed in a Postfix versions before 2.3. Support for these will be removed in a

View File

@ -5027,6 +5027,17 @@ configuration parameter. See there for details. </p>
<p> This feature is available in Postfix 2.3 and later. </p> <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> </DD>
<DT><b><a name="lmtp_tls_fingerprint_cert_match">lmtp_tls_fingerprint_cert_match</a> <DT><b><a name="lmtp_tls_fingerprint_cert_match">lmtp_tls_fingerprint_cert_match</a>
@ -11637,6 +11648,61 @@ key exchange with RSA authentication. </p>
<p> This feature is available in Postfix 2.3 and later. </p> <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> </DD>
<DT><b><a name="smtp_tls_fingerprint_cert_match">smtp_tls_fingerprint_cert_match</a> <DT><b><a name="smtp_tls_fingerprint_cert_match">smtp_tls_fingerprint_cert_match</a>

View File

@ -552,6 +552,11 @@ SMTP(8) SMTP(8)
<b><a href="postconf.5.html#tlsmgr_service_name">tlsmgr_service_name</a> (tlsmgr)</b> <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>. 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> <b>OBSOLETE STARTTLS CONTROLS</b>
The following configuration parameters exist for compatibility with The following configuration parameters exist for compatibility with
Postfix versions before 2.3. Support for these will be removed in a Postfix versions before 2.3. Support for these will be removed in a

View File

@ -2970,6 +2970,11 @@ The LMTP-specific version of the smtp_tls_exclude_ciphers
configuration parameter. See there for details. configuration parameter. See there for details.
.PP .PP
This feature is available in Postfix 2.3 and later. 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) .SH lmtp_tls_fingerprint_cert_match (default: empty)
The LMTP-specific version of the smtp_tls_fingerprint_cert_match The LMTP-specific version of the smtp_tls_fingerprint_cert_match
configuration parameter. See there for details. configuration parameter. See there for details.
@ -7304,6 +7309,63 @@ and "DES-CBC3-MD5". The last setting disables ciphers that use "EDH"
key exchange with RSA authentication. key exchange with RSA authentication.
.PP .PP
This feature is available in Postfix 2.3 and later. 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) .SH smtp_tls_fingerprint_cert_match (default: empty)
List of acceptable remote SMTP server certificate fingerprints for List of acceptable remote SMTP server certificate fingerprints for
the "fingerprint" TLS security level (\fBsmtp_tls_security_level\fR = the "fingerprint" TLS security level (\fBsmtp_tls_security_level\fR =

View File

@ -492,6 +492,10 @@ not an alias and its address records lie in an unsigned zone.
RFC 6698 trust-anchor digest support in the Postfix TLS library. RFC 6698 trust-anchor digest support in the Postfix TLS library.
.IP "\fBtlsmgr_service_name (tlsmgr)\fR" .IP "\fBtlsmgr_service_name (tlsmgr)\fR"
The name of the \fBtlsmgr\fR(8) service entry in master.cf. 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" .SH "OBSOLETE STARTTLS CONTROLS"
.na .na
.nf .nf

View File

@ -7,13 +7,13 @@
/* #include <mail_parm_split.h> /* #include <mail_parm_split.h>
/* /*
/* ARGV *mail_parm_split( /* ARGV *mail_parm_split(
/* cost char *name, /* const char *name,
/* const char *value) /* const char *value)
/* DESCRIPTION /* DESCRIPTION
/* mail_parm_split() splits a parameter list value into its /* mail_parm_split() splits a parameter list value into its
/* elements, and extracts text from inside {}. It uses /* elements, and extracts text from elements that are entirely
/* CHARS_COMMA_SP as list element delimiters, and CHARS_BRACE /* enclosed in {}. It uses CHARS_COMMA_SP as list element
/* for grouping. /* delimiters, and CHARS_BRACE for grouping.
/* /*
/* Arguments: /* Arguments:
/* .IP name /* .IP name
@ -22,7 +22,8 @@
/* .IP value /* .IP value
/* Parameter value. /* Parameter value.
/* DIAGNOSTICS /* DIAGNOSTICS
/* fatal: syntax error while extracting text from {}. /* fatal: syntax error while extracting text from {}, such as:
/* missing closing brace, or text after closing brace.
/* SEE ALSO /* SEE ALSO
/* argv_splitq(3), string array utilities /* argv_splitq(3), string array utilities
/* extpar(3), extract text from parentheses /* extpar(3), extract text from parentheses

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 "20141011" #define MAIL_RELEASE_DATE "20141013"
#define MAIL_VERSION_NUMBER "2.12" #define MAIL_VERSION_NUMBER "2.12"
#ifdef SNAPSHOT #ifdef SNAPSHOT

View File

@ -106,13 +106,11 @@
static char *master_path; /* config file name */ static char *master_path; /* config file name */
static VSTREAM *master_fp; /* config file pointer */ static VSTREAM *master_fp; /* config file pointer */
static int master_line; /* config file line number */ static int master_line; /* config file line number */
static int master_line_first; /* config file line number */
static ARGV *master_disable; /* disabled service patterns */ static ARGV *master_disable; /* disabled service patterns */
static char master_blanks[] = " \t\r\n";/* field delimiters */ static char master_blanks[] = " \t\r\n";/* field delimiters */
static NORETURN fatal_invalid_field(char *, char *);
static NORETURN fatal_with_context(char *,...);
/* fset_master_ent - specify configuration file pathname */ /* fset_master_ent - specify configuration file pathname */
void fset_master_ent(char *path) void fset_master_ent(char *path)
@ -167,9 +165,21 @@ void end_master_ent()
master_disable = 0; master_disable = 0;
} }
/* master_conf_context - plot the target range */
static const char *master_conf_context(void)
{
static VSTRING *context_buf = 0;
if (context_buf == 0)
context_buf = vstring_alloc(100);
vstring_sprintf(context_buf, "%s: line %d", master_path, master_line_first);
return (vstring_str(context_buf));
}
/* fatal_with_context - print fatal error with file/line context */ /* fatal_with_context - print fatal error with file/line context */
static NORETURN fatal_with_context(char *format,...) static NORETURN PRINTFLIKE(1, 2) fatal_with_context(char *format,...)
{ {
const char *myname = "fatal_with_context"; const char *myname = "fatal_with_context";
VSTRING *vp = vstring_alloc(100); VSTRING *vp = vstring_alloc(100);
@ -181,7 +191,7 @@ static NORETURN fatal_with_context(char *format,...)
va_start(ap, format); va_start(ap, format);
vstring_vsprintf(vp, format, ap); vstring_vsprintf(vp, format, ap);
va_end(ap); va_end(ap);
msg_fatal("%s: line %d: %s", master_path, master_line, vstring_str(vp)); msg_fatal("%s: %s", master_conf_context(), vstring_str(vp));
} }
/* fatal_invalid_field - report invalid field value */ /* fatal_invalid_field - report invalid field value */
@ -203,8 +213,8 @@ static char *get_str_ent(char **bufp, char *name, char *def_val)
if (def_val == 0) if (def_val == 0)
fatal_with_context("field \"%s\" has no default value", name); fatal_with_context("field \"%s\" has no default value", name);
if (warn_compat_break_chroot && strcmp(name, "chroot") == 0) if (warn_compat_break_chroot && strcmp(name, "chroot") == 0)
msg_info("%s: line %d: using backwards-compatible default setting " msg_info("%s: using backwards-compatible default setting "
"%s=%s", master_path, master_line, name, def_val); "%s=%s", master_conf_context(), name, def_val);
return (def_val); return (def_val);
} else { } else {
return (value); return (value);
@ -288,7 +298,7 @@ MASTER_SERV *get_master_ent()
* Skip blank lines and comment lines. * Skip blank lines and comment lines.
*/ */
for (;;) { for (;;) {
if (readlline(buf, master_fp, &master_line) == 0) { if (readllines(buf, master_fp, &master_line, &master_line_first) == 0) {
vstring_free(buf); vstring_free(buf);
vstring_free(junk); vstring_free(junk);
return (0); return (0);
@ -340,17 +350,14 @@ MASTER_SERV *get_master_ent()
serv->type = MASTER_SERV_TYPE_INET; serv->type = MASTER_SERV_TYPE_INET;
atmp = mystrdup(name); atmp = mystrdup(name);
if ((parse_err = host_port(atmp, &host, "", &port, (char *) 0)) != 0) if ((parse_err = host_port(atmp, &host, "", &port, (char *) 0)) != 0)
msg_fatal("%s: line %d: %s in \"%s\"", fatal_with_context("%s in \"%s\"", parse_err, name);
VSTREAM_PATH(master_fp), master_line,
parse_err, name);
if (*host) { if (*host) {
serv->flags |= MASTER_FLAG_INETHOST;/* host:port */ serv->flags |= MASTER_FLAG_INETHOST;/* host:port */
MASTER_INET_ADDRLIST(serv) = (INET_ADDR_LIST *) MASTER_INET_ADDRLIST(serv) = (INET_ADDR_LIST *)
mymalloc(sizeof(*MASTER_INET_ADDRLIST(serv))); mymalloc(sizeof(*MASTER_INET_ADDRLIST(serv)));
inet_addr_list_init(MASTER_INET_ADDRLIST(serv)); inet_addr_list_init(MASTER_INET_ADDRLIST(serv));
if (inet_addr_host(MASTER_INET_ADDRLIST(serv), host) == 0) if (inet_addr_host(MASTER_INET_ADDRLIST(serv), host) == 0)
msg_fatal("%s: line %d: bad hostname or network address: %s", fatal_with_context("bad hostname or network address: %s", name);
VSTREAM_PATH(master_fp), master_line, name);
inet_addr_list_uniq(MASTER_INET_ADDRLIST(serv)); inet_addr_list_uniq(MASTER_INET_ADDRLIST(serv));
serv->listen_fd_count = MASTER_INET_ADDRLIST(serv)->used; serv->listen_fd_count = MASTER_INET_ADDRLIST(serv)->used;
} else { } else {
@ -454,8 +461,7 @@ MASTER_SERV *get_master_ent()
* sockets is frozen anyway once we build the command-line vector below. * sockets is frozen anyway once we build the command-line vector below.
*/ */
if (serv->listen_fd_count == 0) { if (serv->listen_fd_count == 0) {
msg_fatal("%s: line %d: no valid IP address found: %s", fatal_with_context("no valid IP address found: %s", name);
VSTREAM_PATH(master_fp), master_line, name);
} }
serv->listen_fd = (int *) mymalloc(sizeof(int) * serv->listen_fd_count); serv->listen_fd = (int *) mymalloc(sizeof(int) * serv->listen_fd_count);
for (n = 0; n < serv->listen_fd_count; n++) for (n = 0; n < serv->listen_fd_count; n++)
@ -557,8 +563,7 @@ MASTER_SERV *get_master_ent()
(char *) 0); (char *) 0);
while ((cp = mystrtokq(&bufp, master_blanks, "{}")) != 0) { while ((cp = mystrtokq(&bufp, master_blanks, "{}")) != 0) {
if (*cp == '{' && (err = extpar(&cp, "{}", EXTPAR_FLAG_STRIP)) != 0) if (*cp == '{' && (err = extpar(&cp, "{}", EXTPAR_FLAG_STRIP)) != 0)
msg_fatal("%s: line %d: %s", fatal_with_context("%s", err);
VSTREAM_PATH(master_fp), master_line, err);
argv_add(serv->args, cp, (char *) 0); argv_add(serv->args, cp, (char *) 0);
} }
argv_terminate(serv->args); argv_terminate(serv->args);

View File

@ -263,6 +263,7 @@ static void postalias(char *map_type, char *path_name, int postalias_flags,
VSTRING *line_buffer; VSTRING *line_buffer;
MKMAP *mkmap; MKMAP *mkmap;
int lineno; int lineno;
int last_line;
VSTRING *key_buffer; VSTRING *key_buffer;
VSTRING *value_buffer; VSTRING *value_buffer;
TOK822 *tok_list; TOK822 *tok_list;
@ -334,8 +335,8 @@ static void postalias(char *map_type, char *path_name, int postalias_flags,
/* /*
* Add records to the database. * Add records to the database.
*/ */
lineno = 0; last_line = 0;
while (readlline(line_buffer, source_fp, &lineno)) { while (readllines(line_buffer, source_fp, &last_line, &lineno)) {
/* /*
* Tokenize the input, so that we do the right thing when a * Tokenize the input, so that we do the right thing when a

View File

@ -395,7 +395,8 @@ void pcf_read_master(int fail_on_open_error)
VSTREAM *fp; VSTREAM *fp;
const char *err; const char *err;
int entry_count = 0; int entry_count = 0;
int line_count = 0; int line_count;
int last_line = 0;
/* /*
* Sanity check. * Sanity check.
@ -425,7 +426,7 @@ void pcf_read_master(int fail_on_open_error)
msg_warn("open %s: %m", path); msg_warn("open %s: %m", path);
} else { } else {
buf = vstring_alloc(100); buf = vstring_alloc(100);
while (readlline(buf, fp, &line_count) != 0) { while (readllines(buf, fp, &last_line, &line_count) != 0) {
pcf_master_table = (PCF_MASTER_ENT *) myrealloc((char *) pcf_master_table, pcf_master_table = (PCF_MASTER_ENT *) myrealloc((char *) pcf_master_table,
(entry_count + 2) * sizeof(*pcf_master_table)); (entry_count + 2) * sizeof(*pcf_master_table));
if ((err = pcf_parse_master_entry(pcf_master_table + entry_count, if ((err = pcf_parse_master_entry(pcf_master_table + entry_count,

View File

@ -332,6 +332,7 @@ static void postmap(char *map_type, char *path_name, int postmap_flags,
VSTRING *line_buffer; VSTRING *line_buffer;
MKMAP *mkmap; MKMAP *mkmap;
int lineno; int lineno;
int last_line;
char *key; char *key;
char *value; char *value;
struct stat st; struct stat st;
@ -397,8 +398,8 @@ static void postmap(char *map_type, char *path_name, int postmap_flags,
/* /*
* Add records to the database. * Add records to the database.
*/ */
lineno = 0; last_line = 0;
while (readlline(line_buffer, source_fp, &lineno)) { while (readllines(line_buffer, source_fp, &last_line, &lineno)) {
/* /*
* Split on the first whitespace character, then trim leading and * Split on the first whitespace character, then trim leading and

View File

@ -453,7 +453,7 @@ typedef struct { /* server response */
/* command - send an SMTP command */ /* command - send an SMTP command */
static void command(STATE *state, int verbose, char *fmt,...) static void PRINTFLIKE(3, 4) command(STATE *state, int verbose, char *fmt,...)
{ {
VSTREAM *stream = state->stream; VSTREAM *stream = state->stream;
VSTRING *buf; VSTRING *buf;

View File

@ -3114,13 +3114,6 @@ static int data_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *unused_argv)
rec_fputs(state->cleanup, REC_TYPE_MESG, ""); rec_fputs(state->cleanup, REC_TYPE_MESG, "");
} }
/*
* PREPEND message headers.
*/
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 * Suppress our own Received: header in the unlikely case that we are an
* intermediate proxy. * intermediate proxy.
@ -3210,6 +3203,14 @@ static int data_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *unused_argv)
"\t(envelope-from %s)", STR(state->buffer)); "\t(envelope-from %s)", STR(state->buffer));
#endif #endif
} }
/*
* PREPEND message headers.
*/
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>"); smtpd_chat_reply(state, "354 End data with <CR><LF>.<CR><LF>");
state->where = SMTPD_AFTER_DATA; state->where = SMTPD_AFTER_DATA;

View File

@ -233,7 +233,7 @@ static VSTREAM *smtpd_proxy_replay_stream;
*/ */
static void smtpd_proxy_fake_server_reply(SMTPD_STATE *, int); static void smtpd_proxy_fake_server_reply(SMTPD_STATE *, int);
static int smtpd_proxy_rdwr_error(SMTPD_STATE *, int); static int smtpd_proxy_rdwr_error(SMTPD_STATE *, int);
static int smtpd_proxy_cmd(SMTPD_STATE *, int, const char *,...); static int PRINTFLIKE(3, 4) smtpd_proxy_cmd(SMTPD_STATE *, int, const char *,...);
static int smtpd_proxy_rec_put(VSTREAM *, int, const char *, ssize_t); static int smtpd_proxy_rec_put(VSTREAM *, int, const char *, ssize_t);
/* /*
@ -652,7 +652,7 @@ static int smtpd_proxy_replay_send(SMTPD_STATE *state)
/* smtpd_proxy_save_cmd - save SMTP command + expected response to replay log */ /* smtpd_proxy_save_cmd - save SMTP command + expected response to replay log */
static int smtpd_proxy_save_cmd(SMTPD_STATE *state, int expect, const char *fmt,...) static int PRINTFLIKE(3, 4) smtpd_proxy_save_cmd(SMTPD_STATE *state, int expect, const char *fmt,...)
{ {
va_list ap; va_list ap;

View File

@ -476,7 +476,7 @@ void dict_load_fp(const char *dict_name, VSTREAM *fp)
char *member; char *member;
char *val; char *val;
const char *old; const char *old;
int old_lineno; int last_line;
int lineno; int lineno;
const char *err; const char *err;
struct stat st; struct stat st;
@ -487,16 +487,15 @@ void dict_load_fp(const char *dict_name, VSTREAM *fp)
*/ */
DICT_FIND_FOR_UPDATE(dict, dict_name); DICT_FIND_FOR_UPDATE(dict, dict_name);
buf = vstring_alloc(100); buf = vstring_alloc(100);
old_lineno = lineno = 0; last_line = 0;
if (fstat(vstream_fileno(fp), &st) < 0) if (fstat(vstream_fileno(fp), &st) < 0)
msg_fatal("fstat %s: %m", VSTREAM_PATH(fp)); msg_fatal("fstat %s: %m", VSTREAM_PATH(fp));
for ( /* void */ ; readlline(buf, fp, &lineno); old_lineno = lineno) { while (readllines(buf, fp, &last_line, &lineno)) {
if ((err = split_nameval(STR(buf), &member, &val)) != 0) if ((err = split_nameval(STR(buf), &member, &val)) != 0)
msg_fatal("%s, line %s: %s: \"%s\"", msg_fatal("%s, line %d: %s: \"%s\"",
VSTREAM_PATH(fp), VSTREAM_PATH(fp),
format_line_number((VSTRING *) 0, lineno,
old_lineno + 1, lineno),
err, STR(buf)); err, STR(buf));
if (msg_verbose > 1) if (msg_verbose > 1)
msg_info("%s: %s = %s", myname, member, val); msg_info("%s: %s = %s", myname, member, val);

View File

@ -171,7 +171,8 @@ DICT *dict_cidr_open(const char *mapname, int open_flags, int dict_flags)
VSTRING *why = 0; VSTRING *why = 0;
DICT_CIDR_ENTRY *rule; DICT_CIDR_ENTRY *rule;
DICT_CIDR_ENTRY *last_rule = 0; DICT_CIDR_ENTRY *last_rule = 0;
int lineno = 0; int last_line = 0;
int lineno;
/* /*
* Let the optimizer worry about eliminating redundant code. * Let the optimizer worry about eliminating redundant code.
@ -223,7 +224,7 @@ DICT *dict_cidr_open(const char *mapname, int open_flags, int dict_flags)
dict_cidr->dict.owner.uid = st.st_uid; dict_cidr->dict.owner.uid = st.st_uid;
dict_cidr->dict.owner.status = (st.st_uid != 0); dict_cidr->dict.owner.status = (st.st_uid != 0);
while (readlline(line_buffer, map_fp, &lineno)) { while (readllines(line_buffer, map_fp, &last_line, &lineno)) {
rule = dict_cidr_parse_rule(vstring_str(line_buffer), why); rule = dict_cidr_parse_rule(vstring_str(line_buffer), why);
if (rule == 0) { if (rule == 0) {
msg_warn("cidr map %s, line %d: %s: skipping this rule", msg_warn("cidr map %s, line %d: %s: skipping this rule",

View File

@ -812,7 +812,8 @@ DICT *dict_pcre_open(const char *mapname, int open_flags, int dict_flags)
VSTRING *line_buffer = 0; VSTRING *line_buffer = 0;
DICT_PCRE_RULE *last_rule = 0; DICT_PCRE_RULE *last_rule = 0;
DICT_PCRE_RULE *rule; DICT_PCRE_RULE *rule;
int lineno = 0; int last_line = 0;
int lineno;
int nesting = 0; int nesting = 0;
char *p; char *p;
@ -870,7 +871,7 @@ DICT *dict_pcre_open(const char *mapname, int open_flags, int dict_flags)
/* /*
* Parse the pcre table. * Parse the pcre table.
*/ */
while (readlline(line_buffer, map_fp, &lineno)) { while (readllines(line_buffer, map_fp, &last_line, &lineno)) {
p = vstring_str(line_buffer); p = vstring_str(line_buffer);
trimblanks(p, 0)[0] = 0; /* Trim space at end */ trimblanks(p, 0)[0] = 0; /* Trim space at end */
if (*p == 0) if (*p == 0)

View File

@ -743,7 +743,8 @@ DICT *dict_regexp_open(const char *mapname, int open_flags, int dict_flags)
VSTRING *line_buffer = 0; VSTRING *line_buffer = 0;
DICT_REGEXP_RULE *rule; DICT_REGEXP_RULE *rule;
DICT_REGEXP_RULE *last_rule = 0; DICT_REGEXP_RULE *last_rule = 0;
int lineno = 0; int lineno;
int last_line = 0;
size_t max_sub = 0; size_t max_sub = 0;
int nesting = 0; int nesting = 0;
char *p; char *p;
@ -797,7 +798,7 @@ DICT *dict_regexp_open(const char *mapname, int open_flags, int dict_flags)
/* /*
* Parse the regexp table. * Parse the regexp table.
*/ */
while (readlline(line_buffer, map_fp, &lineno)) { while (readllines(line_buffer, map_fp, &last_line, &lineno)) {
p = vstring_str(line_buffer); p = vstring_str(line_buffer);
trimblanks(p, 0)[0] = 0; trimblanks(p, 0)[0] = 0;
if (*p == 0) if (*p == 0)

View File

@ -151,6 +151,7 @@ DICT *dict_thash_open(const char *path, int open_flags, int dict_flags)
time_t after; time_t after;
VSTRING *line_buffer = 0; VSTRING *line_buffer = 0;
int lineno; int lineno;
int last_line;
char *key; char *key;
char *value; char *value;
HTABLE *table; HTABLE *table;
@ -189,9 +190,9 @@ DICT *dict_thash_open(const char *path, int open_flags, int dict_flags)
} }
if (line_buffer == 0) if (line_buffer == 0)
line_buffer = vstring_alloc(100); line_buffer = vstring_alloc(100);
lineno = 0; last_line = 0;
table = htable_create(13); table = htable_create(13);
while (readlline(line_buffer, fp, &lineno)) { while (readllines(line_buffer, fp, &last_line, &lineno)) {
/* /*
* Split on the first whitespace character, then trim leading and * Split on the first whitespace character, then trim leading and

View File

@ -6,12 +6,18 @@
/* SYNOPSIS /* SYNOPSIS
/* #include <readlline.h> /* #include <readlline.h>
/* /*
/* VSTRING *readllines(buf, fp, lineno, first_line)
/* VSTRING *buf;
/* VSTREAM *fp;
/* int *lineno;
/* int *first_line;
/*
/* VSTRING *readlline(buf, fp, lineno) /* VSTRING *readlline(buf, fp, lineno)
/* VSTRING *buf; /* VSTRING *buf;
/* VSTREAM *fp; /* VSTREAM *fp;
/* int *lineno; /* int *lineno;
/* DESCRIPTION /* DESCRIPTION
/* readlline() reads one logical line from the named stream. /* readllines() reads one logical line from the named stream.
/* .IP "blank lines and comments" /* .IP "blank lines and comments"
/* Empty lines and whitespace-only lines are ignored, as /* Empty lines and whitespace-only lines are ignored, as
/* are lines whose first non-whitespace character is a `#'. /* are lines whose first non-whitespace character is a `#'.
@ -22,6 +28,8 @@
/* The result value is the input buffer argument or a null pointer /* The result value is the input buffer argument or a null pointer
/* when no input is found. /* when no input is found.
/* /*
/* readlline() is a backwards-compatibility wrapper.
/*
/* Arguments: /* Arguments:
/* .IP buf /* .IP buf
/* A variable-length buffer for input. The result is null terminated. /* A variable-length buffer for input. The result is null terminated.
@ -29,8 +37,11 @@
/* Handle to an open stream. /* Handle to an open stream.
/* .IP lineno /* .IP lineno
/* A null pointer, or a pointer to an integer that is incremented /* A null pointer, or a pointer to an integer that is incremented
/* after reading a newline character. /* after reading a physical line.
/* .RE /* .IP first_line
/* A null pointer, or a pointer to an integer that will contain
/* the line number of the first non-blank, non-comment line
/* in the result logical line.
/* DIAGNOSTICS /* DIAGNOSTICS
/* Warning: a continuation line that does not continue preceding text. /* Warning: a continuation line that does not continue preceding text.
/* The invalid input is ignored, to avoid complicating caller code. /* The invalid input is ignored, to avoid complicating caller code.
@ -66,9 +77,9 @@
#define LEN(x) VSTRING_LEN(x) #define LEN(x) VSTRING_LEN(x)
#define END(x) vstring_end(x) #define END(x) vstring_end(x)
/* readlline - read one logical line */ /* readllines - read one logical line */
VSTRING *readlline(VSTRING *buf, VSTREAM *fp, int *lineno) VSTRING *readllines(VSTRING *buf, VSTREAM *fp, int *lineno, int *first_line)
{ {
int ch; int ch;
int next; int next;
@ -86,13 +97,15 @@ VSTRING *readlline(VSTRING *buf, VSTREAM *fp, int *lineno)
start = LEN(buf); start = LEN(buf);
while ((ch = VSTREAM_GETC(fp)) != VSTREAM_EOF && ch != '\n') while ((ch = VSTREAM_GETC(fp)) != VSTREAM_EOF && ch != '\n')
VSTRING_ADDCH(buf, ch); VSTRING_ADDCH(buf, ch);
if (ch == '\n' && lineno != 0) if (lineno != 0 && (ch == '\n' || LEN(buf) > start))
*lineno += 1; *lineno += 1;
/* Ignore comment line, all whitespace line, or empty line. */ /* Ignore comment line, all whitespace line, or empty line. */
for (cp = STR(buf) + start; cp < END(buf) && ISSPACE(*cp); cp++) for (cp = STR(buf) + start; cp < END(buf) && ISSPACE(*cp); cp++)
/* void */ ; /* void */ ;
if (cp == END(buf) || *cp == '#') if (cp == END(buf) || *cp == '#')
vstring_truncate(buf, start); vstring_truncate(buf, start);
else if (start == 0 && lineno != 0 && first_line != 0)
*first_line = *lineno;
/* Terminate at EOF or at the beginning of the next logical line. */ /* Terminate at EOF or at the beginning of the next logical line. */
if (ch == VSTREAM_EOF) if (ch == VSTREAM_EOF)
break; break;
@ -115,7 +128,7 @@ VSTRING *readlline(VSTRING *buf, VSTREAM *fp, int *lineno)
msg_warn("%s: logical line must not start with whitespace: \"%.30s%s\"", msg_warn("%s: logical line must not start with whitespace: \"%.30s%s\"",
VSTREAM_PATH(fp), STR(buf), VSTREAM_PATH(fp), STR(buf),
LEN(buf) > 30 ? "..." : ""); LEN(buf) > 30 ? "..." : "");
return (readlline(buf, fp, lineno)); return (readllines(buf, fp, lineno, first_line));
} }
/* /*

View File

@ -20,7 +20,9 @@
/* /*
* External interface. * External interface.
*/ */
extern VSTRING *readlline(VSTRING *, VSTREAM *, int *); extern VSTRING *readllines(VSTRING *, VSTREAM *, int *, int *);
#define readlline(bp, fp, lp) readllines((bp), (fp), (lp), (int *) 0)
/* LICENSE /* LICENSE
/* .ad /* .ad