mirror of
https://github.com/vdukhovni/postfix
synced 2025-08-30 13:48:06 +00:00
postfix-2.12-20141013
This commit is contained in:
parent
757df5bc6c
commit
783583def2
@ -20640,3 +20640,25 @@ Apologies for any names omitted.
|
||||
./proto/postconf.proto, global/mail_params.h, smtp/lmtp_params.c,
|
||||
smtp/smtp.c, smtp/smtp.h, smtp/smtp_connect.c, smtp/smtp_params.c,
|
||||
smtp/smtp_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.
|
||||
|
@ -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
|
||||
present or are unusable, mail is deferred.
|
||||
|
||||
* The "example.org" destination uses DANE if possible, but if no TLSA records
|
||||
are found opportunistic TLS is used.
|
||||
* 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.
|
||||
|
||||
main.cf:
|
||||
indexed = ${default_database_type}:${config_directory}/
|
||||
@ -1052,6 +1055,8 @@ default. This is the recommended configuration for early adopters.
|
||||
|
||||
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
|
||||
@ -1632,7 +1637,9 @@ ddaannee
|
||||
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.
|
||||
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
|
||||
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
|
||||
@ -1640,7 +1647,9 @@ ddaannee--oonnllyy
|
||||
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.
|
||||
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
|
||||
Certificate fingerprint verification. Available with Postfix 2.5 and later.
|
||||
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
|
||||
match attributes can be employed. The ":" character is not used as a
|
||||
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
|
||||
Mandatory server certificate verification. Mail is delivered only if the
|
||||
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
|
||||
manner as the "smtp_tls_trust_anchor_file" parameter. The "tafile"
|
||||
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
|
||||
Secure certificate verification. Mail is delivered only if the TLS
|
||||
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"
|
||||
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.
|
||||
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:
|
||||
|
||||
* 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
|
||||
# Postfix 2.5 and later
|
||||
smtp_tls_fingerprint_digest = md5
|
||||
|
||||
/etc/postfix/tls_policy:
|
||||
example.edu none
|
||||
example.mil may
|
||||
@ -1723,6 +1737,8 @@ Example:
|
||||
# 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
|
||||
|
||||
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
|
||||
|
@ -59,6 +59,16 @@ Maintainers may also benefit from the makedefs documentation
|
||||
(mantools/srctoman - makedefs | nroff -man | less) with information
|
||||
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
|
||||
====================================
|
||||
|
||||
@ -73,7 +83,7 @@ Fallback to unauthenticated TLS is logged, so that downgrade attacks
|
||||
are "tamper-evident". Fallback should be used only when testing,
|
||||
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,
|
||||
|
@ -1373,8 +1373,12 @@ for early adopters. <p>
|
||||
<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 if no TLSA
|
||||
records are found opportunistic TLS is used. </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>
|
||||
</ul>
|
||||
|
||||
<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#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
|
||||
</pre>
|
||||
</blockquote>
|
||||
# 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
|
||||
|
||||
<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
|
||||
@ -2146,7 +2140,10 @@ href="#client_tls_encrypt">encrypt</a>. When usable TLSA records
|
||||
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. </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 ≥ 2.12).
|
||||
</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
|
||||
@ -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
|
||||
(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. </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 ≥ 2.12).
|
||||
</dd>
|
||||
|
||||
<dt><b>fingerprint</b></dt> <dd><a href="#client_tls_fprint">Certificate
|
||||
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
|
||||
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. </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.
|
||||
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>
|
||||
|
||||
<dt><b>verify</b></dt> <dd><a href="#client_tls_verify">Mandatory
|
||||
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).
|
||||
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. </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.
|
||||
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>
|
||||
|
||||
<dt><b>secure</b></dt> <dd><a href="#client_tls_secure">Secure certificate
|
||||
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
|
||||
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. </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 ≥ 2.12).
|
||||
</dd>
|
||||
|
||||
</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
|
||||
# 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
|
||||
@ -2256,6 +2264,8 @@ Example:
|
||||
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>
|
||||
|
||||
|
@ -552,6 +552,11 @@ SMTP(8) SMTP(8)
|
||||
<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
|
||||
|
@ -5027,6 +5027,17 @@ configuration parameter. See there for details. </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>
|
||||
|
||||
<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>
|
||||
|
||||
|
||||
</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>
|
||||
|
@ -552,6 +552,11 @@ SMTP(8) SMTP(8)
|
||||
<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
|
||||
|
@ -2970,6 +2970,11 @@ The LMTP-specific version of the smtp_tls_exclude_ciphers
|
||||
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.
|
||||
@ -7304,6 +7309,63 @@ and "DES-CBC3-MD5". The last setting disables ciphers that use "EDH"
|
||||
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 =
|
||||
|
@ -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.
|
||||
.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
|
||||
|
@ -7,13 +7,13 @@
|
||||
/* #include <mail_parm_split.h>
|
||||
/*
|
||||
/* ARGV *mail_parm_split(
|
||||
/* cost char *name,
|
||||
/* const char *name,
|
||||
/* const char *value)
|
||||
/* DESCRIPTION
|
||||
/* mail_parm_split() splits a parameter list value into its
|
||||
/* elements, and extracts text from inside {}. It uses
|
||||
/* CHARS_COMMA_SP as list element delimiters, and CHARS_BRACE
|
||||
/* for grouping.
|
||||
/* elements, and extracts text from elements that are entirely
|
||||
/* enclosed in {}. It uses CHARS_COMMA_SP as list element
|
||||
/* delimiters, and CHARS_BRACE for grouping.
|
||||
/*
|
||||
/* Arguments:
|
||||
/* .IP name
|
||||
@ -22,7 +22,8 @@
|
||||
/* .IP value
|
||||
/* Parameter value.
|
||||
/* 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
|
||||
/* argv_splitq(3), string array utilities
|
||||
/* extpar(3), extract text from parentheses
|
||||
|
@ -20,7 +20,7 @@
|
||||
* Patches change both the patchlevel and the release date. Snapshots have no
|
||||
* patchlevel; they change the release date only.
|
||||
*/
|
||||
#define MAIL_RELEASE_DATE "20141011"
|
||||
#define MAIL_RELEASE_DATE "20141013"
|
||||
#define MAIL_VERSION_NUMBER "2.12"
|
||||
|
||||
#ifdef SNAPSHOT
|
||||
|
@ -106,13 +106,11 @@
|
||||
static char *master_path; /* config file name */
|
||||
static VSTREAM *master_fp; /* config file pointer */
|
||||
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 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 */
|
||||
|
||||
void fset_master_ent(char *path)
|
||||
@ -167,9 +165,21 @@ void end_master_ent()
|
||||
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 */
|
||||
|
||||
static NORETURN fatal_with_context(char *format,...)
|
||||
static NORETURN PRINTFLIKE(1, 2) fatal_with_context(char *format,...)
|
||||
{
|
||||
const char *myname = "fatal_with_context";
|
||||
VSTRING *vp = vstring_alloc(100);
|
||||
@ -181,7 +191,7 @@ static NORETURN fatal_with_context(char *format,...)
|
||||
va_start(ap, format);
|
||||
vstring_vsprintf(vp, format, 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 */
|
||||
@ -203,8 +213,8 @@ static char *get_str_ent(char **bufp, char *name, char *def_val)
|
||||
if (def_val == 0)
|
||||
fatal_with_context("field \"%s\" has no default value", name);
|
||||
if (warn_compat_break_chroot && strcmp(name, "chroot") == 0)
|
||||
msg_info("%s: line %d: using backwards-compatible default setting "
|
||||
"%s=%s", master_path, master_line, name, def_val);
|
||||
msg_info("%s: using backwards-compatible default setting "
|
||||
"%s=%s", master_conf_context(), name, def_val);
|
||||
return (def_val);
|
||||
} else {
|
||||
return (value);
|
||||
@ -288,7 +298,7 @@ MASTER_SERV *get_master_ent()
|
||||
* Skip blank lines and comment lines.
|
||||
*/
|
||||
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(junk);
|
||||
return (0);
|
||||
@ -340,17 +350,14 @@ MASTER_SERV *get_master_ent()
|
||||
serv->type = MASTER_SERV_TYPE_INET;
|
||||
atmp = mystrdup(name);
|
||||
if ((parse_err = host_port(atmp, &host, "", &port, (char *) 0)) != 0)
|
||||
msg_fatal("%s: line %d: %s in \"%s\"",
|
||||
VSTREAM_PATH(master_fp), master_line,
|
||||
parse_err, name);
|
||||
fatal_with_context("%s in \"%s\"", parse_err, name);
|
||||
if (*host) {
|
||||
serv->flags |= MASTER_FLAG_INETHOST;/* host:port */
|
||||
MASTER_INET_ADDRLIST(serv) = (INET_ADDR_LIST *)
|
||||
mymalloc(sizeof(*MASTER_INET_ADDRLIST(serv)));
|
||||
inet_addr_list_init(MASTER_INET_ADDRLIST(serv));
|
||||
if (inet_addr_host(MASTER_INET_ADDRLIST(serv), host) == 0)
|
||||
msg_fatal("%s: line %d: bad hostname or network address: %s",
|
||||
VSTREAM_PATH(master_fp), master_line, name);
|
||||
fatal_with_context("bad hostname or network address: %s", name);
|
||||
inet_addr_list_uniq(MASTER_INET_ADDRLIST(serv));
|
||||
serv->listen_fd_count = MASTER_INET_ADDRLIST(serv)->used;
|
||||
} else {
|
||||
@ -454,8 +461,7 @@ MASTER_SERV *get_master_ent()
|
||||
* sockets is frozen anyway once we build the command-line vector below.
|
||||
*/
|
||||
if (serv->listen_fd_count == 0) {
|
||||
msg_fatal("%s: line %d: no valid IP address found: %s",
|
||||
VSTREAM_PATH(master_fp), master_line, name);
|
||||
fatal_with_context("no valid IP address found: %s", name);
|
||||
}
|
||||
serv->listen_fd = (int *) mymalloc(sizeof(int) * serv->listen_fd_count);
|
||||
for (n = 0; n < serv->listen_fd_count; n++)
|
||||
@ -557,8 +563,7 @@ MASTER_SERV *get_master_ent()
|
||||
(char *) 0);
|
||||
while ((cp = mystrtokq(&bufp, master_blanks, "{}")) != 0) {
|
||||
if (*cp == '{' && (err = extpar(&cp, "{}", EXTPAR_FLAG_STRIP)) != 0)
|
||||
msg_fatal("%s: line %d: %s",
|
||||
VSTREAM_PATH(master_fp), master_line, err);
|
||||
fatal_with_context("%s", err);
|
||||
argv_add(serv->args, cp, (char *) 0);
|
||||
}
|
||||
argv_terminate(serv->args);
|
||||
|
@ -263,6 +263,7 @@ static void postalias(char *map_type, char *path_name, int postalias_flags,
|
||||
VSTRING *line_buffer;
|
||||
MKMAP *mkmap;
|
||||
int lineno;
|
||||
int last_line;
|
||||
VSTRING *key_buffer;
|
||||
VSTRING *value_buffer;
|
||||
TOK822 *tok_list;
|
||||
@ -334,8 +335,8 @@ static void postalias(char *map_type, char *path_name, int postalias_flags,
|
||||
/*
|
||||
* Add records to the database.
|
||||
*/
|
||||
lineno = 0;
|
||||
while (readlline(line_buffer, source_fp, &lineno)) {
|
||||
last_line = 0;
|
||||
while (readllines(line_buffer, source_fp, &last_line, &lineno)) {
|
||||
|
||||
/*
|
||||
* Tokenize the input, so that we do the right thing when a
|
||||
|
@ -395,7 +395,8 @@ void pcf_read_master(int fail_on_open_error)
|
||||
VSTREAM *fp;
|
||||
const char *err;
|
||||
int entry_count = 0;
|
||||
int line_count = 0;
|
||||
int line_count;
|
||||
int last_line = 0;
|
||||
|
||||
/*
|
||||
* Sanity check.
|
||||
@ -425,7 +426,7 @@ void pcf_read_master(int fail_on_open_error)
|
||||
msg_warn("open %s: %m", path);
|
||||
} else {
|
||||
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,
|
||||
(entry_count + 2) * sizeof(*pcf_master_table));
|
||||
if ((err = pcf_parse_master_entry(pcf_master_table + entry_count,
|
||||
|
@ -332,6 +332,7 @@ static void postmap(char *map_type, char *path_name, int postmap_flags,
|
||||
VSTRING *line_buffer;
|
||||
MKMAP *mkmap;
|
||||
int lineno;
|
||||
int last_line;
|
||||
char *key;
|
||||
char *value;
|
||||
struct stat st;
|
||||
@ -397,8 +398,8 @@ static void postmap(char *map_type, char *path_name, int postmap_flags,
|
||||
/*
|
||||
* Add records to the database.
|
||||
*/
|
||||
lineno = 0;
|
||||
while (readlline(line_buffer, source_fp, &lineno)) {
|
||||
last_line = 0;
|
||||
while (readllines(line_buffer, source_fp, &last_line, &lineno)) {
|
||||
|
||||
/*
|
||||
* Split on the first whitespace character, then trim leading and
|
||||
|
@ -453,7 +453,7 @@ typedef struct { /* server response */
|
||||
|
||||
/* 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;
|
||||
VSTRING *buf;
|
||||
|
@ -3114,13 +3114,6 @@ static int data_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *unused_argv)
|
||||
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
|
||||
* 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));
|
||||
#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>");
|
||||
state->where = SMTPD_AFTER_DATA;
|
||||
|
||||
|
@ -233,7 +233,7 @@ static VSTREAM *smtpd_proxy_replay_stream;
|
||||
*/
|
||||
static void smtpd_proxy_fake_server_reply(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);
|
||||
|
||||
/*
|
||||
@ -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 */
|
||||
|
||||
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;
|
||||
|
||||
|
@ -476,7 +476,7 @@ void dict_load_fp(const char *dict_name, VSTREAM *fp)
|
||||
char *member;
|
||||
char *val;
|
||||
const char *old;
|
||||
int old_lineno;
|
||||
int last_line;
|
||||
int lineno;
|
||||
const char *err;
|
||||
struct stat st;
|
||||
@ -487,16 +487,15 @@ void dict_load_fp(const char *dict_name, VSTREAM *fp)
|
||||
*/
|
||||
DICT_FIND_FOR_UPDATE(dict, dict_name);
|
||||
buf = vstring_alloc(100);
|
||||
old_lineno = lineno = 0;
|
||||
last_line = 0;
|
||||
|
||||
if (fstat(vstream_fileno(fp), &st) < 0)
|
||||
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)
|
||||
msg_fatal("%s, line %s: %s: \"%s\"",
|
||||
msg_fatal("%s, line %d: %s: \"%s\"",
|
||||
VSTREAM_PATH(fp),
|
||||
format_line_number((VSTRING *) 0,
|
||||
old_lineno + 1, lineno),
|
||||
lineno,
|
||||
err, STR(buf));
|
||||
if (msg_verbose > 1)
|
||||
msg_info("%s: %s = %s", myname, member, val);
|
||||
|
@ -171,7 +171,8 @@ DICT *dict_cidr_open(const char *mapname, int open_flags, int dict_flags)
|
||||
VSTRING *why = 0;
|
||||
DICT_CIDR_ENTRY *rule;
|
||||
DICT_CIDR_ENTRY *last_rule = 0;
|
||||
int lineno = 0;
|
||||
int last_line = 0;
|
||||
int lineno;
|
||||
|
||||
/*
|
||||
* 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.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);
|
||||
if (rule == 0) {
|
||||
msg_warn("cidr map %s, line %d: %s: skipping this rule",
|
||||
|
@ -812,7 +812,8 @@ DICT *dict_pcre_open(const char *mapname, int open_flags, int dict_flags)
|
||||
VSTRING *line_buffer = 0;
|
||||
DICT_PCRE_RULE *last_rule = 0;
|
||||
DICT_PCRE_RULE *rule;
|
||||
int lineno = 0;
|
||||
int last_line = 0;
|
||||
int lineno;
|
||||
int nesting = 0;
|
||||
char *p;
|
||||
|
||||
@ -870,7 +871,7 @@ DICT *dict_pcre_open(const char *mapname, int open_flags, int dict_flags)
|
||||
/*
|
||||
* 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);
|
||||
trimblanks(p, 0)[0] = 0; /* Trim space at end */
|
||||
if (*p == 0)
|
||||
|
@ -743,7 +743,8 @@ DICT *dict_regexp_open(const char *mapname, int open_flags, int dict_flags)
|
||||
VSTRING *line_buffer = 0;
|
||||
DICT_REGEXP_RULE *rule;
|
||||
DICT_REGEXP_RULE *last_rule = 0;
|
||||
int lineno = 0;
|
||||
int lineno;
|
||||
int last_line = 0;
|
||||
size_t max_sub = 0;
|
||||
int nesting = 0;
|
||||
char *p;
|
||||
@ -797,7 +798,7 @@ DICT *dict_regexp_open(const char *mapname, int open_flags, int dict_flags)
|
||||
/*
|
||||
* 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);
|
||||
trimblanks(p, 0)[0] = 0;
|
||||
if (*p == 0)
|
||||
|
@ -151,6 +151,7 @@ DICT *dict_thash_open(const char *path, int open_flags, int dict_flags)
|
||||
time_t after;
|
||||
VSTRING *line_buffer = 0;
|
||||
int lineno;
|
||||
int last_line;
|
||||
char *key;
|
||||
char *value;
|
||||
HTABLE *table;
|
||||
@ -189,9 +190,9 @@ DICT *dict_thash_open(const char *path, int open_flags, int dict_flags)
|
||||
}
|
||||
if (line_buffer == 0)
|
||||
line_buffer = vstring_alloc(100);
|
||||
lineno = 0;
|
||||
last_line = 0;
|
||||
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
|
||||
|
@ -6,12 +6,18 @@
|
||||
/* SYNOPSIS
|
||||
/* #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 *buf;
|
||||
/* VSTREAM *fp;
|
||||
/* int *lineno;
|
||||
/* DESCRIPTION
|
||||
/* readlline() reads one logical line from the named stream.
|
||||
/* readllines() reads one logical line from the named stream.
|
||||
/* .IP "blank lines and comments"
|
||||
/* Empty lines and whitespace-only lines are ignored, as
|
||||
/* 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
|
||||
/* when no input is found.
|
||||
/*
|
||||
/* readlline() is a backwards-compatibility wrapper.
|
||||
/*
|
||||
/* Arguments:
|
||||
/* .IP buf
|
||||
/* A variable-length buffer for input. The result is null terminated.
|
||||
@ -29,8 +37,11 @@
|
||||
/* Handle to an open stream.
|
||||
/* .IP lineno
|
||||
/* A null pointer, or a pointer to an integer that is incremented
|
||||
/* after reading a newline character.
|
||||
/* .RE
|
||||
/* after reading a physical line.
|
||||
/* .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
|
||||
/* Warning: a continuation line that does not continue preceding text.
|
||||
/* The invalid input is ignored, to avoid complicating caller code.
|
||||
@ -66,9 +77,9 @@
|
||||
#define LEN(x) VSTRING_LEN(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 next;
|
||||
@ -86,13 +97,15 @@ VSTRING *readlline(VSTRING *buf, VSTREAM *fp, int *lineno)
|
||||
start = LEN(buf);
|
||||
while ((ch = VSTREAM_GETC(fp)) != VSTREAM_EOF && ch != '\n')
|
||||
VSTRING_ADDCH(buf, ch);
|
||||
if (ch == '\n' && lineno != 0)
|
||||
if (lineno != 0 && (ch == '\n' || LEN(buf) > start))
|
||||
*lineno += 1;
|
||||
/* Ignore comment line, all whitespace line, or empty line. */
|
||||
for (cp = STR(buf) + start; cp < END(buf) && ISSPACE(*cp); cp++)
|
||||
/* void */ ;
|
||||
if (cp == END(buf) || *cp == '#')
|
||||
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. */
|
||||
if (ch == VSTREAM_EOF)
|
||||
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\"",
|
||||
VSTREAM_PATH(fp), STR(buf),
|
||||
LEN(buf) > 30 ? "..." : "");
|
||||
return (readlline(buf, fp, lineno));
|
||||
return (readllines(buf, fp, lineno, first_line));
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -20,7 +20,9 @@
|
||||
/*
|
||||
* 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
|
||||
/* .ad
|
||||
|
Loading…
x
Reference in New Issue
Block a user