= canonical, virtual, alias, forward, include" to restore
previous behavior.
- Feature: command_expansion_filter and forward_expansion_filter
- configuration parameters that control what characters may
- appear in $name expansions of mailbox_command and forward_path.
+ Feature: forward_expansion_filter configuration parameter
+ that controls what characters may appear in $name expansions
+ of forward_path.
+
+19990509
+
+ Feature: command_expansion_filter to control what characters
+ may appearin message attributes that are exported via
+ environment variables.
+
+ Cleanup: SMTPD reject messages are more informative, and
+ more complete sender/recipient information is logged for
+ the local sysadmin.
-Incompatible changes with snapshot-19990504:
+Incompatible changes with snapshot-19990509:
===========================================
- The Postfix local delivery agent no longer automatically propagates
"propagate_unmatched_extensions = canonical, virtual, alias, forward,
include" to restore the old behavior.
-- The luser_relay syntax has changed. You can specify one address,
-and it is subjected to $user, etc. expansions. See conf/main.cf.
-
-- The mailbox_command parameter is now subjected to $name expansion
-(see below). This means that you can no longer use shell variables
-in mailbox_command, or that you have to use $$ instead of $.
+- The luser_relay syntax has changed. You can specify one address;
+it is subjected to $user, etc. expansions. See conf/main.cf.
- File system reorganization: daemon executables are in the libexec
subdirectory, command executables in the bin subdirectory. The
INSTALL instructions now recommend installing daemons and commands
into separate directories.
-Major changes with snapshot-19990504:
+Major changes with snapshot-19990509:
=====================================
In addition to several little bugfixes, none related to security,
lots of internal code cleanup, lots of new functionality, and lots
of Solaris workarounds.
+- New USER, EXTENSION and DOMAIN environment variables for delivery
+to command by the local delivery agent. As you might expect, the
+information is censored. The list of acceptable characters is
+specified with the command_expansion_filter configuration parameter.
+Unacceptable characters are replaced by underscores.
+
- Specify "forward_path = /var/forward/$user" to avoid looking up
.forward files in user home directories. The default value is
$home/.forward$recipient_delimiter$extension, $home/.forward.
Initial code by Philip A. Prindeville, Mirapoint, Inc., USA.
-- Conditional $name expansion in forward_path, mailbox_command,
-and luser_relay. Available names are: $user (bare user name) $shell
-(user login shell), $home (user home directory), $recipient
-(everything to the left of @), $extension (optional address
-extension), $domain (everything to the right of @), and
-$recipient_delimiter. A simple $name expands as usual. ${name?value}
-expands to value when $name is defined. ${name:value} expands to
-value when $name is not defined. With ${name?value} and ${name:value},
-the value is subject to another iteration of $name expansion.
+- Conditional $name expansion in forward_path and luser_relay.
+Available names are: $user (bare user name) $shell (user login
+shell), $home (user home directory), $recipient (everything to the
+left of @), $extension (optional address extension), $domain
+(everything to the right of @), and $recipient_delimiter. A simple
+$name expands as usual. ${name?value} expands to value when $name
+is defined. ${name:value} expands to value when $name is not
+defined. With ${name?value} and ${name:value}, the value is subject
+to another iteration of $name expansion.
- POSIX regular expression support, enabled by default on 4.4BSD,
LINUX, HP-UX, and Solaris 2.5 and later. See conf/sample-regexp.cf.
mail_name = Postfix
mail_owner = postfix
mail_spool_directory = /var/mail
-mail_version = Snapshot-19990508
+mail_version = Snapshot-19990509
mailbox_command =
mailbox_transport =
maps_rbl_domains = rbl.maps.vix.com
#define DEF_CMD_EXP_FILTER "1234567890!@%-_=+:,./\
abcdefghijklmnopqrstuvwxyz\
ABCDEFGHIJKLMNOPQRSTUVWXYZ"
-extern char *var_cmd_exp_filter;;
+extern char *var_cmd_exp_filter;
#define VAR_FWD_EXP_FILTER "forward_expansion_filter"
#define DEF_FWD_EXP_FILTER "1234567890!@%-_=+:,./\
abcdefghijklmnopqrstuvwxyz\
ABCDEFGHIJKLMNOPQRSTUVWXYZ"
-extern char *var_fwd_exp_filter;;
+extern char *var_fwd_exp_filter;
#define VAR_RCPT_FDELIM "recipient_feature_delimiter"
#define DEF_RCPT_FDELIM ""
* Version of this program.
*/
#define VAR_MAIL_VERSION "mail_version"
-#define DEF_MAIL_VERSION "Snapshot-19990508"
+#define DEF_MAIL_VERSION "Snapshot-19990509"
extern char *var_mail_version;
/* LICENSE
With mailing lists, <b>Delivered-To:</b> can get in the way when
the list exploder uses a "secret" alias that should not be shown
-in outbound mail. In order to tackle this, look up the <b>FEATURE
-CONTROL</b> section in the documentation of the <a
-href="local.8.html">local</a> delivery agent.
+in outbound mail. The recommended solution is to use a regular
+expression-based filter at the SMTP port:
+
+<p>
+
+<dl>
+
+<dt><b>/etc/postfix/main.cf:</b>
+
+<dl>
+
+<dt><tt>smtpd_recipients = ... regexp:/etc/postfix/access_regexp ...</tt>
+
+<dt><tt>smtpd_recipients = ... pcre:/etc/postfix/access_regexp ...</tt>
+
+</dl>
+
+<p>
+
+<dt><b>/etc/postfix/access_regexp:</b>
+
+<dl>
+
+<dt><tt>/^(.*)-outgoing@(.*)/ 554 Use $1@$2 instead</tt>
+
+</dl>
+
+</dl>
+
+<p>
+
+POSIX regular expression support (regexp) is enabled by default on
+modern UNIX systems. Perl-compatible regular expression support
+(pcre) is optional; see the PCRE_README file in the top-level
+Postfix source directory.
<p>
delivery programs - an intruder has to break through several other
programs first. Postfix does not even trust the contents of its
own queue files, or the contents of its own IPC messages. Postfix
-avoids placing sender-provided information into shell environment
-variables. Last but not least, no Postfix program is <i>set-uid</i>.
+filters sender-provided information before exporting it via
+environment variables. Last but not least, no Postfix program is
+<i>set-uid</i>.
</ul>
ter. The command executes with the privileges of the
recipient user (exception: in case of delivery as root,
the command executes with the privileges of
- <b>default</b><i>_</i><b>privs</b>). The command is subject to interpolation
- of <b>$user</b> (recipient username), <b>$home</b> (recipient home
- directory), <b>$shell</b> (recipient shell), <b>$recipient</b> (complete
- recipient address), <b>$extension</b> (recipient address exten-
- sion), <b>$domain</b> (recipient domain), <b>mailbox</b> (entire recipi-
- ent address localpart) and <b>$recipient</b><i>_</i><b>delimiter.</b> The forms
- <i>${name?value}</i> and <i>${name:value}</i> expand conditionally to
- <i>value</i> when <i>$name</i> is (is not) defined. In the result of
- <i>name</i> expansion, characters that have special meaning to
- the shell are replaced by underscores. The list of legal
- characters is specified with the <b>command</b><i>_</i><b>expansion</b><i>_</i><b>filter</b>
- configuration parameter.
+ <b>default</b><i>_</i><b>privs</b>).
+
+ Mailbox delivery can be delegated to alternative message
+ transports specified in the <b>master.cf</b> file. The <b>mail-</b>
+ <b>box</b><i>_</i><b>transport</b> configuration parameter specifies a message
+ transport that is to be used for all local recipients,
+ regardless of whether they are found in the UNIX passwd
+ database. The <b>fallback</b><i>_</i><b>transport</b> parameter specifies a
+ message transport for recipients that are not found in the
+ UNIX passwd database.
- Mailbox delivery can be delegated to alternative message
+ In the case of UNIX-style mailbox delivery, the <b>local</b> dae-
+ mon prepends a "<b>From</b> <i>sender</i> <i>time_stamp</i>" envelope header to
+ each message, prepends a <b>Delivered-To:</b> header with the
LOCAL(8) LOCAL(8)
- transports specified in the <b>master.cf</b> file. The <b>mail-</b>
- <b>box</b><i>_</i><b>transport</b> configuration parameter specifies a message
- transport that is to be used for all local recipients,
- regardless of whether they are found in the UNIX passwd
- database. The <b>fallback</b><i>_</i><b>transport</b> parameter specifies a
- message transport for recipients that are not found in the
- UNIX passwd database.
-
- In the case of UNIX-style mailbox delivery, the <b>local</b> dae-
- mon prepends a "<b>From</b> <i>sender</i> <i>time_stamp</i>" envelope header to
- each message, prepends a <b>Delivered-To:</b> header with the
envelope recipient address, prepends a <b>Return-Path:</b> header
- with the envelope sender address, prepends a > character
- to lines beginning with "<b>From</b> ", and appends an empty
- line. The mailbox is locked for exclusive access while
- delivery is in progress. In case of problems, an attempt
+ with the envelope sender address, prepends a > character
+ to lines beginning with "<b>From</b> ", and appends an empty
+ line. The mailbox is locked for exclusive access while
+ delivery is in progress. In case of problems, an attempt
is made to truncate the mailbox to its original length.
In the case of <b>maildir</b> delivery, the local daemon prepends
a <b>Delivered-To:</b> header with the envelope recipient address
- and prepends a <b>Return-Path:</b> header with the envelope
+ and prepends a <b>Return-Path:</b> header with the envelope
sender address.
<b>EXTERNAL</b> <b>COMMAND</b> <b>DELIVERY</b>
- The <b>allow</b><i>_</i><b>mail</b><i>_</i><b>to</b><i>_</i><b>commands</b> configuration parameter
- restricts delivery to external commands. The default set-
- ting (<b>alias,</b> <b>forward</b>) forbids command destinations in
+ The <b>allow</b><i>_</i><b>mail</b><i>_</i><b>to</b><i>_</i><b>commands</b> configuration parameter
+ restricts delivery to external commands. The default set-
+ ting (<b>alias,</b> <b>forward</b>) forbids command destinations in
<b>:include:</b> files.
- The command is executed directly where possible. Assis-
- tance by the shell (<b>/bin/sh</b> on UNIX systems) is used only
- when the command contains shell magic characters, or when
+ The command is executed directly where possible. Assis-
+ tance by the shell (<b>/bin/sh</b> on UNIX systems) is used only
+ when the command contains shell magic characters, or when
the command invokes a shell built-in command.
- A limited amount of command output (standard output and
- standard error) is captured for inclusion with non-deliv-
- ery status reports. A command is forcibly terminated if
- it does not complete within <b>command</b><i>_</i><b>time</b><i>_</i><b>limit</b> seconds.
- Command exit status codes are expected to follow the con-
+ A limited amount of command output (standard output and
+ standard error) is captured for inclusion with non-deliv-
+ ery status reports. A command is forcibly terminated if
+ it does not complete within <b>command</b><i>_</i><b>time</b><i>_</i><b>limit</b> seconds.
+ Command exit status codes are expected to follow the con-
ventions defined in <<b>sysexits.h</b>>.
- When mail is delivered on behalf of a user, the <b>HOME</b>, <b>LOG-</b>
- <b>NAME</b>, and <b>SHELL</b> environment variables are set accordingly.
+ A limited amount of message context is exported via envi-
+ ronment variables. Characters that may have special mean-
+ ing to the shell are replaced by underscores. The list of
+ acceptable characters is specified with the <b>command</b><i>_</i><b>expan-</b>
+ <b>sion</b><i>_</i><b>filter</b> configuration parameter.
+
+ <b>SHELL</b> The recipient user's login shell.
+
+ <b>HOME</b> The recipient user's home directory.
+
+ <b>USER</b> The bare recipient name.
+
+ <b>EXTENSION</b>
+ The optional recipient address extension.
+
+ <b>DOMAIN</b> The recipient address domain part.
+
+ <b>LOGNAME</b>
+ The bare recipient name.
+
The <b>PATH</b> environment variable is always reset to a system-
dependent default path, and the <b>TZ</b> (time zone) environment
variable is always passed on without change.
- The current working directory is the mail queue directory.
-
- The <b>local</b> daemon prepends a "<b>From</b> <i>sender</i> <i>time_stamp</i>" enve-
- lope header to each message, prepends a <b>Delivered-To:</b>
- header with the recipient envelope address, prepends a
- <b>Return-Path:</b> header with the sender envelope address, and
- appends an empty line.
LOCAL(8) LOCAL(8)
+ The current working directory is the mail queue directory.
+
+ The <b>local</b> daemon prepends a "<b>From</b> <i>sender</i> <i>time_stamp</i>" enve-
+ lope header to each message, prepends a <b>Delivered-To:</b>
+ header with the recipient envelope address, prepends a
+ <b>Return-Path:</b> header with the sender envelope address, and
+ appends an empty line.
+
<b>EXTERNAL</b> <b>FILE</b> <b>DELIVERY</b>
- The <b>allow</b><i>_</i><b>mail</b><i>_</i><b>to</b><i>_</i><b>files</b> configuration parameter restricts
- delivery to external files. The default setting (<b>alias,</b>
- <b>forward</b>) forbids file destinations in <b>:include:</b> files.
+ The <b>allow</b><i>_</i><b>mail</b><i>_</i><b>to</b><i>_</i><b>files</b> configuration parameter restricts
+ delivery to external files. The default setting (<b>alias,</b>
+ <b>forward</b>) forbids file destinations in <b>:include:</b> files.
Specify a pathname ending in <b>/</b> for <b>qmail</b>-compatible
<b>maildir</b> delivery.
The <b>local</b> daemon prepends a "<b>From</b> <i>sender</i> <i>time_stamp</i>" enve-
- lope header to each message, prepends a <b>Delivered-To:</b>
- header with the recipient envelope address, prepends a >
- character to lines beginning with "<b>From</b> ", and appends an
- empty line. The envelope sender address is available in
- the <b>Return-Path:</b> header. When the destination is a regu-
+ lope header to each message, prepends a <b>Delivered-To:</b>
+ header with the recipient envelope address, prepends a >
+ character to lines beginning with "<b>From</b> ", and appends an
+ empty line. The envelope sender address is available in
+ the <b>Return-Path:</b> header. When the destination is a regu-
lar file, it is locked for exclusive access while delivery
is in progress. In case of problems, an attempt is made to
truncate a regular file to its original length.
In the case of <b>maildir</b> delivery, the local daemon prepends
- a <b>Delivered-To:</b> header with the envelope recipient
- address. The envelope sender address is available in the
+ a <b>Delivered-To:</b> header with the envelope recipient
+ address. The envelope sender address is available in the
<b>Return-Path:</b> header.
<b>ADDRESS</b> <b>EXTENSION</b>
- The optional <b>recipient</b><i>_</i><b>delimiter</b> configuration parameter
- specifies how to separate address extensions from local
+ The optional <b>recipient</b><i>_</i><b>delimiter</b> configuration parameter
+ specifies how to separate address extensions from local
recipient names.
- For example, with "<b>recipient</b><i>_</i><b>delimiter</b> <b>=</b> <b>+</b>", mail for
- <i>name</i>+<i>foo</i> is delivered to the alias <i>name</i>+<i>foo</i> or to the
- alias <i>name</i>, to the destinations listed in ~<i>name</i>/.<b>for-</b>
+ For example, with "<b>recipient</b><i>_</i><b>delimiter</b> <b>=</b> <b>+</b>", mail for
+ <i>name</i>+<i>foo</i> is delivered to the alias <i>name</i>+<i>foo</i> or to the
+ alias <i>name</i>, to the destinations listed in ~<i>name</i>/.<b>for-</b>
<b>ward</b>+<i>foo</i> or in ~<i>name</i>/.<b>forward</b>, to the mailbox owned by the
user <i>name</i>, or it is sent back as undeliverable.
- In all cases the <b>local</b> daemon prepends a `<b>Delivered-To:</b>
+ In all cases the <b>local</b> daemon prepends a `<b>Delivered-To:</b>
<i>name</i>+<i>foo</i>' header line.
<b>DELIVERY</b> <b>RIGHTS</b>
- Deliveries to external files and external commands are
+ Deliveries to external files and external commands are
made with the rights of the receiving user on whose behalf
- the delivery is made. In the absence of a user context,
- the <b>local</b> daemon uses the owner rights of the <b>:include:</b>
+ the delivery is made. In the absence of a user context,
+ the <b>local</b> daemon uses the owner rights of the <b>:include:</b>
file or alias database. When those files are owned by the
superuser, delivery is made with the rights specified with
the <b>default</b><i>_</i><b>privs</b> configuration parameter.
-<b>STANDARDS</b>
- RFC 822 (ARPA Internet Text Messages)
-
-<b>DIAGNOSTICS</b>
- Problems and transactions are logged to <b>syslogd</b>(8). Cor-
- rupted message files are marked so that the queue manager
- can move them to the <b>corrupt</b> queue afterwards.
- Depending on the setting of the <b>notify</b><i>_</i><b>classes</b> parameter,
LOCAL(8) LOCAL(8)
- the postmaster is notified of bounces and of other trou-
+<b>STANDARDS</b>
+ RFC 822 (ARPA Internet Text Messages)
+
+<b>DIAGNOSTICS</b>
+ Problems and transactions are logged to <b>syslogd</b>(8). Cor-
+ rupted message files are marked so that the queue manager
+ can move them to the <b>corrupt</b> queue afterwards.
+
+ Depending on the setting of the <b>notify</b><i>_</i><b>classes</b> parameter,
+ the postmaster is notified of bounces and of other trou-
ble.
<b>BUGS</b>
- For security reasons, the message delivery status of
- external commands or of external files is never check-
+ For security reasons, the message delivery status of
+ external commands or of external files is never check-
pointed to file. As a result, the program may occasionally
deliver more than once to a command or external file. Bet-
ter safe than sorry.
- Mutually-recursive aliases or ~/.<b>forward</b> files are not
- detected early. The resulting mail forwarding loop is
+ Mutually-recursive aliases or ~/.<b>forward</b> files are not
+ detected early. The resulting mail forwarding loop is
broken by the use of the <b>Delivered-To:</b> message header.
<b>CONFIGURATION</b> <b>PARAMETERS</b>
- The following <b>main.cf</b> parameters are especially relevant
- to this program. See the Postfix <b>main.cf</b> file for syntax
- details and for default values. Use the <b>postfix</b> <b>reload</b>
+ The following <b>main.cf</b> parameters are especially relevant
+ to this program. See the Postfix <b>main.cf</b> file for syntax
+ details and for default values. Use the <b>postfix</b> <b>reload</b>
command after a configuration change.
<b>Miscellaneous</b>
ject to <i>$name</i> expansion.
<b>local</b><i>_</i><b>command</b><i>_</i><b>shell</b>
- Shell to use for external command execution (for
- example, /some/where/smrsh -c). When a shell is
+ Shell to use for external command execution (for
+ example, /some/where/smrsh -c). When a shell is
specified, it is invoked even when the command con-
- tains no shell built-in commands or meta charac-
+ tains no shell built-in commands or meta charac-
ters.
<b>owner</b><i>_</i><b>request</b><i>_</i><b>special</b>
<b>Mailbox</b> <b>delivery</b>
<b>fallback</b><i>_</i><b>transport</b>
Message transport for recipients that are not found
- in the UNIX passwd database. This parameter over-
- rides <b>luser</b><i>_</i><b>relay</b>.
-
- <b>home</b><i>_</i><b>mailbox</b>
- Pathname of a mailbox relative to a user's home
- directory. Specify a path ending in <b>/</b> for maildir-
- style delivery.
-
-
LOCAL(8) LOCAL(8)
+ in the UNIX passwd database. This parameter over-
+ rides <b>luser</b><i>_</i><b>relay</b>.
+
+ <b>home</b><i>_</i><b>mailbox</b>
+ Pathname of a mailbox relative to a user's home
+ directory. Specify a path ending in <b>/</b> for maildir-
+ style delivery.
+
<b>luser</b><i>_</i><b>relay</b>
- Destination (<i>@domain</i> or <i>address</i>) for non-existent
- users. The <i>address</i> is subjected to <i>$name</i> expan-
+ Destination (<i>@domain</i> or <i>address</i>) for non-existent
+ users. The <i>address</i> is subjected to <i>$name</i> expan-
sion.
<b>mail</b><i>_</i><b>spool</b><i>_</i><b>directory</b>
- Directory with UNIX-style mailboxes. The default
+ Directory with UNIX-style mailboxes. The default
pathname is system dependent.
<b>mailbox</b><i>_</i><b>command</b>
- External command to use for mailbox delivery. The
+ External command to use for mailbox delivery. The
command executes with the recipient privileges
- (exception: root). The string is subject to $name
+ (exception: root). The string is subject to $name
expansions.
<b>mailbox</b><i>_</i><b>transport</b>
- Message transport to use for mailbox delivery to
+ Message transport to use for mailbox delivery to
all local recipients, whether or not they are found
- in the UNIX passwd database. This parameter over-
- rides all other configuration parameters that con-
+ in the UNIX passwd database. This parameter over-
+ rides all other configuration parameters that con-
trol mailbox delivery, including <b>luser</b><i>_</i><b>relay</b>.
<b>Locking</b> <b>controls</b>
<b>deliver</b><i>_</i><b>lock</b><i>_</i><b>attempts</b>
- Limit the number of attempts to acquire an exclu-
+ Limit the number of attempts to acquire an exclu-
sive lock on a mailbox or external file.
<b>deliver</b><i>_</i><b>lock</b><i>_</i><b>delay</b>
- Time in seconds between successive attempts to
+ Time in seconds between successive attempts to
acquire an exclusive lock.
<b>stale</b><i>_</i><b>lock</b><i>_</i><b>time</b>
<b>Resource</b> <b>controls</b>
<b>command</b><i>_</i><b>time</b><i>_</i><b>limit</b>
- Limit the amount of time for delivery to external
+ Limit the amount of time for delivery to external
command.
<b>duplicate</b><i>_</i><b>filter</b><i>_</i><b>limit</b>
- Limit the size of the duplicate filter for results
+ Limit the size of the duplicate filter for results
from alias etc. expansion.
<b>line</b><i>_</i><b>length</b><i>_</i><b>limit</b>
- Limit the amount of memory used for processing a
+ Limit the amount of memory used for processing a
partial input line.
- <b>local</b><i>_</i><b>destination</b><i>_</i><b>concurrency</b><i>_</i><b>limit</b>
- Limit the number of parallel deliveries to the same
- user. The default limit is taken from the
- <b>default</b><i>_</i><b>destination</b><i>_</i><b>concurrency</b><i>_</i><b>limit</b> parameter.
-
- <b>local</b><i>_</i><b>destination</b><i>_</i><b>recipient</b><i>_</i><b>limit</b>
- Limit the number of recipients per message
-
6
LOCAL(8) LOCAL(8)
- delivery. The default limit is taken from the
+ <b>local</b><i>_</i><b>destination</b><i>_</i><b>concurrency</b><i>_</i><b>limit</b>
+ Limit the number of parallel deliveries to the same
+ user. The default limit is taken from the
+ <b>default</b><i>_</i><b>destination</b><i>_</i><b>concurrency</b><i>_</i><b>limit</b> parameter.
+
+ <b>local</b><i>_</i><b>destination</b><i>_</i><b>recipient</b><i>_</i><b>limit</b>
+ Limit the number of recipients per message deliv-
+ ery. The default limit is taken from the
<b>default</b><i>_</i><b>destination</b><i>_</i><b>recipient</b><i>_</i><b>limit</b> parameter.
<b>Security</b> <b>controls</b>
<b>allow</b><i>_</i><b>mail</b><i>_</i><b>to</b><i>_</i><b>commands</b>
- Restrict the usage of mail delivery to external
+ Restrict the usage of mail delivery to external
command.
<b>allow</b><i>_</i><b>mail</b><i>_</i><b>to</b><i>_</i><b>files</b>
- Restrict the usage of mail delivery to external
+ Restrict the usage of mail delivery to external
file.
<b>command</b><i>_</i><b>expansion</b><i>_</i><b>filter</b>
- What characters are allowed to appear in $name
- expansions of mailbox_command. Illegal characters
+ What characters are allowed to appear in $name
+ expansions of mailbox_command. Illegal characters
are replaced by underscores.
<b>default</b><i>_</i><b>privs</b>
- Default rights for delivery to external file or
+ Default rights for delivery to external file or
command.
<b>forward</b><i>_</i><b>expansion</b><i>_</i><b>filter</b>
- What characters are allowed to appear in $name
- expansions of forward_path. Illegal characters are
+ What characters are allowed to appear in $name
+ expansions of forward_path. Illegal characters are
replaced by underscores.
<b>HISTORY</b>
- The <b>Delivered-To:</b> header appears in the <b>qmail</b> system by
+ The <b>Delivered-To:</b> header appears in the <b>qmail</b> system by
Daniel Bernstein.
- The <i>maildir</i> structure appears in the <b>qmail</b> system by
+ The <i>maildir</i> structure appears in the <b>qmail</b> system by
Daniel Bernstein.
<b>SEE</b> <b>ALSO</b>
<a href="qmgr.8.html">qmgr(8)</a> queue manager
<b>LICENSE</b>
- The Secure Mailer license must be distributed with this
+ The Secure Mailer license must be distributed with this
software.
<b>AUTHOR(S)</b>
Wietse Venema
IBM T.J. Watson Research
+
+
+
+ 7
+
+
+
+
+
+LOCAL(8) LOCAL(8)
+
+
P.O. Box 704
Yorktown Heights, NY 10598, USA
- 7
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 8
</pre> </body> </html>
<p>
Of course, Postfix programs do not trust data received from the
-network, either. In particular, no Postfix program places
-sender-provided data into shell command lines or into environment
-variables. If there is one lesson that people have learned from
-Web site security disasters it is this one: <i> don't let any data
-from the network near a shell</i>.
+network, either. In particular, Postfix filters sender-provided
+data before exporting it via environment variables. If there is one
+lesson that people have learned from Web site security disasters
+it is this one: <i> don't let any data from the network near a
+shell</i>. Filtering is the best we can do.
<h2>Large inputs</h2>
/* input. A limited amount of standard output and standard error
/* output is captured for diagnostics purposes.
/* Duplicate commands for the same recipient are suppressed.
+/* A limited amount of information is exported via the environment:
+/* HOME, SHELL, LOGNAME, USER, EXTENSION, and DOMAIN. The exported
+/* information is censored with var_cmd_filter.
/*
/* Arguments:
/* .IP state
#include <unistd.h>
#include <stdlib.h>
#include <stdarg.h>
+#include <string.h>
/* Utility library. */
#include <vstring.h>
#include <vstream.h>
#include <argv.h>
-#include <mac_expand.h>
/* Global library. */
int deliver_status;
ARGV *env;
int copy_flags;
- VSTRING *expanded_cmd = 0;
- char *xcommand ;
+ char **cpp;
+ char *cp;
/*
* Make verbose logging easier to understand.
env = argv_alloc(1);
if (usr_attr.home)
argv_add(env, "HOME", usr_attr.home, ARGV_END);
- if (usr_attr.logname)
- argv_add(env, "LOGNAME", usr_attr.logname, ARGV_END);
+ argv_add(env, "LOGNAME", state.msg_attr.user, ARGV_END);
+ argv_add(env, "USER", state.msg_attr.user, ARGV_END);
if (usr_attr.shell)
argv_add(env, "SHELL", usr_attr.shell, ARGV_END);
+ if (state.msg_attr.domain)
+ argv_add(env, "DOMAIN", state.msg_attr.domain, ARGV_END);
+ if (state.msg_attr.extension)
+ argv_add(env, "EXTENSION", state.msg_attr.extension, ARGV_END);
argv_terminate(env);
- if (command == var_mailbox_command) {
- expanded_cmd = vstring_alloc(100);
- local_expand(expanded_cmd, command, &state,
- &usr_attr, var_cmd_exp_filter);
- xcommand = vstring_str(expanded_cmd);
- } else {
- xcommand = command;
- }
+ /*
+ * Censor out undesirable characters from exported data.
+ */
+ for (cpp = env->argv; *cpp; cpp += 2)
+ for (cp = cpp[1]; *(cp += strspn(cp, var_cmd_exp_filter)) != 0;)
+ *cp++ = '_';
+
cmd_status = pipe_command(state.msg_attr.fp, why,
PIPE_CMD_UID, usr_attr.uid,
PIPE_CMD_GID, usr_attr.gid,
- PIPE_CMD_COMMAND, xcommand,
+ PIPE_CMD_COMMAND, command,
PIPE_CMD_COPY_FLAGS, copy_flags,
PIPE_CMD_SENDER, state.msg_attr.sender,
PIPE_CMD_DELIVERED, state.msg_attr.delivered,
PIPE_CMD_END);
argv_free(env);
- if (expanded_cmd)
- vstring_free(expanded_cmd);
/*
* Depending on the result, bounce or defer the message.
/* \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) defined.
-/* In the result of \fIname\fR expansion, characters that have special
-/* meaning to the shell are replaced by underscores. The list of legal
-/* characters is specified with the \fBforward_expansion_filter\fR
+/* In the result of \fIname\fR expansion, characters that have special
+/* meaning to the shell are replaced by underscores. The list of legal
+/* characters is specified with the \fBforward_expansion_filter\fR
/* configuration parameter.
/*
/* An alias or ~/.\fBforward\fR file may list any combination of external
/* executes with the privileges of the recipient user (exception: in
/* case of delivery as root, the command executes with the privileges
/* of \fBdefault_privs\fR).
-/* The command 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), \fBmailbox\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) defined.
-/* In the result of \fIname\fR expansion, characters that have special
-/* meaning to the shell are replaced by underscores. The list of legal
-/* characters is specified with the \fBcommand_expansion_filter\fR
-/* configuration parameter.
/*
/* Mailbox delivery can be delegated to alternative message transports
/* specified in the \fBmaster.cf\fR file.
/* \fBcommand_time_limit\fR seconds. Command exit status codes are
/* expected to follow the conventions defined in <\fBsysexits.h\fR>.
/*
-/* When mail is delivered on behalf of a user, the \fBHOME\fR,
-/* \fBLOGNAME\fR, and \fBSHELL\fR environment variables are set
-/* accordingly.
+/* A limited amount of message context is exported via environment
+/* variables. Characters that may have special meaning to the shell
+/* are replaced by underscores. The list of acceptable characters
+/* is specified with the \fBcommand_expansion_filter\fR configuration
+/* parameter.
+/* .IP \fBSHELL\fR
+/* The recipient user's login shell.
+/* .IP \fBHOME\fR
+/* The recipient user's home directory.
+/* .IP \fBUSER\fR
+/* The bare recipient name.
+/* .IP \fBEXTENSION\fR
+/* The optional recipient address extension.
+/* .IP \fBDOMAIN\fR
+/* The recipient address domain part.
+/* .IP \fBLOGNAME\fR
+/* The bare recipient name.
+/* .PP
/* The \fBPATH\fR environment variable is always reset to a
/* system-dependent default path, and the \fBTZ\fR (time zone)
/* environment variable is always passed on without change.
\fI$name\fR is (is not) defined.
In the result of \fIname\fR expansion, characters that have special
meaning to the shell are replaced by underscores. The list of legal
-characters is specified with the \fBcommand_expansion_filter\fR
+characters is specified with the \fBforward_expansion_filter\fR
configuration parameter.
An alias or ~/.\fBforward\fR file may list any combination of external
executes with the privileges of the recipient user (exception: in
case of delivery as root, the command executes with the privileges
of \fBdefault_privs\fR).
-The command 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), \fBmailbox\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) defined.
-In the result of \fIname\fR expansion, characters that have special
-meaning to the shell are replaced by underscores. The list of legal
-characters is specified with the \fBforward_expansion_filter\fR
-configuration parameter.
Mailbox delivery can be delegated to alternative message transports
specified in the \fBmaster.cf\fR file.
\fBcommand_time_limit\fR seconds. Command exit status codes are
expected to follow the conventions defined in <\fBsysexits.h\fR>.
-When mail is delivered on behalf of a user, the \fBHOME\fR,
-\fBLOGNAME\fR, and \fBSHELL\fR environment variables are set
-accordingly.
+A limited amount of message context is exported via environment
+variables. Characters that may have special meaning to the shell
+are replaced by underscores. The list of acceptable characters
+is specified with the \fBcommand_expansion_filter\fR configuration
+parameter.
+.IP \fBSHELL\fR
+The recipient user's login shell.
+.IP \fBHOME\fR
+The recipient user's home directory.
+.IP \fBUSER\fR
+The bare recipient name.
+.IP \fBEXTENSION\fR
+The optional recipient address extension.
+.IP \fBDOMAIN\fR
+The recipient address domain part.
+.IP \fBLOGNAME\fR
+The bare recipient name.
+.PP
The \fBPATH\fR environment variable is always reset to a
system-dependent default path, and the \fBTZ\fR (time zone)
environment variable is always passed on without change.
dependent.
.IP \fBmailbox_command\fR
External command to use for mailbox delivery. The command executes
-with the recipient privileges (exception: root).
+with the recipient privileges (exception: root). The string is subject
+to $name expansions.
.IP \fBmailbox_transport\fR
Message transport to use for mailbox delivery to all local
recipients, whether or not they are found in the UNIX passwd database.
.IP \fBallow_mail_to_files\fR
Restrict the usage of mail delivery to external file.
.IP \fBcommand_expansion_filter\fR
-What characters are allowed to appear in $name expansions
-of mailbox_command.
+What characters are allowed to appear in $name expansions of
+mailbox_command. Illegal characters are replaced by underscores.
.IP \fBdefault_privs\fR
Default rights for delivery to external file or command.
.IP \fBforward_expansion_filter\fR
-What characters are allowed to appear in $name expansions
-of forward_path.
+What characters are allowed to appear in $name expansions of
+forward_path. Illegal characters are replaced by underscores.
.SH HISTORY
.na
.nf
smtpd_state.o: ../include/vstream.h
smtpd_state.o: ../include/vbuf.h
smtpd_state.o: ../include/name_mask.h
+smtpd_state.o: ../include/stringops.h
smtpd_state.o: ../include/cleanup_user.h
smtpd_state.o: ../include/mail_params.h
smtpd_state.o: ../include/mail_error.h
return (-1);
}
collapse_args(argc, argv);
- if (SMTPD_STAND_ALONE(state) == 0
- && (err = smtpd_check_helo(state, argv[1].strval)) != 0) {
- smtpd_chat_reply(state, "%s", err);
- return (-1);
- }
state->helo_name = mystrdup(printable(argv[1].strval, '?'));
state->protocol = "SMTP";
smtpd_chat_reply(state, "250 %s", var_myhostname);
return (-1);
}
collapse_args(argc, argv);
- if (SMTPD_STAND_ALONE(state) == 0
- && (err = smtpd_check_helo(state, argv[1].strval)) != 0) {
- smtpd_chat_reply(state, "%s", err);
- return (-1);
- }
state->helo_name = mystrdup(printable(argv[1].strval, '?'));
state->protocol = "ESMTP";
smtpd_chat_reply(state, "250-%s", var_myhostname);
}
}
state->time = time((time_t *) 0);
- if (SMTPD_STAND_ALONE(state) == 0
- && (err = smtpd_check_mail(state, argv[3].strval)) != 0) {
- smtpd_chat_reply(state, "%s", err);
- return (-1);
- }
if ((err = smtpd_check_size(state, size)) != 0) {
smtpd_chat_reply(state, "%s", err);
return (-1);
smtpd_chat_reply(state, "452 Error: too many recipients");
return (-1);
}
- if (SMTPD_STAND_ALONE(state) == 0
- && (err = smtpd_check_rcpt(state, argv[3].strval)) != 0) {
- smtpd_chat_reply(state, "%s", err);
- return (-1);
+ if (SMTPD_STAND_ALONE(state) == 0) {
+ if ((err = smtpd_check_client(state)) != 0) {
+ smtpd_chat_reply(state, "%s", err);
+ return (-1);
+ }
+ if (state->helo_name
+ && (err = smtpd_check_helo(state, state->helo_name)) != 0) {
+ smtpd_chat_reply(state, "%s", err);
+ return (-1);
+ }
+ if (state->sender
+ && (err = smtpd_check_mail(state, state->sender)) != 0) {
+ smtpd_chat_reply(state, "%s", err);
+ return (-1);
+ }
+ if ((err = smtpd_check_rcpt(state, argv[3].strval)) != 0) {
+ smtpd_chat_reply(state, "%s", err);
+ return (-1);
+ }
}
/*
return (-1);
}
collapse_args(argc, argv);
- if (SMTPD_STAND_ALONE(state) == 0)
+ if (SMTPD_STAND_ALONE(state) == 0) {
+ if ((err = smtpd_check_client(state)) != 0) {
+ smtpd_chat_reply(state, "%s", err);
+ return (-1);
+ }
+ if (state->helo_name
+ && (err = smtpd_check_helo(state, state->helo_name)) != 0) {
+ smtpd_chat_reply(state, "%s", err);
+ return (-1);
+ }
+ if (state->sender
+ && (err = smtpd_check_mail(state, state->sender)) != 0) {
+ smtpd_chat_reply(state, "%s", err);
+ return (-1);
+ }
err = smtpd_check_rcpt(state, argv[1].strval);
+ }
/*
* End untokenize.
* rejected. RFC 1985 requires that 459 be sent when the server refuses
* to perform the request.
*/
- if (SMTPD_STAND_ALONE(state) == 0
- && (err = smtpd_check_etrn(state, argv[1].strval)) != 0) {
- smtpd_chat_reply(state, "%s", err);
- return (-1);
+ if (SMTPD_STAND_ALONE(state) == 0) {
+ if ((err = smtpd_check_client(state)) != 0) {
+ smtpd_chat_reply(state, "%s", err);
+ return (-1);
+ }
+ if (state->helo_name
+ && (err = smtpd_check_helo(state, state->helo_name)) != 0) {
+ smtpd_chat_reply(state, "%s", err);
+ return (-1);
+ }
+ if ((err = smtpd_check_etrn(state, argv[1].strval)) != 0) {
+ smtpd_chat_reply(state, "%s", err);
+ return (-1);
+ }
}
/*
debug_peer_check(state.name, state.addr);
/*
- * See if we want to talk to this client at all. Then, log the connection
- * event.
+ * Greet the client and log the connection event.
*/
- if ((state.access_denied = smtpd_check_client(&state)) != 0) {
- smtpd_chat_reply(&state, "%s", state.access_denied);
- } else {
- smtpd_chat_reply(&state, "220 %s", var_smtpd_banner);
- msg_info("connect from %s[%s]", state.name, state.addr);
- }
+ smtpd_chat_reply(&state, "220 %s", var_smtpd_banner);
+ msg_info("connect from %s[%s]", state.name, state.addr);
/*
* Provide the SMTP service.
time_t time;
char *name;
char *addr;
+ char *namaddr;
int error_count;
int error_mask;
int notify_mask;
#include <stdarg.h>
#include <netdb.h>
#include <setjmp.h>
+#include <stdlib.h>
#ifdef STRCASECMP_IN_STRINGS_H
#include <strings.h>
static ARGV *rcpt_restrctions;
static ARGV *etrn_restrctions;
+ /*
+ * Reject context.
+ */
+#define SMTPD_NAME_CLIENT "Client host"
+#define SMTPD_NAME_HELO "Helo command"
+#define SMTPD_NAME_SENDER "Sender address"
+#define SMTPD_NAME_RECIPIENT "Recipient address"
+#define SMTPD_NAME_ETRN "Etrn command"
+
+ /*
+ * YASLM.
+ */
#define STR vstring_str
/* smtpd_check_parse - pre-parse restrictions */
msg_warn("response code configuration error: %s", STR(error_text));
vstring_strcpy(error_text, "450 Service unavailable");
}
-
- /*
- * Give everyone involved a clue.
- */
- if (state->sender) {
- vstring_sprintf_append(error_text, " (from=<%s>", state->sender);
- if (state->recipient)
- vstring_sprintf_append(error_text, " to=<%s>", state->recipient);
- VSTRING_ADDCH(error_text, ')');
- }
printable(STR(error_text), ' ');
/*
* postmaster notices, this may be the only trace left that service was
* rejected. Print the request, client name/address, and response.
*/
- msg_info("%s: reject: %s from %s[%s]: %s", state->queue_id, state->where,
- state->name, state->addr, STR(error_text));
+ msg_info("%s: reject: %s from %s: %s",
+ state->queue_id, state->where,
+ state->namaddr, STR(error_text));
+ /*
+ * Log from/to information if available, for the benefit of the local
+ * sysadmin.
+ */
+ if (state->sender) {
+ msg_info(state->recipient ?
+ "%s: reject: %s from %s: from=<%s> to=<%s>" :
+ "%s: reject: %s from %s: from=<%s>",
+ state->queue_id, state->where, state->namaddr,
+ state->sender, state->recipient);
+ }
return (SMTPD_CHECK_REJECT);
}
if (strcasecmp(state->name, "unknown") == 0)
return (smtpd_check_reject(state, MAIL_ERROR_POLICY,
- "%d Cannot find your hostname, [%s]",
+ "%d Client host rejected: cannot find your hostname, [%s]",
var_unk_client_code, state->addr));
return (SMTPD_CHECK_DUNNO);
}
/* reject_invalid_hostaddr - fail if host address is incorrect */
-static int reject_invalid_hostaddr(SMTPD_STATE *state, char *addr)
+static int reject_invalid_hostaddr(SMTPD_STATE *state, char *addr,
+ char *reply_name, char *reply_class)
{
char *myname = "reject_invalid_hostaddr";
int len;
*/
if (!valid_hostaddr(test_addr))
stat = smtpd_check_reject(state, MAIL_ERROR_POLICY,
- "%d <%s>: Invalid ip address",
- var_bad_name_code, addr);
+ "%d <%s>: %s rejected: invalid ip address",
+ var_bad_name_code, reply_name, reply_class);
else
stat = SMTPD_CHECK_DUNNO;
/* reject_invalid_hostname - fail if host/domain syntax is incorrect */
-static int reject_invalid_hostname(SMTPD_STATE *state, char *name)
+static int reject_invalid_hostname(SMTPD_STATE *state, char *name,
+ char *reply_name, char *reply_class)
{
char *myname = "reject_invalid_hostname";
char *test_name;
*/
if (!valid_hostname(test_name))
stat = smtpd_check_reject(state, MAIL_ERROR_POLICY,
- "%d <%s>: Invalid name",
- var_bad_name_code, name);
+ "%d <%s>: %s rejected: Invalid name",
+ var_bad_name_code, reply_name, reply_class);
else
stat = SMTPD_CHECK_DUNNO;
/* reject_non_fqdn_hostname - fail if host name is not in fqdn form */
-static int reject_non_fqdn_hostname(SMTPD_STATE *state, char *name)
+static int reject_non_fqdn_hostname(SMTPD_STATE *state, char *name,
+ char *reply_name, char *reply_class)
{
char *myname = "reject_non_fqdn_hostname";
char *test_name;
*/
if (!valid_hostname(test_name) || !strchr(test_name, '.'))
stat = smtpd_check_reject(state, MAIL_ERROR_POLICY,
- "%d <%s>: need fully-qualified hostname",
- var_non_fqdn_code, name);
+ "%d <%s>: %s rejected: need fully-qualified hostname",
+ var_non_fqdn_code, reply_name, reply_class);
else
stat = SMTPD_CHECK_DUNNO;
/* reject_unknown_hostname - fail if name has no A or MX record */
-static int reject_unknown_hostname(SMTPD_STATE *state, char *name)
+static int reject_unknown_hostname(SMTPD_STATE *state, char *name,
+ char *reply_name, char *reply_class)
{
char *myname = "reject_unknown_hostname";
int dns_status;
(VSTRING *) 0, T_A, T_MX, 0);
if (dns_status != DNS_OK)
return (smtpd_check_reject(state, MAIL_ERROR_POLICY,
- "%d <%s>: Host not found",
+ "%d <%s>: %s rejected: Host not found",
dns_status == DNS_NOTFOUND ?
- var_unk_name_code : 450, name));
+ var_unk_name_code : 450,
+ reply_name, reply_class));
return (SMTPD_CHECK_DUNNO);
}
/* reject_unknown_mailhost - fail if name has no A or MX record */
-static int reject_unknown_mailhost(SMTPD_STATE *state, char *name)
+static int reject_unknown_mailhost(SMTPD_STATE *state, char *name,
+ char *reply_name, char *reply_class)
{
char *myname = "reject_unknown_mailhost";
int dns_status;
(VSTRING *) 0, T_A, T_MX, 0);
if (dns_status != DNS_OK)
return (smtpd_check_reject(state, MAIL_ERROR_POLICY,
- "%d <%s>: Domain not found",
+ "%d <%s>: %s rejected: Domain not found",
dns_status == DNS_NOTFOUND ?
- var_unk_addr_code : 450, name));
+ var_unk_addr_code : 450,
+ reply_name, reply_class));
return (SMTPD_CHECK_DUNNO);
}
/* check_relay_domains - OK/FAIL for message relaying */
-static int check_relay_domains(SMTPD_STATE *state, char *recipient)
+static int check_relay_domains(SMTPD_STATE *state, char *recipient,
+ char *reply_name, char *reply_class)
{
char *myname = "check_relay_domains";
char *domain;
* Deny relaying between sites that both are not in relay_domains.
*/
return (smtpd_check_reject(state, MAIL_ERROR_POLICY,
- "%d <%s>: Relay access denied",
- var_relay_code, recipient));
+ "%d <%s>: %s rejected: Relay access denied",
+ var_relay_code, reply_name, reply_class));
}
/* has_my_addr - see if this host name lists one of my network addresses */
/* reject_non_fqdn_address - fail if address is not in fqdn form */
-static int reject_non_fqdn_address(SMTPD_STATE *state, char *addr)
+static int reject_non_fqdn_address(SMTPD_STATE *state, char *addr,
+ char *reply_name, char *reply_class)
{
char *myname = "reject_non_fqdn_address";
char *domain;
*/
if (!*test_dom || !valid_hostname(test_dom) || !strchr(test_dom, '.'))
stat = smtpd_check_reject(state, MAIL_ERROR_POLICY,
- "%d <%s>: need fully-qualified address",
- var_non_fqdn_code, addr);
+ "%d <%s>: %s rejected: need fully-qualified address",
+ var_non_fqdn_code, reply_name, reply_class);
else
stat = SMTPD_CHECK_DUNNO;
/* reject_unknown_address - fail if address does not resolve */
-static int reject_unknown_address(SMTPD_STATE *state, char *addr)
+static int reject_unknown_address(SMTPD_STATE *state, char *addr,
+ char *reply_name, char *reply_class)
{
char *myname = "reject_unknown_address";
char *domain;
/*
* Look up the name in the DNS.
*/
- return (reject_unknown_mailhost(state, domain));
+ return (reject_unknown_mailhost(state, domain, reply_name, reply_class));
}
/* check_table_result - translate table lookup result into pass/reject */
static int check_table_result(SMTPD_STATE *state, char *table,
- const char *value, const char *datum)
+ const char *value, const char *datum,
+ char *reply_name, char *reply_class)
{
char *myname = "check_table_result";
+ int code;
if (msg_verbose)
msg_info("%s: %s %s %s", myname, table, value, datum);
*/
if (strcasecmp(value, "REJECT") == 0)
return (smtpd_check_reject(state, MAIL_ERROR_POLICY,
- "%d <%s>: Access denied",
- var_access_map_code, datum));
+ "%d <%s>: %s rejected: Access denied",
+ var_access_map_code, reply_name, reply_class));
/*
* 4xx or 5xx means NO as well. smtpd_check_reject() will validate the
* response status code.
*/
- if (ISDIGIT(value[0]))
- return (smtpd_check_reject(state, MAIL_ERROR_POLICY, "%s", value));
+ if (ISDIGIT(value[0]) && ISDIGIT(value[1]) && ISDIGIT(value[2])) {
+ code = atoi(value);
+ while (ISDIGIT(*value) || ISSPACE(*value))
+ value++;
+ return (smtpd_check_reject(state, MAIL_ERROR_POLICY,
+ "%d <%s>: %s rejected: %s",
+ code, reply_name, reply_class, value));
+ }
/*
* OK or RELAY or whatever means YES.
/* check_access - table lookup without substring magic */
-static int check_access(SMTPD_STATE *state, char *table, char *name, int flags)
+static int check_access(SMTPD_STATE *state, char *table, char *name, int flags,
+ char *reply_name, char *reply_class)
{
char *myname = "check_access";
char *low_name = lowercase(mystrdup(name));
msg_panic("%s: dictionary not found: %s", myname, table);
if (flags == 0 || (flags & dict->flags) != 0) {
if ((value = dict_get(dict, low_name)) != 0)
- CHK_ACCESS_RETURN(check_table_result(state, table, value, name));
+ CHK_ACCESS_RETURN(check_table_result(state, table, value, name,
+ reply_name, reply_class));
if (dict_errno != 0)
msg_fatal("%s: table lookup problem", table);
}
/* check_domain_access - domainname-based table lookup */
static int check_domain_access(SMTPD_STATE *state, char *table,
- char *domain, int flags)
+ char *domain, int flags,
+ char *reply_name, char *reply_class)
{
char *myname = "check_domain_access";
char *low_domain = lowercase(mystrdup(domain));
msg_panic("%s: dictionary not found: %s", myname, table);
if (flags == 0 || (flags & dict->flags) != 0) {
if ((value = dict_get(dict, name)) != 0)
- CHK_DOMAIN_RETURN(check_table_result(state, table, value, domain));
+ CHK_DOMAIN_RETURN(check_table_result(state, table, value,
+ domain, reply_name, reply_class));
if (dict_errno != 0)
msg_fatal("%s: table lookup problem", table);
}
/* check_addr_access - address-based table lookup */
-static int check_addr_access(SMTPD_STATE *state, char *table, char *address,
- int flags)
+static int check_addr_access(SMTPD_STATE *state, char *table,
+ char *address, int flags,
+ char *reply_name, char *reply_class)
{
char *myname = "check_addr_access";
char *addr;
msg_panic("%s: dictionary not found: %s", myname, table);
if (flags == 0 || (flags & dict->flags) != 0) {
if ((value = dict_get(dict, addr)) != 0)
- return (check_table_result(state, table, value, address));
+ return (check_table_result(state, table, value, address,
+ reply_name, reply_class));
if (dict_errno != 0)
msg_fatal("%s: table lookup problem", table);
}
/* check_namadr_access - OK/FAIL based on host name/address lookup */
static int check_namadr_access(SMTPD_STATE *state, char *table,
- char *name, char *addr, int flags)
+ char *name, char *addr, int flags,
+ char *reply_name, char *reply_class)
{
char *myname = "check_namadr_access";
int status;
* Look up the host name, or parent domains thereof. XXX A domain
* wildcard may pre-empt a more specific address table entry.
*/
- if ((status = check_domain_access(state, table, name, flags)) != 0)
+ if ((status = check_domain_access(state, table, name, flags,
+ reply_name, reply_class)) != 0)
return (status);
/*
* Look up the network address, or parent networks thereof.
*/
- if ((status = check_addr_access(state, table, addr, flags)) != 0)
+ if ((status = check_addr_access(state, table, addr, flags,
+ reply_name, reply_class)) != 0)
return (status);
/*
/* check_mail_access - OK/FAIL based on mail address lookup */
-static int check_mail_access(SMTPD_STATE *state, char *table, char *addr)
+static int check_mail_access(SMTPD_STATE *state, char *table, char *addr,
+ char *reply_name, char *reply_class)
{
char *myname = "check_mail_access";
char *ratsign;
/*
* Look up the full address.
*/
- if ((status = check_access(state, table, STR(reply.recipient), FULL)) != 0)
+ if ((status = check_access(state, table, STR(reply.recipient), FULL,
+ reply_name, reply_class)) != 0)
return (status);
/*
* Look up the domain name, or parent domains thereof.
*/
- if ((status = check_domain_access(state, table, ratsign + 1, PARTIAL)) != 0)
+ if ((status = check_domain_access(state, table, ratsign + 1, PARTIAL,
+ reply_name, reply_class)) != 0)
return (status);
/*
*/
local_at = mystrndup(STR(reply.recipient),
ratsign - STR(reply.recipient) + 1);
- status = check_access(state, table, local_at, PARTIAL);
+ status = check_access(state, table, local_at, PARTIAL,
+ reply_name, reply_class);
myfree(local_at);
if (status != 0)
return (status);
/* generic_checks - generic restrictions */
static int generic_checks(SMTPD_STATE *state, char *name,
- char ***cpp, int *status, char *what)
+ char ***cpp, int *status,
+ char *reply_name, char *reply_class)
{
/*
return (1);
}
if (strcasecmp(name, REJECT_ALL) == 0) {
- *status = smtpd_check_reject(state, MAIL_ERROR_POLICY, *what ?
- "%d <%s> Access denied" : "%d Access denied",
- var_reject_code, what);
+ *status = smtpd_check_reject(state, MAIL_ERROR_POLICY,
+ "%d <%s>: %s rejected: Access denied",
+ var_reject_code, reply_name, reply_class);
return (1);
}
return (1);
}
if (is_map_command(name, CHECK_CLIENT_ACL, cpp)) {
- *status = check_namadr_access(state, **cpp, state->name, state->addr, FULL);
+ *status = check_namadr_access(state, **cpp, state->name, state->addr,
+ FULL, state->namaddr, SMTPD_NAME_CLIENT);
return (1);
}
if (strcasecmp(name, REJECT_MAPS_RBL) == 0) {
*/
if (is_map_command(name, CHECK_HELO_ACL, cpp) && state->helo_name) {
if (state->helo_name)
- *status = check_domain_access(state, **cpp, state->helo_name, FULL);
+ *status = check_domain_access(state, **cpp, state->helo_name, FULL,
+ state->helo_name, SMTPD_NAME_HELO);
return (1);
}
if (strcasecmp(name, REJECT_INVALID_HOSTNAME) == 0) {
if (state->helo_name) {
if (*state->helo_name != '[')
- *status = reject_invalid_hostname(state, state->helo_name);
+ *status = reject_invalid_hostname(state, state->helo_name,
+ state->helo_name, SMTPD_NAME_HELO);
else
- *status = reject_invalid_hostaddr(state, state->helo_name);
+ *status = reject_invalid_hostaddr(state, state->helo_name,
+ state->helo_name, SMTPD_NAME_HELO);
}
return (1);
}
if (strcasecmp(name, REJECT_UNKNOWN_HOSTNAME) == 0) {
if (state->helo_name) {
if (*state->helo_name != '[')
- *status = reject_unknown_hostname(state, state->helo_name);
+ *status = reject_unknown_hostname(state, state->helo_name,
+ state->helo_name, SMTPD_NAME_HELO);
else
- *status = reject_invalid_hostaddr(state, state->helo_name);
+ *status = reject_invalid_hostaddr(state, state->helo_name,
+ state->helo_name, SMTPD_NAME_HELO);
}
return (1);
}
if (strcasecmp(name, PERMIT_NAKED_IP_ADDR) == 0) {
if (state->helo_name) {
if (state->helo_name[strspn(state->helo_name, "0123456789.")] == 0
- && (*status = reject_invalid_hostaddr(state, state->helo_name)) == 0)
+ && (*status = reject_invalid_hostaddr(state, state->helo_name,
+ state->helo_name, SMTPD_NAME_HELO)) == 0)
*status = SMTPD_CHECK_OK;
}
return (1);
if (strcasecmp(name, REJECT_NON_FQDN_HOSTNAME) == 0) {
if (state->helo_name) {
if (*state->helo_name != '[')
- *status = reject_non_fqdn_hostname(state, state->helo_name);
+ *status = reject_non_fqdn_hostname(state, state->helo_name,
+ state->helo_name, SMTPD_NAME_HELO);
else
- *status = reject_invalid_hostaddr(state, state->helo_name);
+ *status = reject_invalid_hostaddr(state, state->helo_name,
+ state->helo_name, SMTPD_NAME_HELO);
}
return (1);
}
*/
if (is_map_command(name, CHECK_SENDER_ACL, cpp) && state->sender) {
if (state->sender)
- *status = check_mail_access(state, **cpp, state->sender);
+ *status = check_mail_access(state, **cpp, state->sender,
+ state->sender, SMTPD_NAME_SENDER);
return (1);
}
if (strcasecmp(name, REJECT_UNKNOWN_ADDRESS) == 0) {
if (state->sender)
- *status = reject_unknown_address(state, state->sender);
+ *status = reject_unknown_address(state, state->sender,
+ state->sender, SMTPD_NAME_SENDER);
return (1);
}
if (strcasecmp(name, REJECT_UNKNOWN_SENDDOM) == 0) {
if (state->sender)
- *status = reject_unknown_address(state, state->sender);
+ *status = reject_unknown_address(state, state->sender,
+ state->sender, SMTPD_NAME_SENDER);
return (1);
}
if (strcasecmp(name, REJECT_NON_FQDN_SENDER) == 0) {
if (*state->sender)
- *status = reject_non_fqdn_address(state, state->sender);
+ *status = reject_non_fqdn_address(state, state->sender,
+ state->sender, SMTPD_NAME_SENDER);
return (1);
}
return (0);
*/
for (cpp = client_restrctions->argv; (name = *cpp) != 0; cpp++) {
if (strchr(name, ':') != 0) {
- status = check_namadr_access(state, name, state->name, state->addr, FULL);
- } else if (generic_checks(state, name, &cpp, &status, state->addr) == 0) {
+ status = check_namadr_access(state, name, state->name, state->addr,
+ FULL, state->namaddr, SMTPD_NAME_CLIENT);
+ } else if (generic_checks(state, name, &cpp, &status,
+ state->namaddr, SMTPD_NAME_CLIENT) == 0) {
msg_warn("unknown %s check: \"%s\"", VAR_CLIENT_CHECKS, name);
break;
}
state->helo_name = mystrdup(helohost);
for (cpp = helo_restrctions->argv; (name = *cpp) != 0; cpp++) {
if (strchr(name, ':') != 0) {
- status = check_domain_access(state, name, helohost, FULL);
- } else if (generic_checks(state, name, &cpp, &status, helohost) == 0) {
+ status = check_domain_access(state, name, helohost, FULL,
+ helohost, SMTPD_NAME_HELO);
+ } else if (generic_checks(state, name, &cpp, &status,
+ helohost, SMTPD_NAME_HELO) == 0) {
msg_warn("unknown %s check: \"%s\"", VAR_HELO_CHECKS, name);
break;
}
state->sender = mystrdup(sender);
for (cpp = mail_restrctions->argv; (name = *cpp) != 0; cpp++) {
if (strchr(name, ':') != 0) {
- status = check_mail_access(state, name, sender);
- } else if (generic_checks(state, name, &cpp, &status, sender) == 0) {
+ status = check_mail_access(state, name, sender,
+ sender, SMTPD_NAME_SENDER);
+ } else if (generic_checks(state, name, &cpp, &status,
+ sender, SMTPD_NAME_SENDER) == 0) {
msg_warn("unknown %s check: \"%s\"", VAR_MAIL_CHECKS, name);
return (0);
}
state->recipient = mystrdup(recipient);
for (cpp = rcpt_restrctions->argv; (name = *cpp) != 0; cpp++) {
if (strchr(name, ':') != 0) {
- status = check_mail_access(state, name, recipient);
+ status = check_mail_access(state, name, recipient,
+ recipient, SMTPD_NAME_RECIPIENT);
} else if (is_map_command(name, CHECK_RECIP_ACL, &cpp)) {
- status = check_mail_access(state, *cpp, recipient);
+ status = check_mail_access(state, *cpp, recipient,
+ recipient, SMTPD_NAME_RECIPIENT);
} else if (strcasecmp(name, PERMIT_MX_BACKUP) == 0) {
status = permit_mx_backup(state, recipient);
} else if (strcasecmp(name, CHECK_RELAY_DOMAINS) == 0) {
- status = check_relay_domains(state, recipient);
+ status = check_relay_domains(state, recipient,
+ recipient, SMTPD_NAME_RECIPIENT);
} else if (strcasecmp(name, REJECT_UNKNOWN_RCPTDOM) == 0) {
- status = reject_unknown_address(state, recipient);
+ status = reject_unknown_address(state, recipient,
+ recipient, SMTPD_NAME_RECIPIENT);
} else if (strcasecmp(name, REJECT_NON_FQDN_RCPT) == 0) {
- status = reject_non_fqdn_address(state, recipient);
- } else if (generic_checks(state, name, &cpp, &status, recipient) == 0) {
+ status = reject_non_fqdn_address(state, recipient,
+ recipient, SMTPD_NAME_RECIPIENT);
+ } else if (generic_checks(state, name, &cpp, &status,
+ recipient, SMTPD_NAME_RECIPIENT) == 0) {
msg_warn("unknown %s check: \"%s\"", VAR_RCPT_CHECKS, name);
break;
}
*/
for (cpp = etrn_restrctions->argv; (name = *cpp) != 0; cpp++) {
if (strchr(name, ':') != 0) {
- status = check_domain_access(state, name, domain, FULL);
+ status = check_domain_access(state, name, domain, FULL,
+ domain, SMTPD_NAME_ETRN);
} else if (is_map_command(name, CHECK_ETRN_ACL, &cpp)) {
- status = check_domain_access(state, *cpp, domain, FULL);
- } else if (generic_checks(state, name, &cpp, &status, domain) == 0) {
+ status = check_domain_access(state, *cpp, domain, FULL,
+ domain, SMTPD_NAME_ETRN);
+ } else if (generic_checks(state, name, &cpp, &status,
+ domain, SMTPD_NAME_ETRN) == 0) {
msg_warn("unknown %s check: \"%s\"", VAR_RCPT_CHECKS, name);
break;
}
int_init();
smtpd_check_init();
smtpd_state_init(&state, VSTREAM_IN, "", "");
+ state.queue_id = "<queue id>";
/*
* Main loop: update config parameters or test the client, helo, sender
state.where = "CONNECT";
UPDATE_STRING(state.name, args->argv[1]);
UPDATE_STRING(state.addr, args->argv[2]);
+ if (state.namaddr)
+ myfree(state.namaddr);
+ state.namaddr = concatenate(state.name, "[", state.addr,
+ "]", (char *) 0);
resp = smtpd_check_client(&state);
}
break;
>>> client_restrictions permit_mynetworks,reject_unknown_client,hash:./smtpd_check_access
OK
>>> client unknown 131.155.210.17
-./smtpd_check: reject: CONNECT from unknown[131.155.210.17]: 450 Cannot find your hostname, [131.155.210.17]
-450 Cannot find your hostname, [131.155.210.17]
+./smtpd_check: <queue id>: reject: CONNECT from unknown[131.155.210.17]: 450 Client host rejected: cannot find your hostname, [131.155.210.17]
+450 Client host rejected: cannot find your hostname, [131.155.210.17]
>>> client unknown 168.100.189.13
OK
>>> client random.bad.domain 123.123.123.123
-./smtpd_check: reject: CONNECT from random.bad.domain[123.123.123.123]: 554 match bad.domain
-554 match bad.domain
+./smtpd_check: <queue id>: reject: CONNECT from random.bad.domain[123.123.123.123]: 554 <random.bad.domain[123.123.123.123]>: Client host rejected: match bad.domain
+554 <random.bad.domain[123.123.123.123]>: Client host rejected: match bad.domain
>>> client friend.bad.domain 123.123.123.123
OK
>>> client bad.domain 123.123.123.123
-./smtpd_check: reject: CONNECT from bad.domain[123.123.123.123]: 554 match bad.domain
-554 match bad.domain
+./smtpd_check: <queue id>: reject: CONNECT from bad.domain[123.123.123.123]: 554 <bad.domain[123.123.123.123]>: Client host rejected: match bad.domain
+554 <bad.domain[123.123.123.123]>: Client host rejected: match bad.domain
>>> client wzv.win.tue.nl 131.155.210.17
OK
>>> client aa.win.tue.nl 131.155.210.18
-./smtpd_check: reject: CONNECT from aa.win.tue.nl[131.155.210.18]: 554 match 131.155.210
-554 match 131.155.210
+./smtpd_check: <queue id>: reject: CONNECT from aa.win.tue.nl[131.155.210.18]: 554 <aa.win.tue.nl[131.155.210.18]>: Client host rejected: match 131.155.210
+554 <aa.win.tue.nl[131.155.210.18]>: Client host rejected: match 131.155.210
>>> client_restrictions permit_mynetworks
OK
>>> #
>>> client unknown 131.155.210.17
OK
>>> helo foo.
-./smtpd_check: reject: HELO from unknown[131.155.210.17]: 450 Cannot find your hostname, [131.155.210.17]
-450 Cannot find your hostname, [131.155.210.17]
+./smtpd_check: <queue id>: reject: HELO from unknown[131.155.210.17]: 450 Client host rejected: cannot find your hostname, [131.155.210.17]
+450 Client host rejected: cannot find your hostname, [131.155.210.17]
>>> client foo 123.123.123.123
OK
>>> helo foo.
-./smtpd_check: reject: HELO from foo[123.123.123.123]: 450 <foo.>: Host not found
-450 <foo.>: Host not found
+./smtpd_check: <queue id>: reject: HELO from foo[123.123.123.123]: 450 <foo.>: Helo command rejected: Host not found
+450 <foo.>: Helo command rejected: Host not found
>>> helo foo
-./smtpd_check: reject: HELO from foo[123.123.123.123]: 450 <foo>: Host not found
-450 <foo>: Host not found
+./smtpd_check: <queue id>: reject: HELO from foo[123.123.123.123]: 450 <foo>: Helo command rejected: Host not found
+450 <foo>: Helo command rejected: Host not found
>>> helo spike.porcupine.org
OK
>>> helo_restrictions permit_mynetworks,reject_unknown_client,reject_invalid_hostname,hash:./smtpd_check_access
OK
>>> helo random.bad.domain
-./smtpd_check: reject: HELO from foo[123.123.123.123]: 554 match bad.domain
-554 match bad.domain
+./smtpd_check: <queue id>: reject: HELO from foo[123.123.123.123]: 554 <random.bad.domain>: Helo command rejected: match bad.domain
+554 <random.bad.domain>: Helo command rejected: match bad.domain
>>> helo friend.bad.domain
OK
>>> helo_restrictions reject_invalid_hostname,reject_unknown_hostname
OK
>>> helo 123.123.123.123
./smtpd_check: warning: valid_hostname: numeric hostname: 123.123.123.123
-./smtpd_check: reject: HELO from foo[123.123.123.123]: 450 <123.123.123.123>: Host not found
-450 <123.123.123.123>: Host not found
+./smtpd_check: <queue id>: reject: HELO from foo[123.123.123.123]: 450 <123.123.123.123>: Helo command rejected: Host not found
+450 <123.123.123.123>: Helo command rejected: Host not found
>>> helo_restrictions permit_naked_ip_address,reject_invalid_hostname,reject_unknown_hostname
OK
>>> helo 123.123.123.123
>>> client unknown 131.155.210.17
OK
>>> mail foo@watson.ibm.com
-./smtpd_check: reject: MAIL from unknown[131.155.210.17]: 450 Cannot find your hostname, [131.155.210.17]
-450 Cannot find your hostname, [131.155.210.17]
+./smtpd_check: <queue id>: reject: MAIL from unknown[131.155.210.17]: 450 Client host rejected: cannot find your hostname, [131.155.210.17]
+./smtpd_check: <queue id>: reject: MAIL from unknown[131.155.210.17]: from=<foo@watson.ibm.com>
+450 Client host rejected: cannot find your hostname, [131.155.210.17]
>>> client unknown 168.100.189.13
OK
>>> mail foo@watson.ibm.com
>>> mail foo@watson.ibm.com
OK
>>> mail foo@bad.domain
-./smtpd_check: reject: MAIL from foo[123.123.123.123]: 450 <bad.domain>: Domain not found
-450 <bad.domain>: Domain not found
+./smtpd_check: <queue id>: reject: MAIL from foo[123.123.123.123]: 450 <foo@bad.domain>: Sender address rejected: Domain not found
+./smtpd_check: <queue id>: reject: MAIL from foo[123.123.123.123]: from=<foo@bad.domain>
+450 <foo@bad.domain>: Sender address rejected: Domain not found
>>> sender_restrictions hash:./smtpd_check_access
OK
>>> mail bad-sender@any.domain
-./smtpd_check: reject: MAIL from foo[123.123.123.123]: 554 match bad-sender@
-554 match bad-sender@
+./smtpd_check: <queue id>: reject: MAIL from foo[123.123.123.123]: 554 <bad-sender@any.domain>: Sender address rejected: match bad-sender@
+./smtpd_check: <queue id>: reject: MAIL from foo[123.123.123.123]: from=<bad-sender@any.domain>
+554 <bad-sender@any.domain>: Sender address rejected: match bad-sender@
>>> mail bad-sender@good.domain
OK
>>> mail reject@this.address
-./smtpd_check: reject: MAIL from foo[123.123.123.123]: 554 match reject@this.address
-554 match reject@this.address
+./smtpd_check: <queue id>: reject: MAIL from foo[123.123.123.123]: 554 <reject@this.address>: Sender address rejected: match reject@this.address
+./smtpd_check: <queue id>: reject: MAIL from foo[123.123.123.123]: from=<reject@this.address>
+554 <reject@this.address>: Sender address rejected: match reject@this.address
>>> mail Reject@this.address
-./smtpd_check: reject: MAIL from foo[123.123.123.123]: 554 match reject@this.address
-554 match reject@this.address
+./smtpd_check: <queue id>: reject: MAIL from foo[123.123.123.123]: 554 <Reject@this.address>: Sender address rejected: match reject@this.address
+./smtpd_check: <queue id>: reject: MAIL from foo[123.123.123.123]: from=<Reject@this.address>
+554 <Reject@this.address>: Sender address rejected: match reject@this.address
>>> mail foo@bad.domain
-./smtpd_check: reject: MAIL from foo[123.123.123.123]: 554 match bad.domain
-554 match bad.domain
+./smtpd_check: <queue id>: reject: MAIL from foo[123.123.123.123]: 554 <foo@bad.domain>: Sender address rejected: match bad.domain
+./smtpd_check: <queue id>: reject: MAIL from foo[123.123.123.123]: from=<foo@bad.domain>
+554 <foo@bad.domain>: Sender address rejected: match bad.domain
>>> mail foo@Bad.domain
-./smtpd_check: reject: MAIL from foo[123.123.123.123]: 554 match bad.domain
-554 match bad.domain
+./smtpd_check: <queue id>: reject: MAIL from foo[123.123.123.123]: 554 <foo@Bad.domain>: Sender address rejected: match bad.domain
+./smtpd_check: <queue id>: reject: MAIL from foo[123.123.123.123]: from=<foo@Bad.domain>
+554 <foo@Bad.domain>: Sender address rejected: match bad.domain
>>> mail foo@random.bad.domain
-./smtpd_check: reject: MAIL from foo[123.123.123.123]: 554 match bad.domain
-554 match bad.domain
+./smtpd_check: <queue id>: reject: MAIL from foo[123.123.123.123]: 554 <foo@random.bad.domain>: Sender address rejected: match bad.domain
+./smtpd_check: <queue id>: reject: MAIL from foo[123.123.123.123]: from=<foo@random.bad.domain>
+554 <foo@random.bad.domain>: Sender address rejected: match bad.domain
>>> mail foo@friend.bad.domain
OK
>>> #
>>> client unknown 131.155.210.17
OK
>>> rcpt foo@watson.ibm.com
-./smtpd_check: reject: RCPT from unknown[131.155.210.17]: 450 Cannot find your hostname, [131.155.210.17]
-450 Cannot find your hostname, [131.155.210.17]
+./smtpd_check: <queue id>: reject: RCPT from unknown[131.155.210.17]: 450 Client host rejected: cannot find your hostname, [131.155.210.17]
+./smtpd_check: <queue id>: reject: RCPT from unknown[131.155.210.17]: from=<foo@friend.bad.domain> to=<foo@watson.ibm.com>
+450 Client host rejected: cannot find your hostname, [131.155.210.17]
>>> client unknown 168.100.189.13
OK
>>> rcpt foo@watson.ibm.com
>>> client foo 123.123.123.123
OK
>>> rcpt foo@watson.ibm.com
-./smtpd_check: reject: RCPT from foo[123.123.123.123]: 554 <foo@watson.ibm.com>: Relay access denied
-554 <foo@watson.ibm.com>: Relay access denied
+./smtpd_check: <queue id>: reject: RCPT from foo[123.123.123.123]: 554 <foo@watson.ibm.com>: Recipient address rejected: Relay access denied
+./smtpd_check: <queue id>: reject: RCPT from foo[123.123.123.123]: from=<foo@friend.bad.domain> to=<foo@watson.ibm.com>
+554 <foo@watson.ibm.com>: Recipient address rejected: Relay access denied
>>> rcpt foo@porcupine.org
OK
>>> recipient_restrictions check_relay_domains
>>> client foo 123.123.123.123
OK
>>> rcpt foo@watson.ibm.com
-./smtpd_check: reject: RCPT from foo[123.123.123.123]: 554 <foo@watson.ibm.com>: Relay access denied
-554 <foo@watson.ibm.com>: Relay access denied
+./smtpd_check: <queue id>: reject: RCPT from foo[123.123.123.123]: 554 <foo@watson.ibm.com>: Recipient address rejected: Relay access denied
+./smtpd_check: <queue id>: reject: RCPT from foo[123.123.123.123]: from=<foo@friend.bad.domain> to=<foo@watson.ibm.com>
+554 <foo@watson.ibm.com>: Recipient address rejected: Relay access denied
>>> rcpt foo@porcupine.org
OK
>>> recipient_restrictions hash:./smtpd_check_access
OK
>>> mail bad-sender@any.domain
-./smtpd_check: reject: MAIL from foo[123.123.123.123]: 554 match bad-sender@
-554 match bad-sender@
+./smtpd_check: <queue id>: reject: MAIL from foo[123.123.123.123]: 554 <bad-sender@any.domain>: Sender address rejected: match bad-sender@
+./smtpd_check: <queue id>: reject: MAIL from foo[123.123.123.123]: from=<bad-sender@any.domain>
+554 <bad-sender@any.domain>: Sender address rejected: match bad-sender@
>>> mail bad-sender@good.domain
OK
>>> mail reject@this.address
-./smtpd_check: reject: MAIL from foo[123.123.123.123]: 554 match reject@this.address
-554 match reject@this.address
+./smtpd_check: <queue id>: reject: MAIL from foo[123.123.123.123]: 554 <reject@this.address>: Sender address rejected: match reject@this.address
+./smtpd_check: <queue id>: reject: MAIL from foo[123.123.123.123]: from=<reject@this.address>
+554 <reject@this.address>: Sender address rejected: match reject@this.address
>>> mail foo@bad.domain
-./smtpd_check: reject: MAIL from foo[123.123.123.123]: 554 match bad.domain
-554 match bad.domain
+./smtpd_check: <queue id>: reject: MAIL from foo[123.123.123.123]: 554 <foo@bad.domain>: Sender address rejected: match bad.domain
+./smtpd_check: <queue id>: reject: MAIL from foo[123.123.123.123]: from=<foo@bad.domain>
+554 <foo@bad.domain>: Sender address rejected: match bad.domain
>>> mail foo@random.bad.domain
-./smtpd_check: reject: MAIL from foo[123.123.123.123]: 554 match bad.domain
-554 match bad.domain
+./smtpd_check: <queue id>: reject: MAIL from foo[123.123.123.123]: 554 <foo@random.bad.domain>: Sender address rejected: match bad.domain
+./smtpd_check: <queue id>: reject: MAIL from foo[123.123.123.123]: from=<foo@random.bad.domain>
+554 <foo@random.bad.domain>: Sender address rejected: match bad.domain
>>> mail foo@friend.bad.domain
OK
>>> #
>>> client spike.porcupine.org 168.100.189.2
OK
>>> client foo 127.0.0.2
-./smtpd_check: reject: CONNECT from foo[127.0.0.2]: 554 Service unavailable; [127.0.0.2] blocked using rbl.maps.vix.com
+./smtpd_check: <queue id>: reject: CONNECT from foo[127.0.0.2]: 554 Service unavailable; [127.0.0.2] blocked using rbl.maps.vix.com
+./smtpd_check: <queue id>: reject: CONNECT from foo[127.0.0.2]: from=<foo@friend.bad.domain>
554 Service unavailable; [127.0.0.2] blocked using rbl.maps.vix.com
>>> #
>>> # Hybrids
>>> client foo 131.155.210.17
OK
>>> rcpt foo@watson.ibm.com
-./smtpd_check: reject: RCPT from foo[131.155.210.17]: 554 <foo@watson.ibm.com>: Relay access denied
-554 <foo@watson.ibm.com>: Relay access denied
+./smtpd_check: <queue id>: reject: RCPT from foo[131.155.210.17]: 554 <foo@watson.ibm.com>: Recipient address rejected: Relay access denied
+./smtpd_check: <queue id>: reject: RCPT from foo[131.155.210.17]: from=<foo@friend.bad.domain> to=<foo@watson.ibm.com>
+554 <foo@watson.ibm.com>: Recipient address rejected: Relay access denied
>>> recipient_restrictions check_client_access,hash:./smtpd_check_access,check_relay_domains
OK
>>> client foo 131.155.210.17
>>> recipient_restrictions check_helo_access,hash:./smtpd_check_access,check_relay_domains
OK
>>> helo bad.domain
-./smtpd_check: reject: HELO from foo[131.155.210.17]: 554 match bad.domain
-554 match bad.domain
+./smtpd_check: <queue id>: reject: HELO from foo[131.155.210.17]: 554 <bad.domain>: Helo command rejected: match bad.domain
+./smtpd_check: <queue id>: reject: HELO from foo[131.155.210.17]: from=<foo@friend.bad.domain>
+554 <bad.domain>: Helo command rejected: match bad.domain
>>> rcpt foo@porcupine.org
-./smtpd_check: reject: RCPT from foo[131.155.210.17]: 554 match bad.domain
-554 match bad.domain
+./smtpd_check: <queue id>: reject: RCPT from foo[131.155.210.17]: 554 <bad.domain>: Helo command rejected: match bad.domain
+./smtpd_check: <queue id>: reject: RCPT from foo[131.155.210.17]: from=<foo@friend.bad.domain> to=<foo@porcupine.org>
+554 <bad.domain>: Helo command rejected: match bad.domain
>>> helo 131.155.210.17
./smtpd_check: warning: valid_hostname: numeric hostname: 131.155.210.17
OK
>>> recipient_restrictions check_sender_access,hash:./smtpd_check_access,check_relay_domains
OK
>>> mail foo@bad.domain
-./smtpd_check: reject: MAIL from foo[131.155.210.17]: 554 match bad.domain
-554 match bad.domain
+./smtpd_check: <queue id>: reject: MAIL from foo[131.155.210.17]: 554 <foo@bad.domain>: Sender address rejected: match bad.domain
+./smtpd_check: <queue id>: reject: MAIL from foo[131.155.210.17]: from=<foo@bad.domain>
+554 <foo@bad.domain>: Sender address rejected: match bad.domain
>>> rcpt foo@porcupine.org
-./smtpd_check: reject: RCPT from foo[131.155.210.17]: 554 match bad.domain
-554 match bad.domain
+./smtpd_check: <queue id>: reject: RCPT from foo[131.155.210.17]: 554 <foo@bad.domain>: Sender address rejected: match bad.domain
+./smtpd_check: <queue id>: reject: RCPT from foo[131.155.210.17]: from=<foo@bad.domain> to=<foo@porcupine.org>
+554 <foo@bad.domain>: Sender address rejected: match bad.domain
>>> mail foo@friend.bad.domain
OK
>>> rcpt foo@porcupine.org
>>> rcpt wietse@wzv.win.tue.nl
OK
>>> rcpt wietse@trouble.org
-./smtpd_check: reject: RCPT from foo[131.155.210.17]: 554 <wietse@trouble.org> Access denied
-554 <wietse@trouble.org> Access denied
+./smtpd_check: <queue id>: reject: RCPT from foo[131.155.210.17]: 554 <wietse@trouble.org>: Recipient address rejected: Access denied
+./smtpd_check: <queue id>: reject: RCPT from foo[131.155.210.17]: from=<foo@friend.bad.domain> to=<wietse@trouble.org>
+554 <wietse@trouble.org>: Recipient address rejected: Access denied
>>> rcpt wietse@porcupine.org
OK
>>> #
>>> mail foo@good.domain
OK
>>> rcpt foo@porcupine.org
-./smtpd_check: reject: RCPT from foo[131.155.210.17]: 554 match bad.domain
-554 match bad.domain
+./smtpd_check: <queue id>: reject: RCPT from foo[131.155.210.17]: 554 <bad.domain>: Helo command rejected: match bad.domain
+./smtpd_check: <queue id>: reject: RCPT from foo[131.155.210.17]: from=<foo@good.domain> to=<foo@porcupine.org>
+554 <bad.domain>: Helo command rejected: match bad.domain
>>> helo good.domain
OK
>>> mail foo@bad.domain
OK
>>> rcpt foo@porcupine.org
-./smtpd_check: reject: RCPT from foo[131.155.210.17]: 554 match bad.domain
-554 match bad.domain
+./smtpd_check: <queue id>: reject: RCPT from foo[131.155.210.17]: 554 <foo@bad.domain>: Sender address rejected: match bad.domain
+./smtpd_check: <queue id>: reject: RCPT from foo[131.155.210.17]: from=<foo@bad.domain> to=<foo@porcupine.org>
+554 <foo@bad.domain>: Sender address rejected: match bad.domain
>>> #
>>> # FQDN restrictions
>>> #
>>> helo foo.bar
OK
>>> helo foo
-./smtpd_check: reject: HELO from foo[131.155.210.17]: 504 <foo>: need fully-qualified hostname
-504 <foo>: need fully-qualified hostname
+./smtpd_check: <queue id>: reject: HELO from foo[131.155.210.17]: 504 <foo>: Helo command rejected: need fully-qualified hostname
+./smtpd_check: <queue id>: reject: HELO from foo[131.155.210.17]: from=<foo@bad.domain>
+504 <foo>: Helo command rejected: need fully-qualified hostname
>>> mail foo@foo.bar.
OK
>>> mail foo@foo.bar
OK
>>> mail foo@foo
-./smtpd_check: reject: MAIL from foo[131.155.210.17]: 504 <foo@foo>: need fully-qualified address
-504 <foo@foo>: need fully-qualified address
+./smtpd_check: <queue id>: reject: MAIL from foo[131.155.210.17]: 504 <foo@foo>: Sender address rejected: need fully-qualified address
+./smtpd_check: <queue id>: reject: MAIL from foo[131.155.210.17]: from=<foo@foo>
+504 <foo@foo>: Sender address rejected: need fully-qualified address
>>> mail foo
-./smtpd_check: reject: MAIL from foo[131.155.210.17]: 504 <foo>: need fully-qualified address
-504 <foo>: need fully-qualified address
+./smtpd_check: <queue id>: reject: MAIL from foo[131.155.210.17]: 504 <foo>: Sender address rejected: need fully-qualified address
+./smtpd_check: <queue id>: reject: MAIL from foo[131.155.210.17]: from=<foo>
+504 <foo>: Sender address rejected: need fully-qualified address
>>> rcpt foo@foo.bar.
OK
>>> rcpt foo@foo.bar
OK
>>> rcpt foo@foo
-./smtpd_check: reject: RCPT from foo[131.155.210.17]: 504 <foo@foo>: need fully-qualified address
-504 <foo@foo>: need fully-qualified address
+./smtpd_check: <queue id>: reject: RCPT from foo[131.155.210.17]: 504 <foo@foo>: Recipient address rejected: need fully-qualified address
+./smtpd_check: <queue id>: reject: RCPT from foo[131.155.210.17]: from=<foo> to=<foo@foo>
+504 <foo@foo>: Recipient address rejected: need fully-qualified address
>>> rcpt foo
-./smtpd_check: reject: RCPT from foo[131.155.210.17]: 504 <foo>: need fully-qualified address
-504 <foo>: need fully-qualified address
+./smtpd_check: <queue id>: reject: RCPT from foo[131.155.210.17]: 504 <foo>: Recipient address rejected: need fully-qualified address
+./smtpd_check: <queue id>: reject: RCPT from foo[131.155.210.17]: from=<foo> to=<foo>
+504 <foo>: Recipient address rejected: need fully-qualified address
>>> #
>>> # Numerical HELO checks
>>> #
>>> helo [321.255.255.255]
./smtpd_check: reject_invalid_hostaddr: [321.255.255.255]
./smtpd_check: warning: valid_hostaddr: invalid octet value: 321.255.255.255
-./smtpd_check: reject: HELO from foo[131.155.210.17]: 501 <[321.255.255.255]>: Invalid ip address
-501 <[321.255.255.255]>: Invalid ip address
+./smtpd_check: <queue id>: reject: HELO from foo[131.155.210.17]: 501 <[321.255.255.255]>: Helo command rejected: invalid ip address
+./smtpd_check: <queue id>: reject: HELO from foo[131.155.210.17]: from=<foo>
+501 <[321.255.255.255]>: Helo command rejected: invalid ip address
>>> helo [0.255.255.255]
./smtpd_check: reject_invalid_hostaddr: [0.255.255.255]
./smtpd_check: warning: valid_hostaddr: bad initial octet value: 0.255.255.255
-./smtpd_check: reject: HELO from foo[131.155.210.17]: 501 <[0.255.255.255]>: Invalid ip address
-501 <[0.255.255.255]>: Invalid ip address
+./smtpd_check: <queue id>: reject: HELO from foo[131.155.210.17]: 501 <[0.255.255.255]>: Helo command rejected: invalid ip address
+./smtpd_check: <queue id>: reject: HELO from foo[131.155.210.17]: from=<foo>
+501 <[0.255.255.255]>: Helo command rejected: invalid ip address
>>> helo [1.2.3.321]
./smtpd_check: reject_invalid_hostaddr: [1.2.3.321]
./smtpd_check: warning: valid_hostaddr: invalid octet value: 1.2.3.321
-./smtpd_check: reject: HELO from foo[131.155.210.17]: 501 <[1.2.3.321]>: Invalid ip address
-501 <[1.2.3.321]>: Invalid ip address
+./smtpd_check: <queue id>: reject: HELO from foo[131.155.210.17]: 501 <[1.2.3.321]>: Helo command rejected: invalid ip address
+./smtpd_check: <queue id>: reject: HELO from foo[131.155.210.17]: from=<foo>
+501 <[1.2.3.321]>: Helo command rejected: invalid ip address
>>> helo [1.2.3]
./smtpd_check: reject_invalid_hostaddr: [1.2.3]
./smtpd_check: warning: valid_hostaddr: invalid octet count: 1.2.3
-./smtpd_check: reject: HELO from foo[131.155.210.17]: 501 <[1.2.3]>: Invalid ip address
-501 <[1.2.3]>: Invalid ip address
+./smtpd_check: <queue id>: reject: HELO from foo[131.155.210.17]: 501 <[1.2.3]>: Helo command rejected: invalid ip address
+./smtpd_check: <queue id>: reject: HELO from foo[131.155.210.17]: from=<foo>
+501 <[1.2.3]>: Helo command rejected: invalid ip address
>>> helo [1.2.3.4.5]
./smtpd_check: reject_invalid_hostaddr: [1.2.3.4.5]
./smtpd_check: warning: valid_hostaddr: invalid octet count: 1.2.3.4.5
-./smtpd_check: reject: HELO from foo[131.155.210.17]: 501 <[1.2.3.4.5]>: Invalid ip address
-501 <[1.2.3.4.5]>: Invalid ip address
+./smtpd_check: <queue id>: reject: HELO from foo[131.155.210.17]: 501 <[1.2.3.4.5]>: Helo command rejected: invalid ip address
+./smtpd_check: <queue id>: reject: HELO from foo[131.155.210.17]: from=<foo>
+501 <[1.2.3.4.5]>: Helo command rejected: invalid ip address
>>> helo [1..2.3.4]
./smtpd_check: reject_invalid_hostaddr: [1..2.3.4]
./smtpd_check: warning: valid_hostaddr: misplaced dot: 1..2.3.4
-./smtpd_check: reject: HELO from foo[131.155.210.17]: 501 <[1..2.3.4]>: Invalid ip address
-501 <[1..2.3.4]>: Invalid ip address
+./smtpd_check: <queue id>: reject: HELO from foo[131.155.210.17]: 501 <[1..2.3.4]>: Helo command rejected: invalid ip address
+./smtpd_check: <queue id>: reject: HELO from foo[131.155.210.17]: from=<foo>
+501 <[1..2.3.4]>: Helo command rejected: invalid ip address
>>> helo [.1.2.3.4]
./smtpd_check: reject_invalid_hostaddr: [.1.2.3.4]
./smtpd_check: warning: valid_hostaddr: misplaced dot: .1.2.3.4
-./smtpd_check: reject: HELO from foo[131.155.210.17]: 501 <[.1.2.3.4]>: Invalid ip address
-501 <[.1.2.3.4]>: Invalid ip address
+./smtpd_check: <queue id>: reject: HELO from foo[131.155.210.17]: 501 <[.1.2.3.4]>: Helo command rejected: invalid ip address
+./smtpd_check: <queue id>: reject: HELO from foo[131.155.210.17]: from=<foo>
+501 <[.1.2.3.4]>: Helo command rejected: invalid ip address
>>> helo [1.2.3.4.5.]
./smtpd_check: reject_invalid_hostaddr: [1.2.3.4.5.]
./smtpd_check: warning: valid_hostaddr: misplaced dot: 1.2.3.4.5.
-./smtpd_check: reject: HELO from foo[131.155.210.17]: 501 <[1.2.3.4.5.]>: Invalid ip address
-501 <[1.2.3.4.5.]>: Invalid ip address
+./smtpd_check: <queue id>: reject: HELO from foo[131.155.210.17]: 501 <[1.2.3.4.5.]>: Helo command rejected: invalid ip address
+./smtpd_check: <queue id>: reject: HELO from foo[131.155.210.17]: from=<foo>
+501 <[1.2.3.4.5.]>: Helo command rejected: invalid ip address
>>> helo 1.2.3.4
./smtpd_check: reject_invalid_hostaddr: 1.2.3.4
OK
>>> helo 321.255.255.255
./smtpd_check: reject_invalid_hostaddr: 321.255.255.255
./smtpd_check: warning: valid_hostaddr: invalid octet value: 321.255.255.255
-./smtpd_check: reject: HELO from foo[131.155.210.17]: 501 <321.255.255.255>: Invalid ip address
-501 <321.255.255.255>: Invalid ip address
+./smtpd_check: <queue id>: reject: HELO from foo[131.155.210.17]: 501 <321.255.255.255>: Helo command rejected: invalid ip address
+./smtpd_check: <queue id>: reject: HELO from foo[131.155.210.17]: from=<foo>
+501 <321.255.255.255>: Helo command rejected: invalid ip address
>>> helo 0.255.255.255
./smtpd_check: reject_invalid_hostaddr: 0.255.255.255
./smtpd_check: warning: valid_hostaddr: bad initial octet value: 0.255.255.255
-./smtpd_check: reject: HELO from foo[131.155.210.17]: 501 <0.255.255.255>: Invalid ip address
-501 <0.255.255.255>: Invalid ip address
+./smtpd_check: <queue id>: reject: HELO from foo[131.155.210.17]: 501 <0.255.255.255>: Helo command rejected: invalid ip address
+./smtpd_check: <queue id>: reject: HELO from foo[131.155.210.17]: from=<foo>
+501 <0.255.255.255>: Helo command rejected: invalid ip address
>>> helo 1.2.3.321
./smtpd_check: reject_invalid_hostaddr: 1.2.3.321
./smtpd_check: warning: valid_hostaddr: invalid octet value: 1.2.3.321
-./smtpd_check: reject: HELO from foo[131.155.210.17]: 501 <1.2.3.321>: Invalid ip address
-501 <1.2.3.321>: Invalid ip address
+./smtpd_check: <queue id>: reject: HELO from foo[131.155.210.17]: 501 <1.2.3.321>: Helo command rejected: invalid ip address
+./smtpd_check: <queue id>: reject: HELO from foo[131.155.210.17]: from=<foo>
+501 <1.2.3.321>: Helo command rejected: invalid ip address
>>> helo 1.2.3
./smtpd_check: reject_invalid_hostaddr: 1.2.3
./smtpd_check: warning: valid_hostaddr: invalid octet count: 1.2.3
-./smtpd_check: reject: HELO from foo[131.155.210.17]: 501 <1.2.3>: Invalid ip address
-501 <1.2.3>: Invalid ip address
+./smtpd_check: <queue id>: reject: HELO from foo[131.155.210.17]: 501 <1.2.3>: Helo command rejected: invalid ip address
+./smtpd_check: <queue id>: reject: HELO from foo[131.155.210.17]: from=<foo>
+501 <1.2.3>: Helo command rejected: invalid ip address
>>> helo 1.2.3.4.5
./smtpd_check: reject_invalid_hostaddr: 1.2.3.4.5
./smtpd_check: warning: valid_hostaddr: invalid octet count: 1.2.3.4.5
-./smtpd_check: reject: HELO from foo[131.155.210.17]: 501 <1.2.3.4.5>: Invalid ip address
-501 <1.2.3.4.5>: Invalid ip address
+./smtpd_check: <queue id>: reject: HELO from foo[131.155.210.17]: 501 <1.2.3.4.5>: Helo command rejected: invalid ip address
+./smtpd_check: <queue id>: reject: HELO from foo[131.155.210.17]: from=<foo>
+501 <1.2.3.4.5>: Helo command rejected: invalid ip address
>>> helo 1..2.3.4
./smtpd_check: reject_invalid_hostaddr: 1..2.3.4
./smtpd_check: warning: valid_hostaddr: misplaced dot: 1..2.3.4
-./smtpd_check: reject: HELO from foo[131.155.210.17]: 501 <1..2.3.4>: Invalid ip address
-501 <1..2.3.4>: Invalid ip address
+./smtpd_check: <queue id>: reject: HELO from foo[131.155.210.17]: 501 <1..2.3.4>: Helo command rejected: invalid ip address
+./smtpd_check: <queue id>: reject: HELO from foo[131.155.210.17]: from=<foo>
+501 <1..2.3.4>: Helo command rejected: invalid ip address
>>> helo .1.2.3.4
./smtpd_check: reject_invalid_hostaddr: .1.2.3.4
./smtpd_check: warning: valid_hostaddr: misplaced dot: .1.2.3.4
-./smtpd_check: reject: HELO from foo[131.155.210.17]: 501 <.1.2.3.4>: Invalid ip address
-501 <.1.2.3.4>: Invalid ip address
+./smtpd_check: <queue id>: reject: HELO from foo[131.155.210.17]: 501 <.1.2.3.4>: Helo command rejected: invalid ip address
+./smtpd_check: <queue id>: reject: HELO from foo[131.155.210.17]: from=<foo>
+501 <.1.2.3.4>: Helo command rejected: invalid ip address
>>> helo 1.2.3.4.5.
./smtpd_check: reject_invalid_hostaddr: 1.2.3.4.5.
./smtpd_check: warning: valid_hostaddr: misplaced dot: 1.2.3.4.5.
-./smtpd_check: reject: HELO from foo[131.155.210.17]: 501 <1.2.3.4.5.>: Invalid ip address
-501 <1.2.3.4.5.>: Invalid ip address
+./smtpd_check: <queue id>: reject: HELO from foo[131.155.210.17]: 501 <1.2.3.4.5.>: Helo command rejected: invalid ip address
+./smtpd_check: <queue id>: reject: HELO from foo[131.155.210.17]: from=<foo>
+501 <1.2.3.4.5.>: Helo command rejected: invalid ip address
>>> client_restrictions permit_mynetworks,reject_unknown_client,check_client_access,hash:./smtpd_check_access
OK
>>> client unknown 131.155.210.17
-./smtpd_check: reject: CONNECT from unknown[131.155.210.17]: 450 Cannot find your hostname, [131.155.210.17]
-450 Cannot find your hostname, [131.155.210.17]
+./smtpd_check: <queue id>: reject: CONNECT from unknown[131.155.210.17]: 450 Client host rejected: cannot find your hostname, [131.155.210.17]
+450 Client host rejected: cannot find your hostname, [131.155.210.17]
>>> client unknown 168.100.189.13
OK
>>> client random.bad.domain 123.123.123.123
-./smtpd_check: reject: CONNECT from random.bad.domain[123.123.123.123]: 554 match bad.domain
-554 match bad.domain
+./smtpd_check: <queue id>: reject: CONNECT from random.bad.domain[123.123.123.123]: 554 <random.bad.domain[123.123.123.123]>: Client host rejected: match bad.domain
+554 <random.bad.domain[123.123.123.123]>: Client host rejected: match bad.domain
>>> client friend.bad.domain 123.123.123.123
OK
>>> client bad.domain 123.123.123.123
-./smtpd_check: reject: CONNECT from bad.domain[123.123.123.123]: 554 match bad.domain
-554 match bad.domain
+./smtpd_check: <queue id>: reject: CONNECT from bad.domain[123.123.123.123]: 554 <bad.domain[123.123.123.123]>: Client host rejected: match bad.domain
+554 <bad.domain[123.123.123.123]>: Client host rejected: match bad.domain
>>> client wzv.win.tue.nl 131.155.210.17
OK
>>> client aa.win.tue.nl 131.155.210.18
-./smtpd_check: reject: CONNECT from aa.win.tue.nl[131.155.210.18]: 554 match 131.155.210
-554 match 131.155.210
+./smtpd_check: <queue id>: reject: CONNECT from aa.win.tue.nl[131.155.210.18]: 554 <aa.win.tue.nl[131.155.210.18]>: Client host rejected: match 131.155.210
+554 <aa.win.tue.nl[131.155.210.18]>: Client host rejected: match 131.155.210
>>> client_restrictions permit_mynetworks
OK
>>> #
>>> client unknown 131.155.210.17
OK
>>> helo foo.
-./smtpd_check: reject: HELO from unknown[131.155.210.17]: 450 Cannot find your hostname, [131.155.210.17]
-450 Cannot find your hostname, [131.155.210.17]
+./smtpd_check: <queue id>: reject: HELO from unknown[131.155.210.17]: 450 Client host rejected: cannot find your hostname, [131.155.210.17]
+450 Client host rejected: cannot find your hostname, [131.155.210.17]
>>> client foo 123.123.123.123
OK
>>> helo foo.
-./smtpd_check: reject: HELO from foo[123.123.123.123]: 450 <foo.>: Host not found
-450 <foo.>: Host not found
+./smtpd_check: <queue id>: reject: HELO from foo[123.123.123.123]: 450 <foo.>: Helo command rejected: Host not found
+450 <foo.>: Helo command rejected: Host not found
>>> helo foo
-./smtpd_check: reject: HELO from foo[123.123.123.123]: 450 <foo>: Host not found
-450 <foo>: Host not found
+./smtpd_check: <queue id>: reject: HELO from foo[123.123.123.123]: 450 <foo>: Helo command rejected: Host not found
+450 <foo>: Helo command rejected: Host not found
>>> helo spike.porcupine.org
OK
>>> helo_restrictions permit_mynetworks,reject_unknown_client,reject_invalid_hostname,check_helo_access,hash:./smtpd_check_access
OK
>>> helo random.bad.domain
-./smtpd_check: reject: HELO from foo[123.123.123.123]: 554 match bad.domain
-554 match bad.domain
+./smtpd_check: <queue id>: reject: HELO from foo[123.123.123.123]: 554 <random.bad.domain>: Helo command rejected: match bad.domain
+554 <random.bad.domain>: Helo command rejected: match bad.domain
>>> helo friend.bad.domain
OK
>>> #
>>> client unknown 131.155.210.17
OK
>>> mail foo@watson.ibm.com
-./smtpd_check: reject: MAIL from unknown[131.155.210.17]: 450 Cannot find your hostname, [131.155.210.17]
-450 Cannot find your hostname, [131.155.210.17]
+./smtpd_check: <queue id>: reject: MAIL from unknown[131.155.210.17]: 450 Client host rejected: cannot find your hostname, [131.155.210.17]
+./smtpd_check: <queue id>: reject: MAIL from unknown[131.155.210.17]: from=<foo@watson.ibm.com>
+450 Client host rejected: cannot find your hostname, [131.155.210.17]
>>> client unknown 168.100.189.13
OK
>>> mail foo@watson.ibm.com
>>> mail foo@watson.ibm.com
OK
>>> mail foo@bad.domain
-./smtpd_check: reject: MAIL from foo[123.123.123.123]: 450 <bad.domain>: Domain not found
-450 <bad.domain>: Domain not found
+./smtpd_check: <queue id>: reject: MAIL from foo[123.123.123.123]: 450 <foo@bad.domain>: Sender address rejected: Domain not found
+./smtpd_check: <queue id>: reject: MAIL from foo[123.123.123.123]: from=<foo@bad.domain>
+450 <foo@bad.domain>: Sender address rejected: Domain not found
>>> sender_restrictions check_sender_access,hash:./smtpd_check_access
OK
>>> mail bad-sender@any.domain
-./smtpd_check: reject: MAIL from foo[123.123.123.123]: 554 match bad-sender@
-554 match bad-sender@
+./smtpd_check: <queue id>: reject: MAIL from foo[123.123.123.123]: 554 <bad-sender@any.domain>: Sender address rejected: match bad-sender@
+./smtpd_check: <queue id>: reject: MAIL from foo[123.123.123.123]: from=<bad-sender@any.domain>
+554 <bad-sender@any.domain>: Sender address rejected: match bad-sender@
>>> mail bad-sender@good.domain
OK
>>> mail reject@this.address
-./smtpd_check: reject: MAIL from foo[123.123.123.123]: 554 match reject@this.address
-554 match reject@this.address
+./smtpd_check: <queue id>: reject: MAIL from foo[123.123.123.123]: 554 <reject@this.address>: Sender address rejected: match reject@this.address
+./smtpd_check: <queue id>: reject: MAIL from foo[123.123.123.123]: from=<reject@this.address>
+554 <reject@this.address>: Sender address rejected: match reject@this.address
>>> mail Reject@this.address
-./smtpd_check: reject: MAIL from foo[123.123.123.123]: 554 match reject@this.address
-554 match reject@this.address
+./smtpd_check: <queue id>: reject: MAIL from foo[123.123.123.123]: 554 <Reject@this.address>: Sender address rejected: match reject@this.address
+./smtpd_check: <queue id>: reject: MAIL from foo[123.123.123.123]: from=<Reject@this.address>
+554 <Reject@this.address>: Sender address rejected: match reject@this.address
>>> mail foo@bad.domain
-./smtpd_check: reject: MAIL from foo[123.123.123.123]: 554 match bad.domain
-554 match bad.domain
+./smtpd_check: <queue id>: reject: MAIL from foo[123.123.123.123]: 554 <foo@bad.domain>: Sender address rejected: match bad.domain
+./smtpd_check: <queue id>: reject: MAIL from foo[123.123.123.123]: from=<foo@bad.domain>
+554 <foo@bad.domain>: Sender address rejected: match bad.domain
>>> mail foo@Bad.domain
-./smtpd_check: reject: MAIL from foo[123.123.123.123]: 554 match bad.domain
-554 match bad.domain
+./smtpd_check: <queue id>: reject: MAIL from foo[123.123.123.123]: 554 <foo@Bad.domain>: Sender address rejected: match bad.domain
+./smtpd_check: <queue id>: reject: MAIL from foo[123.123.123.123]: from=<foo@Bad.domain>
+554 <foo@Bad.domain>: Sender address rejected: match bad.domain
>>> mail foo@random.bad.domain
-./smtpd_check: reject: MAIL from foo[123.123.123.123]: 554 match bad.domain
-554 match bad.domain
+./smtpd_check: <queue id>: reject: MAIL from foo[123.123.123.123]: 554 <foo@random.bad.domain>: Sender address rejected: match bad.domain
+./smtpd_check: <queue id>: reject: MAIL from foo[123.123.123.123]: from=<foo@random.bad.domain>
+554 <foo@random.bad.domain>: Sender address rejected: match bad.domain
>>> mail foo@friend.bad.domain
OK
>>> #
>>> client unknown 131.155.210.17
OK
>>> rcpt foo@watson.ibm.com
-./smtpd_check: reject: RCPT from unknown[131.155.210.17]: 450 Cannot find your hostname, [131.155.210.17]
-450 Cannot find your hostname, [131.155.210.17]
+./smtpd_check: <queue id>: reject: RCPT from unknown[131.155.210.17]: 450 Client host rejected: cannot find your hostname, [131.155.210.17]
+./smtpd_check: <queue id>: reject: RCPT from unknown[131.155.210.17]: from=<foo@friend.bad.domain> to=<foo@watson.ibm.com>
+450 Client host rejected: cannot find your hostname, [131.155.210.17]
>>> client unknown 168.100.189.13
OK
>>> rcpt foo@watson.ibm.com
>>> client foo 123.123.123.123
OK
>>> rcpt foo@watson.ibm.com
-./smtpd_check: reject: RCPT from foo[123.123.123.123]: 554 <foo@watson.ibm.com>: Relay access denied
-554 <foo@watson.ibm.com>: Relay access denied
+./smtpd_check: <queue id>: reject: RCPT from foo[123.123.123.123]: 554 <foo@watson.ibm.com>: Recipient address rejected: Relay access denied
+./smtpd_check: <queue id>: reject: RCPT from foo[123.123.123.123]: from=<foo@friend.bad.domain> to=<foo@watson.ibm.com>
+554 <foo@watson.ibm.com>: Recipient address rejected: Relay access denied
>>> rcpt foo@porcupine.org
OK
>>> recipient_restrictions check_relay_domains
>>> client foo 123.123.123.123
OK
>>> rcpt foo@watson.ibm.com
-./smtpd_check: reject: RCPT from foo[123.123.123.123]: 554 <foo@watson.ibm.com>: Relay access denied
-554 <foo@watson.ibm.com>: Relay access denied
+./smtpd_check: <queue id>: reject: RCPT from foo[123.123.123.123]: 554 <foo@watson.ibm.com>: Recipient address rejected: Relay access denied
+./smtpd_check: <queue id>: reject: RCPT from foo[123.123.123.123]: from=<foo@friend.bad.domain> to=<foo@watson.ibm.com>
+554 <foo@watson.ibm.com>: Recipient address rejected: Relay access denied
>>> rcpt foo@porcupine.org
OK
>>> recipient_restrictions check_recipient_access,hash:./smtpd_check_access
OK
>>> mail bad-sender@any.domain
-./smtpd_check: reject: MAIL from foo[123.123.123.123]: 554 match bad-sender@
-554 match bad-sender@
+./smtpd_check: <queue id>: reject: MAIL from foo[123.123.123.123]: 554 <bad-sender@any.domain>: Sender address rejected: match bad-sender@
+./smtpd_check: <queue id>: reject: MAIL from foo[123.123.123.123]: from=<bad-sender@any.domain>
+554 <bad-sender@any.domain>: Sender address rejected: match bad-sender@
>>> mail bad-sender@good.domain
OK
>>> mail reject@this.address
-./smtpd_check: reject: MAIL from foo[123.123.123.123]: 554 match reject@this.address
-554 match reject@this.address
+./smtpd_check: <queue id>: reject: MAIL from foo[123.123.123.123]: 554 <reject@this.address>: Sender address rejected: match reject@this.address
+./smtpd_check: <queue id>: reject: MAIL from foo[123.123.123.123]: from=<reject@this.address>
+554 <reject@this.address>: Sender address rejected: match reject@this.address
>>> mail foo@bad.domain
-./smtpd_check: reject: MAIL from foo[123.123.123.123]: 554 match bad.domain
-554 match bad.domain
+./smtpd_check: <queue id>: reject: MAIL from foo[123.123.123.123]: 554 <foo@bad.domain>: Sender address rejected: match bad.domain
+./smtpd_check: <queue id>: reject: MAIL from foo[123.123.123.123]: from=<foo@bad.domain>
+554 <foo@bad.domain>: Sender address rejected: match bad.domain
>>> mail foo@random.bad.domain
-./smtpd_check: reject: MAIL from foo[123.123.123.123]: 554 match bad.domain
-554 match bad.domain
+./smtpd_check: <queue id>: reject: MAIL from foo[123.123.123.123]: 554 <foo@random.bad.domain>: Sender address rejected: match bad.domain
+./smtpd_check: <queue id>: reject: MAIL from foo[123.123.123.123]: from=<foo@random.bad.domain>
+554 <foo@random.bad.domain>: Sender address rejected: match bad.domain
>>> mail foo@friend.bad.domain
OK
>>> #
>>> client spike.porcupine.org 168.100.189.2
OK
>>> client foo 127.0.0.2
-./smtpd_check: reject: CONNECT from foo[127.0.0.2]: 554 Service unavailable; [127.0.0.2] blocked using rbl.maps.vix.com
+./smtpd_check: <queue id>: reject: CONNECT from foo[127.0.0.2]: 554 Service unavailable; [127.0.0.2] blocked using rbl.maps.vix.com
+./smtpd_check: <queue id>: reject: CONNECT from foo[127.0.0.2]: from=<foo@friend.bad.domain>
554 Service unavailable; [127.0.0.2] blocked using rbl.maps.vix.com
>>> #
>>> # unknown sender/recipient domain
>>> rcpt wietse@porcupine.org
OK
>>> rcpt wietse@no.recipient.domain
-./smtpd_check: reject: RCPT from foo[127.0.0.2]: 554 <no.recipient.domain>: Domain not found
-554 <no.recipient.domain>: Domain not found
+./smtpd_check: <queue id>: reject: RCPT from foo[127.0.0.2]: 554 <wietse@no.recipient.domain>: Recipient address rejected: Domain not found
+./smtpd_check: <queue id>: reject: RCPT from foo[127.0.0.2]: from=<wietse@porcupine.org> to=<wietse@no.recipient.domain>
+554 <wietse@no.recipient.domain>: Recipient address rejected: Domain not found
>>> mail wietse@no.sender.domain
OK
>>> rcpt wietse@porcupine.org
-./smtpd_check: reject: RCPT from foo[127.0.0.2]: 554 <no.sender.domain>: Domain not found
-554 <no.sender.domain>: Domain not found
+./smtpd_check: <queue id>: reject: RCPT from foo[127.0.0.2]: 554 <wietse@no.sender.domain>: Sender address rejected: Domain not found
+./smtpd_check: <queue id>: reject: RCPT from foo[127.0.0.2]: from=<wietse@no.sender.domain> to=<wietse@porcupine.org>
+554 <wietse@no.sender.domain>: Sender address rejected: Domain not found
#include <mymalloc.h>
#include <vstream.h>
#include <name_mask.h>
+#include <stringops.h>
/* Global library. */
state->buffer = vstring_alloc(100);
state->name = mystrdup(name);
state->addr = mystrdup(addr);
+ state->namaddr = concatenate(name, "[", addr, "]", (char *) 0);
state->error_count = 0;
state->error_mask = 0;
state->notify_mask = name_mask(mail_error_masks, var_notify_classes);
myfree(state->name);
if (state->addr)
myfree(state->addr);
+ if (state->namaddr)
+ myfree(state->namaddr);
}
/* .IP "-R interval"
/* Wait for a random period of time 0 <= n <= interval between messages.
/* Suspending one thread does not affect other delivery threads.
-/* threads keep running.
/* .IP "-w interval"
/* Wait a fixed time between messages.
/* Suspending one thread does not affect other delivery threads.