If you change a regexp:, pcre:, cidr: or texthash: file
+then Postfix
may not pick up the file changes immediately. This is because a
Postfix process reads the entire file into memory once and never
examines the file again.
diff --git a/postfix/proto/access b/postfix/proto/access
index 403e080d1..12b56a378 100644
--- a/postfix/proto/access
+++ b/postfix/proto/access
@@ -154,6 +154,8 @@
# An all-numerical result is treated as OK. This format is
# generated by address-based relay authorization schemes
# such as pop-before-smtp.
+# .PP
+# For other accept actions, see "OTHER ACTIONS" below.
# REJECT ACTIONS
# .ad
# .fi
@@ -217,6 +219,8 @@
# Prior to Postfix 2.6, the SMTP reply code is 450.
# .sp
# This feature is available in Postfix 2.1 and later.
+# .PP
+# For other reject actions, see "OTHER ACTIONS" below.
# OTHER ACTIONS
# .ad
# .fi
diff --git a/postfix/proto/canonical b/postfix/proto/canonical
index cdda91818..6fb534816 100644
--- a/postfix/proto/canonical
+++ b/postfix/proto/canonical
@@ -63,9 +63,9 @@
# .ad
# .fi
# The input format for the \fBpostmap\fR(1) command is as follows:
-# .IP "\fIpattern result\fR"
+# .IP "\fIpattern address\fR"
# When \fIpattern\fR matches a mail address, replace it by the
-# corresponding \fIresult\fR.
+# corresponding \fIaddress\fR.
# .IP "blank lines and comments"
# Empty lines and whitespace-only lines are ignored, as
# are lines whose first non-whitespace character is a `#'.
diff --git a/postfix/proto/cidr_table b/postfix/proto/cidr_table
index 4a24d0531..0f1706ad1 100644
--- a/postfix/proto/cidr_table
+++ b/postfix/proto/cidr_table
@@ -35,6 +35,9 @@
# separated by ".", and an IPv6 network address is a sequence
# of three to eight hexadecimal octet pairs separated by ":".
#
+# The \fInetwork_mask\fR is the number of high-order bits in
+# the \fInetwork_address\fR that the search string must match.
+#
# Before comparisons are made, lookup keys and table entries
# are converted from string to binary. Therefore table entries
# will be matched regardless of redundant zero characters.
diff --git a/postfix/proto/postconf.proto b/postfix/proto/postconf.proto
index 1359d1b7c..81c09725a 100644
--- a/postfix/proto/postconf.proto
+++ b/postfix/proto/postconf.proto
@@ -1609,7 +1609,9 @@ execution_directory_expansion_filter parameter.
$recipient_delimiter
-The system-wide recipient address extension delimiter.
+The address extension delimiter that was found in the recipient
+address (Postfix 2.11 and later), or the system-wide recipient
+address extension delimiter (Postfix 2.10 and earlier).
${name?value}
@@ -1670,7 +1672,9 @@ forward_expansion_filter parameter.
$recipient_delimiter
-The system-wide recipient address extension delimiter.
+The address extension delimiter that was found in the recipient
+address (Postfix 2.11 and later), or the system-wide recipient
+address extension delimiter (Postfix 2.10 and earlier).
${name?value}
@@ -2404,7 +2408,9 @@ The following $name expansions are done on luser_relay:
$recipient_delimiter
-The system-wide recipient address extension delimiter.
+The address extension delimiter that was found in the recipient
+address (Postfix 2.11 and later), or the system-wide recipient
+address extension delimiter (Postfix 2.10 and earlier).
$shell
@@ -3495,24 +3501,55 @@ Example:
recipient_canonical_maps = hash:/etc/postfix/recipient_canonical
-%PARAM recipient_delimiter
+%PARAM recipient_delimiter
-
-The separator between user names and address extensions (user+foo).
-See canonical(5), local(8), relocated(5) and virtual(5) for the
-effects this has on aliases, canonical, virtual, relocated and
-on .forward file lookups. Basically, the software tries user+foo
-and .forward+foo before trying user and .forward.
+
The set of characters that can separate a user name from its
+address extension (user+foo). See canonical(5), local(8), relocated(5)
+and virtual(5) for the effects this has on aliases, canonical,
+virtual, and relocated lookups. Basically, the software tries
+user+foo and .forward+foo before trying user and .forward.
+
+ This implementation recognizes one delimiter character per email
+address, and one address extension per email address.
+
+ When the recipient_delimiter set contains multiple characters
+(Postfix 2.11 and later), a user name is separated from its address
+extension by the first character that matches the recipient_delimiter
+set.
+
+ When used in forward_path, ${recipient_delimiter} is replaced
+with the recipient delimiter that was found in the recipient email
+address (Postfix 2.11 and later), or it is replaced with the main.cf
+recipient_delimiter parameter value (Postfix 2.10 and earlier).
+ The recipient_delimiter is not applied to the mailer-daemon
+address, the postmaster address, or the double-bounce address. With
+the default "owner_request_special = yes" setting, the recipient_delimiter
+is also not applied to addresses with the special "owner-" prefix
+or the special "-request" suffix.
+
-Example:
+Examples:
-
+
+# Handle Postfix-style extensions.
recipient_delimiter = +
+
+# Handle both Postfix and qmail extensions (Postfix 2.11 and later).
+recipient_delimiters = +-
+
+
+
+# Use .forward for mail without address extension, and for mail with
+# an unrecognized address extension.
+forward_path = $home/.forward${recipient_delimiter}${extension},
+ $home/.forward
+
+
%PARAM reject_code 554
@@ -13816,6 +13853,21 @@ parameter.
This feature is available in Postfix 2.8.
+%PARAM postscreen_dnsbl_whitelist_threshold 0
+
+ Allow a remote SMTP client to skip "before" and "after 220
+greeting" protocol tests, based on its combined DNSBL score as
+defined with the postscreen_dnsbl_sites parameter.
+
+ Specify a negative value to enable this feature. When a client
+passes the postscreen_dnsbl_whitelist_threshold without having
+failed other tests, all pending or disabled tests are flagged as
+completed with a time-to-live value equal to postscreen_dnsbl_ttl.
+When a test was already completed, its time-to-live value is updated
+if it was less than postscreen_dnsbl_ttl.
+
+ This feature is available in Postfix 2.11.
+
%PARAM postscreen_command_count_limit 20
The limit on the total number of commands per SMTP session for
diff --git a/postfix/proto/virtual b/postfix/proto/virtual
index 8a2d28f60..fd98e2d48 100644
--- a/postfix/proto/virtual
+++ b/postfix/proto/virtual
@@ -61,9 +61,9 @@
# .ad
# .fi
# The input format for the \fBpostmap\fR(1) command is as follows:
-# .IP "\fIpattern result\fR"
+# .IP "\fIpattern address, address, ...\fR"
# When \fIpattern\fR matches a mail address, replace it by the
-# corresponding \fIresult\fR.
+# corresponding \fIaddress\fR.
# .IP "blank lines and comments"
# Empty lines and whitespace-only lines are ignored, as
# are lines whose first non-whitespace character is a `#'.
diff --git a/postfix/src/dns/dns_rr.c b/postfix/src/dns/dns_rr.c
index 870a78f75..4ae4eff6e 100644
--- a/postfix/src/dns/dns_rr.c
+++ b/postfix/src/dns/dns_rr.c
@@ -303,10 +303,12 @@ DNS_RR *dns_rr_shuffle(DNS_RR *list)
rr_array[len] = rr;
/*
- * Shuffle resource records.
+ * Shuffle resource records. Every element has an equal chance of landing
+ * in slot 0. After that every remaining element has an equal chance of
+ * landing in slot 1, ... This is exactly n! states for n! permutations.
*/
- for (i = 0; i < len; i++) {
- r = myrand() % len;
+ for (i = 0; i < len - 1; i++) {
+ r = i + (myrand() % (len - i)); /* Victor&Son */
rr = rr_array[i];
rr_array[i] = rr_array[r];
rr_array[r] = rr;
diff --git a/postfix/src/global/mail_addr_find.c b/postfix/src/global/mail_addr_find.c
index ed8caab6d..e21dd3600 100644
--- a/postfix/src/global/mail_addr_find.c
+++ b/postfix/src/global/mail_addr_find.c
@@ -109,7 +109,7 @@ const char *mail_addr_find(MAPS *path, const char *address, char **extp)
if (*var_rcpt_delim == 0) {
bare_key = saved_ext = 0;
} else {
- bare_key = strip_addr(full_key, &saved_ext, *var_rcpt_delim);
+ bare_key = strip_addr(full_key, &saved_ext, var_rcpt_delim);
}
/*
diff --git a/postfix/src/global/mail_params.c b/postfix/src/global/mail_params.c
index 94ea155d7..5bc95c659 100644
--- a/postfix/src/global/mail_params.c
+++ b/postfix/src/global/mail_params.c
@@ -557,7 +557,7 @@ void mail_params_init()
VAR_MAIL_VERSION, DEF_MAIL_VERSION, &var_mail_version, 1, 0,
VAR_DB_TYPE, DEF_DB_TYPE, &var_db_type, 1, 0,
VAR_HASH_QUEUE_NAMES, DEF_HASH_QUEUE_NAMES, &var_hash_queue_names, 1, 0,
- VAR_RCPT_DELIM, DEF_RCPT_DELIM, &var_rcpt_delim, 0, 1,
+ VAR_RCPT_DELIM, DEF_RCPT_DELIM, &var_rcpt_delim, 0, 0,
VAR_RELAY_DOMAINS, DEF_RELAY_DOMAINS, &var_relay_domains, 0, 0,
VAR_FFLUSH_DOMAINS, DEF_FFLUSH_DOMAINS, &var_fflush_domains, 0, 0,
VAR_EXPORT_ENVIRON, DEF_EXPORT_ENVIRON, &var_export_environ, 0, 0,
diff --git a/postfix/src/global/mail_params.h b/postfix/src/global/mail_params.h
index c40702f13..ef78537ba 100644
--- a/postfix/src/global/mail_params.h
+++ b/postfix/src/global/mail_params.h
@@ -3374,6 +3374,10 @@ extern char *var_psc_dnsbl_sites;
#define DEF_PSC_DNSBL_THRESH 1
extern int var_psc_dnsbl_thresh;
+#define VAR_PSC_DNSBL_WTHRESH "postscreen_dnsbl_whitelist_threshold"
+#define DEF_PSC_DNSBL_WTHRESH 0
+extern int var_psc_dnsbl_wthresh;
+
#define VAR_PSC_DNSBL_ENABLE "postscreen_dnsbl_enable"
#define DEF_PSC_DNSBL_ENABLE 0
extern char *var_psc_dnsbl_enable;
diff --git a/postfix/src/global/mail_version.h b/postfix/src/global/mail_version.h
index ed6467d86..c29863155 100644
--- a/postfix/src/global/mail_version.h
+++ b/postfix/src/global/mail_version.h
@@ -20,19 +20,19 @@
* Patches change both the patchlevel and the release date. Snapshots have no
* patchlevel; they change the release date only.
*/
-#define MAIL_RELEASE_DATE "20130518"
+#define MAIL_RELEASE_DATE "20130530"
#define MAIL_VERSION_NUMBER "2.11"
#ifdef SNAPSHOT
-# define MAIL_VERSION_DATE "-" MAIL_RELEASE_DATE
+#define MAIL_VERSION_DATE "-" MAIL_RELEASE_DATE
#else
-# define MAIL_VERSION_DATE ""
+#define MAIL_VERSION_DATE ""
#endif
#ifdef NONPROD
-# define MAIL_VERSION_PROD "-nonprod"
+#define MAIL_VERSION_PROD "-nonprod"
#else
-# define MAIL_VERSION_PROD ""
+#define MAIL_VERSION_PROD ""
#endif
#define VAR_MAIL_VERSION "mail_version"
diff --git a/postfix/src/global/resolve_clnt.c b/postfix/src/global/resolve_clnt.c
index bbd1b9b3a..5b28772c1 100644
--- a/postfix/src/global/resolve_clnt.c
+++ b/postfix/src/global/resolve_clnt.c
@@ -386,8 +386,11 @@ int main(int argc, char **argv)
VSTRING *buffer = vstring_alloc(1);
while (vstring_fgets_nonl(buffer, VSTREAM_IN)) {
- if ((addr = split_at(STR(buffer), ' ')) == 0 || *STR(buffer) == 0)
- msg_fatal("need as input: class address");
+ addr = split_at(STR(buffer), ' ');
+ if (*STR(buffer) == 0)
+ msg_fatal("need as input: class [address]");
+ if (addr == 0)
+ addr = "";
resolve(STR(buffer), addr, &reply);
}
vstring_free(buffer);
diff --git a/postfix/src/global/split_addr.c b/postfix/src/global/split_addr.c
index 279ad4fb6..7e7cc27c8 100644
--- a/postfix/src/global/split_addr.c
+++ b/postfix/src/global/split_addr.c
@@ -6,12 +6,12 @@
/* SYNOPSIS
/* #include
/*
-/* char *split_addr(localpart, delimiter)
+/* char *split_addr(localpart, delimiter_set)
/* char *localpart;
-/* int delimiter;
+/* const char *delimiter_set;
/* DESCRIPTION
/* split_addr() null-terminates \fIlocalpart\fR at the first
-/* occurrence of the \fIdelimiter\fR character found, and
+/* occurrence of the \fIdelimiter\fR character(s) found, and
/* returns a pointer to the remainder.
/*
/* Reserved addresses are not split: postmaster, mailer-daemon,
@@ -50,7 +50,7 @@
/* split_addr - split address with extreme prejudice */
-char *split_addr(char *localpart, int delimiter)
+char *split_addr(char *localpart, const char *delimiter_set)
{
int len;
@@ -67,7 +67,7 @@ char *split_addr(char *localpart, int delimiter)
/*
* Backwards compatibility: don't split owner-foo or foo-request.
*/
- if (delimiter == '-' && var_ownreq_special != 0) {
+ if (strchr(delimiter_set, '-') != 0 && var_ownreq_special != 0) {
if (strncasecmp(localpart, "owner-", 6) == 0)
return (0);
if ((len = strlen(localpart) - 8) > 0
@@ -79,5 +79,10 @@ char *split_addr(char *localpart, int delimiter)
* Safe to split this address. Do not split the address if the result
* would have a null localpart.
*/
- return (delimiter == *localpart ? 0 : split_at(localpart, delimiter));
+ if ((len = strcspn(localpart, delimiter_set)) == 0 || localpart[len] == 0) {
+ return (0);
+ } else {
+ localpart[len] = 0;
+ return (localpart + len + 1);
+ }
}
diff --git a/postfix/src/global/split_addr.h b/postfix/src/global/split_addr.h
index 1c87fb99a..fa89faeae 100644
--- a/postfix/src/global/split_addr.h
+++ b/postfix/src/global/split_addr.h
@@ -13,7 +13,7 @@
/* External interface. */
-extern char *split_addr(char *, int);
+extern char *split_addr(char *, const char *);
/* LICENSE
/* .ad
diff --git a/postfix/src/global/strip_addr.c b/postfix/src/global/strip_addr.c
index 803db87f8..6792d35f3 100644
--- a/postfix/src/global/strip_addr.c
+++ b/postfix/src/global/strip_addr.c
@@ -6,10 +6,10 @@
/* SYNOPSIS
/* #include
/*
-/* char *strip_addr(address, extension, delimiter)
+/* char *strip_addr(address, extension, delimiter_set)
/* const char *address;
/* char **extension;
-/* int delimiter;
+/* const char *delimiter_set;
/* DESCRIPTION
/* strip_addr() takes an address and either returns a null
/* pointer when the address contains no address extension,
@@ -25,8 +25,8 @@
/* that had to be chopped off.
/* The copy includes the recipient address delimiter.
/* The caller is expected to pass the copy to myfree().
-/* .IP delimiter
-/* Recipient address delimiter.
+/* .IP delimiter_set
+/* Set of recipient address delimiter characters.
/* SEE ALSO
/* split_addr(3) strip extension from localpart
/* LICENSE
@@ -56,7 +56,7 @@
/* strip_addr - strip extension from address */
-char *strip_addr(const char *full, char **extension, int delimiter)
+char *strip_addr(const char *full, char **extension, const char *delimiter_set)
{
char *ratsign;
char *extent;
@@ -66,16 +66,16 @@ char *strip_addr(const char *full, char **extension, int delimiter)
/*
* A quick test to eliminate inputs without delimiter anywhere.
*/
- if (delimiter == 0 || strchr(full, delimiter) == 0) {
+ if (*delimiter_set == 0 || full[strcspn(full, delimiter_set)] == 0) {
stripped = saved_ext = 0;
} else {
stripped = mystrdup(full);
if ((ratsign = strrchr(stripped, '@')) != 0)
*ratsign = 0;
- if ((extent = split_addr(stripped, delimiter)) != 0) {
+ if ((extent = split_addr(stripped, delimiter_set)) != 0) {
extent -= 1;
if (extension) {
- *extent = delimiter;
+ *extent = full[strlen(stripped)];
saved_ext = mystrdup(extent);
*extent = 0;
} else
@@ -105,17 +105,19 @@ int main(int unused_argc, char **unused_argv)
{
char *extension;
char *stripped;
- int delim = '-';
+ char* delim = "+-";
+
+#define NO_DELIM ""
/*
* Incredible. This function takes only three arguments, and the tests
* already take more lines of code than the code being tested.
*/
- stripped = strip_addr("foo", (char **) 0, 0);
+ stripped = strip_addr("foo", (char **) 0, NO_DELIM);
if (stripped != 0)
msg_panic("strip_addr botch 1");
- stripped = strip_addr("foo", &extension, 0);
+ stripped = strip_addr("foo", &extension, NO_DELIM);
if (stripped != 0)
msg_panic("strip_addr botch 2");
if (extension != 0)
@@ -131,11 +133,11 @@ int main(int unused_argc, char **unused_argv)
if (extension != 0)
msg_panic("strip_addr botch 6");
- stripped = strip_addr("foo@bar", (char **) 0, 0);
+ stripped = strip_addr("foo@bar", (char **) 0, NO_DELIM);
if (stripped != 0)
msg_panic("strip_addr botch 7");
- stripped = strip_addr("foo@bar", &extension, 0);
+ stripped = strip_addr("foo@bar", &extension, NO_DELIM);
if (stripped != 0)
msg_panic("strip_addr botch 8");
if (extension != 0)
@@ -151,11 +153,11 @@ int main(int unused_argc, char **unused_argv)
if (extension != 0)
msg_panic("strip_addr botch 12");
- stripped = strip_addr("foo-ext", (char **) 0, 0);
+ stripped = strip_addr("foo-ext", (char **) 0, NO_DELIM);
if (stripped != 0)
msg_panic("strip_addr botch 13");
- stripped = strip_addr("foo-ext", &extension, 0);
+ stripped = strip_addr("foo-ext", &extension, NO_DELIM);
if (stripped != 0)
msg_panic("strip_addr botch 14");
if (extension != 0)
@@ -178,11 +180,11 @@ int main(int unused_argc, char **unused_argv)
myfree(stripped);
myfree(extension);
- stripped = strip_addr("foo-ext@bar", (char **) 0, 0);
+ stripped = strip_addr("foo-ext@bar", (char **) 0, NO_DELIM);
if (stripped != 0)
msg_panic("strip_addr botch 19");
- stripped = strip_addr("foo-ext@bar", &extension, 0);
+ stripped = strip_addr("foo-ext@bar", &extension, NO_DELIM);
if (stripped != 0)
msg_panic("strip_addr botch 20");
if (extension != 0)
@@ -205,6 +207,16 @@ int main(int unused_argc, char **unused_argv)
myfree(stripped);
myfree(extension);
+ stripped = strip_addr("foo+ext@bar", &extension, delim);
+ if (stripped == 0)
+ msg_panic("strip_addr botch 25");
+ if (extension == 0)
+ msg_panic("strip_addr botch 26");
+ msg_info("wanted: foo+ext@bar -> %s %s", "foo@bar", "+ext");
+ msg_info("strip_addr foo+ext@bar -> %s %s", stripped, extension);
+ myfree(stripped);
+ myfree(extension);
+
return (0);
}
diff --git a/postfix/src/global/strip_addr.h b/postfix/src/global/strip_addr.h
index e99c6fdf8..19530e1ba 100644
--- a/postfix/src/global/strip_addr.h
+++ b/postfix/src/global/strip_addr.h
@@ -13,7 +13,7 @@
/* External interface. */
-extern char *strip_addr(const char *, char **, int);
+extern char *strip_addr(const char *, char **, const char *);
/* LICENSE
/* .ad
diff --git a/postfix/src/global/strip_addr.ref b/postfix/src/global/strip_addr.ref
index 3068918ca..af218e5c0 100644
--- a/postfix/src/global/strip_addr.ref
+++ b/postfix/src/global/strip_addr.ref
@@ -6,3 +6,5 @@ unknown: wanted: foo-ext@bar -> foo@bar
unknown: strip_addr foo-ext@bar -> foo@bar
unknown: wanted: foo-ext@bar -> foo@bar -ext
unknown: strip_addr foo-ext@bar -> foo@bar -ext
+unknown: wanted: foo+ext@bar -> foo@bar +ext
+unknown: strip_addr foo+ext@bar -> foo@bar +ext
diff --git a/postfix/src/local/bounce_workaround.c b/postfix/src/local/bounce_workaround.c
index 8d1670c80..e7211ec55 100644
--- a/postfix/src/local/bounce_workaround.c
+++ b/postfix/src/local/bounce_workaround.c
@@ -109,7 +109,7 @@ int bounce_workaround(LOCAL_STATE state)
if (alias_maps->error == 0 && owner_expansion == 0
&& (stripped_recipient = strip_addr(state.msg_attr.rcpt.address,
(char **) 0,
- *var_rcpt_delim)) != 0) {
+ var_rcpt_delim)) != 0) {
myfree(owner_alias);
FIND_OWNER(owner_alias, owner_expansion, stripped_recipient);
myfree(stripped_recipient);
diff --git a/postfix/src/local/forward.c b/postfix/src/local/forward.c
index 6ebe74f18..fb7da4f2e 100644
--- a/postfix/src/local/forward.c
+++ b/postfix/src/local/forward.c
@@ -118,6 +118,11 @@ static FORWARD_INFO *forward_open(DELIVER_REQUEST *request, const char *sender)
FORWARD_INFO *info;
VSTREAM *cleanup;
+#define FORWARD_OPEN_RETURN(res) do { \
+ vstring_free(buffer); \
+ return (res); \
+ } while (0)
+
/*
* Contact the cleanup service and save the new mail queue id. Request
* that the cleanup service bounces bad messages to the sender so that we
@@ -129,13 +134,13 @@ static FORWARD_INFO *forward_open(DELIVER_REQUEST *request, const char *sender)
*/
cleanup = mail_connect(MAIL_CLASS_PUBLIC, var_cleanup_service, BLOCKING);
if (cleanup == 0)
- return (0);
+ FORWARD_OPEN_RETURN(0);
close_on_exec(vstream_fileno(cleanup), CLOSE_ON_EXEC);
if (attr_scan(cleanup, ATTR_FLAG_STRICT,
ATTR_TYPE_STR, MAIL_ATTR_QUEUEID, buffer,
ATTR_TYPE_END) != 1) {
vstream_fclose(cleanup);
- return (0);
+ FORWARD_OPEN_RETURN(0);
}
info = (FORWARD_INFO *) mymalloc(sizeof(FORWARD_INFO));
info->cleanup = cleanup;
@@ -190,8 +195,7 @@ static FORWARD_INFO *forward_open(DELIVER_REQUEST *request, const char *sender)
PASS_ATTR(cleanup, MAIL_ATTR_LOG_IDENT, request->log_ident);
PASS_ATTR(cleanup, MAIL_ATTR_RWR_CONTEXT, request->rewrite_context);
- vstring_free(buffer);
- return (info);
+ FORWARD_OPEN_RETURN(info);
}
/* forward_append - append recipient to message envelope */
diff --git a/postfix/src/local/local.c b/postfix/src/local/local.c
index cec231263..32da88bca 100644
--- a/postfix/src/local/local.c
+++ b/postfix/src/local/local.c
@@ -531,7 +531,8 @@
/* .IP "\fBqueue_directory (see 'postconf -d' output)\fR"
/* The location of the Postfix top-level queue directory.
/* .IP "\fBrecipient_delimiter (empty)\fR"
-/* The separator between user names and address extensions (user+foo).
+/* The set of characters that can separate a user name from its
+/* address extension (user+foo).
/* .IP "\fBrequire_home_directory (no)\fR"
/* Require that a \fBlocal\fR(8) recipient's home directory exists
/* before mail delivery is attempted.
diff --git a/postfix/src/local/local_expand.c b/postfix/src/local/local_expand.c
index db5121ee8..612e68094 100644
--- a/postfix/src/local/local_expand.c
+++ b/postfix/src/local/local_expand.c
@@ -113,6 +113,7 @@ typedef struct {
static const char *local_expand_lookup(const char *name, int mode, char *ptr)
{
LOCAL_EXP *local = (LOCAL_EXP *) ptr;
+ static char rcpt_delim[2];
#define STREQ(x,y) (*(x) == *(y) && strcmp((x), (y)) == 0)
@@ -135,7 +136,10 @@ static const char *local_expand_lookup(const char *name, int mode, char *ptr)
local->status |= LOCAL_EXP_EXTENSION_MATCHED;
return (local->state->msg_attr.extension);
} else if (STREQ(name, "recipient_delimiter")) {
- return (*var_rcpt_delim ? var_rcpt_delim : 0);
+ rcpt_delim[0] =
+ local->state->msg_attr.local[strlen(local->state->msg_attr.user)];
+ rcpt_delim[1] = 0;
+ return (rcpt_delim[0] ? rcpt_delim : 0);
#if 0
} else if (STREQ(name, "client_hostname")) {
return (local->state->msg_attr.request->client_name);
diff --git a/postfix/src/local/recipient.c b/postfix/src/local/recipient.c
index 192144493..8017942e5 100644
--- a/postfix/src/local/recipient.c
+++ b/postfix/src/local/recipient.c
@@ -270,7 +270,7 @@ int deliver_recipient(LOCAL_STATE state, USER_ATTR usr_attr)
state.msg_attr.user = mystrdup(state.msg_attr.local);
if (*var_rcpt_delim) {
state.msg_attr.extension =
- split_addr(state.msg_attr.user, *var_rcpt_delim);
+ split_addr(state.msg_attr.user, var_rcpt_delim);
if (state.msg_attr.extension && strchr(state.msg_attr.extension, '/')) {
msg_warn("%s: address with illegal extension: %s",
state.msg_attr.queue_id, state.msg_attr.local);
diff --git a/postfix/src/local/resolve.c b/postfix/src/local/resolve.c
index 89c330325..a6aa9d035 100644
--- a/postfix/src/local/resolve.c
+++ b/postfix/src/local/resolve.c
@@ -90,6 +90,7 @@ int deliver_resolve_tree(LOCAL_STATE state, USER_ATTR usr_attr, TOK822 *addr
int status;
ssize_t ext_len;
char *ratsign;
+ int rcpt_delim;
/*
* Make verbose logging easier to understand.
@@ -130,8 +131,9 @@ int deliver_resolve_tree(LOCAL_STATE state, USER_ATTR usr_attr, TOK822 *addr
* Splice in the optional unmatched address extension.
*/
if (state.msg_attr.unmatched) {
+ rcpt_delim = state.msg_attr.local[strlen(state.msg_attr.user)];
if ((ratsign = strrchr(STR(reply.recipient), '@')) == 0) {
- VSTRING_ADDCH(reply.recipient, *var_rcpt_delim);
+ VSTRING_ADDCH(reply.recipient, rcpt_delim);
vstring_strcat(reply.recipient, state.msg_attr.unmatched);
} else {
ext_len = strlen(state.msg_attr.unmatched);
@@ -139,7 +141,7 @@ int deliver_resolve_tree(LOCAL_STATE state, USER_ATTR usr_attr, TOK822 *addr
if ((ratsign = strrchr(STR(reply.recipient), '@')) == 0)
msg_panic("%s: recipient @ botch", myname);
memmove(ratsign + ext_len + 1, ratsign, strlen(ratsign) + 1);
- *ratsign = *var_rcpt_delim;
+ *ratsign = rcpt_delim;
memcpy(ratsign + 1, state.msg_attr.unmatched, ext_len);
VSTRING_SKIP(reply.recipient);
}
diff --git a/postfix/src/oqmgr/qmgr_message.c b/postfix/src/oqmgr/qmgr_message.c
index 71955d4f3..e2f923741 100644
--- a/postfix/src/oqmgr/qmgr_message.c
+++ b/postfix/src/oqmgr/qmgr_message.c
@@ -1175,7 +1175,7 @@ static void qmgr_message_resolve(QMGR_MESSAGE *message)
: strlen(STR(reply.recipient)));
vstring_strncpy(queue_name, STR(reply.recipient), len);
/* Remove the address extension from the recipient localpart. */
- if (*var_rcpt_delim && split_addr(STR(queue_name), *var_rcpt_delim))
+ if (*var_rcpt_delim && split_addr(STR(queue_name), var_rcpt_delim))
vstring_truncate(queue_name, strlen(STR(queue_name)));
/* Assume the recipient domain is equivalent to nexthop. */
vstring_sprintf_append(queue_name, "@%s", STR(reply.nexthop));
diff --git a/postfix/src/pipe/pipe.c b/postfix/src/pipe/pipe.c
index 73e9978bb..b6329f02f 100644
--- a/postfix/src/pipe/pipe.c
+++ b/postfix/src/pipe/pipe.c
@@ -390,7 +390,8 @@
/* .IP "\fBqueue_directory (see 'postconf -d' output)\fR"
/* The location of the Postfix top-level queue directory.
/* .IP "\fBrecipient_delimiter (empty)\fR"
-/* The separator between user names and address extensions (user+foo).
+/* The set of characters that can separate a user name from its
+/* address extension (user+foo).
/* .IP "\fBsyslog_facility (mail)\fR"
/* The syslog facility of Postfix logging.
/* .IP "\fBsyslog_name (see 'postconf -d' output)\fR"
@@ -717,7 +718,7 @@ static ARGV *expand_argv(const char *service, char **argv,
msg_warn("no @ in recipient address: %s",
rcpt_list->info[i].address);
if (*var_rcpt_delim)
- split_addr(STR(buf), *var_rcpt_delim);
+ split_addr(STR(buf), var_rcpt_delim);
if (*STR(buf) == 0)
continue;
dict_update(PIPE_DICT_TABLE, PIPE_DICT_USER, STR(buf));
@@ -735,7 +736,7 @@ static ARGV *expand_argv(const char *service, char **argv,
msg_warn("no @ in recipient address: %s",
rcpt_list->info[i].address);
if (*var_rcpt_delim == 0
- || (ext = split_addr(STR(buf), *var_rcpt_delim)) == 0)
+ || (ext = split_addr(STR(buf), var_rcpt_delim)) == 0)
ext = ""; /* insert null arg */
dict_update(PIPE_DICT_TABLE, PIPE_DICT_EXTENSION, ext);
}
diff --git a/postfix/src/postscreen/Makefile.in b/postfix/src/postscreen/Makefile.in
index 4d2f8265a..9c29a3d55 100644
--- a/postfix/src/postscreen/Makefile.in
+++ b/postfix/src/postscreen/Makefile.in
@@ -385,6 +385,7 @@ postscreen_tests.o: ../../include/match_list.h
postscreen_tests.o: ../../include/msg.h
postscreen_tests.o: ../../include/myaddrinfo.h
postscreen_tests.o: ../../include/myflock.h
+postscreen_tests.o: ../../include/name_code.h
postscreen_tests.o: ../../include/server_acl.h
postscreen_tests.o: ../../include/string_list.h
postscreen_tests.o: ../../include/sys_defs.h
diff --git a/postfix/src/postscreen/postscreen.c b/postfix/src/postscreen/postscreen.c
index 0149b59ad..deff9abfa 100644
--- a/postfix/src/postscreen/postscreen.c
+++ b/postfix/src/postscreen/postscreen.c
@@ -214,6 +214,12 @@
/* .IP "\fBsmtpd_service_name (smtpd)\fR"
/* The internal service that \fBpostscreen\fR(8) hands off allowed
/* connections to.
+/* .PP
+/* Available in Postfix version 2.11 and later:
+/* .IP "\fBpostscreen_dnsbl_whitelist_threshold (0)\fR"
+/* Allow a remote SMTP client to skip "before" and "after 220
+/* greeting" protocol tests, based on its combined DNSBL score as
+/* defined with the postscreen_dnsbl_sites parameter.
/* AFTER-GREETING TESTS
/* .ad
/* .fi
@@ -465,6 +471,7 @@ int var_psc_pregr_ttl;
char *var_psc_dnsbl_sites;
char *var_psc_dnsbl_reply;
int var_psc_dnsbl_thresh;
+int var_psc_dnsbl_wthresh;
char *var_psc_dnsbl_action;
int var_psc_dnsbl_ttl;
@@ -1095,6 +1102,7 @@ int main(int argc, char **argv)
static const CONFIG_INT_TABLE int_table[] = {
VAR_PROC_LIMIT, DEF_PROC_LIMIT, &var_proc_limit, 1, 0,
VAR_PSC_DNSBL_THRESH, DEF_PSC_DNSBL_THRESH, &var_psc_dnsbl_thresh, 0, 0,
+ VAR_PSC_DNSBL_WTHRESH, DEF_PSC_DNSBL_WTHRESH, &var_psc_dnsbl_wthresh, 0, 0,
VAR_PSC_CMD_COUNT, DEF_PSC_CMD_COUNT, &var_psc_cmd_count, 1, 0,
VAR_SMTPD_CCONN_LIMIT, DEF_SMTPD_CCONN_LIMIT, &var_smtpd_cconn_limit, 0, 0,
0,
diff --git a/postfix/src/postscreen/postscreen.h b/postfix/src/postscreen/postscreen.h
index 3fe0a9b6b..ebc048a02 100644
--- a/postfix/src/postscreen/postscreen.h
+++ b/postfix/src/postscreen/postscreen.h
@@ -35,6 +35,25 @@
*/
#define PSC_READ_BUF_SIZE 1024
+ /*
+ * Numeric indices and symbolic names for tests whose time stamps and status
+ * flags can be accessed by numeric index.
+ */
+#define PSC_TINDX_PREGR 0 /* pregreet */
+#define PSC_TINDX_DNSBL 1 /* dnsbl */
+#define PSC_TINDX_PIPEL 2 /* pipelining */
+#define PSC_TINDX_NSMTP 3 /* non-smtp command */
+#define PSC_TINDX_BARLF 4 /* bare newline */
+#define PSC_TINDX_COUNT 5 /* number of tests */
+
+#define PSC_TNAME_PREGR "pregreet"
+#define PSC_TNAME_DNSBL "dnsbl"
+#define PSC_TNAME_PIPEL "pipelining"
+#define PSC_TNAME_NSMTP "non-smtp command"
+#define PSC_TNAME_BARLF "bare newline"
+
+#define PSC_TINDX_BYTNAME(tname) (PSC_TINDX_ ## tname)
+
/*
* Per-session state.
*/
@@ -53,16 +72,11 @@ typedef struct {
/* Test context. */
struct timeval start_time; /* start of current test */
const char *test_name; /* name of current test */
- /* Before-handshake tests. */
- time_t pregr_stamp; /* pregreet expiration time */
- time_t dnsbl_stamp; /* dnsbl expiration time */
+ time_t expire_time[PSC_TINDX_COUNT]; /* per-test expiration */
VSTRING *dnsbl_reply; /* dnsbl reject text */
+ int dnsbl_score; /* saved DNSBL score */
+ const char *dnsbl_name; /* DNSBL name with largest weight */
int dnsbl_index; /* dnsbl request index */
- time_t penal_stamp; /* penalty expiration time */
- /* Built-in SMTP protocol engine. */
- time_t pipel_stamp; /* pipelining expiration time */
- time_t nsmtp_stamp; /* non-smtp command expiration time */
- time_t barlf_stamp; /* bare newline expiration time */
const char *rcpt_reply; /* how to reject recipients */
int command_count; /* error + junk command count */
const char *protocol; /* SMTP or ESMTP */
@@ -76,10 +90,26 @@ typedef struct {
const char *where; /* SMTP protocol state */
} PSC_STATE;
+ /*
+ * Emulate legacy ad-hoc variables on top of indexable time stamps. This
+ * avoids massive scar tissue during initial feature development.
+ */
+#define pregr_stamp expire_time[PSC_TINDX_PREGR]
+#define dnsbl_stamp expire_time[PSC_TINDX_DNSBL]
+#define pipel_stamp expire_time[PSC_TINDX_PIPEL]
+#define nsmtp_stamp expire_time[PSC_TINDX_NSMTP]
+#define barlf_stamp expire_time[PSC_TINDX_BARLF]
+
+ /*
+ * Special expiration time values.
+ */
#define PSC_TIME_STAMP_NEW (0) /* test was never passed */
#define PSC_TIME_STAMP_DISABLED (1) /* never passed but disabled */
#define PSC_TIME_STAMP_INVALID (-1) /* must not be cached */
+ /*
+ * Status flags.
+ */
#define PSC_STATE_FLAG_NOFORWARD (1<<0) /* don't forward this session */
#define PSC_STATE_FLAG_USING_TLS (1<<1) /* using the TLS proxy */
#define PSC_STATE_FLAG_UNUSED2 (1<<2) /* use me! */
@@ -88,8 +118,11 @@ typedef struct {
#define PSC_STATE_FLAG_HANGUP (1<<5) /* NOT a test failure */
#define PSC_STATE_FLAG_SMTPD_X21 (1<<6) /* hang up after command */
#define PSC_STATE_FLAG_WLIST_FAIL (1<<7) /* do not whitelist */
+#define PSC_STATE_FLAG_TEST_BASE (8) /* start of indexable flags */
/*
+ * Tests whose flags and expiration time can be accessed by numerical index.
+ *
* Important: every MUMBLE_TODO flag must have a MUMBLE_PASS flag, such that
* MUMBLE_PASS == PSC_STATE_FLAGS_TODO_TO_PASS(MUMBLE_TODO).
*
@@ -107,39 +140,74 @@ typedef struct {
* the result was ignored. MUMBLE_FAIL, on the other hand, is always final.
* We use MUMBLE_SKIP to indicate that a decision was either "fail" or
* forced "pass".
+ *
+ * The difference between DONE and SKIP is in the beholder's eye. These flags
+ * share the same bit.
*/
#define PSC_STATE_FLAGS_TODO_TO_PASS(todo_flags) ((todo_flags) >> 1)
#define PSC_STATE_FLAGS_TODO_TO_DONE(todo_flags) ((todo_flags) << 1)
-#define PSC_STATE_FLAG_PENAL_UPDATE (1<<6) /* save new penalty */
-#define PSC_STATE_FLAG_PENAL_FAIL (1<<7) /* penalty is active */
-
-#define PSC_STATE_FLAG_PREGR_FAIL (1<<8) /* failed pregreet test */
-#define PSC_STATE_FLAG_PREGR_PASS (1<<9) /* passed pregreet test */
-#define PSC_STATE_FLAG_PREGR_TODO (1<<10) /* pregreet test expired */
-#define PSC_STATE_FLAG_PREGR_DONE (1<<11) /* decision is final */
-
-#define PSC_STATE_FLAG_DNSBL_FAIL (1<<12) /* failed DNSBL test */
-#define PSC_STATE_FLAG_DNSBL_PASS (1<<13) /* passed DNSBL test */
-#define PSC_STATE_FLAG_DNSBL_TODO (1<<14) /* DNSBL test expired */
-#define PSC_STATE_FLAG_DNSBL_DONE (1<<15) /* decision is final */
-
- /* Room here for one more after-handshake test. */
+#define PSC_STATE_FLAG_SHIFT_FAIL (0) /* failed test */
+#define PSC_STATE_FLAG_SHIFT_PASS (1) /* passed test */
+#define PSC_STATE_FLAG_SHIFT_TODO (2) /* expired test */
+#define PSC_STATE_FLAG_SHIFT_DONE (3) /* decision is final */
+#define PSC_STATE_FLAG_SHIFT_SKIP (3) /* action is already logged */
+#define PSC_STATE_FLAG_SHIFT_STRIDE (4) /* nr of flags per test */
-#define PSC_STATE_FLAG_PIPEL_FAIL (1<<20) /* failed pipelining test */
-#define PSC_STATE_FLAG_PIPEL_PASS (1<<21) /* passed pipelining test */
-#define PSC_STATE_FLAG_PIPEL_TODO (1<<22) /* pipelining test expired */
-#define PSC_STATE_FLAG_PIPEL_SKIP (1<<23) /* action is already logged */
+#define PSC_STATE_FLAG_SHIFT_BYFNAME(fname) (PSC_STATE_FLAG_SHIFT_ ## fname)
-#define PSC_STATE_FLAG_NSMTP_FAIL (1<<24) /* failed non-SMTP test */
-#define PSC_STATE_FLAG_NSMTP_PASS (1<<25) /* passed non-SMTP test */
-#define PSC_STATE_FLAG_NSMTP_TODO (1<<26) /* non-SMTP test expired */
-#define PSC_STATE_FLAG_NSMTP_SKIP (1<<27) /* action is already logged */
+ /*
+ * Indexable per-test flags. These are used for DNS whitelisting multiple
+ * tests, without needing per-test ad-hoc code.
+ */
+#define PSC_STATE_FLAG_BYTINDX_FNAME(tindx, fname) \
+ (1U << (PSC_STATE_FLAG_TEST_BASE \
+ + PSC_STATE_FLAG_SHIFT_STRIDE * (tindx) \
+ + PSC_STATE_FLAG_SHIFT_BYFNAME(fname)))
+
+#define PSC_STATE_FLAG_BYTINDX_FAIL(tindx) \
+ PSC_STATE_FLAG_BYTINDX_FNAME((tindx), FAIL)
+#define PSC_STATE_FLAG_BYTINDX_PASS(tindx) \
+ PSC_STATE_FLAG_BYTINDX_FNAME((tindx), PASS)
+#define PSC_STATE_FLAG_BYTINDX_TODO(tindx) \
+ PSC_STATE_FLAG_BYTINDX_FNAME((tindx), TODO)
+#define PSC_STATE_FLAG_BYTINDX_DONE(tindx) \
+ PSC_STATE_FLAG_BYTINDX_FNAME((tindx), DONE)
+#define PSC_STATE_FLAG_BYTINDX_SKIP(tindx) \
+ PSC_STATE_FLAG_BYTINDX_FNAME((tindx), SKIP)
-#define PSC_STATE_FLAG_BARLF_FAIL (1<<28) /* failed bare newline test */
-#define PSC_STATE_FLAG_BARLF_PASS (1<<29) /* passed bare newline test */
-#define PSC_STATE_FLAG_BARLF_TODO (1<<30) /* bare newline test expired */
-#define PSC_STATE_FLAG_BARLF_SKIP (1<<31) /* action is already logged */
+ /*
+ * Flags with distinct names. These are used in the per-test ad-hoc code.
+ */
+#define PSC_STATE_FLAG_BYTNAME_FNAME(tname, fname) \
+ (1U << (PSC_STATE_FLAG_TEST_BASE \
+ + PSC_STATE_FLAG_SHIFT_STRIDE * PSC_TINDX_BYTNAME(tname) \
+ + PSC_STATE_FLAG_SHIFT_BYFNAME(fname)))
+
+#define PSC_STATE_FLAG_PREGR_FAIL PSC_STATE_FLAG_BYTNAME_FNAME(PREGR, FAIL)
+#define PSC_STATE_FLAG_PREGR_PASS PSC_STATE_FLAG_BYTNAME_FNAME(PREGR, PASS)
+#define PSC_STATE_FLAG_PREGR_TODO PSC_STATE_FLAG_BYTNAME_FNAME(PREGR, TODO)
+#define PSC_STATE_FLAG_PREGR_DONE PSC_STATE_FLAG_BYTNAME_FNAME(PREGR, DONE)
+
+#define PSC_STATE_FLAG_DNSBL_FAIL PSC_STATE_FLAG_BYTNAME_FNAME(DNSBL, FAIL)
+#define PSC_STATE_FLAG_DNSBL_PASS PSC_STATE_FLAG_BYTNAME_FNAME(DNSBL, PASS)
+#define PSC_STATE_FLAG_DNSBL_TODO PSC_STATE_FLAG_BYTNAME_FNAME(DNSBL, TODO)
+#define PSC_STATE_FLAG_DNSBL_DONE PSC_STATE_FLAG_BYTNAME_FNAME(DNSBL, DONE)
+
+#define PSC_STATE_FLAG_PIPEL_FAIL PSC_STATE_FLAG_BYTNAME_FNAME(PIPEL, FAIL)
+#define PSC_STATE_FLAG_PIPEL_PASS PSC_STATE_FLAG_BYTNAME_FNAME(PIPEL, PASS)
+#define PSC_STATE_FLAG_PIPEL_TODO PSC_STATE_FLAG_BYTNAME_FNAME(PIPEL, TODO)
+#define PSC_STATE_FLAG_PIPEL_SKIP PSC_STATE_FLAG_BYTNAME_FNAME(PIPEL, SKIP)
+
+#define PSC_STATE_FLAG_NSMTP_FAIL PSC_STATE_FLAG_BYTNAME_FNAME(NSMTP, FAIL)
+#define PSC_STATE_FLAG_NSMTP_PASS PSC_STATE_FLAG_BYTNAME_FNAME(NSMTP, PASS)
+#define PSC_STATE_FLAG_NSMTP_TODO PSC_STATE_FLAG_BYTNAME_FNAME(NSMTP, TODO)
+#define PSC_STATE_FLAG_NSMTP_SKIP PSC_STATE_FLAG_BYTNAME_FNAME(NSMTP, SKIP)
+
+#define PSC_STATE_FLAG_BARLF_FAIL PSC_STATE_FLAG_BYTNAME_FNAME(BARLF, FAIL)
+#define PSC_STATE_FLAG_BARLF_PASS PSC_STATE_FLAG_BYTNAME_FNAME(BARLF, PASS)
+#define PSC_STATE_FLAG_BARLF_TODO PSC_STATE_FLAG_BYTNAME_FNAME(BARLF, TODO)
+#define PSC_STATE_FLAG_BARLF_SKIP PSC_STATE_FLAG_BYTNAME_FNAME(BARLF, SKIP)
/*
* Aggregates for individual tests.
@@ -155,6 +223,8 @@ typedef struct {
#define PSC_STATE_MASK_BARLF_TODO_FAIL \
(PSC_STATE_FLAG_BARLF_TODO | PSC_STATE_FLAG_BARLF_FAIL)
+#define PSC_STATE_MASK_PREGR_TODO_DONE \
+ (PSC_STATE_FLAG_PREGR_TODO | PSC_STATE_FLAG_PREGR_DONE)
#define PSC_STATE_MASK_PIPEL_TODO_SKIP \
(PSC_STATE_FLAG_PIPEL_TODO | PSC_STATE_FLAG_PIPEL_SKIP)
#define PSC_STATE_MASK_NSMTP_TODO_SKIP \
@@ -162,6 +232,9 @@ typedef struct {
#define PSC_STATE_MASK_BARLF_TODO_SKIP \
(PSC_STATE_FLAG_BARLF_TODO | PSC_STATE_FLAG_BARLF_SKIP)
+#define PSC_STATE_MASK_PREGR_FAIL_DONE \
+ (PSC_STATE_FLAG_PREGR_FAIL | PSC_STATE_FLAG_PREGR_DONE)
+
#define PSC_STATE_MASK_PIPEL_TODO_PASS_FAIL \
(PSC_STATE_MASK_PIPEL_TODO_FAIL | PSC_STATE_FLAG_PIPEL_PASS)
#define PSC_STATE_MASK_NSMTP_TODO_PASS_FAIL \
@@ -195,7 +268,7 @@ typedef struct {
* Super-aggregates for all tests combined.
*/
#define PSC_STATE_MASK_ANY_FAIL \
- (PSC_STATE_FLAG_BLIST_FAIL | PSC_STATE_FLAG_PENAL_FAIL | \
+ (PSC_STATE_FLAG_BLIST_FAIL | \
PSC_STATE_MASK_EARLY_FAIL | PSC_STATE_MASK_SMTPD_FAIL | \
PSC_STATE_FLAG_WLIST_FAIL)
@@ -209,7 +282,7 @@ typedef struct {
(PSC_STATE_MASK_ANY_TODO | PSC_STATE_MASK_ANY_FAIL)
#define PSC_STATE_MASK_ANY_UPDATE \
- (PSC_STATE_MASK_ANY_PASS | PSC_STATE_FLAG_PENAL_UPDATE)
+ (PSC_STATE_MASK_ANY_PASS)
/*
* Meta-commands for state->where that reflect the initial command processor
@@ -414,12 +487,12 @@ extern int psc_dnsbl_request(const char *, void (*) (int, char *), char *);
* postscreen_tests.c
*/
#define PSC_INIT_TESTS(dst) do { \
+ time_t *_it_stamp_p; \
(dst)->flags = 0; \
- (dst)->pregr_stamp = PSC_TIME_STAMP_INVALID; \
- (dst)->dnsbl_stamp = PSC_TIME_STAMP_INVALID; \
- (dst)->pipel_stamp = PSC_TIME_STAMP_INVALID; \
- (dst)->barlf_stamp = PSC_TIME_STAMP_INVALID; \
- (dst)->penal_stamp = PSC_TIME_STAMP_INVALID; \
+ for (_it_stamp_p = (dst)->expire_time; \
+ _it_stamp_p < (dst)->expire_time + PSC_TINDX_COUNT; \
+ _it_stamp_p++) \
+ *_it_stamp_p = PSC_TIME_STAMP_INVALID; \
} while (0)
#define PSC_BEGIN_TESTS(state, name) do { \
(state)->test_name = (name); \
@@ -430,6 +503,7 @@ extern void psc_parse_tests(PSC_STATE *, const char *, time_t);
extern char *psc_print_tests(VSTRING *, PSC_STATE *);
extern char *psc_print_grey_key(VSTRING *, const char *, const char *,
const char *, const char *);
+extern const char *psc_test_name(int);
#define PSC_MIN(x, y) ((x) < (y) ? (x) : (y))
#define PSC_MAX(x, y) ((x) > (y) ? (x) : (y))
diff --git a/postfix/src/postscreen/postscreen_early.c b/postfix/src/postscreen/postscreen_early.c
index cd77f5afd..a540703d9 100644
--- a/postfix/src/postscreen/postscreen_early.c
+++ b/postfix/src/postscreen/postscreen_early.c
@@ -31,6 +31,7 @@
#include
#include
+#include
/* Utility library. */
@@ -50,6 +51,48 @@
static char *psc_teaser_greeting;
static VSTRING *psc_escape_buf;
+/* psc_whitelist_non_dnsbl - whitelist pending non-dnsbl tests */
+
+static void psc_whitelist_non_dnsbl(PSC_STATE *state)
+{
+ time_t now;
+ int tindx;
+
+ /*
+ * If no tests failed (we can't undo those), and if the whitelist
+ * threshold is met, flag non-dnsbl tests that are pending or disabled as
+ * successfully completed, and set their expiration times equal to the
+ * DNSBL expiration time, except for tests that would expire later.
+ *
+ * Why flag disabled tests as passed? When a disabled test is turned on,
+ * postscreen should not apply that test to clients that are already
+ * whitelisted based on their combined DNSBL score.
+ */
+ if ((state->flags & PSC_STATE_MASK_ANY_FAIL) == 0
+ && state->dnsbl_score < var_psc_dnsbl_thresh
+ && var_psc_dnsbl_wthresh < 0
+ && state->dnsbl_score <= var_psc_dnsbl_wthresh) {
+ now = event_time();
+ for (tindx = 0; tindx < PSC_TINDX_COUNT; tindx++) {
+ if (tindx == PSC_TINDX_DNSBL)
+ continue;
+ if ((state->flags & PSC_STATE_FLAG_BYTINDX_TODO(tindx))
+ && !(state->flags & PSC_STATE_FLAG_BYTINDX_PASS(tindx))) {
+ if (msg_verbose)
+ msg_info("skip %s test for [%s]:%s",
+ psc_test_name(tindx), PSC_CLIENT_ADDR_PORT(state));
+ /* Wrong for deep protocol tests, but we disable those. */
+ state->flags |= PSC_STATE_FLAG_BYTINDX_DONE(tindx);
+ /* This also disables pending deep protocol tests. */
+ state->flags |= PSC_STATE_FLAG_BYTINDX_PASS(tindx);
+ }
+ /* Update expiration even if the test was completed or disabled. */
+ if (state->expire_time[tindx] < now + var_psc_dnsbl_ttl)
+ state->expire_time[tindx] = now + var_psc_dnsbl_ttl;
+ }
+ }
+}
+
/* psc_early_event - handle pre-greet, EOF, and DNSBL results. */
static void psc_early_event(int event, char *context)
@@ -58,9 +101,7 @@ static void psc_early_event(int event, char *context)
PSC_STATE *state = (PSC_STATE *) context;
char read_buf[PSC_READ_BUF_SIZE];
int read_count;
- int dnsbl_score;
DELTA_TIME elapsed;
- const char *dnsbl_name;
if (msg_verbose > 1)
msg_info("%s: sq=%d cq=%d event %d on smtp socket %d from [%s]:%s flags=%s",
@@ -83,15 +124,16 @@ static void psc_early_event(int event, char *context)
switch (event) {
/*
- * We reached the end of the early tests time limit.
+ * We either reached the end of the early tests time limit, or all
+ * early tests completed before the pregreet timer would go off.
*/
case EVENT_TIME:
/*
* Check if the SMTP client spoke before its turn.
*/
- if ((state->flags & PSC_STATE_MASK_PREGR_TODO_FAIL)
- == PSC_STATE_FLAG_PREGR_TODO) {
+ if ((state->flags & PSC_STATE_FLAG_PREGR_TODO) != 0
+ && (state->flags & PSC_STATE_MASK_PREGR_FAIL_DONE) == 0) {
state->pregr_stamp = event_time() + var_psc_pregr_ttl;
PSC_PASS_SESSION_STATE(state, "pregreet test",
PSC_STATE_FLAG_PREGR_PASS);
@@ -103,35 +145,47 @@ static void psc_early_event(int event, char *context)
}
/*
+ * Collect the DNSBL score, and whitelist other tests if applicable.
+ * Note: this score will be partial when some DNS lookup did not
+ * complete before the pregreet timer expired.
+ *
* If the client is DNS blocklisted, drop the connection, send the
* client to a dummy protocol engine, or continue to the next test.
*/
#define PSC_DNSBL_FORMAT \
"%s 5.7.1 Service unavailable; client [%s] blocked using %s\r\n"
+#define NO_DNSBL_SCORE INT_MAX
if (state->flags & PSC_STATE_FLAG_DNSBL_TODO) {
- dnsbl_score =
- psc_dnsbl_retrieve(state->smtp_client_addr, &dnsbl_name,
- state->dnsbl_index);
- if (dnsbl_score < var_psc_dnsbl_thresh) {
+ if (state->dnsbl_score == NO_DNSBL_SCORE) {
+ state->dnsbl_score =
+ psc_dnsbl_retrieve(state->smtp_client_addr,
+ &state->dnsbl_name,
+ state->dnsbl_index);
+ if (var_psc_dnsbl_wthresh < 0)
+ psc_whitelist_non_dnsbl(state);
+ }
+ if (state->dnsbl_score < var_psc_dnsbl_thresh) {
state->dnsbl_stamp = event_time() + var_psc_dnsbl_ttl;
PSC_PASS_SESSION_STATE(state, "dnsbl test",
PSC_STATE_FLAG_DNSBL_PASS);
} else {
msg_info("DNSBL rank %d for [%s]:%s",
- dnsbl_score, PSC_CLIENT_ADDR_PORT(state));
+ state->dnsbl_score, PSC_CLIENT_ADDR_PORT(state));
PSC_FAIL_SESSION_STATE(state, PSC_STATE_FLAG_DNSBL_FAIL);
switch (psc_dnsbl_action) {
case PSC_ACT_DROP:
state->dnsbl_reply = vstring_sprintf(vstring_alloc(100),
PSC_DNSBL_FORMAT, "521",
- state->smtp_client_addr, dnsbl_name);
+ state->smtp_client_addr,
+ state->dnsbl_name);
PSC_DROP_SESSION_STATE(state, STR(state->dnsbl_reply));
return;
case PSC_ACT_ENFORCE:
state->dnsbl_reply = vstring_sprintf(vstring_alloc(100),
PSC_DNSBL_FORMAT, "550",
- state->smtp_client_addr, dnsbl_name);
+ state->smtp_client_addr,
+ state->dnsbl_name);
PSC_ENFORCE_SESSION_STATE(state, STR(state->dnsbl_reply));
break;
case PSC_ACT_IGNORE:
@@ -150,7 +204,9 @@ static void psc_early_event(int event, char *context)
* Pass the connection to a real SMTP server, or enter the dummy
* engine for deep tests.
*/
- if (state->flags & (PSC_STATE_FLAG_NOFORWARD | PSC_STATE_MASK_SMTPD_TODO))
+ if ((state->flags & PSC_STATE_FLAG_NOFORWARD) != 0
+ || ((state->flags & PSC_STATE_MASK_SMTPD_PASS)
+ != PSC_STATE_FLAGS_TODO_TO_PASS(state->flags & PSC_STATE_MASK_SMTPD_TODO)))
psc_smtpd_tests(state);
else
psc_conclude(state);
@@ -165,8 +221,10 @@ static void psc_early_event(int event, char *context)
if ((read_count = recv(vstream_fileno(state->smtp_client_stream),
read_buf, sizeof(read_buf) - 1, MSG_PEEK)) <= 0) {
/* Avoid memory leak. */
- if (state->flags & PSC_STATE_FLAG_DNSBL_TODO)
- (void) psc_dnsbl_retrieve(state->smtp_client_addr, &dnsbl_name,
+ if (state->dnsbl_score == NO_DNSBL_SCORE
+ && (state->flags & PSC_STATE_FLAG_DNSBL_TODO))
+ (void) psc_dnsbl_retrieve(state->smtp_client_addr,
+ &state->dnsbl_name,
state->dnsbl_index);
/* XXX Wait for DNS replies to come in. */
psc_hangup_event(state);
@@ -181,8 +239,10 @@ static void psc_early_event(int event, char *context)
switch (psc_pregr_action) {
case PSC_ACT_DROP:
/* Avoid memory leak. */
- if (state->flags & PSC_STATE_FLAG_DNSBL_TODO)
- (void) psc_dnsbl_retrieve(state->smtp_client_addr, &dnsbl_name,
+ if (state->dnsbl_score == NO_DNSBL_SCORE
+ && (state->flags & PSC_STATE_FLAG_DNSBL_TODO))
+ (void) psc_dnsbl_retrieve(state->smtp_client_addr,
+ &state->dnsbl_name,
state->dnsbl_index);
PSC_DROP_SESSION_STATE(state, "521 5.5.1 Protocol error\r\n");
return;
@@ -230,6 +290,15 @@ static void psc_early_dnsbl_event(int unused_event, char *context)
if (msg_verbose)
msg_info("%s: notify [%s]:%s", myname, PSC_CLIENT_ADDR_PORT(state));
+ /*
+ * Collect the DNSBL score, and whitelist other tests if applicable.
+ */
+ state->dnsbl_score =
+ psc_dnsbl_retrieve(state->smtp_client_addr, &state->dnsbl_name,
+ state->dnsbl_index);
+ if (var_psc_dnsbl_wthresh < 0)
+ psc_whitelist_non_dnsbl(state);
+
/*
* Terminate the greet delay if we're just waiting for DNSBL lookup to
* complete. Don't call psc_early_event directly, that would result in a
@@ -272,6 +341,7 @@ void psc_early_tests(PSC_STATE *state)
(char *) state);
else
state->dnsbl_index = -1;
+ state->dnsbl_score = NO_DNSBL_SCORE;
/*
* Wait for the client to respond or for DNS lookup to complete.
diff --git a/postfix/src/postscreen/postscreen_state.c b/postfix/src/postscreen/postscreen_state.c
index 5b97ce032..c7472cc62 100644
--- a/postfix/src/postscreen/postscreen_state.c
+++ b/postfix/src/postscreen/postscreen_state.c
@@ -268,9 +268,6 @@ const char *psc_print_state_flags(int flags, const char *context)
/* unused */
"WLIST_FAIL", PSC_STATE_FLAG_WLIST_FAIL,
- "PENAL_UPDATE", PSC_STATE_FLAG_PENAL_UPDATE,
- "PENAL_FAIL", PSC_STATE_FLAG_PENAL_FAIL,
-
"PREGR_FAIL", PSC_STATE_FLAG_PREGR_FAIL,
"PREGR_PASS", PSC_STATE_FLAG_PREGR_PASS,
"PREGR_TODO", PSC_STATE_FLAG_PREGR_TODO,
diff --git a/postfix/src/postscreen/postscreen_tests.c b/postfix/src/postscreen/postscreen_tests.c
index 57bfd6999..17b7a3926 100644
--- a/postfix/src/postscreen/postscreen_tests.c
+++ b/postfix/src/postscreen/postscreen_tests.c
@@ -27,6 +27,9 @@
/* const char *helo;
/* const char *sender;
/* const char *rcpt;
+/*
+/* const char *psc_test_name(tindx)
+/* int tindx;
/* DESCRIPTION
/* The functions in this module overwrite the per-test expiration
/* time stamps and all flags bits. Some functions are implemented
@@ -54,6 +57,9 @@
/* This may modify the time stamps for disabled tests.
/*
/* psc_print_grey_key() prints a greylist lookup key.
+/*
+/* psc_test_name() returns the name for the specified text
+/* index.
/* LICENSE
/* .ad
/* .fi
@@ -69,10 +75,12 @@
#include
#include /* sscanf */
+#include /* strtoul */
/* Utility library. */
#include
+#include
/* Global library. */
@@ -132,7 +140,6 @@ void psc_new_tests(PSC_STATE *state)
state->pipel_stamp = PSC_TIME_STAMP_NEW;
state->nsmtp_stamp = PSC_TIME_STAMP_NEW;
state->barlf_stamp = PSC_TIME_STAMP_NEW;
- state->penal_stamp = PSC_TIME_STAMP_NEW;
/*
* Don't flag disabled tests as "todo", because there would be no way to
@@ -156,17 +163,10 @@ void psc_parse_tests(PSC_STATE *state,
const char *stamp_str,
time_t time_value)
{
- unsigned long pregr_stamp;
- unsigned long dnsbl_stamp;
- unsigned long pipel_stamp;
- unsigned long nsmtp_stamp;
- unsigned long barlf_stamp;
- unsigned long penal_stamp;
-
-#ifdef NONPROD
- time_t penalty_left;
-
-#endif
+ const char *start = stamp_str;
+ char *cp;
+ time_t *time_stamps = state->expire_time;
+ time_t *sp;
/*
* We don't know what tests have expired or have never passed.
@@ -182,37 +182,19 @@ void psc_parse_tests(PSC_STATE *state,
* enabled tests, but the remote SMTP client has not yet passed all those
* tests.
*/
- switch (sscanf(stamp_str, "%lu;%lu;%lu;%lu;%lu;%lu",
- &pregr_stamp, &dnsbl_stamp, &pipel_stamp, &nsmtp_stamp,
- &barlf_stamp, &penal_stamp)) {
- case 0:
- pregr_stamp = PSC_TIME_STAMP_DISABLED;
- case 1:
- dnsbl_stamp = PSC_TIME_STAMP_DISABLED;
- case 2:
- pipel_stamp = PSC_TIME_STAMP_DISABLED;
- case 3:
- nsmtp_stamp = PSC_TIME_STAMP_DISABLED;
- case 4:
- barlf_stamp = PSC_TIME_STAMP_DISABLED;
- case 5:
- penal_stamp = PSC_TIME_STAMP_DISABLED;
- default:
- break;
+ for (sp = time_stamps; sp < time_stamps + PSC_TINDX_COUNT; sp++) {
+ *sp = strtoul(start, &cp, 10);
+ if (*start == 0 || (*cp != '\0' && *cp != ';') || errno == ERANGE)
+ *sp = PSC_TIME_STAMP_DISABLED;
+ if (*sp == PSC_TIME_STAMP_NEW)
+ state->flags |= PSC_STATE_FLAG_NEW;
+ if (msg_verbose)
+ msg_info("%s -> %lu", start, (unsigned long) *sp);
+ if (*cp == ';')
+ start = cp + 1;
+ else
+ start = cp;
}
- state->pregr_stamp = pregr_stamp;
- state->dnsbl_stamp = dnsbl_stamp;
- state->pipel_stamp = pipel_stamp;
- state->nsmtp_stamp = nsmtp_stamp;
- state->barlf_stamp = barlf_stamp;
- state->penal_stamp = penal_stamp;
-
- if (pregr_stamp == PSC_TIME_STAMP_NEW
- || dnsbl_stamp == PSC_TIME_STAMP_NEW
- || pipel_stamp == PSC_TIME_STAMP_NEW
- || nsmtp_stamp == PSC_TIME_STAMP_NEW
- || barlf_stamp == PSC_TIME_STAMP_NEW)
- state->flags |= PSC_STATE_FLAG_NEW;
/*
* Don't flag disabled tests as "todo", because there would be no way to
@@ -270,41 +252,6 @@ void psc_parse_tests(PSC_STATE *state,
state->flags |= PSC_STATE_FLAG_DNSBL_TODO;
}
#endif
-
- /*
- * Apply unexpired penalty for past behavior.
- *
- * XXX Before we can drop connections, change this function to return
- * success/fail, to inform the caller that the state object no longer
- * exists.
- */
-#ifdef NONPROD
- if ((penalty_left = state->penal_stamp - event_time()) > 0) {
- msg_info("PENALTY %ld for %s",
- (long) penalty_left, state->smtp_client_addr);
- PSC_FAIL_SESSION_STATE(state, PSC_STATE_FLAG_PENAL_FAIL);
-#if 0
- switch (psc_penal_action) {
- case PSC_ACT_DROP:
- PSC_DROP_SESSION_STATE(state,
- "421 4.3.2 Service currently unavailable\r\n");
- break;
- case PSC_ACT_ENFORCE:
-#endif
- PSC_ENFORCE_SESSION_STATE(state,
- "450 4.3.2 Service currently unavailable\r\n");
-#if 0
- break;
- case PSC_ACT_IGNORE:
- PSC_UNFAIL_SESSION_STATE(state, PSC_STATE_FLAG_PENAL_FAIL);
- break;
- default:
- msg_panic("%s: unknown penalty action value %d",
- myname, psc_penal_action);
- }
-#endif
- }
-#endif /* NONPROD */
}
/* psc_print_tests - print postscreen cache record */
@@ -319,25 +266,6 @@ char *psc_print_tests(VSTRING *buf, PSC_STATE *state)
if ((state->flags & PSC_STATE_MASK_ANY_UPDATE) == 0)
msg_panic("%s: attempt to save a no-update record", myname);
- /*
- * Don't record a client as "passed" while subject to penalty. Be sure to
- * produce correct PASS OLD/NEW logging.
- *
- * XXX This needs to be refined - we should not reset the result of tests
- * that were passed in previous sessions, otherwise a client may never
- * pass a multi-stage test such as greylisting. One solution is to keep
- * the original and updated time stamps around, and to save an updated
- * time stamp only when the corresponding "pass" flag is raised.
- */
-#ifdef NONPROD
- if (state->flags & PSC_STATE_FLAG_PENAL_FAIL) {
- state->pregr_stamp = state->dnsbl_stamp = state->pipel_stamp =
- state->nsmtp_stamp = state->barlf_stamp =
- ((state->flags & PSC_STATE_FLAG_NEW) ?
- PSC_TIME_STAMP_NEW : PSC_TIME_STAMP_DISABLED);
- }
-#endif
-
/*
* Give disabled tests a dummy time stamp so that we don't log a client
* with "pass new" when some disabled test becomes enabled at some later
@@ -354,13 +282,12 @@ char *psc_print_tests(VSTRING *buf, PSC_STATE *state)
if (var_psc_barlf_enable == 0 && state->barlf_stamp == PSC_TIME_STAMP_NEW)
state->barlf_stamp = PSC_TIME_STAMP_DISABLED;
- vstring_sprintf(buf, "%lu;%lu;%lu;%lu;%lu;%lu",
+ vstring_sprintf(buf, "%lu;%lu;%lu;%lu;%lu",
(unsigned long) state->pregr_stamp,
(unsigned long) state->dnsbl_stamp,
(unsigned long) state->pipel_stamp,
(unsigned long) state->nsmtp_stamp,
- (unsigned long) state->barlf_stamp,
- (unsigned long) state->penal_stamp);
+ (unsigned long) state->barlf_stamp);
return (STR(buf));
}
@@ -373,3 +300,23 @@ char *psc_print_grey_key(VSTRING *buf, const char *client,
return (STR(vstring_sprintf(buf, "%s/%s/%s/%s",
client, helo, sender, rcpt)));
}
+
+/* psc_test_name - map test index to symbolic name */
+
+const char *psc_test_name(int tindx)
+{
+ const char *myname = "psc_test_name";
+ const NAME_CODE test_name_map[] = {
+ PSC_TNAME_PREGR, PSC_TINDX_PREGR,
+ PSC_TNAME_DNSBL, PSC_TINDX_DNSBL,
+ PSC_TNAME_PIPEL, PSC_TINDX_PIPEL,
+ PSC_TNAME_NSMTP, PSC_TINDX_NSMTP,
+ PSC_TNAME_BARLF, PSC_TINDX_BARLF,
+ 0, -1,
+ };
+ const char *result;
+
+ if ((result = str_name_code(test_name_map, tindx)) == 0)
+ msg_panic("%s: bad index %d", myname, tindx);
+ return (result);
+}
diff --git a/postfix/src/posttls-finger/posttls-finger.c b/postfix/src/posttls-finger/posttls-finger.c
index fffad281e..3ca448ac3 100644
--- a/postfix/src/posttls-finger/posttls-finger.c
+++ b/postfix/src/posttls-finger/posttls-finger.c
@@ -425,8 +425,8 @@ typedef struct STATE {
TLS_SESS_STATE *tls_context; /* Session TLS context */
TLS_DANE *dane; /* DANE TLSA validation structure */
TLS_DANE *ddane; /* DANE TLSA from DNS */
- char *grade; /* Minimum cipher grade */
- char *protocols; /* Protocol inclusion/exclusion */
+ char *grade; /* Minimum cipher grade */
+ char *protocols; /* Protocol inclusion/exclusion */
#endif
OPTIONS options; /* JCL */
} STATE;
diff --git a/postfix/src/posttls-finger/tlsmgrmem.c b/postfix/src/posttls-finger/tlsmgrmem.c
index 413fcfbc4..d6b09d87c 100644
--- a/postfix/src/posttls-finger/tlsmgrmem.c
+++ b/postfix/src/posttls-finger/tlsmgrmem.c
@@ -140,4 +140,3 @@ int tls_mgr_delete(const char *unused_type, const char *key)
}
#endif
-
diff --git a/postfix/src/posttls-finger/tlsmgrmem.h b/postfix/src/posttls-finger/tlsmgrmem.h
index be2946b14..706b206b7 100644
--- a/postfix/src/posttls-finger/tlsmgrmem.h
+++ b/postfix/src/posttls-finger/tlsmgrmem.h
@@ -26,4 +26,3 @@ extern void tlsmgrmem_flush(void);
/*
/* Viktor Dukhovni
/*--*/
-
diff --git a/postfix/src/qmgr/qmgr_message.c b/postfix/src/qmgr/qmgr_message.c
index 576fb2d6f..e6bbaf65c 100644
--- a/postfix/src/qmgr/qmgr_message.c
+++ b/postfix/src/qmgr/qmgr_message.c
@@ -1234,7 +1234,7 @@ static void qmgr_message_resolve(QMGR_MESSAGE *message)
: strlen(STR(reply.recipient)));
vstring_strncpy(queue_name, STR(reply.recipient), len);
/* Remove the address extension from the recipient localpart. */
- if (*var_rcpt_delim && split_addr(STR(queue_name), *var_rcpt_delim))
+ if (*var_rcpt_delim && split_addr(STR(queue_name), var_rcpt_delim))
vstring_truncate(queue_name, strlen(STR(queue_name)));
/* Assume the recipient domain is equivalent to nexthop. */
vstring_sprintf_append(queue_name, "@%s", STR(reply.nexthop));
diff --git a/postfix/src/smtpd/smtpd.c b/postfix/src/smtpd/smtpd.c
index 1f219e187..ce2b31d26 100644
--- a/postfix/src/smtpd/smtpd.c
+++ b/postfix/src/smtpd/smtpd.c
@@ -90,10 +90,6 @@
/* not contain RFC 822 style comments or phrases.
/* .PP
/* Available in Postfix version 2.1 and later:
-/* .IP "\fBresolve_null_domain (no)\fR"
-/* Resolve an address that ends in the "@" null domain as if the
-/* local hostname were specified, instead of rejecting the address as
-/* invalid.
/* .IP "\fBsmtpd_reject_unlisted_sender (no)\fR"
/* Request that the Postfix SMTP server rejects mail from unknown
/* sender addresses, even when no explicit reject_unlisted_sender
@@ -956,7 +952,8 @@
/* .IP "\fBqueue_directory (see 'postconf -d' output)\fR"
/* The location of the Postfix top-level queue directory.
/* .IP "\fBrecipient_delimiter (empty)\fR"
-/* The separator between user names and address extensions (user+foo).
+/* The set of characters that can separate a user name from its
+/* address extension (user+foo).
/* .IP "\fBsmtpd_banner ($myhostname ESMTP $mail_name)\fR"
/* The text that follows the 220 status code in the SMTP greeting
/* banner.
diff --git a/postfix/src/smtpd/smtpd_check.c b/postfix/src/smtpd/smtpd_check.c
index e5b165bf1..a27dc7012 100644
--- a/postfix/src/smtpd/smtpd_check.c
+++ b/postfix/src/smtpd/smtpd_check.c
@@ -2866,7 +2866,7 @@ static int check_mail_access(SMTPD_STATE *state, const char *table,
if (*var_rcpt_delim == 0) {
bare_addr = 0;
} else {
- bare_addr = strip_addr(addr, (char **) 0, *var_rcpt_delim);
+ bare_addr = strip_addr(addr, (char **) 0, var_rcpt_delim);
}
#define CHECK_MAIL_ACCESS_RETURN(x) \
diff --git a/postfix/src/smtpd/smtpd_proxy.c b/postfix/src/smtpd/smtpd_proxy.c
index f77885436..aec804974 100644
--- a/postfix/src/smtpd/smtpd_proxy.c
+++ b/postfix/src/smtpd/smtpd_proxy.c
@@ -30,9 +30,6 @@
/* int expect;
/* const char *format;
/*
-/* void smtpd_proxy_disconnect(state)
-/* SMTPD_STATE *state;
-/*
/* void smtpd_proxy_free(state)
/* SMTPD_STATE *state;
/*
@@ -92,10 +89,6 @@
/* In case of error, proxy->cmd() updates the state->error_mask
/* and state->err fields.
/*
-/* smtpd_proxy_disconnect() disconnects from a proxy server.
-/* The last proxy server reply or error description remains
-/* available via the proxy->buffer field.
-/*
/* smtpd_proxy_free() destroys a proxy server handle and resets
/* the state->proxy field.
/*
diff --git a/postfix/src/tls/tls_dane.c b/postfix/src/tls/tls_dane.c
index d961199bf..e9c94daf8 100644
--- a/postfix/src/tls/tls_dane.c
+++ b/postfix/src/tls/tls_dane.c
@@ -158,7 +158,7 @@
#include
#include
#include
-#include /* event_time() */
+#include /* event_time() */
#include
#include
@@ -201,22 +201,22 @@ static CTABLE *dane_cache;
/* tls_dane_verbose - enable/disable verbose logging */
-void tls_dane_verbose(int on)
+void tls_dane_verbose(int on)
{
dane_verbose = on;
}
/* tls_dane_avail - check for availability of dane required digests */
-int tls_dane_avail(void)
+int tls_dane_avail(void)
{
-#ifdef TLSEXT_MAXLEN_host_name /* DANE mandates client SNI. */
+#ifdef TLSEXT_MAXLEN_host_name /* DANE mandates client SNI. */
static int avail = -1;
const EVP_MD *sha256md;
const EVP_MD *sha512md;
static NAME_MASK ta_dgsts[] = {
- TLS_DANE_CC, TLS_DANE_ENABLE_CC,
- TLS_DANE_TAA, TLS_DANE_ENABLE_TAA,
+ TLS_DANE_CC, TLS_DANE_ENABLE_CC,
+ TLS_DANE_TAA, TLS_DANE_ENABLE_TAA,
0,
};
@@ -239,13 +239,13 @@ int tls_dane_avail(void)
return (avail = 1);
#else
- return (0);
+ return (0);
#endif
}
/* tls_dane_flush - flush the cache */
-void tls_dane_flush(void)
+void tls_dane_flush(void)
{
if (dane_cache)
ctable_free(dane_cache);
@@ -256,7 +256,7 @@ void tls_dane_flush(void)
TLS_DANE *tls_dane_alloc(int flags)
{
- TLS_DANE *dane = (TLS_DANE *)mymalloc(sizeof(*dane));
+ TLS_DANE *dane = (TLS_DANE *) mymalloc(sizeof(*dane));
dane->ta = 0;
dane->ee = 0;
@@ -270,7 +270,7 @@ TLS_DANE *tls_dane_alloc(int flags)
static void ta_cert_insert(TLS_DANE *d, X509 *x)
{
- TLS_CERTS *new = (TLS_CERTS *)mymalloc(sizeof(*new));
+ TLS_CERTS *new = (TLS_CERTS *) mymalloc(sizeof(*new));
CRYPTO_add(&x->references, 1, CRYPTO_LOCK_X509);
new->cert = x;
@@ -286,13 +286,13 @@ static void free_ta_certs(TLS_DANE *d)
for (head = d->certs; head; head = next) {
next = head->next;
X509_free(head->cert);
- myfree((char *)head);
+ myfree((char *) head);
}
}
static void ta_pkey_insert(TLS_DANE *d, EVP_PKEY *k)
{
- TLS_PKEYS *new = (TLS_PKEYS *)mymalloc(sizeof(*new));
+ TLS_PKEYS *new = (TLS_PKEYS *) mymalloc(sizeof(*new));
CRYPTO_add(&k->references, 1, CRYPTO_LOCK_EVP_PKEY);
new->pkey = k;
@@ -308,7 +308,7 @@ static void free_ta_pkeys(TLS_DANE *d)
for (head = d->pkeys; head; head = next) {
next = head->next;
EVP_PKEY_free(head->pkey);
- myfree((char *)head);
+ myfree((char *) head);
}
}
@@ -320,12 +320,12 @@ static void tlsa_free(TLS_TLSA *tlsa)
argv_free(tlsa->certs);
if (tlsa->pkeys)
argv_free(tlsa->pkeys);
- myfree((char *)tlsa);
+ myfree((char *) tlsa);
}
/* tls_dane_free - free a TLS_DANE structure */
-void tls_dane_free(TLS_DANE *dane)
+void tls_dane_free(TLS_DANE *dane)
{
TLS_TLSA *tlsa;
TLS_TLSA *next;
@@ -347,14 +347,14 @@ void tls_dane_free(TLS_DANE *dane)
free_ta_certs(dane);
free_ta_pkeys(dane);
- myfree((char *)dane);
+ myfree((char *) dane);
}
/* dane_free - ctable style */
static void dane_free(void *dane, void *unused_context)
{
- tls_dane_free((TLS_DANE *)dane);
+ tls_dane_free((TLS_DANE *) dane);
}
/* tlsa_sort - sort digests for a single certusage */
@@ -373,6 +373,7 @@ static void tlsa_sort(TLS_TLSA *tlsa)
TLS_DANE *tls_dane_final(TLS_DANE *dane)
{
+
/*
* We only sort the trust anchors, see tls_serverid_digest().
*/
@@ -390,8 +391,8 @@ static TLS_TLSA **dane_locate(TLS_TLSA **tlsap, const char *mdalg)
/*
* Correct computation of the session cache serverid requires a TLSA
- * digest list that is sorted by algorithm name. Below we maintain
- * the sort order (by algorithm name canonicalized to lowercase).
+ * digest list that is sorted by algorithm name. Below we maintain the
+ * sort order (by algorithm name canonicalized to lowercase).
*/
for (; *tlsap; tlsap = &(*tlsap)->next) {
int cmp = strcasecmp(mdalg, (*tlsap)->mdalg);
@@ -402,7 +403,7 @@ static TLS_TLSA **dane_locate(TLS_TLSA **tlsap, const char *mdalg)
break;
}
- new = (TLS_TLSA *)mymalloc(sizeof(*new));
+ new = (TLS_TLSA *) mymalloc(sizeof(*new));
new->mdalg = lowercase(mystrdup(mdalg));
new->certs = 0;
new->pkeys = 0;
@@ -414,8 +415,8 @@ static TLS_TLSA **dane_locate(TLS_TLSA **tlsap, const char *mdalg)
/* tls_dane_split - split and append digests */
-void tls_dane_split(TLS_DANE *dane, int certusage, int selector,
- const char *mdalg, const char *digest, const char *delim)
+void tls_dane_split(TLS_DANE *dane, int certusage, int selector,
+ const char *mdalg, const char *digest, const char *delim)
{
TLS_TLSA **tlsap;
TLS_TLSA *tlsa;
@@ -450,7 +451,7 @@ void tls_dane_split(TLS_DANE *dane, int certusage, int selector,
/* dane_add - add a digest entry */
static void dane_add(TLS_DANE *dane, int certusage, int selector,
- const char *mdalg, char *digest)
+ const char *mdalg, char *digest)
{
TLS_TLSA **tlsap;
TLS_TLSA *tlsa;
@@ -462,11 +463,11 @@ static void dane_add(TLS_DANE *dane, int certusage, int selector,
switch (certusage) {
case DNS_TLSA_USAGE_CA_CONSTRAINT:
case DNS_TLSA_USAGE_TRUST_ANCHOR_ASSERTION:
- certusage = TLS_DANE_TA; /* Collapse 0/2 -> 2 */
+ certusage = TLS_DANE_TA; /* Collapse 0/2 -> 2 */
break;
case DNS_TLSA_USAGE_SERVICE_CERTIFICATE_CONSTRAINT:
case DNS_TLSA_USAGE_DOMAIN_ISSUED_CERTIFICATE:
- certusage = TLS_DANE_EE; /* Collapse 1/3 -> 3 */
+ certusage = TLS_DANE_EE; /* Collapse 1/3 -> 3 */
break;
}
@@ -498,18 +499,18 @@ static void parse_tlsa_rrs(TLS_DANE *dane, DNS_RR *rr)
uint8_t mtype;
int mlen;
const unsigned char *p;
- X509 *x = 0; /* OpenSSL tries to re-use *x if x!=0 */
- EVP_PKEY *k = 0; /* OpenSSL tries to re-use *k if k!=0 */
+ X509 *x = 0; /* OpenSSL tries to re-use *x if x!=0 */
+ EVP_PKEY *k = 0; /* OpenSSL tries to re-use *k if k!=0 */
if (rr == 0)
msg_panic("null TLSA rr");
- for (/* nop */; rr; rr = rr->next) {
+ for ( /* nop */ ; rr; rr = rr->next) {
const char *mdalg = 0;
int mdlen;
char *digest;
int same = (strcasecmp(rr->rname, rr->qname) == 0);
- uint8_t *ip = (uint8_t *)rr->data;
+ uint8_t *ip = (uint8_t *) rr->data;
#define rcname(rr) (same ? "" : rr->qname)
#define rarrow(rr) (same ? "" : " -> ")
@@ -521,10 +522,9 @@ static void parse_tlsa_rrs(TLS_DANE *dane, DNS_RR *rr)
/* Skip malformed */
if ((mlen = rr->data_len - 3) < 0) {
msg_warn("truncated length %u RR: %s%s%s IN TLSA ...",
- (unsigned)rr->data_len, rcname(rr), rarrow(rr), rr->rname);
+ (unsigned) rr->data_len, rcname(rr), rarrow(rr), rr->rname);
continue;
}
-
switch (usage = *ip++) {
default:
msg_warn("unsupported certificate usage %u in RR: "
@@ -594,11 +594,11 @@ static void parse_tlsa_rrs(TLS_DANE *dane, DNS_RR *rr)
break;
}
dane_add(dane, usage, selector, mdalg,
- digest = tls_digest_encode((unsigned char *)ip, mdlen));
+ digest = tls_digest_encode((unsigned char *) ip, mdlen));
break;
case DNS_TLSA_MATCHING_TYPE_NO_HASH_USED:
- p = (unsigned char *)ip;
+ p = (unsigned char *) ip;
/* Validate the cert or public key via d2i_mumble() */
switch (selector) {
@@ -610,13 +610,14 @@ static void parse_tlsa_rrs(TLS_DANE *dane, DNS_RR *rr)
usage, selector, mtype);
continue;
}
+
/*
* When a full trust-anchor certificate is published via DNS,
* we may need to use it to validate the server trust chain.
- * Store it away for later use. We collapse certificate usage
- * 0/2 because MTAs don't stock a complete list of the usual
- * browser-trusted CAs. Thus, here (and in the public key
- * case below) we treat the usages identically.
+ * Store it away for later use. We collapse certificate
+ * usage 0/2 because MTAs don't stock a complete list of the
+ * usual browser-trusted CAs. Thus, here (and in the public
+ * key case below) we treat the usages identically.
*/
switch (usage) {
case DNS_TLSA_USAGE_CA_CONSTRAINT:
@@ -644,12 +645,13 @@ static void parse_tlsa_rrs(TLS_DANE *dane, DNS_RR *rr)
EVP_PKEY_free(k);
break;
}
+
/*
- * The cert or key was valid, just digest the raw object,
- * and encode the digest value. We choose SHA256.
+ * The cert or key was valid, just digest the raw object, and
+ * encode the digest value. We choose SHA256.
*/
dane_add(dane, usage, selector, sha256,
- digest = tls_data_fprint((char *)ip, mlen, sha256));
+ digest = tls_data_fprint((char *) ip, mlen, sha256));
break;
}
if (msg_verbose || dane_verbose)
@@ -705,13 +707,13 @@ static void *dane_lookup(const char *tlsa_fqdn, void *unused_ctx)
break;
}
- return ((void *)tls_dane_final(dane));
+ return ((void *) tls_dane_final(dane));
}
/* tls_dane_resolve - cached map: (host, proto, port) -> TLS_DANE */
TLS_DANE *tls_dane_resolve(const char *host, const char *proto,
- unsigned port)
+ unsigned port)
{
static VSTRING *qname;
TLS_DANE *dane;
@@ -725,9 +727,9 @@ TLS_DANE *tls_dane_resolve(const char *host, const char *proto,
if (qname == 0)
qname = vstring_alloc(64);
vstring_sprintf(qname, "_%u._%s.%s", ntohs(port), proto, host);
- dane = (TLS_DANE *)ctable_locate(dane_cache, STR(qname));
+ dane = (TLS_DANE *) ctable_locate(dane_cache, STR(qname));
if (timecmp(event_time(), dane->expires) > 0)
- dane = (TLS_DANE *)ctable_refresh(dane_cache, STR(qname));
+ dane = (TLS_DANE *) ctable_refresh(dane_cache, STR(qname));
if (dane->flags & TLS_DANE_FLAG_ERROR)
return (0);
@@ -738,7 +740,7 @@ TLS_DANE *tls_dane_resolve(const char *host, const char *proto,
/* tls_dane_load_trustfile - load trust anchor certs or keys from file */
-int tls_dane_load_trustfile(TLS_DANE *dane, const char *tafile)
+int tls_dane_load_trustfile(TLS_DANE *dane, const char *tafile)
{
BIO *bp;
char *name = 0;
@@ -746,22 +748,22 @@ int tls_dane_load_trustfile(TLS_DANE *dane, const char *tafile)
unsigned char *data = 0;
long len;
int tacount;
- char *errtype = 0; /* if error: cert or pkey? */
+ char *errtype = 0; /* if error: cert or pkey? */
/* nop */
if (tafile == 0 || *tafile == 0)
return (1);
/*
- * On each call, PEM_read() wraps a stdio file in a BIO_NOCLOSE bio, calls
- * PEM_read_bio() and then frees the bio. It is just as easy to open a
- * BIO as a stdio file, so we use BIOs and call PEM_read_bio() directly.
+ * On each call, PEM_read() wraps a stdio file in a BIO_NOCLOSE bio,
+ * calls PEM_read_bio() and then frees the bio. It is just as easy to
+ * open a BIO as a stdio file, so we use BIOs and call PEM_read_bio()
+ * directly.
*/
if ((bp = BIO_new_file(tafile, "r")) == NULL) {
msg_warn("error opening trust anchor file: %s: %m", tafile);
return (0);
}
-
/* Don't report old news */
ERR_clear_error();
@@ -779,7 +781,7 @@ int tls_dane_load_trustfile(TLS_DANE *dane, const char *tafile)
if (cert && (p - data) == len) {
selector = DNS_TLSA_SELECTOR_FULL_CERTIFICATE;
- digest = tls_data_fprint((char *)data, len, sha256);
+ digest = tls_data_fprint((char *) data, len, sha256);
dane_add(dane, usage, selector, sha256, digest);
myfree(digest);
ta_cert_insert(dane, cert);
@@ -792,7 +794,7 @@ int tls_dane_load_trustfile(TLS_DANE *dane, const char *tafile)
if (pkey && (p - data) == len) {
selector = DNS_TLSA_SELECTOR_SUBJECTPUBLICKEYINFO;
- digest = tls_data_fprint((char *)data, len, sha256);
+ digest = tls_data_fprint((char *) data, len, sha256);
dane_add(dane, usage, selector, sha256, digest);
myfree(digest);
ta_pkey_insert(dane, pkey);
@@ -817,13 +819,11 @@ int tls_dane_load_trustfile(TLS_DANE *dane, const char *tafile)
tafile, errtype);
return (0);
}
-
if (ERR_GET_REASON(ERR_peek_last_error()) == PEM_R_NO_START_LINE) {
/* Reached end of PEM file */
ERR_clear_error();
return (tacount > 0);
}
-
/* Some other PEM read error */
tls_print_errors();
return (0);
diff --git a/postfix/src/tls/tls_misc.c b/postfix/src/tls/tls_misc.c
index 93b5fb1d5..86f47759b 100644
--- a/postfix/src/tls/tls_misc.c
+++ b/postfix/src/tls/tls_misc.c
@@ -950,11 +950,12 @@ long tls_bug_bits(void)
}
/*
- * Allow users to set options not in SSL_OP_ALL, and not already
- * managed via other Postfix parameters.
+ * Allow users to set options not in SSL_OP_ALL, and not already managed
+ * via other Postfix parameters.
*/
if (*var_tls_ssl_options) {
- long enable;
+ long enable;
+
enable = long_name_mask_opt(VAR_TLS_SSL_OPTIONS, ssl_op_tweaks,
var_tls_ssl_options, NAME_MASK_ANY_CASE |
NAME_MASK_NUMBER | NAME_MASK_WARN);
diff --git a/postfix/src/trivial-rewrite/resolve.c b/postfix/src/trivial-rewrite/resolve.c
index c0b6d9964..d9a709e30 100644
--- a/postfix/src/trivial-rewrite/resolve.c
+++ b/postfix/src/trivial-rewrite/resolve.c
@@ -324,9 +324,18 @@ static void resolve_addr(RES_CONTEXT *rp, char *sender, char *addr,
tok822_free(tree->head);
tree->head = 0;
}
- /* XXX must be localpart only, not user@domain form. */
- if (tree->head == 0)
+ /* XXX Re-resolve the surrogate, in case already in user@domain form. */
+ if (tree->head == 0) {
tree->head = tok822_scan(var_empty_addr, &tree->tail);
+ continue;
+ }
+
+ /* XXX Re-resolve with @$myhostname for backwards compatibility. */
+ if (domain == 0 && saved_domain == 0) {
+ tok822_sub_append(tree, tok822_alloc('@', (char *) 0));
+ tok822_sub_append(tree, tok822_scan(var_myhostname, (TOK822 **) 0));
+ continue;
+ }
/*
* We're done. There are no domains left to strip off the address,
diff --git a/postfix/src/trivial-rewrite/transport.c b/postfix/src/trivial-rewrite/transport.c
index 29720541c..61937ae42 100644
--- a/postfix/src/trivial-rewrite/transport.c
+++ b/postfix/src/trivial-rewrite/transport.c
@@ -286,7 +286,7 @@ int transport_lookup(TRANSPORT_INFO *tp, const char *addr,
* partial lookup keys with regular expressions.
*/
if ((stripped_addr = strip_addr(addr, DISCARD_EXTENSION,
- *var_rcpt_delim)) != 0) {
+ var_rcpt_delim)) != 0) {
found = find_transport_entry(tp, stripped_addr, rcpt_domain, PARTIAL,
channel, nexthop);
diff --git a/postfix/src/trivial-rewrite/trivial-rewrite.c b/postfix/src/trivial-rewrite/trivial-rewrite.c
index b8cc438c2..c5dbe0663 100644
--- a/postfix/src/trivial-rewrite/trivial-rewrite.c
+++ b/postfix/src/trivial-rewrite/trivial-rewrite.c
@@ -83,10 +83,14 @@
/* .IP "\fBresolve_dequoted_address (yes)\fR"
/* Resolve a recipient address safely instead of correctly, by
/* looking inside quotes.
+/* .PP
+/* Available with Postfix version 2.1 and later:
/* .IP "\fBresolve_null_domain (no)\fR"
/* Resolve an address that ends in the "@" null domain as if the
/* local hostname were specified, instead of rejecting the address as
/* invalid.
+/* .PP
+/* Available with Postfix version 2.3 and later:
/* .IP "\fBresolve_numeric_domain (no)\fR"
/* Resolve "user@ipaddress" as "user@[ipaddress]", instead of
/* rejecting the address as invalid.
@@ -110,7 +114,8 @@
/* With locally submitted mail, append the string ".$mydomain" to
/* addresses that have no ".domain" information.
/* .IP "\fBrecipient_delimiter (empty)\fR"
-/* The separator between user names and address extensions (user+foo).
+/* The set of characters that can separate a user name from its
+/* address extension (user+foo).
/* .IP "\fBswap_bangpath (yes)\fR"
/* Enable the rewriting of "site!user" into "user@site".
/* .PP
diff --git a/postfix/src/util/argv.c b/postfix/src/util/argv.c
index 35bb56db5..5b2eec3eb 100644
--- a/postfix/src/util/argv.c
+++ b/postfix/src/util/argv.c
@@ -156,8 +156,9 @@ ARGV *argv_alloc(ssize_t len)
static int argv_cmp(const void *e1, const void *e2)
{
- const char *s1 = *(const char **)e1;
- const char *s2 = *(const char **)e2;
+ const char *s1 = *(const char **) e1;
+ const char *s2 = *(const char **) e2;
+
return strcmp(s1, s2);
}
diff --git a/postfix/src/util/dict.c b/postfix/src/util/dict.c
index 8d77883f5..3c4a9b1b8 100644
--- a/postfix/src/util/dict.c
+++ b/postfix/src/util/dict.c
@@ -431,6 +431,7 @@ void dict_load_fp(const char *dict_name, VSTREAM *fp)
VSTRING *buf;
char *member;
char *val;
+ const char *old;
int old_lineno;
int lineno;
const char *err;
@@ -455,6 +456,10 @@ void dict_load_fp(const char *dict_name, VSTREAM *fp)
err, STR(buf));
if (msg_verbose > 1)
msg_info("%s: %s = %s", myname, member, val);
+ if ((old = dict->lookup(dict, member)) != 0
+ && strcmp(old, val) != 0)
+ msg_warn("%s, line %d: overriding earlier entry: %s=%s",
+ VSTREAM_PATH(fp), lineno, member, old);
if (dict->update(dict, member, val) != 0)
msg_fatal("%s, line %d: unable to update %s:%s",
VSTREAM_PATH(fp), lineno, dict->type, dict->name);
diff --git a/postfix/src/util/poll_fd.c b/postfix/src/util/poll_fd.c
index e8c7ed21f..80cd0f67d 100644
--- a/postfix/src/util/poll_fd.c
+++ b/postfix/src/util/poll_fd.c
@@ -27,8 +27,8 @@
/* int true_res;
/* int false_res;
/* DESCRIPTION
-/* The functions in this module are macros that provide a
-/* convenient interface to poll_fd().
+/* The read*() and write*() functions in this module are macros
+/* that provide a convenient interface to poll_fd().
/*
/* readable() asks the kernel if the specified file descriptor
/* is readable, i.e. a read operation would not block.
@@ -72,8 +72,8 @@
/* it is false. They never return an error indication.
/*
/* read_wait() and write_wait() return zero when the requested
-/* POLL_FD_READ or POLL_FD_WRITE condition is true, -1 with
-/* errno set to ETIMEDOUT when it is false.
+/* POLL_FD_READ or POLL_FD_WRITE condition is true, -1 (with
+/* errno set to ETIMEDOUT) when it is false.
/*
/* poll_fd() returns true_res when the requested POLL_FD_READ
/* or POLL_FD_WRITE condition is true, false_res when it is