From 783583def21145c67bfe9969af3c33dabf345266 Mon Sep 17 00:00:00 2001 From: Wietse Venema Date: Mon, 13 Oct 2014 00:00:00 -0500 Subject: [PATCH] postfix-2.12-20141013 --- postfix/HISTORY | 22 +++++++ postfix/README_FILES/TLS_README | 30 +++++++--- postfix/RELEASE_NOTES | 12 +++- postfix/html/TLS_README.html | 64 +++++++++++--------- postfix/html/lmtp.8.html | 5 ++ postfix/html/postconf.5.html | 66 +++++++++++++++++++++ postfix/html/smtp.8.html | 5 ++ postfix/man/man5/postconf.5 | 62 +++++++++++++++++++ postfix/man/man8/smtp.8 | 4 ++ postfix/src/global/mail_parm_split.c | 11 ++-- postfix/src/global/mail_version.h | 2 +- postfix/src/master/master_ent.c | 39 ++++++------ postfix/src/postalias/postalias.c | 5 +- postfix/src/postconf/postconf_master.c | 5 +- postfix/src/postmap/postmap.c | 5 +- postfix/src/posttls-finger/posttls-finger.c | 2 +- postfix/src/smtpd/smtpd.c | 15 ++--- postfix/src/smtpd/smtpd_proxy.c | 4 +- postfix/src/util/dict.c | 11 ++-- postfix/src/util/dict_cidr.c | 5 +- postfix/src/util/dict_pcre.c | 5 +- postfix/src/util/dict_regexp.c | 5 +- postfix/src/util/dict_thash.c | 5 +- postfix/src/util/readlline.c | 27 ++++++--- postfix/src/util/readlline.h | 4 +- 25 files changed, 324 insertions(+), 96 deletions(-) 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