2
0
mirror of https://github.com/vdukhovni/postfix synced 2025-08-29 13:18:12 +00:00

snapshot-19990509

This commit is contained in:
Wietse Venema 1999-05-09 00:00:00 -05:00
parent 5d89d7ae94
commit 138a7cbb80
20 changed files with 786 additions and 496 deletions

View File

@ -2745,6 +2745,16 @@ Apologies for any names omitted.
= canonical, virtual, alias, forward, include" to restore = canonical, virtual, alias, forward, include" to restore
previous behavior. previous behavior.
Feature: command_expansion_filter and forward_expansion_filter Feature: forward_expansion_filter configuration parameter
configuration parameters that control what characters may that controls what characters may appear in $name expansions
appear in $name expansions of mailbox_command and forward_path. 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.

View File

@ -1,4 +1,4 @@
Incompatible changes with snapshot-19990504: Incompatible changes with snapshot-19990509:
=========================================== ===========================================
- The Postfix local delivery agent no longer automatically propagates - The Postfix local delivery agent no longer automatically propagates
@ -6,39 +6,41 @@ the address extension to aliases/include/forward addresses. Specify
"propagate_unmatched_extensions = canonical, virtual, alias, forward, "propagate_unmatched_extensions = canonical, virtual, alias, forward,
include" to restore the old behavior. include" to restore the old behavior.
- The luser_relay syntax has changed. You can specify one address, - The luser_relay syntax has changed. You can specify one address;
and it is subjected to $user, etc. expansions. See conf/main.cf. 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 $.
- File system reorganization: daemon executables are in the libexec - File system reorganization: daemon executables are in the libexec
subdirectory, command executables in the bin subdirectory. The subdirectory, command executables in the bin subdirectory. The
INSTALL instructions now recommend installing daemons and commands INSTALL instructions now recommend installing daemons and commands
into separate directories. into separate directories.
Major changes with snapshot-19990504: Major changes with snapshot-19990509:
===================================== =====================================
In addition to several little bugfixes, none related to security, In addition to several little bugfixes, none related to security,
lots of internal code cleanup, lots of new functionality, and lots lots of internal code cleanup, lots of new functionality, and lots
of Solaris workarounds. 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 - Specify "forward_path = /var/forward/$user" to avoid looking up
.forward files in user home directories. The default value is .forward files in user home directories. The default value is
$home/.forward$recipient_delimiter$extension, $home/.forward. $home/.forward$recipient_delimiter$extension, $home/.forward.
Initial code by Philip A. Prindeville, Mirapoint, Inc., USA. Initial code by Philip A. Prindeville, Mirapoint, Inc., USA.
- Conditional $name expansion in forward_path, mailbox_command, - Conditional $name expansion in forward_path and luser_relay.
and luser_relay. Available names are: $user (bare user name) $shell Available names are: $user (bare user name) $shell (user login
(user login shell), $home (user home directory), $recipient shell), $home (user home directory), $recipient (everything to the
(everything to the left of @), $extension (optional address left of @), $extension (optional address extension), $domain
extension), $domain (everything to the right of @), and (everything to the right of @), and $recipient_delimiter. A simple
$recipient_delimiter. A simple $name expands as usual. ${name?value} $name expands as usual. ${name?value} expands to value when $name
expands to value when $name is defined. ${name:value} expands to is defined. ${name:value} expands to value when $name is not
value when $name is not defined. With ${name?value} and ${name:value}, defined. With ${name?value} and ${name:value}, the value is subject
the value is subject to another iteration of $name expansion. to another iteration of $name expansion.
- POSIX regular expression support, enabled by default on 4.4BSD, - POSIX regular expression support, enabled by default on 4.4BSD,
LINUX, HP-UX, and Solaris 2.5 and later. See conf/sample-regexp.cf. LINUX, HP-UX, and Solaris 2.5 and later. See conf/sample-regexp.cf.

View File

@ -63,7 +63,7 @@ luser_relay =
mail_name = Postfix mail_name = Postfix
mail_owner = postfix mail_owner = postfix
mail_spool_directory = /var/mail mail_spool_directory = /var/mail
mail_version = Snapshot-19990508 mail_version = Snapshot-19990509
mailbox_command = mailbox_command =
mailbox_transport = mailbox_transport =
maps_rbl_domains = rbl.maps.vix.com maps_rbl_domains = rbl.maps.vix.com

View File

@ -340,13 +340,13 @@ extern char *var_rcpt_delim;
#define DEF_CMD_EXP_FILTER "1234567890!@%-_=+:,./\ #define DEF_CMD_EXP_FILTER "1234567890!@%-_=+:,./\
abcdefghijklmnopqrstuvwxyz\ abcdefghijklmnopqrstuvwxyz\
ABCDEFGHIJKLMNOPQRSTUVWXYZ" ABCDEFGHIJKLMNOPQRSTUVWXYZ"
extern char *var_cmd_exp_filter;; extern char *var_cmd_exp_filter;
#define VAR_FWD_EXP_FILTER "forward_expansion_filter" #define VAR_FWD_EXP_FILTER "forward_expansion_filter"
#define DEF_FWD_EXP_FILTER "1234567890!@%-_=+:,./\ #define DEF_FWD_EXP_FILTER "1234567890!@%-_=+:,./\
abcdefghijklmnopqrstuvwxyz\ abcdefghijklmnopqrstuvwxyz\
ABCDEFGHIJKLMNOPQRSTUVWXYZ" ABCDEFGHIJKLMNOPQRSTUVWXYZ"
extern char *var_fwd_exp_filter;; extern char *var_fwd_exp_filter;
#define VAR_RCPT_FDELIM "recipient_feature_delimiter" #define VAR_RCPT_FDELIM "recipient_feature_delimiter"
#define DEF_RCPT_FDELIM "" #define DEF_RCPT_FDELIM ""

View File

@ -15,7 +15,7 @@
* Version of this program. * Version of this program.
*/ */
#define VAR_MAIL_VERSION "mail_version" #define VAR_MAIL_VERSION "mail_version"
#define DEF_MAIL_VERSION "Snapshot-19990508" #define DEF_MAIL_VERSION "Snapshot-19990509"
extern char *var_mail_version; extern char *var_mail_version;
/* LICENSE /* LICENSE

View File

@ -395,9 +395,41 @@ and <b>/usr/lib/Mail.rc</b>).
With mailing lists, <b>Delivered-To:</b> can get in the way when 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 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 in outbound mail. The recommended solution is to use a regular
CONTROL</b> section in the documentation of the <a expression-based filter at the SMTP port:
href="local.8.html">local</a> delivery agent.
<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> <p>

View File

@ -76,8 +76,9 @@ is no direct path from the network to the security-sensitive local
delivery programs - an intruder has to break through several other delivery programs - an intruder has to break through several other
programs first. Postfix does not even trust the contents of its programs first. Postfix does not even trust the contents of its
own queue files, or the contents of its own IPC messages. Postfix own queue files, or the contents of its own IPC messages. Postfix
avoids placing sender-provided information into shell environment filters sender-provided information before exporting it via
variables. Last but not least, no Postfix program is <i>set-uid</i>. environment variables. Last but not least, no Postfix program is
<i>set-uid</i>.
</ul> </ul>

View File

@ -111,20 +111,20 @@ LOCAL(8) LOCAL(8)
ter. The command executes with the privileges of the ter. The command executes with the privileges of the
recipient user (exception: in case of delivery as root, recipient user (exception: in case of delivery as root,
the command executes with the privileges of the command executes with the privileges of
<b>default</b><i>_</i><b>privs</b>). The command is subject to interpolation <b>default</b><i>_</i><b>privs</b>).
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.
Mailbox delivery can be delegated to alternative message 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.
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
@ -137,60 +137,60 @@ LOCAL(8) LOCAL(8)
LOCAL(8) LOCAL(8) 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 envelope recipient address, prepends a <b>Return-Path:</b> header
with the envelope sender address, prepends a &gt; character with the envelope sender address, prepends a &gt; character
to lines beginning with "<b>From</b> ", and appends an empty to lines beginning with "<b>From</b> ", and appends an empty
line. The mailbox is locked for exclusive access while line. The mailbox is locked for exclusive access while
delivery is in progress. In case of problems, an attempt delivery is in progress. In case of problems, an attempt
is made to truncate the mailbox to its original length. is made to truncate the mailbox to its original length.
In the case of <b>maildir</b> delivery, the local daemon prepends In the case of <b>maildir</b> delivery, the local daemon prepends
a <b>Delivered-To:</b> header with the envelope recipient address 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. sender address.
<b>EXTERNAL</b> <b>COMMAND</b> <b>DELIVERY</b> <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 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- restricts delivery to external commands. The default set-
ting (<b>alias,</b> <b>forward</b>) forbids command destinations in ting (<b>alias,</b> <b>forward</b>) forbids command destinations in
<b>:include:</b> files. <b>:include:</b> files.
The command is executed directly where possible. Assis- The command is executed directly where possible. Assis-
tance by the shell (<b>/bin/sh</b> on UNIX systems) is used only tance by the shell (<b>/bin/sh</b> on UNIX systems) is used only
when the command contains shell magic characters, or when when the command contains shell magic characters, or when
the command invokes a shell built-in command. the command invokes a shell built-in command.
A limited amount of command output (standard output and A limited amount of command output (standard output and
standard error) is captured for inclusion with non-deliv- standard error) is captured for inclusion with non-deliv-
ery status reports. A command is forcibly terminated if 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. 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- Command exit status codes are expected to follow the con-
ventions defined in &lt;<b>sysexits.h</b>&gt;. ventions defined in &lt;<b>sysexits.h</b>&gt;.
When mail is delivered on behalf of a user, the <b>HOME</b>, <b>LOG-</b> A limited amount of message context is exported via envi-
<b>NAME</b>, and <b>SHELL</b> environment variables are set accordingly. 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- The <b>PATH</b> environment variable is always reset to a system-
dependent default path, and the <b>TZ</b> (time zone) environment dependent default path, and the <b>TZ</b> (time zone) environment
variable is always passed on without change. 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.
@ -203,60 +203,60 @@ LOCAL(8) LOCAL(8)
LOCAL(8) LOCAL(8) 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> <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 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> delivery to external files. The default setting (<b>alias,</b>
<b>forward</b>) forbids file destinations in <b>:include:</b> files. <b>forward</b>) forbids file destinations in <b>:include:</b> files.
Specify a pathname ending in <b>/</b> for <b>qmail</b>-compatible Specify a pathname ending in <b>/</b> for <b>qmail</b>-compatible
<b>maildir</b> delivery. <b>maildir</b> delivery.
The <b>local</b> daemon prepends a "<b>From</b> <i>sender</i> <i>time_stamp</i>" enve- 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> lope header to each message, prepends a <b>Delivered-To:</b>
header with the recipient envelope address, prepends a &gt; header with the recipient envelope address, prepends a &gt;
character to lines beginning with "<b>From</b> ", and appends an character to lines beginning with "<b>From</b> ", and appends an
empty line. The envelope sender address is available in empty line. The envelope sender address is available in
the <b>Return-Path:</b> header. When the destination is a regu- the <b>Return-Path:</b> header. When the destination is a regu-
lar file, it is locked for exclusive access while delivery lar file, it is locked for exclusive access while delivery
is in progress. In case of problems, an attempt is made to is in progress. In case of problems, an attempt is made to
truncate a regular file to its original length. truncate a regular file to its original length.
In the case of <b>maildir</b> delivery, the local daemon prepends In the case of <b>maildir</b> delivery, the local daemon prepends
a <b>Delivered-To:</b> header with the envelope recipient a <b>Delivered-To:</b> header with the envelope recipient
address. The envelope sender address is available in the address. The envelope sender address is available in the
<b>Return-Path:</b> header. <b>Return-Path:</b> header.
<b>ADDRESS</b> <b>EXTENSION</b> <b>ADDRESS</b> <b>EXTENSION</b>
The optional <b>recipient</b><i>_</i><b>delimiter</b> configuration parameter The optional <b>recipient</b><i>_</i><b>delimiter</b> configuration parameter
specifies how to separate address extensions from local specifies how to separate address extensions from local
recipient names. recipient names.
For example, with "<b>recipient</b><i>_</i><b>delimiter</b> <b>=</b> <b>+</b>", mail for 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 <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> 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 <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. 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. <i>name</i>+<i>foo</i>' header line.
<b>DELIVERY</b> <b>RIGHTS</b> <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 made with the rights of the receiving user on whose behalf
the delivery is made. In the absence of a user context, 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 <b>local</b> daemon uses the owner rights of the <b>:include:</b>
file or alias database. When those files are owned by the file or alias database. When those files are owned by the
superuser, delivery is made with the rights specified with superuser, delivery is made with the rights specified with
the <b>default</b><i>_</i><b>privs</b> configuration parameter. 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,
@ -269,24 +269,33 @@ LOCAL(8) LOCAL(8)
LOCAL(8) LOCAL(8) 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. ble.
<b>BUGS</b> <b>BUGS</b>
For security reasons, the message delivery status of For security reasons, the message delivery status of
external commands or of external files is never check- external commands or of external files is never check-
pointed to file. As a result, the program may occasionally pointed to file. As a result, the program may occasionally
deliver more than once to a command or external file. Bet- deliver more than once to a command or external file. Bet-
ter safe than sorry. ter safe than sorry.
Mutually-recursive aliases or ~/.<b>forward</b> files are not Mutually-recursive aliases or ~/.<b>forward</b> files are not
detected early. The resulting mail forwarding loop is detected early. The resulting mail forwarding loop is
broken by the use of the <b>Delivered-To:</b> message header. broken by the use of the <b>Delivered-To:</b> message header.
<b>CONFIGURATION</b> <b>PARAMETERS</b> <b>CONFIGURATION</b> <b>PARAMETERS</b>
The following <b>main.cf</b> parameters are especially relevant The following <b>main.cf</b> parameters are especially relevant
to this program. See the Postfix <b>main.cf</b> file for syntax 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> details and for default values. Use the <b>postfix</b> <b>reload</b>
command after a configuration change. command after a configuration change.
<b>Miscellaneous</b> <b>Miscellaneous</b>
@ -298,10 +307,10 @@ LOCAL(8) LOCAL(8)
ject to <i>$name</i> expansion. ject to <i>$name</i> expansion.
<b>local</b><i>_</i><b>command</b><i>_</i><b>shell</b> <b>local</b><i>_</i><b>command</b><i>_</i><b>shell</b>
Shell to use for external command execution (for Shell to use for external command execution (for
example, /some/where/smrsh -c). When a shell is example, /some/where/smrsh -c). When a shell is
specified, it is invoked even when the command con- 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. ters.
<b>owner</b><i>_</i><b>request</b><i>_</i><b>special</b> <b>owner</b><i>_</i><b>request</b><i>_</i><b>special</b>
@ -314,15 +323,6 @@ LOCAL(8) LOCAL(8)
<b>Mailbox</b> <b>delivery</b> <b>Mailbox</b> <b>delivery</b>
<b>fallback</b><i>_</i><b>transport</b> <b>fallback</b><i>_</i><b>transport</b>
Message transport for recipients that are not found 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.
@ -335,35 +335,43 @@ LOCAL(8) LOCAL(8)
LOCAL(8) LOCAL(8) 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> <b>luser</b><i>_</i><b>relay</b>
Destination (<i>@domain</i> or <i>address</i>) for non-existent Destination (<i>@domain</i> or <i>address</i>) for non-existent
users. The <i>address</i> is subjected to <i>$name</i> expan- users. The <i>address</i> is subjected to <i>$name</i> expan-
sion. sion.
<b>mail</b><i>_</i><b>spool</b><i>_</i><b>directory</b> <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. pathname is system dependent.
<b>mailbox</b><i>_</i><b>command</b> <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 command executes with the recipient privileges
(exception: root). The string is subject to $name (exception: root). The string is subject to $name
expansions. expansions.
<b>mailbox</b><i>_</i><b>transport</b> <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 all local recipients, whether or not they are found
in the UNIX passwd database. This parameter over- in the UNIX passwd database. This parameter over-
rides all other configuration parameters that con- rides all other configuration parameters that con-
trol mailbox delivery, including <b>luser</b><i>_</i><b>relay</b>. trol mailbox delivery, including <b>luser</b><i>_</i><b>relay</b>.
<b>Locking</b> <b>controls</b> <b>Locking</b> <b>controls</b>
<b>deliver</b><i>_</i><b>lock</b><i>_</i><b>attempts</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. sive lock on a mailbox or external file.
<b>deliver</b><i>_</i><b>lock</b><i>_</i><b>delay</b> <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. acquire an exclusive lock.
<b>stale</b><i>_</i><b>lock</b><i>_</i><b>time</b> <b>stale</b><i>_</i><b>lock</b><i>_</i><b>time</b>
@ -371,25 +379,17 @@ LOCAL(8) LOCAL(8)
<b>Resource</b> <b>controls</b> <b>Resource</b> <b>controls</b>
<b>command</b><i>_</i><b>time</b><i>_</i><b>limit</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. command.
<b>duplicate</b><i>_</i><b>filter</b><i>_</i><b>limit</b> <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. from alias etc. expansion.
<b>line</b><i>_</i><b>length</b><i>_</i><b>limit</b> <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. 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 6
@ -401,37 +401,44 @@ LOCAL(8) LOCAL(8)
LOCAL(8) LOCAL(8) 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>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>Security</b> <b>controls</b>
<b>allow</b><i>_</i><b>mail</b><i>_</i><b>to</b><i>_</i><b>commands</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. command.
<b>allow</b><i>_</i><b>mail</b><i>_</i><b>to</b><i>_</i><b>files</b> <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. file.
<b>command</b><i>_</i><b>expansion</b><i>_</i><b>filter</b> <b>command</b><i>_</i><b>expansion</b><i>_</i><b>filter</b>
What characters are allowed to appear in $name What characters are allowed to appear in $name
expansions of mailbox_command. Illegal characters expansions of mailbox_command. Illegal characters
are replaced by underscores. are replaced by underscores.
<b>default</b><i>_</i><b>privs</b> <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. command.
<b>forward</b><i>_</i><b>expansion</b><i>_</i><b>filter</b> <b>forward</b><i>_</i><b>expansion</b><i>_</i><b>filter</b>
What characters are allowed to appear in $name What characters are allowed to appear in $name
expansions of forward_path. Illegal characters are expansions of forward_path. Illegal characters are
replaced by underscores. replaced by underscores.
<b>HISTORY</b> <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. 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. Daniel Bernstein.
<b>SEE</b> <b>ALSO</b> <b>SEE</b> <b>ALSO</b>
@ -442,12 +449,24 @@ LOCAL(8) LOCAL(8)
<a href="qmgr.8.html">qmgr(8)</a> queue manager <a href="qmgr.8.html">qmgr(8)</a> queue manager
<b>LICENSE</b> <b>LICENSE</b>
The Secure Mailer license must be distributed with this The Secure Mailer license must be distributed with this
software. software.
<b>AUTHOR(S)</b> <b>AUTHOR(S)</b>
Wietse Venema Wietse Venema
IBM T.J. Watson Research IBM T.J. Watson Research
7
LOCAL(8) LOCAL(8)
P.O. Box 704 P.O. Box 704
Yorktown Heights, NY 10598, USA Yorktown Heights, NY 10598, USA
@ -458,7 +477,54 @@ LOCAL(8) LOCAL(8)
7
8
</pre> </body> </html> </pre> </body> </html>

View File

@ -116,11 +116,11 @@ decisions on the basis of first-hand information.
<p> <p>
Of course, Postfix programs do not trust data received from the Of course, Postfix programs do not trust data received from the
network, either. In particular, no Postfix program places network, either. In particular, Postfix filters sender-provided
sender-provided data into shell command lines or into environment data before exporting it via environment variables. If there is one
variables. If there is one lesson that people have learned from lesson that people have learned from Web site security disasters
Web site security disasters it is this one: <i> don't let any data it is this one: <i> don't let any data from the network near a
from the network near a shell</i>. shell</i>. Filtering is the best we can do.
<h2>Large inputs</h2> <h2>Large inputs</h2>

View File

@ -15,6 +15,9 @@
/* input. A limited amount of standard output and standard error /* input. A limited amount of standard output and standard error
/* output is captured for diagnostics purposes. /* output is captured for diagnostics purposes.
/* Duplicate commands for the same recipient are suppressed. /* 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: /* Arguments:
/* .IP state /* .IP state
@ -49,6 +52,7 @@
#include <unistd.h> #include <unistd.h>
#include <stdlib.h> #include <stdlib.h>
#include <stdarg.h> #include <stdarg.h>
#include <string.h>
/* Utility library. */ /* Utility library. */
@ -57,7 +61,6 @@
#include <vstring.h> #include <vstring.h>
#include <vstream.h> #include <vstream.h>
#include <argv.h> #include <argv.h>
#include <mac_expand.h>
/* Global library. */ /* Global library. */
@ -83,8 +86,8 @@ int deliver_command(LOCAL_STATE state, USER_ATTR usr_attr, char *command)
int deliver_status; int deliver_status;
ARGV *env; ARGV *env;
int copy_flags; int copy_flags;
VSTRING *expanded_cmd = 0; char **cpp;
char *xcommand ; char *cp;
/* /*
* Make verbose logging easier to understand. * Make verbose logging easier to understand.
@ -143,24 +146,27 @@ int deliver_command(LOCAL_STATE state, USER_ATTR usr_attr, char *command)
env = argv_alloc(1); env = argv_alloc(1);
if (usr_attr.home) if (usr_attr.home)
argv_add(env, "HOME", usr_attr.home, ARGV_END); argv_add(env, "HOME", usr_attr.home, ARGV_END);
if (usr_attr.logname) argv_add(env, "LOGNAME", state.msg_attr.user, ARGV_END);
argv_add(env, "LOGNAME", usr_attr.logname, ARGV_END); argv_add(env, "USER", state.msg_attr.user, ARGV_END);
if (usr_attr.shell) if (usr_attr.shell)
argv_add(env, "SHELL", usr_attr.shell, ARGV_END); 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); argv_terminate(env);
if (command == var_mailbox_command) { /*
expanded_cmd = vstring_alloc(100); * Censor out undesirable characters from exported data.
local_expand(expanded_cmd, command, &state, */
&usr_attr, var_cmd_exp_filter); for (cpp = env->argv; *cpp; cpp += 2)
xcommand = vstring_str(expanded_cmd); for (cp = cpp[1]; *(cp += strspn(cp, var_cmd_exp_filter)) != 0;)
} else { *cp++ = '_';
xcommand = command;
}
cmd_status = pipe_command(state.msg_attr.fp, why, cmd_status = pipe_command(state.msg_attr.fp, why,
PIPE_CMD_UID, usr_attr.uid, PIPE_CMD_UID, usr_attr.uid,
PIPE_CMD_GID, usr_attr.gid, PIPE_CMD_GID, usr_attr.gid,
PIPE_CMD_COMMAND, xcommand, PIPE_CMD_COMMAND, command,
PIPE_CMD_COPY_FLAGS, copy_flags, PIPE_CMD_COPY_FLAGS, copy_flags,
PIPE_CMD_SENDER, state.msg_attr.sender, PIPE_CMD_SENDER, state.msg_attr.sender,
PIPE_CMD_DELIVERED, state.msg_attr.delivered, PIPE_CMD_DELIVERED, state.msg_attr.delivered,
@ -170,8 +176,6 @@ int deliver_command(LOCAL_STATE state, USER_ATTR usr_attr, char *command)
PIPE_CMD_END); PIPE_CMD_END);
argv_free(env); argv_free(env);
if (expanded_cmd)
vstring_free(expanded_cmd);
/* /*
* Depending on the result, bounce or defer the message. * Depending on the result, bounce or defer the message.

View File

@ -95,18 +95,6 @@
/* executes with the privileges of the recipient user (exception: in /* executes with the privileges of the recipient user (exception: in
/* case of delivery as root, the command executes with the privileges /* case of delivery as root, the command executes with the privileges
/* of \fBdefault_privs\fR). /* 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 /* Mailbox delivery can be delegated to alternative message transports
/* specified in the \fBmaster.cf\fR file. /* specified in the \fBmaster.cf\fR file.
@ -148,9 +136,24 @@
/* \fBcommand_time_limit\fR seconds. Command exit status codes are /* \fBcommand_time_limit\fR seconds. Command exit status codes are
/* expected to follow the conventions defined in <\fBsysexits.h\fR>. /* expected to follow the conventions defined in <\fBsysexits.h\fR>.
/* /*
/* When mail is delivered on behalf of a user, the \fBHOME\fR, /* A limited amount of message context is exported via environment
/* \fBLOGNAME\fR, and \fBSHELL\fR environment variables are set /* variables. Characters that may have special meaning to the shell
/* accordingly. /* 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 /* The \fBPATH\fR environment variable is always reset to a
/* system-dependent default path, and the \fBTZ\fR (time zone) /* system-dependent default path, and the \fBTZ\fR (time zone)
/* environment variable is always passed on without change. /* environment variable is always passed on without change.

View File

@ -50,7 +50,7 @@ extension), \fB$domain\fR (recipient domain), \fBmailbox\fR
\fI$name\fR is (is not) defined. \fI$name\fR is (is not) defined.
In the result of \fIname\fR expansion, characters that have special In the result of \fIname\fR expansion, characters that have special
meaning to the shell are replaced by underscores. The list of legal 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. configuration parameter.
An alias or ~/.\fBforward\fR file may list any combination of external An alias or ~/.\fBforward\fR file may list any combination of external
@ -107,18 +107,6 @@ with the \fBmailbox_command\fR configuration parameter. The command
executes with the privileges of the recipient user (exception: in executes with the privileges of the recipient user (exception: in
case of delivery as root, the command executes with the privileges case of delivery as root, the command executes with the privileges
of \fBdefault_privs\fR). 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 Mailbox delivery can be delegated to alternative message transports
specified in the \fBmaster.cf\fR file. specified in the \fBmaster.cf\fR file.
@ -162,9 +150,24 @@ A command is forcibly terminated if it does not complete within
\fBcommand_time_limit\fR seconds. Command exit status codes are \fBcommand_time_limit\fR seconds. Command exit status codes are
expected to follow the conventions defined in <\fBsysexits.h\fR>. expected to follow the conventions defined in <\fBsysexits.h\fR>.
When mail is delivered on behalf of a user, the \fBHOME\fR, A limited amount of message context is exported via environment
\fBLOGNAME\fR, and \fBSHELL\fR environment variables are set variables. Characters that may have special meaning to the shell
accordingly. 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 The \fBPATH\fR environment variable is always reset to a
system-dependent default path, and the \fBTZ\fR (time zone) system-dependent default path, and the \fBTZ\fR (time zone)
environment variable is always passed on without change. environment variable is always passed on without change.
@ -301,7 +304,8 @@ Directory with UNIX-style mailboxes. The default pathname is system
dependent. dependent.
.IP \fBmailbox_command\fR .IP \fBmailbox_command\fR
External command to use for mailbox delivery. The command executes 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 .IP \fBmailbox_transport\fR
Message transport to use for mailbox delivery to all local Message transport to use for mailbox delivery to all local
recipients, whether or not they are found in the UNIX passwd database. recipients, whether or not they are found in the UNIX passwd database.
@ -345,13 +349,13 @@ Restrict the usage of mail delivery to external command.
.IP \fBallow_mail_to_files\fR .IP \fBallow_mail_to_files\fR
Restrict the usage of mail delivery to external file. Restrict the usage of mail delivery to external file.
.IP \fBcommand_expansion_filter\fR .IP \fBcommand_expansion_filter\fR
What characters are allowed to appear in $name expansions What characters are allowed to appear in $name expansions of
of mailbox_command. mailbox_command. Illegal characters are replaced by underscores.
.IP \fBdefault_privs\fR .IP \fBdefault_privs\fR
Default rights for delivery to external file or command. Default rights for delivery to external file or command.
.IP \fBforward_expansion_filter\fR .IP \fBforward_expansion_filter\fR
What characters are allowed to appear in $name expansions What characters are allowed to appear in $name expansions of
of forward_path. forward_path. Illegal characters are replaced by underscores.
.SH HISTORY .SH HISTORY
.na .na
.nf .nf

View File

@ -174,6 +174,7 @@ smtpd_state.o: ../include/mymalloc.h
smtpd_state.o: ../include/vstream.h smtpd_state.o: ../include/vstream.h
smtpd_state.o: ../include/vbuf.h smtpd_state.o: ../include/vbuf.h
smtpd_state.o: ../include/name_mask.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/cleanup_user.h
smtpd_state.o: ../include/mail_params.h smtpd_state.o: ../include/mail_params.h
smtpd_state.o: ../include/mail_error.h smtpd_state.o: ../include/mail_error.h

View File

@ -314,11 +314,6 @@ static int helo_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *argv)
return (-1); return (-1);
} }
collapse_args(argc, argv); 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->helo_name = mystrdup(printable(argv[1].strval, '?'));
state->protocol = "SMTP"; state->protocol = "SMTP";
smtpd_chat_reply(state, "250 %s", var_myhostname); smtpd_chat_reply(state, "250 %s", var_myhostname);
@ -342,11 +337,6 @@ static int ehlo_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *argv)
return (-1); return (-1);
} }
collapse_args(argc, argv); 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->helo_name = mystrdup(printable(argv[1].strval, '?'));
state->protocol = "ESMTP"; state->protocol = "ESMTP";
smtpd_chat_reply(state, "250-%s", var_myhostname); smtpd_chat_reply(state, "250-%s", var_myhostname);
@ -461,11 +451,6 @@ static int mail_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *argv)
} }
} }
state->time = time((time_t *) 0); 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) { if ((err = smtpd_check_size(state, size)) != 0) {
smtpd_chat_reply(state, "%s", err); smtpd_chat_reply(state, "%s", err);
return (-1); return (-1);
@ -548,10 +533,25 @@ static int rcpt_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *argv)
smtpd_chat_reply(state, "452 Error: too many recipients"); smtpd_chat_reply(state, "452 Error: too many recipients");
return (-1); return (-1);
} }
if (SMTPD_STAND_ALONE(state) == 0 if (SMTPD_STAND_ALONE(state) == 0) {
&& (err = smtpd_check_rcpt(state, argv[3].strval)) != 0) { if ((err = smtpd_check_client(state)) != 0) {
smtpd_chat_reply(state, "%s", err); smtpd_chat_reply(state, "%s", err);
return (-1); 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);
}
} }
/* /*
@ -795,8 +795,23 @@ static int vrfy_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *argv)
return (-1); return (-1);
} }
collapse_args(argc, argv); 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); err = smtpd_check_rcpt(state, argv[1].strval);
}
/* /*
* End untokenize. * End untokenize.
@ -847,10 +862,20 @@ static int etrn_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *argv)
* rejected. RFC 1985 requires that 459 be sent when the server refuses * rejected. RFC 1985 requires that 459 be sent when the server refuses
* to perform the request. * to perform the request.
*/ */
if (SMTPD_STAND_ALONE(state) == 0 if (SMTPD_STAND_ALONE(state) == 0) {
&& (err = smtpd_check_etrn(state, argv[1].strval)) != 0) { if ((err = smtpd_check_client(state)) != 0) {
smtpd_chat_reply(state, "%s", err); smtpd_chat_reply(state, "%s", err);
return (-1); 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);
}
} }
/* /*
@ -1043,15 +1068,10 @@ static void smtpd_service(VSTREAM *stream, char *unused_service, char **argv)
debug_peer_check(state.name, state.addr); debug_peer_check(state.name, state.addr);
/* /*
* See if we want to talk to this client at all. Then, log the connection * Greet the client and log the connection event.
* event.
*/ */
if ((state.access_denied = smtpd_check_client(&state)) != 0) { smtpd_chat_reply(&state, "220 %s", var_smtpd_banner);
smtpd_chat_reply(&state, "%s", state.access_denied); msg_info("connect from %s[%s]", state.name, state.addr);
} else {
smtpd_chat_reply(&state, "220 %s", var_smtpd_banner);
msg_info("connect from %s[%s]", state.name, state.addr);
}
/* /*
* Provide the SMTP service. * Provide the SMTP service.

View File

@ -33,6 +33,7 @@ typedef struct SMTPD_STATE {
time_t time; time_t time;
char *name; char *name;
char *addr; char *addr;
char *namaddr;
int error_count; int error_count;
int error_mask; int error_mask;
int notify_mask; int notify_mask;

View File

@ -217,6 +217,7 @@
#include <stdarg.h> #include <stdarg.h>
#include <netdb.h> #include <netdb.h>
#include <setjmp.h> #include <setjmp.h>
#include <stdlib.h>
#ifdef STRCASECMP_IN_STRINGS_H #ifdef STRCASECMP_IN_STRINGS_H
#include <strings.h> #include <strings.h>
@ -293,6 +294,18 @@ static ARGV *mail_restrctions;
static ARGV *rcpt_restrctions; static ARGV *rcpt_restrctions;
static ARGV *etrn_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 #define STR vstring_str
/* smtpd_check_parse - pre-parse restrictions */ /* smtpd_check_parse - pre-parse restrictions */
@ -380,16 +393,6 @@ static int smtpd_check_reject(SMTPD_STATE *state, int error_class,
msg_warn("response code configuration error: %s", STR(error_text)); msg_warn("response code configuration error: %s", STR(error_text));
vstring_strcpy(error_text, "450 Service unavailable"); 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), ' '); printable(STR(error_text), ' ');
/* /*
@ -397,9 +400,21 @@ static int smtpd_check_reject(SMTPD_STATE *state, int error_class,
* postmaster notices, this may be the only trace left that service was * postmaster notices, this may be the only trace left that service was
* rejected. Print the request, client name/address, and response. * rejected. Print the request, client name/address, and response.
*/ */
msg_info("%s: reject: %s from %s[%s]: %s", state->queue_id, state->where, msg_info("%s: reject: %s from %s: %s",
state->name, state->addr, STR(error_text)); 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); return (SMTPD_CHECK_REJECT);
} }
@ -414,7 +429,7 @@ static int reject_unknown_client(SMTPD_STATE *state)
if (strcasecmp(state->name, "unknown") == 0) if (strcasecmp(state->name, "unknown") == 0)
return (smtpd_check_reject(state, MAIL_ERROR_POLICY, 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)); var_unk_client_code, state->addr));
return (SMTPD_CHECK_DUNNO); return (SMTPD_CHECK_DUNNO);
} }
@ -454,7 +469,8 @@ static char *dup_if_truncate(char *name)
/* reject_invalid_hostaddr - fail if host address is incorrect */ /* 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"; char *myname = "reject_invalid_hostaddr";
int len; int len;
@ -474,8 +490,8 @@ static int reject_invalid_hostaddr(SMTPD_STATE *state, char *addr)
*/ */
if (!valid_hostaddr(test_addr)) if (!valid_hostaddr(test_addr))
stat = smtpd_check_reject(state, MAIL_ERROR_POLICY, stat = smtpd_check_reject(state, MAIL_ERROR_POLICY,
"%d <%s>: Invalid ip address", "%d <%s>: %s rejected: invalid ip address",
var_bad_name_code, addr); var_bad_name_code, reply_name, reply_class);
else else
stat = SMTPD_CHECK_DUNNO; stat = SMTPD_CHECK_DUNNO;
@ -490,7 +506,8 @@ static int reject_invalid_hostaddr(SMTPD_STATE *state, char *addr)
/* reject_invalid_hostname - fail if host/domain syntax is incorrect */ /* 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 *myname = "reject_invalid_hostname";
char *test_name; char *test_name;
@ -509,8 +526,8 @@ static int reject_invalid_hostname(SMTPD_STATE *state, char *name)
*/ */
if (!valid_hostname(test_name)) if (!valid_hostname(test_name))
stat = smtpd_check_reject(state, MAIL_ERROR_POLICY, stat = smtpd_check_reject(state, MAIL_ERROR_POLICY,
"%d <%s>: Invalid name", "%d <%s>: %s rejected: Invalid name",
var_bad_name_code, name); var_bad_name_code, reply_name, reply_class);
else else
stat = SMTPD_CHECK_DUNNO; stat = SMTPD_CHECK_DUNNO;
@ -525,7 +542,8 @@ static int reject_invalid_hostname(SMTPD_STATE *state, char *name)
/* reject_non_fqdn_hostname - fail if host name is not in fqdn form */ /* 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 *myname = "reject_non_fqdn_hostname";
char *test_name; char *test_name;
@ -544,8 +562,8 @@ static int reject_non_fqdn_hostname(SMTPD_STATE *state, char *name)
*/ */
if (!valid_hostname(test_name) || !strchr(test_name, '.')) if (!valid_hostname(test_name) || !strchr(test_name, '.'))
stat = smtpd_check_reject(state, MAIL_ERROR_POLICY, stat = smtpd_check_reject(state, MAIL_ERROR_POLICY,
"%d <%s>: need fully-qualified hostname", "%d <%s>: %s rejected: need fully-qualified hostname",
var_non_fqdn_code, name); var_non_fqdn_code, reply_name, reply_class);
else else
stat = SMTPD_CHECK_DUNNO; stat = SMTPD_CHECK_DUNNO;
@ -560,7 +578,8 @@ static int reject_non_fqdn_hostname(SMTPD_STATE *state, char *name)
/* reject_unknown_hostname - fail if name has no A or MX record */ /* 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"; char *myname = "reject_unknown_hostname";
int dns_status; int dns_status;
@ -572,15 +591,17 @@ static int reject_unknown_hostname(SMTPD_STATE *state, char *name)
(VSTRING *) 0, T_A, T_MX, 0); (VSTRING *) 0, T_A, T_MX, 0);
if (dns_status != DNS_OK) if (dns_status != DNS_OK)
return (smtpd_check_reject(state, MAIL_ERROR_POLICY, return (smtpd_check_reject(state, MAIL_ERROR_POLICY,
"%d <%s>: Host not found", "%d <%s>: %s rejected: Host not found",
dns_status == DNS_NOTFOUND ? dns_status == DNS_NOTFOUND ?
var_unk_name_code : 450, name)); var_unk_name_code : 450,
reply_name, reply_class));
return (SMTPD_CHECK_DUNNO); return (SMTPD_CHECK_DUNNO);
} }
/* reject_unknown_mailhost - fail if name has no A or MX record */ /* 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"; char *myname = "reject_unknown_mailhost";
int dns_status; int dns_status;
@ -592,15 +613,17 @@ static int reject_unknown_mailhost(SMTPD_STATE *state, char *name)
(VSTRING *) 0, T_A, T_MX, 0); (VSTRING *) 0, T_A, T_MX, 0);
if (dns_status != DNS_OK) if (dns_status != DNS_OK)
return (smtpd_check_reject(state, MAIL_ERROR_POLICY, return (smtpd_check_reject(state, MAIL_ERROR_POLICY,
"%d <%s>: Domain not found", "%d <%s>: %s rejected: Domain not found",
dns_status == DNS_NOTFOUND ? dns_status == DNS_NOTFOUND ?
var_unk_addr_code : 450, name)); var_unk_addr_code : 450,
reply_name, reply_class));
return (SMTPD_CHECK_DUNNO); return (SMTPD_CHECK_DUNNO);
} }
/* check_relay_domains - OK/FAIL for message relaying */ /* 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 *myname = "check_relay_domains";
char *domain; char *domain;
@ -639,8 +662,8 @@ static int check_relay_domains(SMTPD_STATE *state, char *recipient)
* Deny relaying between sites that both are not in relay_domains. * Deny relaying between sites that both are not in relay_domains.
*/ */
return (smtpd_check_reject(state, MAIL_ERROR_POLICY, return (smtpd_check_reject(state, MAIL_ERROR_POLICY,
"%d <%s>: Relay access denied", "%d <%s>: %s rejected: Relay access denied",
var_relay_code, recipient)); var_relay_code, reply_name, reply_class));
} }
/* has_my_addr - see if this host name lists one of my network addresses */ /* has_my_addr - see if this host name lists one of my network addresses */
@ -770,7 +793,8 @@ static int permit_mx_backup(SMTPD_STATE *unused_state, const char *recipient)
/* reject_non_fqdn_address - fail if address is not in fqdn form */ /* 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 *myname = "reject_non_fqdn_address";
char *domain; char *domain;
@ -806,8 +830,8 @@ static int reject_non_fqdn_address(SMTPD_STATE *state, char *addr)
*/ */
if (!*test_dom || !valid_hostname(test_dom) || !strchr(test_dom, '.')) if (!*test_dom || !valid_hostname(test_dom) || !strchr(test_dom, '.'))
stat = smtpd_check_reject(state, MAIL_ERROR_POLICY, stat = smtpd_check_reject(state, MAIL_ERROR_POLICY,
"%d <%s>: need fully-qualified address", "%d <%s>: %s rejected: need fully-qualified address",
var_non_fqdn_code, addr); var_non_fqdn_code, reply_name, reply_class);
else else
stat = SMTPD_CHECK_DUNNO; stat = SMTPD_CHECK_DUNNO;
@ -822,7 +846,8 @@ static int reject_non_fqdn_address(SMTPD_STATE *state, char *addr)
/* reject_unknown_address - fail if address does not resolve */ /* 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 *myname = "reject_unknown_address";
char *domain; char *domain;
@ -851,15 +876,17 @@ static int reject_unknown_address(SMTPD_STATE *state, char *addr)
/* /*
* Look up the name in the DNS. * 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 */ /* check_table_result - translate table lookup result into pass/reject */
static int check_table_result(SMTPD_STATE *state, char *table, 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"; char *myname = "check_table_result";
int code;
if (msg_verbose) if (msg_verbose)
msg_info("%s: %s %s %s", myname, table, value, datum); msg_info("%s: %s %s %s", myname, table, value, datum);
@ -869,15 +896,21 @@ static int check_table_result(SMTPD_STATE *state, char *table,
*/ */
if (strcasecmp(value, "REJECT") == 0) if (strcasecmp(value, "REJECT") == 0)
return (smtpd_check_reject(state, MAIL_ERROR_POLICY, return (smtpd_check_reject(state, MAIL_ERROR_POLICY,
"%d <%s>: Access denied", "%d <%s>: %s rejected: Access denied",
var_access_map_code, datum)); var_access_map_code, reply_name, reply_class));
/* /*
* 4xx or 5xx means NO as well. smtpd_check_reject() will validate the * 4xx or 5xx means NO as well. smtpd_check_reject() will validate the
* response status code. * response status code.
*/ */
if (ISDIGIT(value[0])) if (ISDIGIT(value[0]) && ISDIGIT(value[1]) && ISDIGIT(value[2])) {
return (smtpd_check_reject(state, MAIL_ERROR_POLICY, "%s", value)); 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. * OK or RELAY or whatever means YES.
@ -887,7 +920,8 @@ static int check_table_result(SMTPD_STATE *state, char *table,
/* check_access - table lookup without substring magic */ /* 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 *myname = "check_access";
char *low_name = lowercase(mystrdup(name)); char *low_name = lowercase(mystrdup(name));
@ -905,7 +939,8 @@ static int check_access(SMTPD_STATE *state, char *table, char *name, int flags)
msg_panic("%s: dictionary not found: %s", myname, table); msg_panic("%s: dictionary not found: %s", myname, table);
if (flags == 0 || (flags & dict->flags) != 0) { if (flags == 0 || (flags & dict->flags) != 0) {
if ((value = dict_get(dict, low_name)) != 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) if (dict_errno != 0)
msg_fatal("%s: table lookup problem", table); msg_fatal("%s: table lookup problem", table);
} }
@ -915,7 +950,8 @@ static int check_access(SMTPD_STATE *state, char *table, char *name, int flags)
/* check_domain_access - domainname-based table lookup */ /* check_domain_access - domainname-based table lookup */
static int check_domain_access(SMTPD_STATE *state, char *table, 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 *myname = "check_domain_access";
char *low_domain = lowercase(mystrdup(domain)); char *low_domain = lowercase(mystrdup(domain));
@ -937,7 +973,8 @@ static int check_domain_access(SMTPD_STATE *state, char *table,
msg_panic("%s: dictionary not found: %s", myname, table); msg_panic("%s: dictionary not found: %s", myname, table);
if (flags == 0 || (flags & dict->flags) != 0) { if (flags == 0 || (flags & dict->flags) != 0) {
if ((value = dict_get(dict, name)) != 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) if (dict_errno != 0)
msg_fatal("%s: table lookup problem", table); msg_fatal("%s: table lookup problem", table);
} }
@ -948,8 +985,9 @@ static int check_domain_access(SMTPD_STATE *state, char *table,
/* check_addr_access - address-based table lookup */ /* check_addr_access - address-based table lookup */
static int check_addr_access(SMTPD_STATE *state, char *table, char *address, static int check_addr_access(SMTPD_STATE *state, char *table,
int flags) char *address, int flags,
char *reply_name, char *reply_class)
{ {
char *myname = "check_addr_access"; char *myname = "check_addr_access";
char *addr; char *addr;
@ -969,7 +1007,8 @@ static int check_addr_access(SMTPD_STATE *state, char *table, char *address,
msg_panic("%s: dictionary not found: %s", myname, table); msg_panic("%s: dictionary not found: %s", myname, table);
if (flags == 0 || (flags & dict->flags) != 0) { if (flags == 0 || (flags & dict->flags) != 0) {
if ((value = dict_get(dict, addr)) != 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) if (dict_errno != 0)
msg_fatal("%s: table lookup problem", table); msg_fatal("%s: table lookup problem", table);
} }
@ -982,7 +1021,8 @@ static int check_addr_access(SMTPD_STATE *state, char *table, char *address,
/* check_namadr_access - OK/FAIL based on host name/address lookup */ /* check_namadr_access - OK/FAIL based on host name/address lookup */
static int check_namadr_access(SMTPD_STATE *state, char *table, 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"; char *myname = "check_namadr_access";
int status; int status;
@ -994,13 +1034,15 @@ static int check_namadr_access(SMTPD_STATE *state, char *table,
* Look up the host name, or parent domains thereof. XXX A domain * Look up the host name, or parent domains thereof. XXX A domain
* wildcard may pre-empt a more specific address table entry. * 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); return (status);
/* /*
* Look up the network address, or parent networks thereof. * 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); return (status);
/* /*
@ -1011,7 +1053,8 @@ static int check_namadr_access(SMTPD_STATE *state, char *table,
/* check_mail_access - OK/FAIL based on mail address lookup */ /* 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 *myname = "check_mail_access";
char *ratsign; char *ratsign;
@ -1039,13 +1082,15 @@ static int check_mail_access(SMTPD_STATE *state, char *table, char *addr)
/* /*
* Look up the full address. * 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); return (status);
/* /*
* Look up the domain name, or parent domains thereof. * 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); return (status);
/* /*
@ -1053,7 +1098,8 @@ static int check_mail_access(SMTPD_STATE *state, char *table, char *addr)
*/ */
local_at = mystrndup(STR(reply.recipient), local_at = mystrndup(STR(reply.recipient),
ratsign - STR(reply.recipient) + 1); 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); myfree(local_at);
if (status != 0) if (status != 0)
return (status); return (status);
@ -1149,7 +1195,8 @@ static int is_map_command(char *name, char *command, char ***argp)
/* generic_checks - generic restrictions */ /* generic_checks - generic restrictions */
static int generic_checks(SMTPD_STATE *state, char *name, 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)
{ {
/* /*
@ -1160,9 +1207,9 @@ static int generic_checks(SMTPD_STATE *state, char *name,
return (1); return (1);
} }
if (strcasecmp(name, REJECT_ALL) == 0) { if (strcasecmp(name, REJECT_ALL) == 0) {
*status = smtpd_check_reject(state, MAIL_ERROR_POLICY, *what ? *status = smtpd_check_reject(state, MAIL_ERROR_POLICY,
"%d <%s> Access denied" : "%d Access denied", "%d <%s>: %s rejected: Access denied",
var_reject_code, what); var_reject_code, reply_name, reply_class);
return (1); return (1);
} }
@ -1178,7 +1225,8 @@ static int generic_checks(SMTPD_STATE *state, char *name,
return (1); return (1);
} }
if (is_map_command(name, CHECK_CLIENT_ACL, cpp)) { 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); return (1);
} }
if (strcasecmp(name, REJECT_MAPS_RBL) == 0) { if (strcasecmp(name, REJECT_MAPS_RBL) == 0) {
@ -1191,31 +1239,37 @@ static int generic_checks(SMTPD_STATE *state, char *name,
*/ */
if (is_map_command(name, CHECK_HELO_ACL, cpp) && state->helo_name) { if (is_map_command(name, CHECK_HELO_ACL, cpp) && state->helo_name) {
if (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); return (1);
} }
if (strcasecmp(name, REJECT_INVALID_HOSTNAME) == 0) { if (strcasecmp(name, REJECT_INVALID_HOSTNAME) == 0) {
if (state->helo_name) { if (state->helo_name) {
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 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); return (1);
} }
if (strcasecmp(name, REJECT_UNKNOWN_HOSTNAME) == 0) { if (strcasecmp(name, REJECT_UNKNOWN_HOSTNAME) == 0) {
if (state->helo_name) { if (state->helo_name) {
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 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); return (1);
} }
if (strcasecmp(name, PERMIT_NAKED_IP_ADDR) == 0) { if (strcasecmp(name, PERMIT_NAKED_IP_ADDR) == 0) {
if (state->helo_name) { if (state->helo_name) {
if (state->helo_name[strspn(state->helo_name, "0123456789.")] == 0 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; *status = SMTPD_CHECK_OK;
} }
return (1); return (1);
@ -1223,9 +1277,11 @@ static int generic_checks(SMTPD_STATE *state, char *name,
if (strcasecmp(name, REJECT_NON_FQDN_HOSTNAME) == 0) { if (strcasecmp(name, REJECT_NON_FQDN_HOSTNAME) == 0) {
if (state->helo_name) { if (state->helo_name) {
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 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); return (1);
} }
@ -1235,22 +1291,26 @@ static int generic_checks(SMTPD_STATE *state, char *name,
*/ */
if (is_map_command(name, CHECK_SENDER_ACL, cpp) && state->sender) { if (is_map_command(name, CHECK_SENDER_ACL, cpp) && state->sender) {
if (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); return (1);
} }
if (strcasecmp(name, REJECT_UNKNOWN_ADDRESS) == 0) { if (strcasecmp(name, REJECT_UNKNOWN_ADDRESS) == 0) {
if (state->sender) if (state->sender)
*status = reject_unknown_address(state, state->sender); *status = reject_unknown_address(state, state->sender,
state->sender, SMTPD_NAME_SENDER);
return (1); return (1);
} }
if (strcasecmp(name, REJECT_UNKNOWN_SENDDOM) == 0) { if (strcasecmp(name, REJECT_UNKNOWN_SENDDOM) == 0) {
if (state->sender) if (state->sender)
*status = reject_unknown_address(state, state->sender); *status = reject_unknown_address(state, state->sender,
state->sender, SMTPD_NAME_SENDER);
return (1); return (1);
} }
if (strcasecmp(name, REJECT_NON_FQDN_SENDER) == 0) { if (strcasecmp(name, REJECT_NON_FQDN_SENDER) == 0) {
if (*state->sender) 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 (1);
} }
return (0); return (0);
@ -1276,8 +1336,10 @@ char *smtpd_check_client(SMTPD_STATE *state)
*/ */
for (cpp = client_restrctions->argv; (name = *cpp) != 0; cpp++) { for (cpp = client_restrctions->argv; (name = *cpp) != 0; cpp++) {
if (strchr(name, ':') != 0) { if (strchr(name, ':') != 0) {
status = check_namadr_access(state, name, state->name, state->addr, FULL); status = check_namadr_access(state, name, state->name, state->addr,
} else if (generic_checks(state, name, &cpp, &status, state->addr) == 0) { 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); msg_warn("unknown %s check: \"%s\"", VAR_CLIENT_CHECKS, name);
break; break;
} }
@ -1310,8 +1372,10 @@ char *smtpd_check_helo(SMTPD_STATE *state, char *helohost)
state->helo_name = mystrdup(helohost); state->helo_name = mystrdup(helohost);
for (cpp = helo_restrctions->argv; (name = *cpp) != 0; cpp++) { for (cpp = helo_restrctions->argv; (name = *cpp) != 0; cpp++) {
if (strchr(name, ':') != 0) { if (strchr(name, ':') != 0) {
status = check_domain_access(state, name, helohost, FULL); status = check_domain_access(state, name, helohost, FULL,
} else if (generic_checks(state, name, &cpp, &status, helohost) == 0) { 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); msg_warn("unknown %s check: \"%s\"", VAR_HELO_CHECKS, name);
break; break;
} }
@ -1346,8 +1410,10 @@ char *smtpd_check_mail(SMTPD_STATE *state, char *sender)
state->sender = mystrdup(sender); state->sender = mystrdup(sender);
for (cpp = mail_restrctions->argv; (name = *cpp) != 0; cpp++) { for (cpp = mail_restrctions->argv; (name = *cpp) != 0; cpp++) {
if (strchr(name, ':') != 0) { if (strchr(name, ':') != 0) {
status = check_mail_access(state, name, sender); status = check_mail_access(state, name, sender,
} else if (generic_checks(state, name, &cpp, &status, sender) == 0) { 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); msg_warn("unknown %s check: \"%s\"", VAR_MAIL_CHECKS, name);
return (0); return (0);
} }
@ -1382,18 +1448,24 @@ char *smtpd_check_rcpt(SMTPD_STATE *state, char *recipient)
state->recipient = mystrdup(recipient); state->recipient = mystrdup(recipient);
for (cpp = rcpt_restrctions->argv; (name = *cpp) != 0; cpp++) { for (cpp = rcpt_restrctions->argv; (name = *cpp) != 0; cpp++) {
if (strchr(name, ':') != 0) { 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)) { } 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) { } else if (strcasecmp(name, PERMIT_MX_BACKUP) == 0) {
status = permit_mx_backup(state, recipient); status = permit_mx_backup(state, recipient);
} else if (strcasecmp(name, CHECK_RELAY_DOMAINS) == 0) { } 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) { } 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) { } else if (strcasecmp(name, REJECT_NON_FQDN_RCPT) == 0) {
status = reject_non_fqdn_address(state, recipient); status = reject_non_fqdn_address(state, recipient,
} else if (generic_checks(state, name, &cpp, &status, recipient) == 0) { 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); msg_warn("unknown %s check: \"%s\"", VAR_RCPT_CHECKS, name);
break; break;
} }
@ -1425,10 +1497,13 @@ char *smtpd_check_etrn(SMTPD_STATE *state, char *domain)
*/ */
for (cpp = etrn_restrctions->argv; (name = *cpp) != 0; cpp++) { for (cpp = etrn_restrctions->argv; (name = *cpp) != 0; cpp++) {
if (strchr(name, ':') != 0) { 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)) { } else if (is_map_command(name, CHECK_ETRN_ACL, &cpp)) {
status = check_domain_access(state, *cpp, domain, FULL); status = check_domain_access(state, *cpp, domain, FULL,
} else if (generic_checks(state, name, &cpp, &status, domain) == 0) { 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); msg_warn("unknown %s check: \"%s\"", VAR_RCPT_CHECKS, name);
break; break;
} }
@ -1708,6 +1783,7 @@ main(int argc, char **argv)
int_init(); int_init();
smtpd_check_init(); smtpd_check_init();
smtpd_state_init(&state, VSTREAM_IN, "", ""); smtpd_state_init(&state, VSTREAM_IN, "", "");
state.queue_id = "<queue id>";
/* /*
* Main loop: update config parameters or test the client, helo, sender * Main loop: update config parameters or test the client, helo, sender
@ -1748,6 +1824,10 @@ main(int argc, char **argv)
state.where = "CONNECT"; state.where = "CONNECT";
UPDATE_STRING(state.name, args->argv[1]); UPDATE_STRING(state.name, args->argv[1]);
UPDATE_STRING(state.addr, args->argv[2]); 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); resp = smtpd_check_client(&state);
} }
break; break;

View File

@ -13,23 +13,23 @@ OK
>>> client_restrictions permit_mynetworks,reject_unknown_client,hash:./smtpd_check_access >>> client_restrictions permit_mynetworks,reject_unknown_client,hash:./smtpd_check_access
OK OK
>>> client unknown 131.155.210.17 >>> 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] ./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 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 >>> client unknown 168.100.189.13
OK OK
>>> client random.bad.domain 123.123.123.123 >>> client random.bad.domain 123.123.123.123
./smtpd_check: reject: CONNECT from random.bad.domain[123.123.123.123]: 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 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 >>> client friend.bad.domain 123.123.123.123
OK OK
>>> client bad.domain 123.123.123.123 >>> client bad.domain 123.123.123.123
./smtpd_check: reject: CONNECT from bad.domain[123.123.123.123]: 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 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 >>> client wzv.win.tue.nl 131.155.210.17
OK OK
>>> client aa.win.tue.nl 131.155.210.18 >>> 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 ./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 match 131.155.210 554 <aa.win.tue.nl[131.155.210.18]>: Client host rejected: match 131.155.210
>>> client_restrictions permit_mynetworks >>> client_restrictions permit_mynetworks
OK OK
>>> # >>> #
@ -40,31 +40,31 @@ OK
>>> client unknown 131.155.210.17 >>> client unknown 131.155.210.17
OK OK
>>> helo foo. >>> helo foo.
./smtpd_check: reject: HELO from unknown[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 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 >>> client foo 123.123.123.123
OK OK
>>> helo foo. >>> helo foo.
./smtpd_check: reject: HELO from foo[123.123.123.123]: 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.>: Host not found 450 <foo.>: Helo command rejected: Host not found
>>> helo foo >>> helo foo
./smtpd_check: reject: HELO from foo[123.123.123.123]: 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>: Host not found 450 <foo>: Helo command rejected: Host not found
>>> helo spike.porcupine.org >>> helo spike.porcupine.org
OK OK
>>> helo_restrictions permit_mynetworks,reject_unknown_client,reject_invalid_hostname,hash:./smtpd_check_access >>> helo_restrictions permit_mynetworks,reject_unknown_client,reject_invalid_hostname,hash:./smtpd_check_access
OK OK
>>> helo random.bad.domain >>> helo random.bad.domain
./smtpd_check: reject: HELO from foo[123.123.123.123]: 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 match bad.domain 554 <random.bad.domain>: Helo command rejected: match bad.domain
>>> helo friend.bad.domain >>> helo friend.bad.domain
OK OK
>>> helo_restrictions reject_invalid_hostname,reject_unknown_hostname >>> helo_restrictions reject_invalid_hostname,reject_unknown_hostname
OK OK
>>> helo 123.123.123.123 >>> helo 123.123.123.123
./smtpd_check: warning: valid_hostname: numeric hostname: 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 ./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>: 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 >>> helo_restrictions permit_naked_ip_address,reject_invalid_hostname,reject_unknown_hostname
OK OK
>>> helo 123.123.123.123 >>> helo 123.123.123.123
@ -77,8 +77,9 @@ OK
>>> client unknown 131.155.210.17 >>> client unknown 131.155.210.17
OK OK
>>> mail foo@watson.ibm.com >>> mail foo@watson.ibm.com
./smtpd_check: reject: MAIL from unknown[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]
450 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 >>> client unknown 168.100.189.13
OK OK
>>> mail foo@watson.ibm.com >>> mail foo@watson.ibm.com
@ -92,30 +93,37 @@ OK
>>> mail foo@watson.ibm.com >>> mail foo@watson.ibm.com
OK OK
>>> mail foo@bad.domain >>> mail foo@bad.domain
./smtpd_check: reject: MAIL from foo[123.123.123.123]: 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
450 <bad.domain>: 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 >>> sender_restrictions hash:./smtpd_check_access
OK OK
>>> mail bad-sender@any.domain >>> mail bad-sender@any.domain
./smtpd_check: reject: MAIL from foo[123.123.123.123]: 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@
554 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 >>> mail bad-sender@good.domain
OK OK
>>> mail reject@this.address >>> mail reject@this.address
./smtpd_check: reject: MAIL from foo[123.123.123.123]: 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
554 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 >>> mail Reject@this.address
./smtpd_check: reject: MAIL from foo[123.123.123.123]: 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
554 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 >>> mail foo@bad.domain
./smtpd_check: reject: MAIL from foo[123.123.123.123]: 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
554 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 >>> mail foo@Bad.domain
./smtpd_check: reject: MAIL from foo[123.123.123.123]: 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
554 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 >>> mail foo@random.bad.domain
./smtpd_check: reject: MAIL from foo[123.123.123.123]: 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
554 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 >>> mail foo@friend.bad.domain
OK OK
>>> # >>> #
@ -126,8 +134,9 @@ OK
>>> client unknown 131.155.210.17 >>> client unknown 131.155.210.17
OK OK
>>> rcpt foo@watson.ibm.com >>> rcpt foo@watson.ibm.com
./smtpd_check: reject: RCPT from unknown[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]
450 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 >>> client unknown 168.100.189.13
OK OK
>>> rcpt foo@watson.ibm.com >>> rcpt foo@watson.ibm.com
@ -135,8 +144,9 @@ OK
>>> client foo 123.123.123.123 >>> client foo 123.123.123.123
OK OK
>>> rcpt foo@watson.ibm.com >>> rcpt foo@watson.ibm.com
./smtpd_check: reject: RCPT from foo[123.123.123.123]: 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
554 <foo@watson.ibm.com>: 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 >>> rcpt foo@porcupine.org
OK OK
>>> recipient_restrictions check_relay_domains >>> recipient_restrictions check_relay_domains
@ -150,26 +160,31 @@ OK
>>> client foo 123.123.123.123 >>> client foo 123.123.123.123
OK OK
>>> rcpt foo@watson.ibm.com >>> rcpt foo@watson.ibm.com
./smtpd_check: reject: RCPT from foo[123.123.123.123]: 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
554 <foo@watson.ibm.com>: 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 >>> rcpt foo@porcupine.org
OK OK
>>> recipient_restrictions hash:./smtpd_check_access >>> recipient_restrictions hash:./smtpd_check_access
OK OK
>>> mail bad-sender@any.domain >>> mail bad-sender@any.domain
./smtpd_check: reject: MAIL from foo[123.123.123.123]: 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@
554 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 >>> mail bad-sender@good.domain
OK OK
>>> mail reject@this.address >>> mail reject@this.address
./smtpd_check: reject: MAIL from foo[123.123.123.123]: 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
554 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 >>> mail foo@bad.domain
./smtpd_check: reject: MAIL from foo[123.123.123.123]: 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
554 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 >>> mail foo@random.bad.domain
./smtpd_check: reject: MAIL from foo[123.123.123.123]: 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
554 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 >>> mail foo@friend.bad.domain
OK OK
>>> # >>> #
@ -180,7 +195,8 @@ OK
>>> client spike.porcupine.org 168.100.189.2 >>> client spike.porcupine.org 168.100.189.2
OK OK
>>> client foo 127.0.0.2 >>> 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 554 Service unavailable; [127.0.0.2] blocked using rbl.maps.vix.com
>>> # >>> #
>>> # Hybrids >>> # Hybrids
@ -190,8 +206,9 @@ OK
>>> client foo 131.155.210.17 >>> client foo 131.155.210.17
OK OK
>>> rcpt foo@watson.ibm.com >>> rcpt foo@watson.ibm.com
./smtpd_check: reject: RCPT from foo[131.155.210.17]: 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
554 <foo@watson.ibm.com>: 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 >>> recipient_restrictions check_client_access,hash:./smtpd_check_access,check_relay_domains
OK OK
>>> client foo 131.155.210.17 >>> client foo 131.155.210.17
@ -203,11 +220,13 @@ OK
>>> recipient_restrictions check_helo_access,hash:./smtpd_check_access,check_relay_domains >>> recipient_restrictions check_helo_access,hash:./smtpd_check_access,check_relay_domains
OK OK
>>> helo bad.domain >>> helo bad.domain
./smtpd_check: reject: HELO from foo[131.155.210.17]: 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
554 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 >>> rcpt foo@porcupine.org
./smtpd_check: reject: RCPT from foo[131.155.210.17]: 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
554 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 >>> helo 131.155.210.17
./smtpd_check: warning: valid_hostname: numeric hostname: 131.155.210.17 ./smtpd_check: warning: valid_hostname: numeric hostname: 131.155.210.17
OK OK
@ -216,11 +235,13 @@ OK
>>> recipient_restrictions check_sender_access,hash:./smtpd_check_access,check_relay_domains >>> recipient_restrictions check_sender_access,hash:./smtpd_check_access,check_relay_domains
OK OK
>>> mail foo@bad.domain >>> mail foo@bad.domain
./smtpd_check: reject: MAIL from foo[131.155.210.17]: 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
554 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 >>> rcpt foo@porcupine.org
./smtpd_check: reject: RCPT from foo[131.155.210.17]: 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
554 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 >>> mail foo@friend.bad.domain
OK OK
>>> rcpt foo@porcupine.org >>> rcpt foo@porcupine.org
@ -237,8 +258,9 @@ OK
>>> rcpt wietse@wzv.win.tue.nl >>> rcpt wietse@wzv.win.tue.nl
OK OK
>>> rcpt wietse@trouble.org >>> rcpt wietse@trouble.org
./smtpd_check: reject: RCPT from foo[131.155.210.17]: 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
554 <wietse@trouble.org> 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 >>> rcpt wietse@porcupine.org
OK OK
>>> # >>> #
@ -257,15 +279,17 @@ OK
>>> mail foo@good.domain >>> mail foo@good.domain
OK OK
>>> rcpt foo@porcupine.org >>> rcpt foo@porcupine.org
./smtpd_check: reject: RCPT from foo[131.155.210.17]: 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
554 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 >>> helo good.domain
OK OK
>>> mail foo@bad.domain >>> mail foo@bad.domain
OK OK
>>> rcpt foo@porcupine.org >>> rcpt foo@porcupine.org
./smtpd_check: reject: RCPT from foo[131.155.210.17]: 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
554 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 >>> # FQDN restrictions
>>> # >>> #
@ -280,28 +304,33 @@ OK
>>> helo foo.bar >>> helo foo.bar
OK OK
>>> helo foo >>> helo foo
./smtpd_check: reject: HELO from foo[131.155.210.17]: 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
504 <foo>: 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. >>> mail foo@foo.bar.
OK OK
>>> mail foo@foo.bar >>> mail foo@foo.bar
OK OK
>>> mail foo@foo >>> mail foo@foo
./smtpd_check: reject: MAIL from foo[131.155.210.17]: 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
504 <foo@foo>: 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 >>> mail foo
./smtpd_check: reject: MAIL from foo[131.155.210.17]: 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
504 <foo>: 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. >>> rcpt foo@foo.bar.
OK OK
>>> rcpt foo@foo.bar >>> rcpt foo@foo.bar
OK OK
>>> rcpt foo@foo >>> rcpt foo@foo
./smtpd_check: reject: RCPT from foo[131.155.210.17]: 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
504 <foo@foo>: 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 >>> rcpt foo
./smtpd_check: reject: RCPT from foo[131.155.210.17]: 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
504 <foo>: 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 >>> # Numerical HELO checks
>>> # >>> #
@ -315,83 +344,99 @@ OK
>>> helo [321.255.255.255] >>> helo [321.255.255.255]
./smtpd_check: reject_invalid_hostaddr: [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: 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 ./smtpd_check: <queue id>: reject: HELO from foo[131.155.210.17]: 501 <[321.255.255.255]>: Helo command rejected: invalid ip address
501 <[321.255.255.255]>: 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] >>> helo [0.255.255.255]
./smtpd_check: reject_invalid_hostaddr: [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: 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 ./smtpd_check: <queue id>: reject: HELO from foo[131.155.210.17]: 501 <[0.255.255.255]>: Helo command rejected: invalid ip address
501 <[0.255.255.255]>: 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] >>> helo [1.2.3.321]
./smtpd_check: reject_invalid_hostaddr: [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: 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 ./smtpd_check: <queue id>: reject: HELO from foo[131.155.210.17]: 501 <[1.2.3.321]>: Helo command rejected: invalid ip address
501 <[1.2.3.321]>: 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] >>> helo [1.2.3]
./smtpd_check: reject_invalid_hostaddr: [1.2.3] ./smtpd_check: reject_invalid_hostaddr: [1.2.3]
./smtpd_check: warning: valid_hostaddr: invalid octet count: 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 ./smtpd_check: <queue id>: reject: HELO from foo[131.155.210.17]: 501 <[1.2.3]>: Helo command rejected: invalid ip address
501 <[1.2.3]>: 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] >>> helo [1.2.3.4.5]
./smtpd_check: reject_invalid_hostaddr: [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: 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 ./smtpd_check: <queue id>: reject: HELO from foo[131.155.210.17]: 501 <[1.2.3.4.5]>: Helo command rejected: invalid ip address
501 <[1.2.3.4.5]>: 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] >>> helo [1..2.3.4]
./smtpd_check: reject_invalid_hostaddr: [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: 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 ./smtpd_check: <queue id>: reject: HELO from foo[131.155.210.17]: 501 <[1..2.3.4]>: Helo command rejected: invalid ip address
501 <[1..2.3.4]>: 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] >>> helo [.1.2.3.4]
./smtpd_check: reject_invalid_hostaddr: [.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: 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 ./smtpd_check: <queue id>: reject: HELO from foo[131.155.210.17]: 501 <[.1.2.3.4]>: Helo command rejected: invalid ip address
501 <[.1.2.3.4]>: 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.] >>> helo [1.2.3.4.5.]
./smtpd_check: reject_invalid_hostaddr: [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: 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 ./smtpd_check: <queue id>: reject: HELO from foo[131.155.210.17]: 501 <[1.2.3.4.5.]>: Helo command rejected: invalid ip address
501 <[1.2.3.4.5.]>: 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 >>> helo 1.2.3.4
./smtpd_check: reject_invalid_hostaddr: 1.2.3.4 ./smtpd_check: reject_invalid_hostaddr: 1.2.3.4
OK OK
>>> helo 321.255.255.255 >>> helo 321.255.255.255
./smtpd_check: reject_invalid_hostaddr: 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: 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 ./smtpd_check: <queue id>: reject: HELO from foo[131.155.210.17]: 501 <321.255.255.255>: Helo command rejected: invalid ip address
501 <321.255.255.255>: 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 >>> helo 0.255.255.255
./smtpd_check: reject_invalid_hostaddr: 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: 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 ./smtpd_check: <queue id>: reject: HELO from foo[131.155.210.17]: 501 <0.255.255.255>: Helo command rejected: invalid ip address
501 <0.255.255.255>: 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 >>> helo 1.2.3.321
./smtpd_check: reject_invalid_hostaddr: 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: 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 ./smtpd_check: <queue id>: reject: HELO from foo[131.155.210.17]: 501 <1.2.3.321>: Helo command rejected: invalid ip address
501 <1.2.3.321>: 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 >>> helo 1.2.3
./smtpd_check: reject_invalid_hostaddr: 1.2.3 ./smtpd_check: reject_invalid_hostaddr: 1.2.3
./smtpd_check: warning: valid_hostaddr: invalid octet count: 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 ./smtpd_check: <queue id>: reject: HELO from foo[131.155.210.17]: 501 <1.2.3>: Helo command rejected: invalid ip address
501 <1.2.3>: 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 >>> helo 1.2.3.4.5
./smtpd_check: reject_invalid_hostaddr: 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: 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 ./smtpd_check: <queue id>: reject: HELO from foo[131.155.210.17]: 501 <1.2.3.4.5>: Helo command rejected: invalid ip address
501 <1.2.3.4.5>: 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 >>> helo 1..2.3.4
./smtpd_check: reject_invalid_hostaddr: 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: 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 ./smtpd_check: <queue id>: reject: HELO from foo[131.155.210.17]: 501 <1..2.3.4>: Helo command rejected: invalid ip address
501 <1..2.3.4>: 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 >>> helo .1.2.3.4
./smtpd_check: reject_invalid_hostaddr: .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: 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 ./smtpd_check: <queue id>: reject: HELO from foo[131.155.210.17]: 501 <.1.2.3.4>: Helo command rejected: invalid ip address
501 <.1.2.3.4>: 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. >>> helo 1.2.3.4.5.
./smtpd_check: reject_invalid_hostaddr: 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: 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 ./smtpd_check: <queue id>: reject: HELO from foo[131.155.210.17]: 501 <1.2.3.4.5.>: Helo command rejected: invalid ip address
501 <1.2.3.4.5.>: 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

View File

@ -13,23 +13,23 @@ OK
>>> client_restrictions permit_mynetworks,reject_unknown_client,check_client_access,hash:./smtpd_check_access >>> client_restrictions permit_mynetworks,reject_unknown_client,check_client_access,hash:./smtpd_check_access
OK OK
>>> client unknown 131.155.210.17 >>> 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] ./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 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 >>> client unknown 168.100.189.13
OK OK
>>> client random.bad.domain 123.123.123.123 >>> client random.bad.domain 123.123.123.123
./smtpd_check: reject: CONNECT from random.bad.domain[123.123.123.123]: 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 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 >>> client friend.bad.domain 123.123.123.123
OK OK
>>> client bad.domain 123.123.123.123 >>> client bad.domain 123.123.123.123
./smtpd_check: reject: CONNECT from bad.domain[123.123.123.123]: 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 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 >>> client wzv.win.tue.nl 131.155.210.17
OK OK
>>> client aa.win.tue.nl 131.155.210.18 >>> 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 ./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 match 131.155.210 554 <aa.win.tue.nl[131.155.210.18]>: Client host rejected: match 131.155.210
>>> client_restrictions permit_mynetworks >>> client_restrictions permit_mynetworks
OK OK
>>> # >>> #
@ -40,23 +40,23 @@ OK
>>> client unknown 131.155.210.17 >>> client unknown 131.155.210.17
OK OK
>>> helo foo. >>> helo foo.
./smtpd_check: reject: HELO from unknown[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 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 >>> client foo 123.123.123.123
OK OK
>>> helo foo. >>> helo foo.
./smtpd_check: reject: HELO from foo[123.123.123.123]: 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.>: Host not found 450 <foo.>: Helo command rejected: Host not found
>>> helo foo >>> helo foo
./smtpd_check: reject: HELO from foo[123.123.123.123]: 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>: Host not found 450 <foo>: Helo command rejected: Host not found
>>> helo spike.porcupine.org >>> helo spike.porcupine.org
OK OK
>>> helo_restrictions permit_mynetworks,reject_unknown_client,reject_invalid_hostname,check_helo_access,hash:./smtpd_check_access >>> helo_restrictions permit_mynetworks,reject_unknown_client,reject_invalid_hostname,check_helo_access,hash:./smtpd_check_access
OK OK
>>> helo random.bad.domain >>> helo random.bad.domain
./smtpd_check: reject: HELO from foo[123.123.123.123]: 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 match bad.domain 554 <random.bad.domain>: Helo command rejected: match bad.domain
>>> helo friend.bad.domain >>> helo friend.bad.domain
OK OK
>>> # >>> #
@ -67,8 +67,9 @@ OK
>>> client unknown 131.155.210.17 >>> client unknown 131.155.210.17
OK OK
>>> mail foo@watson.ibm.com >>> mail foo@watson.ibm.com
./smtpd_check: reject: MAIL from unknown[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]
450 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 >>> client unknown 168.100.189.13
OK OK
>>> mail foo@watson.ibm.com >>> mail foo@watson.ibm.com
@ -82,30 +83,37 @@ OK
>>> mail foo@watson.ibm.com >>> mail foo@watson.ibm.com
OK OK
>>> mail foo@bad.domain >>> mail foo@bad.domain
./smtpd_check: reject: MAIL from foo[123.123.123.123]: 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
450 <bad.domain>: 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 >>> sender_restrictions check_sender_access,hash:./smtpd_check_access
OK OK
>>> mail bad-sender@any.domain >>> mail bad-sender@any.domain
./smtpd_check: reject: MAIL from foo[123.123.123.123]: 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@
554 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 >>> mail bad-sender@good.domain
OK OK
>>> mail reject@this.address >>> mail reject@this.address
./smtpd_check: reject: MAIL from foo[123.123.123.123]: 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
554 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 >>> mail Reject@this.address
./smtpd_check: reject: MAIL from foo[123.123.123.123]: 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
554 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 >>> mail foo@bad.domain
./smtpd_check: reject: MAIL from foo[123.123.123.123]: 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
554 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 >>> mail foo@Bad.domain
./smtpd_check: reject: MAIL from foo[123.123.123.123]: 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
554 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 >>> mail foo@random.bad.domain
./smtpd_check: reject: MAIL from foo[123.123.123.123]: 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
554 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 >>> mail foo@friend.bad.domain
OK OK
>>> # >>> #
@ -116,8 +124,9 @@ OK
>>> client unknown 131.155.210.17 >>> client unknown 131.155.210.17
OK OK
>>> rcpt foo@watson.ibm.com >>> rcpt foo@watson.ibm.com
./smtpd_check: reject: RCPT from unknown[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]
450 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 >>> client unknown 168.100.189.13
OK OK
>>> rcpt foo@watson.ibm.com >>> rcpt foo@watson.ibm.com
@ -125,8 +134,9 @@ OK
>>> client foo 123.123.123.123 >>> client foo 123.123.123.123
OK OK
>>> rcpt foo@watson.ibm.com >>> rcpt foo@watson.ibm.com
./smtpd_check: reject: RCPT from foo[123.123.123.123]: 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
554 <foo@watson.ibm.com>: 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 >>> rcpt foo@porcupine.org
OK OK
>>> recipient_restrictions check_relay_domains >>> recipient_restrictions check_relay_domains
@ -140,26 +150,31 @@ OK
>>> client foo 123.123.123.123 >>> client foo 123.123.123.123
OK OK
>>> rcpt foo@watson.ibm.com >>> rcpt foo@watson.ibm.com
./smtpd_check: reject: RCPT from foo[123.123.123.123]: 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
554 <foo@watson.ibm.com>: 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 >>> rcpt foo@porcupine.org
OK OK
>>> recipient_restrictions check_recipient_access,hash:./smtpd_check_access >>> recipient_restrictions check_recipient_access,hash:./smtpd_check_access
OK OK
>>> mail bad-sender@any.domain >>> mail bad-sender@any.domain
./smtpd_check: reject: MAIL from foo[123.123.123.123]: 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@
554 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 >>> mail bad-sender@good.domain
OK OK
>>> mail reject@this.address >>> mail reject@this.address
./smtpd_check: reject: MAIL from foo[123.123.123.123]: 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
554 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 >>> mail foo@bad.domain
./smtpd_check: reject: MAIL from foo[123.123.123.123]: 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
554 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 >>> mail foo@random.bad.domain
./smtpd_check: reject: MAIL from foo[123.123.123.123]: 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
554 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 >>> mail foo@friend.bad.domain
OK OK
>>> # >>> #
@ -170,7 +185,8 @@ OK
>>> client spike.porcupine.org 168.100.189.2 >>> client spike.porcupine.org 168.100.189.2
OK OK
>>> client foo 127.0.0.2 >>> 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 554 Service unavailable; [127.0.0.2] blocked using rbl.maps.vix.com
>>> # >>> #
>>> # unknown sender/recipient domain >>> # unknown sender/recipient domain
@ -184,10 +200,12 @@ OK
>>> rcpt wietse@porcupine.org >>> rcpt wietse@porcupine.org
OK OK
>>> rcpt wietse@no.recipient.domain >>> rcpt wietse@no.recipient.domain
./smtpd_check: reject: RCPT from foo[127.0.0.2]: 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
554 <no.recipient.domain>: 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 >>> mail wietse@no.sender.domain
OK OK
>>> rcpt wietse@porcupine.org >>> rcpt wietse@porcupine.org
./smtpd_check: reject: RCPT from foo[127.0.0.2]: 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
554 <no.sender.domain>: 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

View File

@ -53,6 +53,7 @@
#include <mymalloc.h> #include <mymalloc.h>
#include <vstream.h> #include <vstream.h>
#include <name_mask.h> #include <name_mask.h>
#include <stringops.h>
/* Global library. */ /* Global library. */
@ -80,6 +81,7 @@ void smtpd_state_init(SMTPD_STATE *state, VSTREAM *stream,
state->buffer = vstring_alloc(100); state->buffer = vstring_alloc(100);
state->name = mystrdup(name); state->name = mystrdup(name);
state->addr = mystrdup(addr); state->addr = mystrdup(addr);
state->namaddr = concatenate(name, "[", addr, "]", (char *) 0);
state->error_count = 0; state->error_count = 0;
state->error_mask = 0; state->error_mask = 0;
state->notify_mask = name_mask(mail_error_masks, var_notify_classes); state->notify_mask = name_mask(mail_error_masks, var_notify_classes);
@ -118,4 +120,6 @@ void smtpd_state_reset(SMTPD_STATE *state)
myfree(state->name); myfree(state->name);
if (state->addr) if (state->addr)
myfree(state->addr); myfree(state->addr);
if (state->namaddr)
myfree(state->namaddr);
} }

View File

@ -41,7 +41,6 @@
/* .IP "-R interval" /* .IP "-R interval"
/* Wait for a random period of time 0 <= n <= interval between messages. /* Wait for a random period of time 0 <= n <= interval between messages.
/* Suspending one thread does not affect other delivery threads. /* Suspending one thread does not affect other delivery threads.
/* threads keep running.
/* .IP "-w interval" /* .IP "-w interval"
/* Wait a fixed time between messages. /* Wait a fixed time between messages.
/* Suspending one thread does not affect other delivery threads. /* Suspending one thread does not affect other delivery threads.