diff --git a/postfix/HISTORY b/postfix/HISTORY
index 97028e976..c0cd97f12 100644
--- a/postfix/HISTORY
+++ b/postfix/HISTORY
@@ -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.
diff --git a/postfix/README_FILES/TLS_README b/postfix/README_FILES/TLS_README
index adca4c825..67a2e3f8c 100644
--- a/postfix/README_FILES/TLS_README
+++ b/postfix/README_FILES/TLS_README
@@ -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
diff --git a/postfix/RELEASE_NOTES b/postfix/RELEASE_NOTES
index cde2d69a2..99f22c5a1 100644
--- a/postfix/RELEASE_NOTES
+++ b/postfix/RELEASE_NOTES
@@ -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,
diff --git a/postfix/html/TLS_README.html b/postfix/html/TLS_README.html
index 2548b9f57..286bf394c 100644
--- a/postfix/html/TLS_README.html
+++ b/postfix/html/TLS_README.html
@@ -1373,8 +1373,12 @@ 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.
@@ -1394,26 +1398,16 @@ records are found opportunistic TLS is used.
# default_transport = smtp, but some destinations are special:
#
transport_maps = ${indexed}transport
-
-
-
-
transport:
example.com dane
example.org dane
-
-
-
-
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
-o smtp_dns_support_level=dnssec
@@ -2146,7 +2140,10 @@ href="#client_tls_encrypt">encrypt. When usable TLSA records
are obtained for the remote SMTP server, SSLv2 is automatically
disabled (see smtp_tls_mandatory_protocols), and the server certificate
must match the TLSA records. RFC 6698 (DANE) TLS authentication
-and DNSSEC support is available with Postfix 2.11 and later.
+and DNSSEC support is available with Postfix 2.11 and later.
+The optional "fallback" attribute provides a per-site override of
+the main.cf smtp_tls_fallback_level parameter (Postfix ≥ 2.12).
+
dane-only Mandatory DANE TLS.
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 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.
+DNSSEC support is available with Postfix 2.11 and later.
+The optional "fallback" attribute provides a per-site override of
+the main.cf smtp_tls_fallback_level parameter (Postfix ≥ 2.12).
+
fingerprint Certificate
fingerprint verification. Available with Postfix 2.5 and
@@ -2164,13 +2164,15 @@ authorities. The certificate trust chain, expiration date, ... are
not checked. Instead, the optional match attribute, or else
the main.cf smtp_tls_fingerprint_cert_match 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
-smtp_tls_fingerprint_digest 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.
+(Postfix 2.9 and later). The digest algorithm used to calculate
+fingerprints is selected by the smtp_tls_fingerprint_digest
+parameter. Multiple fingerprints can be combined with a "|" delimiter
+in a single match attribute, or multiple match attributes can be
+employed. The ":" character is not used as a delimiter as it occurs
+between each pair of fingerprint (hexadecimal) digits.
+The optional "fallback" attribute provides a per-site override of
+the main.cf smtp_tls_fallback_level parameter (Postfix ≥ 2.12).
+
verify Mandatory
server certificate verification. Mail is delivered only if the
@@ -2181,9 +2183,11 @@ the optional "match" attribute (or the main.cf smtp_tls_trust_anchor_file" parameter. The "tafile" attribute
-may be specified multiple times to load multiple trust-anchor
-files.
+"smtp_tls_trust_anchor_file" parameter. The "tafile" attribute may
+be specified multiple times to load multiple trust-anchor files.
+The optional "fallback" attribute provides a per-site override of
+the main.cf smtp_tls_fallback_level parameter (Postfix ≥ 2.12).
+
secure Secure certificate
verification. 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 "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).
+
@@ -2242,6 +2249,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
@@ -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 smtp_tls_fallback_level
+ fallback.example secure fallback=encrypt
diff --git a/postfix/html/lmtp.8.html b/postfix/html/lmtp.8.html
index f07bc31f1..2299c5cc5 100644
--- a/postfix/html/lmtp.8.html
+++ b/postfix/html/lmtp.8.html
@@ -552,6 +552,11 @@ SMTP(8) SMTP(8)
tlsmgr_service_name (tlsmgr)
The name of the tlsmgr(8) service entry in master.cf.
+ Available in Postfix version 2.12 and later:
+
+ smtp_tls_fallback_level (empty)
+ Optional fallback levels for authenticated TLS levels.
+
OBSOLETE STARTTLS CONTROLS
The following configuration parameters exist for compatibility with
Postfix versions before 2.3. Support for these will be removed in a
diff --git a/postfix/html/postconf.5.html b/postfix/html/postconf.5.html
index e4e47d80d..c40fe6f61 100644
--- a/postfix/html/postconf.5.html
+++ b/postfix/html/postconf.5.html
@@ -5027,6 +5027,17 @@ configuration parameter. See there for details.
This feature is available in Postfix 2.3 and later.
+
+
+lmtp_tls_fallback_level
+(default: empty)
+
+ The LMTP-specific version of the smtp_tls_fallback_level
+configuration parameter. See there for details.
+
+ This feature is available in Postfix 2.12 and later.
+
+
lmtp_tls_fingerprint_cert_match
@@ -11637,6 +11648,61 @@ key exchange with RSA authentication.
This feature is available in Postfix 2.3 and later.
+
+
+smtp_tls_fallback_level
+(default: empty)
+
+ Optional fallback levels for authenticated TLS levels. Specify
+a white-space or comma-separated list of
+policy_level=fallback_level pairs. The policy_level
+must require authentication (one of dane, dane-only, fingerprint,
+verify, secure). The fallback_level 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.
+
+ 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.
+
+ Example:
+
+
+
+/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
+
+
+
+
+
+/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
+
+
+
+ This feature is available in Postfix 2.12 and later.
+
+
smtp_tls_fingerprint_cert_match
diff --git a/postfix/html/smtp.8.html b/postfix/html/smtp.8.html
index f07bc31f1..2299c5cc5 100644
--- a/postfix/html/smtp.8.html
+++ b/postfix/html/smtp.8.html
@@ -552,6 +552,11 @@ SMTP(8) SMTP(8)
tlsmgr_service_name (tlsmgr)
The name of the tlsmgr(8) service entry in master.cf.
+ Available in Postfix version 2.12 and later:
+
+ smtp_tls_fallback_level (empty)
+ Optional fallback levels for authenticated TLS levels.
+
OBSOLETE STARTTLS CONTROLS
The following configuration parameters exist for compatibility with
Postfix versions before 2.3. Support for these will be removed in a
diff --git a/postfix/man/man5/postconf.5 b/postfix/man/man5/postconf.5
index daeebcb9c..c8b16dfe0 100644
--- a/postfix/man/man5/postconf.5
+++ b/postfix/man/man5/postconf.5
@@ -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 =
diff --git a/postfix/man/man8/smtp.8 b/postfix/man/man8/smtp.8
index c0c3ed2bc..05ff23f2b 100644
--- a/postfix/man/man8/smtp.8
+++ b/postfix/man/man8/smtp.8
@@ -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
diff --git a/postfix/src/global/mail_parm_split.c b/postfix/src/global/mail_parm_split.c
index 0b206d059..1c54ab015 100644
--- a/postfix/src/global/mail_parm_split.c
+++ b/postfix/src/global/mail_parm_split.c
@@ -7,13 +7,13 @@
/* #include
/*
/* 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
diff --git a/postfix/src/global/mail_version.h b/postfix/src/global/mail_version.h
index 2b7e101ee..6c7a07078 100644
--- a/postfix/src/global/mail_version.h
+++ b/postfix/src/global/mail_version.h
@@ -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
diff --git a/postfix/src/master/master_ent.c b/postfix/src/master/master_ent.c
index 3235996d9..15ae3076d 100644
--- a/postfix/src/master/master_ent.c
+++ b/postfix/src/master/master_ent.c
@@ -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);
diff --git a/postfix/src/postalias/postalias.c b/postfix/src/postalias/postalias.c
index 430c15641..b5b4bf6e9 100644
--- a/postfix/src/postalias/postalias.c
+++ b/postfix/src/postalias/postalias.c
@@ -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
diff --git a/postfix/src/postconf/postconf_master.c b/postfix/src/postconf/postconf_master.c
index 481c35730..a745df20c 100644
--- a/postfix/src/postconf/postconf_master.c
+++ b/postfix/src/postconf/postconf_master.c
@@ -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,
diff --git a/postfix/src/postmap/postmap.c b/postfix/src/postmap/postmap.c
index e10ac1669..85301cc7f 100644
--- a/postfix/src/postmap/postmap.c
+++ b/postfix/src/postmap/postmap.c
@@ -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
diff --git a/postfix/src/posttls-finger/posttls-finger.c b/postfix/src/posttls-finger/posttls-finger.c
index c0c22b605..f02acf590 100644
--- a/postfix/src/posttls-finger/posttls-finger.c
+++ b/postfix/src/posttls-finger/posttls-finger.c
@@ -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;
diff --git a/postfix/src/smtpd/smtpd.c b/postfix/src/smtpd/smtpd.c
index d282122be..55627c6d2 100644
--- a/postfix/src/smtpd/smtpd.c
+++ b/postfix/src/smtpd/smtpd.c
@@ -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 .");
state->where = SMTPD_AFTER_DATA;
diff --git a/postfix/src/smtpd/smtpd_proxy.c b/postfix/src/smtpd/smtpd_proxy.c
index f20e673c5..552c61abe 100644
--- a/postfix/src/smtpd/smtpd_proxy.c
+++ b/postfix/src/smtpd/smtpd_proxy.c
@@ -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;
diff --git a/postfix/src/util/dict.c b/postfix/src/util/dict.c
index 769b16b3c..fefd0ad4e 100644
--- a/postfix/src/util/dict.c
+++ b/postfix/src/util/dict.c
@@ -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);
diff --git a/postfix/src/util/dict_cidr.c b/postfix/src/util/dict_cidr.c
index 76577fcb3..0ee9c4cc2 100644
--- a/postfix/src/util/dict_cidr.c
+++ b/postfix/src/util/dict_cidr.c
@@ -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",
diff --git a/postfix/src/util/dict_pcre.c b/postfix/src/util/dict_pcre.c
index 3f1833868..23ac2cd6f 100644
--- a/postfix/src/util/dict_pcre.c
+++ b/postfix/src/util/dict_pcre.c
@@ -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)
diff --git a/postfix/src/util/dict_regexp.c b/postfix/src/util/dict_regexp.c
index d64157882..c32925122 100644
--- a/postfix/src/util/dict_regexp.c
+++ b/postfix/src/util/dict_regexp.c
@@ -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)
diff --git a/postfix/src/util/dict_thash.c b/postfix/src/util/dict_thash.c
index bd4af6ce6..1bee77d30 100644
--- a/postfix/src/util/dict_thash.c
+++ b/postfix/src/util/dict_thash.c
@@ -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
diff --git a/postfix/src/util/readlline.c b/postfix/src/util/readlline.c
index 95bb29bb7..015877a2f 100644
--- a/postfix/src/util/readlline.c
+++ b/postfix/src/util/readlline.c
@@ -6,12 +6,18 @@
/* SYNOPSIS
/* #include
/*
+/* 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));
}
/*
diff --git a/postfix/src/util/readlline.h b/postfix/src/util/readlline.h
index 8a8bd5487..d63cf7d21 100644
--- a/postfix/src/util/readlline.h
+++ b/postfix/src/util/readlline.h
@@ -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