From: Wietse Venema
Date: Mon, 28 Jun 2004 05:00:00 +0000 (-0500)
Subject: postfix-2.2-20040628
X-Git-Tag: v2.2.0-RC1~51
X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=94a16728a993ab0e41453d5cf309144656133752;p=thirdparty%2Fpostfix.git
postfix-2.2-20040628
---
diff --git a/postfix/HISTORY b/postfix/HISTORY
index 9c442ceed..5d1e4644d 100644
--- a/postfix/HISTORY
+++ b/postfix/HISTORY
@@ -9422,14 +9422,14 @@ Apologies for any names omitted.
explicit "multiple sessions per delivery request" model.
This uncovered ESMTP and SASL missing re-initialization
problems that were fixed in past week. Design by Victor
- and Wietse, initial implementation by Victor Duchovny.
+ and Wietse, initial implementation by Victor Duchovni.
20040620
Future proofing: after the reorganization of SMTP request
state and session state, added code to the smtp client
error handling routines to more consistently deal with the
- possibility that session information is not be available.
+ possibility that session information is not available.
20040621
@@ -9448,6 +9448,19 @@ Apologies for any names omitted.
Support for external command execution directory. Files:
global/pipe_command.[hc].
+20040622
+
+ Safety: when mail is delivered to a transport with per-delivery
+ recipient limit of 1, split the recipient address on the
+ recipient delimiter if one is defined, so that extended
+ addresses don't get extra delivery concurrency slots.
+ Files: *qmgr/qmgr_message.c.
+
+20040623
+
+ Workaround for fragile clients: add microsecond time to
+ maildir filename. Files: virtual/maildir.c, local/maildir.c.
+
Open problems:
Low: make sure CCARGS -I options come at the end.
diff --git a/postfix/README_FILES/BACKSCATTER_README b/postfix/README_FILES/BACKSCATTER_README
index 86e8aa8e1..bee27caf9 100644
--- a/postfix/README_FILES/BACKSCATTER_README
+++ b/postfix/README_FILES/BACKSCATTER_README
@@ -53,8 +53,9 @@ Thus, if returned mail has a Received: message header like this:
Received: from porcupine.org ...
-Then I know that this is almost certainly forged mail. Mail that is really sent
-by my systems looks like this:
+Then I know that this is almost certainly forged mail (almost; see next section
+for the fly in the ointment). Mail that is really sent by my systems looks like
+this:
Received: from hostname.porcupine.org ...
@@ -66,6 +67,13 @@ result of forgery:
Received: from host.example.com (HELO porcupine.org) ...
Received: from host.example.com (EHLO porcupine.org) ...
+Another frequent sign of forgery is the Message-ID: header. My systems produce
+a Message-ID: of . The following are forgeries,
+especially the first one:
+
+ Message-ID: <1cb479435d8eb9.2beb1.qmail@porcupine.org>
+ Message-ID:
+
To block such backscatter I use header_checks and body_checks patterns like
this:
@@ -79,6 +87,8 @@ this:
/^Received: +from +[^ ]+ +\(([^ ]+ +[he]+lo=|[he]+lo +)
(porcupine\.org)\)/
reject forged client name in Received: header: $2
+ /^Message-ID:.*@(porcupine\.org)/
+ reject forged domain name in Message-ID: header: $1
/etc/postfix/body_checks:
/^[> ]*Received: +from +(porcupine\.org) /
@@ -86,6 +96,8 @@ this:
/^[> ]*Received: +from +[^ ]+ +\(([^ ]+ +[he]+lo=|[he]+lo +)
(porcupine\.org)\)/
reject forged client name in Received: header: $2
+ /^[> ]*Message-ID:.*@(porcupine\.org)/
+ reject forged domain name in Message-ID: header: $1
Notes:
@@ -135,11 +147,11 @@ mail is obviously forged and is very easy to stop.
/etc/postfix/header_checks:
/^(From|Return-Path):.*[[:<:]](user@domain\.tld)[[:>:]]/
- reject forged sender address in $1: message header: $2
+ reject forged sender address in $1: header: $2
/etc/postfix/body_checks:
/^[> ]*(From|Return-Path):.*[[:<:]](user@domain\.tld)[[:>:]]/
- reject forged sender address in $1: message header: $2
+ reject forged sender address in $1: header: $2
Notes:
diff --git a/postfix/html/BACKSCATTER_README.html b/postfix/html/BACKSCATTER_README.html
index f2889feaf..0af36f398 100644
--- a/postfix/html/BACKSCATTER_README.html
+++ b/postfix/html/BACKSCATTER_README.html
@@ -104,8 +104,9 @@ Received: from porcupine.org ...
- Then I know that this is almost certainly forged mail. Mail
-that is really sent by my systems looks like this:
+ Then I know that this is almost certainly forged mail (almost;
+see next section for the fly in the ointment). Mail that is really
+sent by my systems looks like this:
@@ -125,6 +126,18 @@ Received: from host.example.com (EHLO porcupine.org) ...
+ Another frequent sign of forgery is the Message-ID: header. My
+systems produce a Message-ID: of
+<stuff@hostname.porcupine.org>. The following
+are forgeries, especially the first one:
+
+
+
+Message-ID: <1cb479435d8eb9.2beb1.qmail@porcupine.org>
+Message-ID: <yulszqocfzsficvzzju@porcupine.org>
+
+
+
To block such backscatter I use header_checks and body_checks
patterns like this:
@@ -139,12 +152,16 @@ patterns like this:
reject forged client name in Received: header: $1
/^Received: +from +[^ ]+ +\(([^ ]+ +[he]+lo=|[he]+lo +)(porcupine\.org)\)/
reject forged client name in Received: header: $2
+ /^Message-ID:.*@(porcupine\.org)/
+ reject forged domain name in Message-ID: header: $1
/etc/postfix/body_checks:
/^[> ]*Received: +from +(porcupine\.org) /
reject forged client name in Received: header: $1
/^[> ]*Received: +from +[^ ]+ +\(([^ ]+ +[he]+lo=|[he]+lo +)(porcupine\.org)\)/
reject forged client name in Received: header: $2
+ /^[> ]*Message-ID:.*@(porcupine\.org)/
+ reject forged domain name in Message-ID: header: $1
@@ -213,11 +230,11 @@ and is very easy to stop.
/etc/postfix/header_checks:
/^(From|Return-Path):.*[[:<:]](user@domain\.tld)[[:>:]]/
- reject forged sender address in $1: message header: $2
+ reject forged sender address in $1: header: $2
/etc/postfix/body_checks:
/^[> ]*(From|Return-Path):.*[[:<:]](user@domain\.tld)[[:>:]]/
- reject forged sender address in $1: message header: $2
+ reject forged sender address in $1: header: $2
diff --git a/postfix/html/local.8.html b/postfix/html/local.8.html
index 0ca93411d..aaf1769c9 100644
--- a/postfix/html/local.8.html
+++ b/postfix/html/local.8.html
@@ -49,8 +49,8 @@ LOCAL(8) LOCAL(8)
$user (recipient username), $home (recipient home direc-
tory), $shell (recipient shell), $recipient (complete
recipient address), $extension (recipient address exten-
- sion), $domain (recipient domain), local (entire recipient
- address localpart) and $recipient_delimiter. The forms
+ sion), $domain (recipient domain), $local (entire recipi-
+ ent address localpart) and $recipient_delimiter. The forms
${name?value} and ${name:value} expand conditionally to
value when $name is (is not) defined. Characters that may
have special meaning to the shell or file system are
@@ -154,7 +154,7 @@ LOCAL(8) LOCAL(8)
(recipient home directory), $shell (recipient shell),
$recipient (complete recipient address), $extension
(recipient address extension), $domain (recipient domain),
- local (entire recipient address localpart) and $recipi-
+ $local (entire recipient address localpart) and $recipi-
ent_delimiter. The forms ${name?value} and ${name:value}
expand conditionally to value when $name is (is not)
defined. Characters that may have special meaning to the
diff --git a/postfix/html/postconf.5.html b/postfix/html/postconf.5.html
index e91f74924..3edff6d40 100644
--- a/postfix/html/postconf.5.html
+++ b/postfix/html/postconf.5.html
@@ -607,6 +607,11 @@ NOTE: if mail to the BCC address bounces it will be returned to
the sender.
+ NOTE: automatic BCC recipients are produced only for new mail.
+To avoid mailer loops, automatic BCC recipients are not generated
+for mail that Postfix forwards internally, nor for mail that Postfix
+generates itself.
+
@@ -4539,6 +4544,11 @@ NOTE: if mail to the BCC address bounces it will be returned to
the sender.
+ NOTE: automatic BCC recipients are produced only for new mail.
+To avoid mailer loops, automatic BCC recipients are not generated
+for mail that Postfix forwards internally, nor for mail that Postfix
+generates itself.
+
Example:
@@ -4948,6 +4958,11 @@ NOTE: if mail to the BCC address bounces it will be returned to
the sender.
+ NOTE: automatic BCC recipients are produced only for new mail.
+To avoid mailer loops, automatic BCC recipients are not generated
+for mail that Postfix forwards internally, nor for mail that Postfix
+generates itself.
+
Example:
diff --git a/postfix/man/man5/postconf.5 b/postfix/man/man5/postconf.5
index a60c2b9b1..c473165cd 100644
--- a/postfix/man/man5/postconf.5
+++ b/postfix/man/man5/postconf.5
@@ -326,6 +326,11 @@ that is received by the Postfix mail system.
.PP
NOTE: if mail to the BCC address bounces it will be returned to
the sender.
+.PP
+NOTE: automatic BCC recipients are produced only for new mail.
+To avoid mailer loops, automatic BCC recipients are not generated
+for mail that Postfix forwards internally, nor for mail that Postfix
+generates itself.
.SH anvil_rate_time_unit (default: 60s)
The time unit over which client connection rates and other rates
are calculated.
@@ -2328,6 +2333,11 @@ run "\fBpostmap /etc/postfix/recipient_bcc\fR".
NOTE: if mail to the BCC address bounces it will be returned to
the sender.
.PP
+NOTE: automatic BCC recipients are produced only for new mail.
+To avoid mailer loops, automatic BCC recipients are not generated
+for mail that Postfix forwards internally, nor for mail that Postfix
+generates itself.
+.PP
Example:
.PP
.nf
@@ -2579,6 +2589,11 @@ run "\fBpostmap /etc/postfix/sender_bcc\fR".
NOTE: if mail to the BCC address bounces it will be returned to
the sender.
.PP
+NOTE: automatic BCC recipients are produced only for new mail.
+To avoid mailer loops, automatic BCC recipients are not generated
+for mail that Postfix forwards internally, nor for mail that Postfix
+generates itself.
+.PP
Example:
.PP
.nf
diff --git a/postfix/man/man8/local.8 b/postfix/man/man8/local.8
index a7c20e364..6d56a7727 100644
--- a/postfix/man/man8/local.8
+++ b/postfix/man/man8/local.8
@@ -51,7 +51,7 @@ The \fBforward_path\fR parameter is subject to interpolation of
\fB$user\fR (recipient username), \fB$home\fR (recipient home
directory), \fB$shell\fR (recipient shell), \fB$recipient\fR
(complete recipient address), \fB$extension\fR (recipient address
-extension), \fB$domain\fR (recipient domain), \fBlocal\fR
+extension), \fB$domain\fR (recipient domain), \fB$local\fR
(entire recipient address localpart) and
\fB$recipient_delimiter.\fR The forms \fI${name?value}\fR and
\fI${name:value}\fR expand conditionally to \fIvalue\fR when
@@ -165,7 +165,7 @@ to interpolation of \fB$user\fR (recipient username),
\fB$home\fR (recipient home directory), \fB$shell\fR
(recipient shell), \fB$recipient\fR (complete recipient
address), \fB$extension\fR (recipient address extension),
-\fB$domain\fR (recipient domain), \fBlocal\fR (entire
+\fB$domain\fR (recipient domain), \fB$local\fR (entire
recipient address localpart) and \fB$recipient_delimiter.\fR
The forms \fI${name?value}\fR and \fI${name:value}\fR expand
conditionally to \fIvalue\fR when \fI$name\fR is (is not)
diff --git a/postfix/proto/BACKSCATTER_README.html b/postfix/proto/BACKSCATTER_README.html
index 069bf60e1..258d85fde 100644
--- a/postfix/proto/BACKSCATTER_README.html
+++ b/postfix/proto/BACKSCATTER_README.html
@@ -104,8 +104,9 @@ Received: from porcupine.org ...
- Then I know that this is almost certainly forged mail. Mail
-that is really sent by my systems looks like this:
+ Then I know that this is almost certainly forged mail (almost;
+see next section for the fly in the ointment). Mail that is really
+sent by my systems looks like this:
@@ -125,6 +126,18 @@ Received: from host.example.com (EHLO porcupine.org) ...
+ Another frequent sign of forgery is the Message-ID: header. My
+systems produce a Message-ID: of
+<stuff@hostname.porcupine.org>. The following
+are forgeries, especially the first one:
+
+
+
+Message-ID: <1cb479435d8eb9.2beb1.qmail@porcupine.org>
+Message-ID: <yulszqocfzsficvzzju@porcupine.org>
+
+
+
To block such backscatter I use header_checks and body_checks
patterns like this:
@@ -139,12 +152,16 @@ patterns like this:
reject forged client name in Received: header: $1
/^Received: +from +[^ ]+ +\(([^ ]+ +[he]+lo=|[he]+lo +)(porcupine\.org)\)/
reject forged client name in Received: header: $2
+ /^Message-ID:.*@(porcupine\.org)/
+ reject forged domain name in Message-ID: header: $1
/etc/postfix/body_checks:
/^[> ]*Received: +from +(porcupine\.org) /
reject forged client name in Received: header: $1
/^[> ]*Received: +from +[^ ]+ +\(([^ ]+ +[he]+lo=|[he]+lo +)(porcupine\.org)\)/
reject forged client name in Received: header: $2
+ /^[> ]*Message-ID:.*@(porcupine\.org)/
+ reject forged domain name in Message-ID: header: $1
@@ -213,11 +230,11 @@ and is very easy to stop.
/etc/postfix/header_checks:
/^(From|Return-Path):.*[[:<:]](user@domain\.tld)[[:>:]]/
- reject forged sender address in $1: message header: $2
+ reject forged sender address in $1: header: $2
/etc/postfix/body_checks:
/^[> ]*(From|Return-Path):.*[[:<:]](user@domain\.tld)[[:>:]]/
- reject forged sender address in $1: message header: $2
+ reject forged sender address in $1: header: $2
diff --git a/postfix/proto/postconf.proto b/postfix/proto/postconf.proto
index 80dfd2a39..a71bccf55 100644
--- a/postfix/proto/postconf.proto
+++ b/postfix/proto/postconf.proto
@@ -535,6 +535,11 @@ NOTE: if mail to the BCC address bounces it will be returned to
the sender.
+ NOTE: automatic BCC recipients are produced only for new mail.
+To avoid mailer loops, automatic BCC recipients are not generated
+for mail that Postfix forwards internally, nor for mail that Postfix
+generates itself.
+
%PARAM berkeley_db_create_buffer_size 16777216
@@ -2827,6 +2832,11 @@ NOTE: if mail to the BCC address bounces it will be returned to
the sender.
+ NOTE: automatic BCC recipients are produced only for new mail.
+To avoid mailer loops, automatic BCC recipients are not generated
+for mail that Postfix forwards internally, nor for mail that Postfix
+generates itself.
+
Example:
@@ -3094,6 +3104,11 @@ NOTE: if mail to the BCC address bounces it will be returned to
the sender.
+ NOTE: automatic BCC recipients are produced only for new mail.
+To avoid mailer loops, automatic BCC recipients are not generated
+for mail that Postfix forwards internally, nor for mail that Postfix
+generates itself.
+
Example:
diff --git a/postfix/src/global/mail_version.h b/postfix/src/global/mail_version.h
index 23b742184..0ab9ea1e9 100644
--- a/postfix/src/global/mail_version.h
+++ b/postfix/src/global/mail_version.h
@@ -20,7 +20,7 @@
* Patches change the patchlevel and the release date. Snapshots change the
* release date only.
*/
-#define MAIL_RELEASE_DATE "20040621"
+#define MAIL_RELEASE_DATE "20040628"
#define MAIL_VERSION_NUMBER "2.2"
#define VAR_MAIL_VERSION "mail_version"
diff --git a/postfix/src/local/local.c b/postfix/src/local/local.c
index 4fb88a99d..3cc7dc011 100644
--- a/postfix/src/local/local.c
+++ b/postfix/src/local/local.c
@@ -43,7 +43,7 @@
/* \fB$user\fR (recipient username), \fB$home\fR (recipient home
/* directory), \fB$shell\fR (recipient shell), \fB$recipient\fR
/* (complete recipient address), \fB$extension\fR (recipient address
-/* extension), \fB$domain\fR (recipient domain), \fBlocal\fR
+/* extension), \fB$domain\fR (recipient domain), \fB$local\fR
/* (entire recipient address localpart) and
/* \fB$recipient_delimiter.\fR The forms \fI${name?value}\fR and
/* \fI${name:value}\fR expand conditionally to \fIvalue\fR when
@@ -151,7 +151,7 @@
/* \fB$home\fR (recipient home directory), \fB$shell\fR
/* (recipient shell), \fB$recipient\fR (complete recipient
/* address), \fB$extension\fR (recipient address extension),
-/* \fB$domain\fR (recipient domain), \fBlocal\fR (entire
+/* \fB$domain\fR (recipient domain), \fB$local\fR (entire
/* recipient address localpart) and \fB$recipient_delimiter.\fR
/* The forms \fI${name?value}\fR and \fI${name:value}\fR expand
/* conditionally to \fIvalue\fR when \fI$name\fR is (is not)
diff --git a/postfix/src/local/maildir.c b/postfix/src/local/maildir.c
index e2d20cb42..5d0ab04af 100644
--- a/postfix/src/local/maildir.c
+++ b/postfix/src/local/maildir.c
@@ -41,6 +41,7 @@
#include "sys_defs.h"
#include
+#include
#include
#include
#include
@@ -86,7 +87,9 @@ int deliver_maildir(LOCAL_STATE state, USER_ATTR usr_attr, char *path)
int deliver_status;
int copy_flags;
struct stat st;
- time_t starttime = time((time_t *) 0);
+ struct timeval starttime;
+
+ GETTIMEOFDAY(&starttime);
/*
* Make verbose logging easier to understand.
@@ -166,7 +169,8 @@ int deliver_maildir(LOCAL_STATE state, USER_ATTR usr_attr, char *path)
* filesystem: a maildir has to be within a single UNIX device for link()
* and rename() to work.)
*
- * [...]
+ * Mn, where n is (in decimal) the microsecond counter from the same
+ * gettimeofday() used for the left part of the unique name.
*
* Pn, where n is (in decimal) the process ID.
*
@@ -176,7 +180,7 @@ int deliver_maildir(LOCAL_STATE state, USER_ATTR usr_attr, char *path)
set_eugid(usr_attr.uid, usr_attr.gid);
vstring_sprintf(buf, "%lu.P%d.%s",
- (unsigned long) starttime, var_pid, get_hostname());
+ (unsigned long) starttime.tv_sec, var_pid, get_hostname());
tmpfile = concatenate(tmpdir, STR(buf), (char *) 0);
newfile = 0;
if ((dst = vstream_fopen(tmpfile, O_WRONLY | O_CREAT | O_EXCL, 0600)) == 0
@@ -187,9 +191,12 @@ int deliver_maildir(LOCAL_STATE state, USER_ATTR usr_attr, char *path)
} else if (fstat(vstream_fileno(dst), &st) < 0) {
vstring_sprintf(why, "create %s: %m", tmpfile);
} else {
- vstring_sprintf(buf, "%lu.V%lxI%lx.%s",
- (unsigned long) starttime, (unsigned long) st.st_dev,
- (unsigned long) st.st_ino, get_hostname());
+ vstring_sprintf(buf, "%lu.V%lxI%lxM%lu.%s",
+ (unsigned long) starttime.tv_sec,
+ (unsigned long) st.st_dev,
+ (unsigned long) st.st_ino,
+ (unsigned long) starttime.tv_usec,
+ get_hostname());
newfile = concatenate(newdir, STR(buf), (char *) 0);
if ((mail_copy_status = mail_copy(COPY_ATTR(state.msg_attr),
dst, copy_flags, "\n", why)) == 0) {
diff --git a/postfix/src/oqmgr/qmgr_message.c b/postfix/src/oqmgr/qmgr_message.c
index a722d0908..658d1d74e 100644
--- a/postfix/src/oqmgr/qmgr_message.c
+++ b/postfix/src/oqmgr/qmgr_message.c
@@ -936,10 +936,9 @@ static void qmgr_message_resolve(QMGR_MESSAGE *message)
* agent resources. We use recipient@nexthop as queue name rather
* than the actual recipient domain name, so that one recipient in
* multiple equivalent domains cannot evade the per-recipient
- * concurrency limit. XXX Should split the address on the recipient
- * delimiter if one is defined, but doing a proper job requires
- * knowledge of local aliases. Yuck! I don't want to duplicate
- * delivery-agent specific knowledge in the queue manager.
+ * concurrency limit. Split the address on the recipient delimiter if
+ * one is defined, so that extended addresses don't get extra
+ * delivery slots.
*
* Fold the result to lower case so that we don't have multiple queues
* for the same name.
@@ -947,18 +946,32 @@ static void qmgr_message_resolve(QMGR_MESSAGE *message)
* Important! All recipients in a queue must have the same nexthop
* value. It is OK to have multiple queues with the same nexthop
* value, but only when those queues are named after recipients.
+ *
+ * The single-recipient code below was written for local(8) like
+ * delivery agents, and assumes that all domains that deliver to the
+ * same (transport + nexthop) are aliases for $nexthop. Delivery
+ * concurrency is changed from per-domain into per-recipient, by
+ * changing the queue name from nexthop into localpart@nexthop.
+ *
+ * XXX This assumption is incorrect when different destinations share
+ * the same (transport + nexthop). In reality, such transports are
+ * rarely configured to use single-recipient deliveries. The fix is
+ * to decouple the per-destination recipient limit from the
+ * per-destination concurrency.
*/
vstring_strcpy(queue_name, STR(reply.nexthop));
if (strcmp(transport->name, MAIL_SERVICE_ERROR) != 0
&& transport->recipient_limit == 1) {
+ /* Copy the recipient localpart. */
at = strrchr(STR(reply.recipient), '@');
len = (at ? (at - STR(reply.recipient))
: strlen(STR(reply.recipient)));
- VSTRING_SPACE(queue_name, len + 2);
- memmove(STR(queue_name) + len + 1, STR(queue_name),
- LEN(queue_name) + 1);
- memcpy(STR(queue_name), STR(reply.recipient), len);
- STR(queue_name)[len] = '@';
+ 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))
+ 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));
}
lowercase(STR(queue_name));
diff --git a/postfix/src/qmgr/qmgr_message.c b/postfix/src/qmgr/qmgr_message.c
index 708f48923..724cbd1ab 100644
--- a/postfix/src/qmgr/qmgr_message.c
+++ b/postfix/src/qmgr/qmgr_message.c
@@ -980,10 +980,9 @@ static void qmgr_message_resolve(QMGR_MESSAGE *message)
* agent resources. We use recipient@nexthop as queue name rather
* than the actual recipient domain name, so that one recipient in
* multiple equivalent domains cannot evade the per-recipient
- * concurrency limit. XXX Should split the address on the recipient
- * delimiter if one is defined, but doing a proper job requires
- * knowledge of local aliases. Yuck! I don't want to duplicate
- * delivery-agent specific knowledge in the queue manager.
+ * concurrency limit. Split the address on the recipient delimiter if
+ * one is defined, so that extended addresses don't get extra
+ * delivery slots.
*
* Fold the result to lower case so that we don't have multiple queues
* for the same name.
@@ -991,18 +990,32 @@ static void qmgr_message_resolve(QMGR_MESSAGE *message)
* Important! All recipients in a queue must have the same nexthop
* value. It is OK to have multiple queues with the same nexthop
* value, but only when those queues are named after recipients.
+ *
+ * The single-recipient code below was written for local(8) like
+ * delivery agents, and assumes that all domains that deliver to the
+ * same (transport + nexthop) are aliases for $nexthop. Delivery
+ * concurrency is changed from per-domain into per-recipient, by
+ * changing the queue name from nexthop into localpart@nexthop.
+ *
+ * XXX This assumption is incorrect when different destinations share
+ * the same (transport + nexthop). In reality, such transports are
+ * rarely configured to use single-recipient deliveries. The fix is
+ * to decouple the per-destination recipient limit from the
+ * per-destination concurrency.
*/
vstring_strcpy(queue_name, STR(reply.nexthop));
if (strcmp(transport->name, MAIL_SERVICE_ERROR) != 0
&& transport->recipient_limit == 1) {
+ /* Copy the recipient localpart. */
at = strrchr(STR(reply.recipient), '@');
len = (at ? (at - STR(reply.recipient))
: strlen(STR(reply.recipient)));
- VSTRING_SPACE(queue_name, len + 2);
- memmove(STR(queue_name) + len + 1, STR(queue_name),
- LEN(queue_name) + 1);
- memcpy(STR(queue_name), STR(reply.recipient), len);
- STR(queue_name)[len] = '@';
+ 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))
+ 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));
}
lowercase(STR(queue_name));
diff --git a/postfix/src/virtual/maildir.c b/postfix/src/virtual/maildir.c
index c51a4e7c5..b7f46bddd 100644
--- a/postfix/src/virtual/maildir.c
+++ b/postfix/src/virtual/maildir.c
@@ -36,6 +36,8 @@
#include "sys_defs.h"
#include
+#include
+#include
#include
#include
@@ -84,7 +86,9 @@ int deliver_maildir(LOCAL_STATE state, USER_ATTR usr_attr)
int deliver_status;
int copy_flags;
struct stat st;
- time_t starttime = time((time_t *) 0);
+ struct timeval starttime;
+
+ GETTIMEOFDAY(&starttime);
/*
* Make verbose logging easier to understand.
@@ -163,7 +167,8 @@ int deliver_maildir(LOCAL_STATE state, USER_ATTR usr_attr)
* filesystem: a maildir has to be within a single UNIX device for link()
* and rename() to work.)
*
- * [...]
+ * Mn, where n is (in decimal) the microsecond counter from the same
+ * gettimeofday() used for the left part of the unique name.
*
* Pn, where n is (in decimal) the process ID.
*
@@ -173,7 +178,7 @@ int deliver_maildir(LOCAL_STATE state, USER_ATTR usr_attr)
set_eugid(usr_attr.uid, usr_attr.gid);
vstring_sprintf(buf, "%lu.P%d.%s",
- (unsigned long) starttime, var_pid, get_hostname());
+ (unsigned long) starttime.tv_sec, var_pid, get_hostname());
tmpfile = concatenate(tmpdir, STR(buf), (char *) 0);
newfile = 0;
if ((dst = vstream_fopen(tmpfile, O_WRONLY | O_CREAT | O_EXCL, 0600)) == 0
@@ -184,9 +189,12 @@ int deliver_maildir(LOCAL_STATE state, USER_ATTR usr_attr)
} else if (fstat(vstream_fileno(dst), &st) < 0) {
vstring_sprintf(why, "create %s: %m", tmpfile);
} else {
- vstring_sprintf(buf, "%lu.V%lxI%lx.%s",
- (unsigned long) starttime, (unsigned long) st.st_dev,
- (unsigned long) st.st_ino, get_hostname());
+ vstring_sprintf(buf, "%lu.V%lxI%lxM%lu.%s",
+ (unsigned long) starttime.tv_sec,
+ (unsigned long) st.st_dev,
+ (unsigned long) st.st_ino,
+ (unsigned long) starttime.tv_usec,
+ get_hostname());
newfile = concatenate(newdir, STR(buf), (char *) 0);
if ((mail_copy_status = mail_copy(COPY_ATTR(state.msg_attr),
dst, copy_flags, "\n", why)) == 0) {