./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.
* 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}/
tls_policy:
example.com dane-only
+ # Postfix >= 2.12, per-destination smtp_tls_fallback_level override
+ example.org dane fallback=encrypt
master.cf:
dane unix - - n - - smtp
obtained for the remote SMTP server, SSLv2 is automatically disabled (see
smtp_tls_mandatory_protocols), and the server certificate must match the
TLSA records. RFC 6698 (DANE) TLS authentication and DNSSEC support is
- available with Postfix 2.11 and later.
+ 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).
d\bda\ban\bne\be-\b-o\bon\bnl\bly\by
Mandatory DANE TLS. The TLS policy for the destination is obtained via TLSA
records in DNSSEC. If no TLSA records are found, or none are usable, no
the remote SMTP server, SSLv2 is automatically disabled (see
smtp_tls_mandatory_protocols), and the server certificate must match the
TLSA records. RFC 6698 (DANE) TLS authentication and DNSSEC support is
- available with Postfix 2.11 and later.
+ 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).
f\bfi\bin\bng\bge\ber\brp\bpr\bri\bin\bnt\bt
Certificate fingerprint verification. Available with Postfix 2.5 and later.
At this security level, there are no trusted certificate authorities. The
combined with a "|" delimiter in a single match attribute, or multiple
match attributes can be employed. The ":" character is not used as a
delimiter as it occurs between each pair of fingerprint (hexadecimal)
- digits.
+ digits. The optional "fallback" attribute provides a per-site override of
+ the main.cf smtp_tls_fallback_level parameter (Postfix >= 2.12).
v\bve\ber\bri\bif\bfy\by
Mandatory server certificate verification. Mail is delivered only if the
TLS handshake succeeds, if the remote SMTP server certificate can be
"tafile" attribute optionally modifies trust chain verification in the same
manner as the "smtp_tls_trust_anchor_file" parameter. The "tafile"
attribute may be specified multiple times to load multiple trust-anchor
- files.
+ files. The optional "fallback" attribute provides a per-site override of
+ the main.cf smtp_tls_fallback_level parameter (Postfix >= 2.12).
s\bse\bec\bcu\bur\bre\be
Secure certificate verification. Mail is delivered only if the TLS
handshake succeeds, if the remote SMTP server certificate can be validated
"match" attribute is specified). With Postfix >= 2.11 the "tafile"
attribute optionally modifies trust chain verification in the same manner
as the "smtp_tls_trust_anchor_file" parameter. The "tafile" attribute may
- be specified multiple times to load multiple trust-anchor files.
+ 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
smtp_tls_policy_maps = hash:/etc/postfix/tls_policy
# Postfix 2.5 and later
smtp_tls_fingerprint_digest = md5
+
/etc/postfix/tls_policy:
example.edu none
example.mil may
# Postfix 2.6 and later
example.info may protocols=!SSLv2 ciphers=medium
exclude=3DES
+ # Postfix 2.12 and later override of smtp_tls_fallback_level
+ fallback.example secure fallback=encrypt
N\bNo\bot\bte\be:\b: The "hostname" strategy if listed in a non-default setting of
smtp_tls_secure_cert_match or in the "match" attribute in the policy table can
(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
====================================
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,
<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>
# <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
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
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
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
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,
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>
<a href="postconf.5.html#smtp_tls_policy_maps">smtp_tls_policy_maps</a> = <a href="DATABASE_README.html#types">hash</a>:/etc/postfix/tls_policy
# Postfix 2.5 and later
<a href="postconf.5.html#smtp_tls_fingerprint_digest">smtp_tls_fingerprint_digest</a> = md5
+
/etc/postfix/tls_policy:
example.edu none
example.mil may
match=3D:95:34:51:24:66:33:B9:D2:40:99:C0:C1:17:0B:D1
# Postfix 2.6 and later
example.info may protocols=!SSLv2 ciphers=medium exclude=3DES
+ # Postfix 2.12 and later override of <a href="postconf.5.html#smtp_tls_fallback_level">smtp_tls_fallback_level</a>
+ fallback.example secure fallback=encrypt
</pre>
</blockquote>
<b><a href="postconf.5.html#tlsmgr_service_name">tlsmgr_service_name</a> (tlsmgr)</b>
The name of the <a href="tlsmgr.8.html"><b>tlsmgr</b>(8)</a> service entry in <a href="master.5.html">master.cf</a>.
+ Available in Postfix version 2.12 and later:
+
+ <b><a href="postconf.5.html#smtp_tls_fallback_level">smtp_tls_fallback_level</a> (empty)</b>
+ Optional fallback levels for authenticated TLS levels.
+
<b>OBSOLETE STARTTLS CONTROLS</b>
The following configuration parameters exist for compatibility with
Postfix versions before 2.3. Support for these will be removed in a
<p> This feature is available in Postfix 2.3 and later. </p>
+</DD>
+
+<DT><b><a name="lmtp_tls_fallback_level">lmtp_tls_fallback_level</a>
+(default: empty)</b></DT><DD>
+
+<p> The LMTP-specific version of the <a href="postconf.5.html#smtp_tls_fallback_level">smtp_tls_fallback_level</a>
+configuration parameter. See there for details. </p>
+
+<p> This feature is available in Postfix 2.12 and later. </p>
+
+
</DD>
<DT><b><a name="lmtp_tls_fingerprint_cert_match">lmtp_tls_fingerprint_cert_match</a>
<p> This feature is available in Postfix 2.3 and later. </p>
+</DD>
+
+<DT><b><a name="smtp_tls_fallback_level">smtp_tls_fallback_level</a>
+(default: empty)</b></DT><DD>
+
+<p> Optional fallback levels for authenticated TLS levels. Specify
+a white-space or comma-separated list of
+<b>policy_level</b>=<b>fallback_level</b> pairs. The <b>policy_level</b>
+must require authentication (one of dane, dane-only, fingerprint,
+verify, secure). The <b>fallback_level</b> must be "encrypt" or
+"may". When an authenticated connection at some desired policy
+level cannot be established, delivery will proceed at the correponding
+fallback level if possible. A warning will be logged
+indicating the fallback reason. </p>
+
+<p> The TLS <a href="TLS_README.html#client_tls_policy">policy</a> table
+can be used to specify a destination-specific fallback strategy via the
+"fallback" policy attribute. The value of the "fallback" attribute, if
+specified, must be "may", "encrypt" or "none". If not "none", this
+specifies the fallback level for the destination in question. If the
+attribute value is "none", fallback is suppressed for the destination
+even if enabled via a global setting of <a href="postconf.5.html#smtp_tls_fallback_level">smtp_tls_fallback_level</a>. </p>
+
+<p> Example: </p>
+
+<blockquote>
+<pre>
+/etc/postfix/<a href="postconf.5.html">main.cf</a>:
+ # When authentication fails, log a warning and deliver anyway
+ # over an unauthenticated TLS connection.
+ #
+ <a href="postconf.5.html#smtp_tls_fallback_level">smtp_tls_fallback_level</a> =
+ dane=encrypt,
+ dane-only=encrypt,
+ fingerprint=encrypt,
+ verify=encrypt,
+ secure=encrypt
+ indexed = ${<a href="postconf.5.html#default_database_type">default_database_type</a>}:${<a href="postconf.5.html#config_directory">config_directory</a>}/
+ <a href="postconf.5.html#smtp_tls_policy_maps">smtp_tls_policy_maps</a> = ${indexed}tls-policy
+</pre>
+</blockquote>
+
+<blockquote>
+<pre>
+/etc/postfix/tls-policy:
+ # No fallback for example.com
+ example.com secure fallback=none
+ # For example.net tolerate cleartext fallback
+ example.net dane fallback=may
+</pre>
+</blockquote>
+
+<p> This feature is available in Postfix 2.12 and later. </p>
+
+
</DD>
<DT><b><a name="smtp_tls_fingerprint_cert_match">smtp_tls_fingerprint_cert_match</a>
<b><a href="postconf.5.html#tlsmgr_service_name">tlsmgr_service_name</a> (tlsmgr)</b>
The name of the <a href="tlsmgr.8.html"><b>tlsmgr</b>(8)</a> service entry in <a href="master.5.html">master.cf</a>.
+ Available in Postfix version 2.12 and later:
+
+ <b><a href="postconf.5.html#smtp_tls_fallback_level">smtp_tls_fallback_level</a> (empty)</b>
+ Optional fallback levels for authenticated TLS levels.
+
<b>OBSOLETE STARTTLS CONTROLS</b>
The following configuration parameters exist for compatibility with
Postfix versions before 2.3. Support for these will be removed in a
configuration parameter. See there for details.
.PP
This feature is available in Postfix 2.3 and later.
+.SH lmtp_tls_fallback_level (default: empty)
+The LMTP-specific version of the smtp_tls_fallback_level
+configuration parameter. See there for details.
+.PP
+This feature is available in Postfix 2.12 and later.
.SH lmtp_tls_fingerprint_cert_match (default: empty)
The LMTP-specific version of the smtp_tls_fingerprint_cert_match
configuration parameter. See there for details.
key exchange with RSA authentication.
.PP
This feature is available in Postfix 2.3 and later.
+.SH smtp_tls_fallback_level (default: empty)
+Optional fallback levels for authenticated TLS levels. Specify
+a white-space or comma-separated list of
+\fBpolicy_level\fR=\fBfallback_level\fR pairs. The \fBpolicy_level\fR
+must require authentication (one of dane, dane-only, fingerprint,
+verify, secure). The \fBfallback_level\fR must be "encrypt" or
+"may". When an authenticated connection at some desired policy
+level cannot be established, delivery will proceed at the correponding
+fallback level if possible. A warning will be logged
+indicating the fallback reason.
+.PP
+The TLS policy table
+can be used to specify a destination-specific fallback strategy via the
+"fallback" policy attribute. The value of the "fallback" attribute, if
+specified, must be "may", "encrypt" or "none". If not "none", this
+specifies the fallback level for the destination in question. If the
+attribute value is "none", fallback is suppressed for the destination
+even if enabled via a global setting of smtp_tls_fallback_level.
+.PP
+Example:
+.sp
+.in +4
+.nf
+.na
+.ft C
+/etc/postfix/main.cf:
+ # When authentication fails, log a warning and deliver anyway
+ # over an unauthenticated TLS connection.
+ #
+ smtp_tls_fallback_level =
+ dane=encrypt,
+ dane-only=encrypt,
+ fingerprint=encrypt,
+ verify=encrypt,
+ secure=encrypt
+ indexed = ${default_database_type}:${config_directory}/
+ smtp_tls_policy_maps = ${indexed}tls-policy
+.fi
+.ad
+.ft R
+.in -4
+.sp
+.in +4
+.nf
+.na
+.ft C
+/etc/postfix/tls-policy:
+ # No fallback for example.com
+ example.com secure fallback=none
+ # For example.net tolerate cleartext fallback
+ example.net dane fallback=may
+.fi
+.ad
+.ft R
+.in -4
+.PP
+This feature is available in Postfix 2.12 and later.
.SH smtp_tls_fingerprint_cert_match (default: empty)
List of acceptable remote SMTP server certificate fingerprints for
the "fingerprint" TLS security level (\fBsmtp_tls_security_level\fR =
RFC 6698 trust-anchor digest support in the Postfix TLS library.
.IP "\fBtlsmgr_service_name (tlsmgr)\fR"
The name of the \fBtlsmgr\fR(8) service entry in master.cf.
+.PP
+Available in Postfix version 2.12 and later:
+.IP "\fBsmtp_tls_fallback_level (empty)\fR"
+Optional fallback levels for authenticated TLS levels.
.SH "OBSOLETE STARTTLS CONTROLS"
.na
.nf
/* #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
/* .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
* 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
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)
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);
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 */
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);
* 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);
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 {
* 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++)
(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);
VSTRING *line_buffer;
MKMAP *mkmap;
int lineno;
+ int last_line;
VSTRING *key_buffer;
VSTRING *value_buffer;
TOK822 *tok_list;
/*
* 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
VSTREAM *fp;
const char *err;
int entry_count = 0;
- int line_count = 0;
+ int line_count;
+ int last_line = 0;
/*
* Sanity check.
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,
VSTRING *line_buffer;
MKMAP *mkmap;
int lineno;
+ int last_line;
char *key;
char *value;
struct stat st;
/*
* 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
/* 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;
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.
"\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;
*/
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);
/*
/* 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;
char *member;
char *val;
const char *old;
- int old_lineno;
+ int last_line;
int lineno;
const char *err;
struct stat st;
*/
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);
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.
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",
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;
/*
* 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)
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;
/*
* 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)
time_t after;
VSTRING *line_buffer = 0;
int lineno;
+ int last_line;
char *key;
char *value;
HTABLE *table;
}
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
/* 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 `#'.
/* 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.
/* 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.
#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;
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;
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));
}
/*
/*
* 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