2
0
mirror of https://github.com/vdukhovni/postfix synced 2025-08-28 20:57:56 +00:00

postfix-2.11-20130405

This commit is contained in:
Wietse Venema 2013-04-05 00:00:00 -05:00 committed by Viktor Dukhovni
parent 46a1d9a44f
commit 030e4ddd54
34 changed files with 278 additions and 86 deletions

View File

@ -18410,3 +18410,24 @@ Apologies for any names omitted.
Documentation: in smtpd.c, the comment that justifies the Documentation: in smtpd.c, the comment that justifies the
454 reply for "TLS unavailable" cited the wrong RFC. 454 reply for "TLS unavailable" cited the wrong RFC.
20130404
Human factors: warning when a main.cf parameter has multiple
entries with different values. File: util/dict.c.
20130405
Feature: the recipient_delimiter parameter can now specify
a set of characters. A user name is now separated from its
address extension by the first character that matches the
recipient_delimiter set. Files: proto/postconf.proto,
src/global/mail_addr_find.c, src/global/mail_params.c,
src/global/split_addr.c, src/global/split_addr.h,
src/global/strip_addr.c, src/global/strip_addr.h,
src/global/strip_addr.ref, src/local/bounce_workaround.c,
src/local/local.c, src/local/local_expand.c, src/local/recipient.c,
src/local/resolve.c, src/oqmgr/qmgr_message.c, src/pipe/pipe.c,
src/qmgr/qmgr_message.c, src/smtpd/smtpd.c,
src/smtpd/smtpd_check.c, src/trivial-rewrite/transport.c,
src/trivial-rewrite/trivial-rewrite.c.

View File

@ -14,6 +14,19 @@ specifies the release date of a stable release or snapshot release.
If you upgrade from Postfix 2.9 or earlier, read RELEASE_NOTES-2.10 If you upgrade from Postfix 2.9 or earlier, read RELEASE_NOTES-2.10
before proceeding. before proceeding.
Major changes with snapshot 20130405
====================================
The recipient_delimiter parameter can now specify a set of characters.
A user name is now separated from its address extension by the first
character that matches the recipient_delimiter set.
For example, specify "recipient_delimiter = +-" to support both the
Postfix-style "+" and the qmail-style "-" extension delimiter.
As before, this implementation recognizes one delimiter character
per email address, and one address extension per email address.
Major changes with snapshot 20130319 Major changes with snapshot 20130319
==================================== ====================================

View File

@ -608,8 +608,8 @@ LOCAL(8) LOCAL(8)
tory. tory.
<b><a href="postconf.5.html#recipient_delimiter">recipient_delimiter</a> (empty)</b> <b><a href="postconf.5.html#recipient_delimiter">recipient_delimiter</a> (empty)</b>
The separator between user names and address exten- The set of characters that can separate a user name
sions (user+foo). from its address extension (user+foo).
<b><a href="postconf.5.html#require_home_directory">require_home_directory</a> (no)</b> <b><a href="postconf.5.html#require_home_directory">require_home_directory</a> (no)</b>
Require that a <a href="local.8.html"><b>local</b>(8)</a> recipient's home directory Require that a <a href="local.8.html"><b>local</b>(8)</a> recipient's home directory

View File

@ -481,8 +481,8 @@ PIPE(8) PIPE(8)
tory. tory.
<b><a href="postconf.5.html#recipient_delimiter">recipient_delimiter</a> (empty)</b> <b><a href="postconf.5.html#recipient_delimiter">recipient_delimiter</a> (empty)</b>
The separator between user names and address exten- The set of characters that can separate a user name
sions (user+foo). from its address extension (user+foo).
<b><a href="postconf.5.html#syslog_facility">syslog_facility</a> (mail)</b> <b><a href="postconf.5.html#syslog_facility">syslog_facility</a> (mail)</b>
The syslog facility of Postfix logging. The syslog facility of Postfix logging.

View File

@ -1451,7 +1451,9 @@ with the character set that is specified with the
<dt><b>$<a href="postconf.5.html#recipient_delimiter">recipient_delimiter</a></b></dt> <dt><b>$<a href="postconf.5.html#recipient_delimiter">recipient_delimiter</a></b></dt>
<dd>The system-wide recipient address extension delimiter. </dd> <dd>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). </dd>
<dt><b>${name?value}</b></dt> <dt><b>${name?value}</b></dt>
@ -3254,7 +3256,9 @@ filtered with the character set that is specified with the
<dt><b>$<a href="postconf.5.html#recipient_delimiter">recipient_delimiter</a></b></dt> <dt><b>$<a href="postconf.5.html#recipient_delimiter">recipient_delimiter</a></b></dt>
<dd>The system-wide recipient address extension delimiter. </dd> <dd>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). </dd>
<dt><b>${name?value}</b></dt> <dt><b>${name?value}</b></dt>
@ -5308,7 +5312,9 @@ The following $name expansions are done on <a href="postconf.5.html#luser_relay"
<dt><b>$<a href="postconf.5.html#recipient_delimiter">recipient_delimiter</a></b></dt> <dt><b>$<a href="postconf.5.html#recipient_delimiter">recipient_delimiter</a></b></dt>
<dd>The system-wide recipient address extension delimiter. </dd> <dd>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). </dd>
<dt><b>$shell</b></dt> <dt><b>$shell</b></dt>
@ -8498,22 +8504,53 @@ Example:
<DT><b><a name="recipient_delimiter">recipient_delimiter</a> <DT><b><a name="recipient_delimiter">recipient_delimiter</a>
(default: empty)</b></DT><DD> (default: empty)</b></DT><DD>
<p> <p> The set of characters that can separate a user name from its
The separator between user names and address extensions (user+foo). address extension (user+foo). See <a href="canonical.5.html">canonical(5)</a>, <a href="local.8.html">local(8)</a>, <a href="relocated.5.html">relocated(5)</a>
See <a href="canonical.5.html">canonical(5)</a>, <a href="local.8.html">local(8)</a>, <a href="relocated.5.html">relocated(5)</a> and <a href="virtual.5.html">virtual(5)</a> for the and <a href="virtual.5.html">virtual(5)</a> for the effects this has on aliases, canonical,
effects this has on aliases, canonical, virtual, relocated and virtual, and relocated lookups. Basically, the software tries
on .forward file lookups. Basically, the software tries user+foo user+foo and .forward+foo before trying user and .forward. </p>
and .forward+foo before trying user and .forward.
<p> This implementation recognizes one delimiter character per email
address, and one address extension per email address. </p>
<p> When the <a href="postconf.5.html#recipient_delimiter">recipient_delimiter</a> 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 <a href="postconf.5.html#recipient_delimiter">recipient_delimiter</a>
set. </p>
<p> When used in <a href="postconf.5.html#forward_path">forward_path</a>, ${<a href="postconf.5.html#recipient_delimiter">recipient_delimiter</a>} 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 <a href="postconf.5.html">main.cf</a>
<a href="postconf.5.html#recipient_delimiter">recipient_delimiter</a> parameter value (Postfix 2.10 and earlier).
</p> </p>
<p> The <a href="postconf.5.html#recipient_delimiter">recipient_delimiter</a> is not applied to the mailer-daemon
address, the postmaster address, or the double-bounce address. With
the default "<a href="postconf.5.html#owner_request_special">owner_request_special</a> = yes" setting, the <a href="postconf.5.html#recipient_delimiter">recipient_delimiter</a>
is also not applied to addresses with the special "owner-" prefix
or the special "-request" suffix. </p>
<p> <p>
Example: Examples:
</p> </p>
<pre> <pre>
# Handle Postfix-style extensions.
<a href="postconf.5.html#recipient_delimiter">recipient_delimiter</a> = + <a href="postconf.5.html#recipient_delimiter">recipient_delimiter</a> = +
</pre> </pre>
<pre>
# Handle both Postfix and qmail extensions (Postfix 2.11 and later).
recipient_delimiters = +-
</pre>
<pre>
# Use .forward for mail without address extension, and for mail with
# an unrecognized address extension.
<a href="postconf.5.html#forward_path">forward_path</a> = $home/.forward${<a href="postconf.5.html#recipient_delimiter">recipient_delimiter</a>}${extension},
$home/.forward,
</pre>
</DD> </DD>

View File

@ -1293,8 +1293,8 @@ SMTPD(8) SMTPD(8)
tory. tory.
<b><a href="postconf.5.html#recipient_delimiter">recipient_delimiter</a> (empty)</b> <b><a href="postconf.5.html#recipient_delimiter">recipient_delimiter</a> (empty)</b>
The separator between user names and address exten- The set of characters that can separate a user name
sions (user+foo). from its address extension (user+foo).
<b><a href="postconf.5.html#smtpd_banner">smtpd_banner</a> ($<a href="postconf.5.html#myhostname">myhostname</a> ESMTP $<a href="postconf.5.html#mail_name">mail_name</a>)</b> <b><a href="postconf.5.html#smtpd_banner">smtpd_banner</a> ($<a href="postconf.5.html#myhostname">myhostname</a> ESMTP $<a href="postconf.5.html#mail_name">mail_name</a>)</b>
The text that follows the 220 status code in the The text that follows the 220 status code in the

View File

@ -133,8 +133,8 @@ TRIVIAL-REWRITE(8) TRIVIAL-REWRITE(8)
information. information.
<b><a href="postconf.5.html#recipient_delimiter">recipient_delimiter</a> (empty)</b> <b><a href="postconf.5.html#recipient_delimiter">recipient_delimiter</a> (empty)</b>
The separator between user names and address exten- The set of characters that can separate a user name
sions (user+foo). from its address extension (user+foo).
<b><a href="postconf.5.html#swap_bangpath">swap_bangpath</a> (yes)</b> <b><a href="postconf.5.html#swap_bangpath">swap_bangpath</a> (yes)</b>
Enable the rewriting of "site!user" into Enable the rewriting of "site!user" into

View File

@ -835,7 +835,9 @@ The recipient domain.
The entire recipient localpart. The entire recipient localpart.
.br .br
.IP "\fB$recipient_delimiter\fR" .IP "\fB$recipient_delimiter\fR"
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).
.br .br
.IP "\fB${name?value}\fR" .IP "\fB${name?value}\fR"
Expands to \fIvalue\fR when \fI$name\fR is non-empty. Expands to \fIvalue\fR when \fI$name\fR is non-empty.
@ -1919,7 +1921,9 @@ The recipient domain.
The entire recipient localpart. The entire recipient localpart.
.br .br
.IP "\fB$recipient_delimiter\fR" .IP "\fB$recipient_delimiter\fR"
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).
.br .br
.IP "\fB${name?value}\fR" .IP "\fB${name?value}\fR"
Expands to \fIvalue\fR when \fI$name\fR is non-empty. Expands to \fIvalue\fR when \fI$name\fR is non-empty.
@ -3068,7 +3072,9 @@ The entire recipient address localpart.
The full recipient address. The full recipient address.
.br .br
.IP "\fB$recipient_delimiter\fR" .IP "\fB$recipient_delimiter\fR"
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).
.br .br
.IP "\fB$shell\fR" .IP "\fB$shell\fR"
The recipient's login shell. The recipient's login shell.
@ -5095,21 +5101,61 @@ recipient_canonical_maps = hash:/etc/postfix/recipient_canonical
.ad .ad
.ft R .ft R
.SH recipient_delimiter (default: empty) .SH recipient_delimiter (default: empty)
The separator between user names and address extensions (user+foo). The set of characters that can separate a user name from its
See \fBcanonical\fR(5), \fBlocal\fR(8), \fBrelocated\fR(5) and \fBvirtual\fR(5) for the address extension (user+foo). See \fBcanonical\fR(5), \fBlocal\fR(8), \fBrelocated\fR(5)
effects this has on aliases, canonical, virtual, relocated and and \fBvirtual\fR(5) for the effects this has on aliases, canonical,
on .forward file lookups. Basically, the software tries user+foo virtual, and relocated lookups. Basically, the software tries
and .forward+foo before trying user and .forward. user+foo and .forward+foo before trying user and .forward.
.PP .PP
Example: This implementation recognizes one delimiter character per email
address, and one address extension per email address.
.PP
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.
.PP
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).
.PP
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.
.PP
Examples:
.PP .PP
.nf .nf
.na .na
.ft C .ft C
# Handle Postfix-style extensions.
recipient_delimiter = + recipient_delimiter = +
.fi .fi
.ad .ad
.ft R .ft R
.PP
.nf
.na
.ft C
# Handle both Postfix and qmail extensions (Postfix 2.11 and later).
recipient_delimiters = +-
.fi
.ad
.ft R
.PP
.nf
.na
.ft C
# Use .forward for mail without address extension, and for mail with
# an unrecognized address extension.
forward_path = $home/.forward${recipient_delimiter}${extension},
$home/.forward,
.fi
.ad
.ft R
.SH reject_code (default: 554) .SH reject_code (default: 554)
The numerical Postfix SMTP server response code when a remote SMTP The numerical Postfix SMTP server response code when a remote SMTP
client request is rejected by the "reject" restriction. client request is rejected by the "reject" restriction.

View File

@ -575,7 +575,8 @@ key to the lookup result.
.IP "\fBqueue_directory (see 'postconf -d' output)\fR" .IP "\fBqueue_directory (see 'postconf -d' output)\fR"
The location of the Postfix top-level queue directory. The location of the Postfix top-level queue directory.
.IP "\fBrecipient_delimiter (empty)\fR" .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" .IP "\fBrequire_home_directory (no)\fR"
Require that a \fBlocal\fR(8) recipient's home directory exists Require that a \fBlocal\fR(8) recipient's home directory exists
before mail delivery is attempted. before mail delivery is attempted.

View File

@ -412,7 +412,8 @@ The process name of a Postfix command or daemon process.
.IP "\fBqueue_directory (see 'postconf -d' output)\fR" .IP "\fBqueue_directory (see 'postconf -d' output)\fR"
The location of the Postfix top-level queue directory. The location of the Postfix top-level queue directory.
.IP "\fBrecipient_delimiter (empty)\fR" .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" .IP "\fBsyslog_facility (mail)\fR"
The syslog facility of Postfix logging. The syslog facility of Postfix logging.
.IP "\fBsyslog_name (see 'postconf -d' output)\fR" .IP "\fBsyslog_name (see 'postconf -d' output)\fR"

View File

@ -1012,7 +1012,8 @@ The process name of a Postfix command or daemon process.
.IP "\fBqueue_directory (see 'postconf -d' output)\fR" .IP "\fBqueue_directory (see 'postconf -d' output)\fR"
The location of the Postfix top-level queue directory. The location of the Postfix top-level queue directory.
.IP "\fBrecipient_delimiter (empty)\fR" .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" .IP "\fBsmtpd_banner ($myhostname ESMTP $mail_name)\fR"
The text that follows the 220 status code in the SMTP greeting The text that follows the 220 status code in the SMTP greeting
banner. banner.

View File

@ -130,7 +130,8 @@ addresses without domain information.
With locally submitted mail, append the string ".$mydomain" to With locally submitted mail, append the string ".$mydomain" to
addresses that have no ".domain" information. addresses that have no ".domain" information.
.IP "\fBrecipient_delimiter (empty)\fR" .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" .IP "\fBswap_bangpath (yes)\fR"
Enable the rewriting of "site!user" into "user@site". Enable the rewriting of "site!user" into "user@site".
.PP .PP

View File

@ -1609,7 +1609,9 @@ execution_directory_expansion_filter parameter. </p>
<dt><b>$recipient_delimiter</b></dt> <dt><b>$recipient_delimiter</b></dt>
<dd>The system-wide recipient address extension delimiter. </dd> <dd>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). </dd>
<dt><b>${name?value}</b></dt> <dt><b>${name?value}</b></dt>
@ -1670,7 +1672,9 @@ forward_expansion_filter parameter. </p>
<dt><b>$recipient_delimiter</b></dt> <dt><b>$recipient_delimiter</b></dt>
<dd>The system-wide recipient address extension delimiter. </dd> <dd>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). </dd>
<dt><b>${name?value}</b></dt> <dt><b>${name?value}</b></dt>
@ -2404,7 +2408,9 @@ The following $name expansions are done on luser_relay:
<dt><b>$recipient_delimiter</b></dt> <dt><b>$recipient_delimiter</b></dt>
<dd>The system-wide recipient address extension delimiter. </dd> <dd>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). </dd>
<dt><b>$shell</b></dt> <dt><b>$shell</b></dt>
@ -3497,22 +3503,53 @@ recipient_canonical_maps = hash:/etc/postfix/recipient_canonical
%PARAM recipient_delimiter %PARAM recipient_delimiter
<p> <p> The set of characters that can separate a user name from its
The separator between user names and address extensions (user+foo). address extension (user+foo). See canonical(5), local(8), relocated(5)
See canonical(5), local(8), relocated(5) and virtual(5) for the and virtual(5) for the effects this has on aliases, canonical,
effects this has on aliases, canonical, virtual, relocated and virtual, and relocated lookups. Basically, the software tries
on .forward file lookups. Basically, the software tries user+foo user+foo and .forward+foo before trying user and .forward. </p>
and .forward+foo before trying user and .forward.
<p> This implementation recognizes one delimiter character per email
address, and one address extension per email address. </p>
<p> 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. </p>
<p> 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).
</p> </p>
<p> 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. </p>
<p> <p>
Example: Examples:
</p> </p>
<pre> <pre>
# Handle Postfix-style extensions.
recipient_delimiter = + recipient_delimiter = +
</pre> </pre>
<pre>
# Handle both Postfix and qmail extensions (Postfix 2.11 and later).
recipient_delimiters = +-
</pre>
<pre>
# Use .forward for mail without address extension, and for mail with
# an unrecognized address extension.
forward_path = $home/.forward${recipient_delimiter}${extension},
$home/.forward,
</pre>
%PARAM reject_code 554 %PARAM reject_code 554
<p> <p>

View File

@ -109,7 +109,7 @@ const char *mail_addr_find(MAPS *path, const char *address, char **extp)
if (*var_rcpt_delim == 0) { if (*var_rcpt_delim == 0) {
bare_key = saved_ext = 0; bare_key = saved_ext = 0;
} else { } else {
bare_key = strip_addr(full_key, &saved_ext, *var_rcpt_delim); bare_key = strip_addr(full_key, &saved_ext, var_rcpt_delim);
} }
/* /*

View File

@ -557,7 +557,7 @@ void mail_params_init()
VAR_MAIL_VERSION, DEF_MAIL_VERSION, &var_mail_version, 1, 0, VAR_MAIL_VERSION, DEF_MAIL_VERSION, &var_mail_version, 1, 0,
VAR_DB_TYPE, DEF_DB_TYPE, &var_db_type, 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_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_RELAY_DOMAINS, DEF_RELAY_DOMAINS, &var_relay_domains, 0, 0,
VAR_FFLUSH_DOMAINS, DEF_FFLUSH_DOMAINS, &var_fflush_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, VAR_EXPORT_ENVIRON, DEF_EXPORT_ENVIRON, &var_export_environ, 0, 0,

View File

@ -20,7 +20,7 @@
* Patches change both the patchlevel and the release date. Snapshots have no * Patches change both the patchlevel and the release date. Snapshots have no
* patchlevel; they change the release date only. * patchlevel; they change the release date only.
*/ */
#define MAIL_RELEASE_DATE "20130403" #define MAIL_RELEASE_DATE "20130405"
#define MAIL_VERSION_NUMBER "2.11" #define MAIL_VERSION_NUMBER "2.11"
#ifdef SNAPSHOT #ifdef SNAPSHOT

View File

@ -6,12 +6,12 @@
/* SYNOPSIS /* SYNOPSIS
/* #include <split_addr.h> /* #include <split_addr.h>
/* /*
/* char *split_addr(localpart, delimiter) /* char *split_addr(localpart, delimiter_set)
/* char *localpart; /* char *localpart;
/* int delimiter; /* const char *delimiter_set;
/* DESCRIPTION /* DESCRIPTION
/* split_addr() null-terminates \fIlocalpart\fR at the first /* 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. /* returns a pointer to the remainder.
/* /*
/* Reserved addresses are not split: postmaster, mailer-daemon, /* Reserved addresses are not split: postmaster, mailer-daemon,
@ -50,7 +50,7 @@
/* split_addr - split address with extreme prejudice */ /* 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; int len;
@ -67,7 +67,7 @@ char *split_addr(char *localpart, int delimiter)
/* /*
* Backwards compatibility: don't split owner-foo or foo-request. * 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) if (strncasecmp(localpart, "owner-", 6) == 0)
return (0); return (0);
if ((len = strlen(localpart) - 8) > 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 * Safe to split this address. Do not split the address if the result
* would have a null localpart. * 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);
}
} }

View File

@ -13,7 +13,7 @@
/* External interface. */ /* External interface. */
extern char *split_addr(char *, int); extern char *split_addr(char *, const char *);
/* LICENSE /* LICENSE
/* .ad /* .ad

View File

@ -6,10 +6,10 @@
/* SYNOPSIS /* SYNOPSIS
/* #include <strip_addr.h> /* #include <strip_addr.h>
/* /*
/* char *strip_addr(address, extension, delimiter) /* char *strip_addr(address, extension, delimiter_set)
/* const char *address; /* const char *address;
/* char **extension; /* char **extension;
/* int delimiter; /* const char *delimiter_set;
/* DESCRIPTION /* DESCRIPTION
/* strip_addr() takes an address and either returns a null /* strip_addr() takes an address and either returns a null
/* pointer when the address contains no address extension, /* pointer when the address contains no address extension,
@ -25,8 +25,8 @@
/* that had to be chopped off. /* that had to be chopped off.
/* The copy includes the recipient address delimiter. /* The copy includes the recipient address delimiter.
/* The caller is expected to pass the copy to myfree(). /* The caller is expected to pass the copy to myfree().
/* .IP delimiter /* .IP delimiter_set
/* Recipient address delimiter. /* Set of recipient address delimiter characters.
/* SEE ALSO /* SEE ALSO
/* split_addr(3) strip extension from localpart /* split_addr(3) strip extension from localpart
/* LICENSE /* LICENSE
@ -56,7 +56,7 @@
/* strip_addr - strip extension from address */ /* 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 *ratsign;
char *extent; 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. * 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; stripped = saved_ext = 0;
} else { } else {
stripped = mystrdup(full); stripped = mystrdup(full);
if ((ratsign = strrchr(stripped, '@')) != 0) if ((ratsign = strrchr(stripped, '@')) != 0)
*ratsign = 0; *ratsign = 0;
if ((extent = split_addr(stripped, delimiter)) != 0) { if ((extent = split_addr(stripped, delimiter_set)) != 0) {
extent -= 1; extent -= 1;
if (extension) { if (extension) {
*extent = delimiter; *extent = full[strlen(stripped)];
saved_ext = mystrdup(extent); saved_ext = mystrdup(extent);
*extent = 0; *extent = 0;
} else } else
@ -105,17 +105,19 @@ int main(int unused_argc, char **unused_argv)
{ {
char *extension; char *extension;
char *stripped; char *stripped;
int delim = '-'; char* delim = "+-";
#define NO_DELIM ""
/* /*
* Incredible. This function takes only three arguments, and the tests * Incredible. This function takes only three arguments, and the tests
* already take more lines of code than the code being tested. * 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) if (stripped != 0)
msg_panic("strip_addr botch 1"); msg_panic("strip_addr botch 1");
stripped = strip_addr("foo", &extension, 0); stripped = strip_addr("foo", &extension, NO_DELIM);
if (stripped != 0) if (stripped != 0)
msg_panic("strip_addr botch 2"); msg_panic("strip_addr botch 2");
if (extension != 0) if (extension != 0)
@ -131,11 +133,11 @@ int main(int unused_argc, char **unused_argv)
if (extension != 0) if (extension != 0)
msg_panic("strip_addr botch 6"); 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) if (stripped != 0)
msg_panic("strip_addr botch 7"); msg_panic("strip_addr botch 7");
stripped = strip_addr("foo@bar", &extension, 0); stripped = strip_addr("foo@bar", &extension, NO_DELIM);
if (stripped != 0) if (stripped != 0)
msg_panic("strip_addr botch 8"); msg_panic("strip_addr botch 8");
if (extension != 0) if (extension != 0)
@ -151,11 +153,11 @@ int main(int unused_argc, char **unused_argv)
if (extension != 0) if (extension != 0)
msg_panic("strip_addr botch 12"); 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) if (stripped != 0)
msg_panic("strip_addr botch 13"); msg_panic("strip_addr botch 13");
stripped = strip_addr("foo-ext", &extension, 0); stripped = strip_addr("foo-ext", &extension, NO_DELIM);
if (stripped != 0) if (stripped != 0)
msg_panic("strip_addr botch 14"); msg_panic("strip_addr botch 14");
if (extension != 0) if (extension != 0)
@ -178,11 +180,11 @@ int main(int unused_argc, char **unused_argv)
myfree(stripped); myfree(stripped);
myfree(extension); myfree(extension);
stripped = strip_addr("foo-ext@bar", (char **) 0, 0); stripped = strip_addr("foo-ext@bar", (char **) 0, NO_DELIM);
if (stripped != 0) if (stripped != 0)
msg_panic("strip_addr botch 19"); 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) if (stripped != 0)
msg_panic("strip_addr botch 20"); msg_panic("strip_addr botch 20");
if (extension != 0) if (extension != 0)
@ -205,6 +207,16 @@ int main(int unused_argc, char **unused_argv)
myfree(stripped); myfree(stripped);
myfree(extension); 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); return (0);
} }

View File

@ -13,7 +13,7 @@
/* External interface. */ /* External interface. */
extern char *strip_addr(const char *, char **, int); extern char *strip_addr(const char *, char **, const char *);
/* LICENSE /* LICENSE
/* .ad /* .ad

View File

@ -6,3 +6,5 @@ unknown: wanted: foo-ext@bar -> foo@bar
unknown: strip_addr foo-ext@bar -> foo@bar unknown: strip_addr foo-ext@bar -> foo@bar
unknown: wanted: foo-ext@bar -> foo@bar -ext unknown: wanted: foo-ext@bar -> foo@bar -ext
unknown: strip_addr 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

View File

@ -109,7 +109,7 @@ int bounce_workaround(LOCAL_STATE state)
if (alias_maps->error == 0 && owner_expansion == 0 if (alias_maps->error == 0 && owner_expansion == 0
&& (stripped_recipient = strip_addr(state.msg_attr.rcpt.address, && (stripped_recipient = strip_addr(state.msg_attr.rcpt.address,
(char **) 0, (char **) 0,
*var_rcpt_delim)) != 0) { var_rcpt_delim)) != 0) {
myfree(owner_alias); myfree(owner_alias);
FIND_OWNER(owner_alias, owner_expansion, stripped_recipient); FIND_OWNER(owner_alias, owner_expansion, stripped_recipient);
myfree(stripped_recipient); myfree(stripped_recipient);

View File

@ -531,7 +531,8 @@
/* .IP "\fBqueue_directory (see 'postconf -d' output)\fR" /* .IP "\fBqueue_directory (see 'postconf -d' output)\fR"
/* The location of the Postfix top-level queue directory. /* The location of the Postfix top-level queue directory.
/* .IP "\fBrecipient_delimiter (empty)\fR" /* .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" /* .IP "\fBrequire_home_directory (no)\fR"
/* Require that a \fBlocal\fR(8) recipient's home directory exists /* Require that a \fBlocal\fR(8) recipient's home directory exists
/* before mail delivery is attempted. /* before mail delivery is attempted.

View File

@ -113,6 +113,7 @@ typedef struct {
static const char *local_expand_lookup(const char *name, int mode, char *ptr) static const char *local_expand_lookup(const char *name, int mode, char *ptr)
{ {
LOCAL_EXP *local = (LOCAL_EXP *) ptr; LOCAL_EXP *local = (LOCAL_EXP *) ptr;
static char rcpt_delim[2];
#define STREQ(x,y) (*(x) == *(y) && strcmp((x), (y)) == 0) #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; local->status |= LOCAL_EXP_EXTENSION_MATCHED;
return (local->state->msg_attr.extension); return (local->state->msg_attr.extension);
} else if (STREQ(name, "recipient_delimiter")) { } 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 #if 0
} else if (STREQ(name, "client_hostname")) { } else if (STREQ(name, "client_hostname")) {
return (local->state->msg_attr.request->client_name); return (local->state->msg_attr.request->client_name);

View File

@ -270,7 +270,7 @@ int deliver_recipient(LOCAL_STATE state, USER_ATTR usr_attr)
state.msg_attr.user = mystrdup(state.msg_attr.local); state.msg_attr.user = mystrdup(state.msg_attr.local);
if (*var_rcpt_delim) { if (*var_rcpt_delim) {
state.msg_attr.extension = 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, '/')) { if (state.msg_attr.extension && strchr(state.msg_attr.extension, '/')) {
msg_warn("%s: address with illegal extension: %s", msg_warn("%s: address with illegal extension: %s",
state.msg_attr.queue_id, state.msg_attr.local); state.msg_attr.queue_id, state.msg_attr.local);

View File

@ -90,6 +90,7 @@ int deliver_resolve_tree(LOCAL_STATE state, USER_ATTR usr_attr, TOK822 *addr
int status; int status;
ssize_t ext_len; ssize_t ext_len;
char *ratsign; char *ratsign;
int rcpt_delim;
/* /*
* Make verbose logging easier to understand. * 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. * Splice in the optional unmatched address extension.
*/ */
if (state.msg_attr.unmatched) { if (state.msg_attr.unmatched) {
rcpt_delim = state.msg_attr.local[strlen(state.msg_attr.user)];
if ((ratsign = strrchr(STR(reply.recipient), '@')) == 0) { 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); vstring_strcat(reply.recipient, state.msg_attr.unmatched);
} else { } else {
ext_len = strlen(state.msg_attr.unmatched); 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) if ((ratsign = strrchr(STR(reply.recipient), '@')) == 0)
msg_panic("%s: recipient @ botch", myname); msg_panic("%s: recipient @ botch", myname);
memmove(ratsign + ext_len + 1, ratsign, strlen(ratsign) + 1); 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); memcpy(ratsign + 1, state.msg_attr.unmatched, ext_len);
VSTRING_SKIP(reply.recipient); VSTRING_SKIP(reply.recipient);
} }

View File

@ -1175,7 +1175,7 @@ static void qmgr_message_resolve(QMGR_MESSAGE *message)
: strlen(STR(reply.recipient))); : strlen(STR(reply.recipient)));
vstring_strncpy(queue_name, STR(reply.recipient), len); vstring_strncpy(queue_name, STR(reply.recipient), len);
/* Remove the address extension from the recipient localpart. */ /* 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))); vstring_truncate(queue_name, strlen(STR(queue_name)));
/* Assume the recipient domain is equivalent to nexthop. */ /* Assume the recipient domain is equivalent to nexthop. */
vstring_sprintf_append(queue_name, "@%s", STR(reply.nexthop)); vstring_sprintf_append(queue_name, "@%s", STR(reply.nexthop));

View File

@ -390,7 +390,8 @@
/* .IP "\fBqueue_directory (see 'postconf -d' output)\fR" /* .IP "\fBqueue_directory (see 'postconf -d' output)\fR"
/* The location of the Postfix top-level queue directory. /* The location of the Postfix top-level queue directory.
/* .IP "\fBrecipient_delimiter (empty)\fR" /* .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" /* .IP "\fBsyslog_facility (mail)\fR"
/* The syslog facility of Postfix logging. /* The syslog facility of Postfix logging.
/* .IP "\fBsyslog_name (see 'postconf -d' output)\fR" /* .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", msg_warn("no @ in recipient address: %s",
rcpt_list->info[i].address); rcpt_list->info[i].address);
if (*var_rcpt_delim) if (*var_rcpt_delim)
split_addr(STR(buf), *var_rcpt_delim); split_addr(STR(buf), var_rcpt_delim);
if (*STR(buf) == 0) if (*STR(buf) == 0)
continue; continue;
dict_update(PIPE_DICT_TABLE, PIPE_DICT_USER, STR(buf)); 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", msg_warn("no @ in recipient address: %s",
rcpt_list->info[i].address); rcpt_list->info[i].address);
if (*var_rcpt_delim == 0 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 */ ext = ""; /* insert null arg */
dict_update(PIPE_DICT_TABLE, PIPE_DICT_EXTENSION, ext); dict_update(PIPE_DICT_TABLE, PIPE_DICT_EXTENSION, ext);
} }

View File

@ -1234,7 +1234,7 @@ static void qmgr_message_resolve(QMGR_MESSAGE *message)
: strlen(STR(reply.recipient))); : strlen(STR(reply.recipient)));
vstring_strncpy(queue_name, STR(reply.recipient), len); vstring_strncpy(queue_name, STR(reply.recipient), len);
/* Remove the address extension from the recipient localpart. */ /* 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))); vstring_truncate(queue_name, strlen(STR(queue_name)));
/* Assume the recipient domain is equivalent to nexthop. */ /* Assume the recipient domain is equivalent to nexthop. */
vstring_sprintf_append(queue_name, "@%s", STR(reply.nexthop)); vstring_sprintf_append(queue_name, "@%s", STR(reply.nexthop));

View File

@ -956,7 +956,8 @@
/* .IP "\fBqueue_directory (see 'postconf -d' output)\fR" /* .IP "\fBqueue_directory (see 'postconf -d' output)\fR"
/* The location of the Postfix top-level queue directory. /* The location of the Postfix top-level queue directory.
/* .IP "\fBrecipient_delimiter (empty)\fR" /* .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" /* .IP "\fBsmtpd_banner ($myhostname ESMTP $mail_name)\fR"
/* The text that follows the 220 status code in the SMTP greeting /* The text that follows the 220 status code in the SMTP greeting
/* banner. /* banner.

View File

@ -2866,7 +2866,7 @@ static int check_mail_access(SMTPD_STATE *state, const char *table,
if (*var_rcpt_delim == 0) { if (*var_rcpt_delim == 0) {
bare_addr = 0; bare_addr = 0;
} else { } 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) \ #define CHECK_MAIL_ACCESS_RETURN(x) \

View File

@ -286,7 +286,7 @@ int transport_lookup(TRANSPORT_INFO *tp, const char *addr,
* partial lookup keys with regular expressions. * partial lookup keys with regular expressions.
*/ */
if ((stripped_addr = strip_addr(addr, DISCARD_EXTENSION, 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, found = find_transport_entry(tp, stripped_addr, rcpt_domain, PARTIAL,
channel, nexthop); channel, nexthop);

View File

@ -110,7 +110,8 @@
/* With locally submitted mail, append the string ".$mydomain" to /* With locally submitted mail, append the string ".$mydomain" to
/* addresses that have no ".domain" information. /* addresses that have no ".domain" information.
/* .IP "\fBrecipient_delimiter (empty)\fR" /* .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" /* .IP "\fBswap_bangpath (yes)\fR"
/* Enable the rewriting of "site!user" into "user@site". /* Enable the rewriting of "site!user" into "user@site".
/* .PP /* .PP

View File

@ -431,6 +431,7 @@ void dict_load_fp(const char *dict_name, VSTREAM *fp)
VSTRING *buf; VSTRING *buf;
char *member; char *member;
char *val; char *val;
const char *old;
int old_lineno; int old_lineno;
int lineno; int lineno;
const char *err; const char *err;
@ -455,6 +456,10 @@ void dict_load_fp(const char *dict_name, VSTREAM *fp)
err, STR(buf)); err, STR(buf));
if (msg_verbose > 1) if (msg_verbose > 1)
msg_info("%s: %s = %s", myname, member, val); 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) if (dict->update(dict, member, val) != 0)
msg_fatal("%s, line %d: unable to update %s:%s", msg_fatal("%s, line %d: unable to update %s:%s",
VSTREAM_PATH(fp), lineno, dict->type, dict->name); VSTREAM_PATH(fp), lineno, dict->type, dict->name);