diff --git a/postfix/HISTORY b/postfix/HISTORY
index 29ffa67ed..ab94cf30c 100644
--- a/postfix/HISTORY
+++ b/postfix/HISTORY
@@ -10230,10 +10230,25 @@ Apologies for any names omitted.
than $line_length_limit, causing postdrop to reject the
mail. Diagnosis by Victor Duchovni. File: sendmail/sendmail.c.
+20050202
+
+ Cleanup: explicit Makefile targets for "make package" and
+ "make non-interactive-package" to create ready-to-install
+ packages for distribution to other systems. Added extra
+ sanity checks to prevent attempts to overwrite your running
+ Postfix instance. Files: Makefile.in, proto/PACKAGE_README.
+
+ Cleanup: when bounce_queue_lifetime > maximal_queue_lifetime,
+ it is adjusted to maximal_queue_lifetime, and a warning is
+ logged. Files: *qmgr/qmgr.c.
+
+ Cleanup: trivial-rewrite detects changes to maps even in
+ the absence of connection events. File: trivial-rewrite.c.
+
Open problems:
- Low: document regexp usage in aliases and other sensitive
- maps.
+ Med: SunOS 4 has no strtoul(). Instead of sprintf/strtoul()
+ use hexen/decode() for the process generation number.
Low: pointers to postfinger and saslfinger. postfinger
is now bundled.
@@ -10261,16 +10276,11 @@ Open problems:
really try all the possibilities that one might expect to
be tried. For now, this gotcha is documented in access(5).
- Low: cap bounce queue life time with regular queue life
- time.
-
Med: the TLS certificate verification depth parameters
never worked.
Med: eliminate the tls_info data structure.
- Low: something to alias sdbm:name into btree:name?
-
Med: implement ${name[?:]value} in main.cf or update the
postconf(5) manual.
@@ -10279,20 +10289,12 @@ Open problems:
Low: should the Delivered-To: test in local(8) be configurable?
- Low: document propagate_unmatched_extensions in aliases(5)
- etc.
-
Low: make mail_addr_find() lookup configurable.
- Low: anvil(8) should log cache peak size, like scache(8).
-
Low: update events.c so that 1-second timer requests do
not suffer from rounding errors. This is needed for 1-second
SMTP session caching time limits.
- Low: trivial-rewrite should examine the map change status
- every N seconds.
-
Low: per-sender resolver personalities?
Low: configurable internal/system locking method.
diff --git a/postfix/Makefile.in b/postfix/Makefile.in
index daab25797..22b3fa19d 100644
--- a/postfix/Makefile.in
+++ b/postfix/Makefile.in
@@ -37,9 +37,15 @@ printfck: update
install: update
$(SHELL) postfix-install
+package: update
+ $(SHELL) postfix-install -package
+
upgrade: update
$(SHELL) postfix-install -non-interactive
+non-interactive-package: update
+ $(SHELL) postfix-install -non-interactive -package
+
depend clean:
set -e; for i in $(DIRS); do \
(set -e; echo "[$$i]"; cd $$i; $(MAKE) $@) || exit 1; \
diff --git a/postfix/README_FILES/PACKAGE_README b/postfix/README_FILES/PACKAGE_README
index 2ca445ae2..71cec7151 100644
--- a/postfix/README_FILES/PACKAGE_README
+++ b/postfix/README_FILES/PACKAGE_README
@@ -11,8 +11,8 @@ for general use.
GGeenneerraall ddiissttrriibbuuttiioonnss:: pplleeaassee pprroovviiddee aa ssmmaallll ddeeffaauulltt mmaaiinn..ccff ffiillee
The installed main.cf file must be small. PLEASE resist the temptation to list
-all 300+ parameters in the main.cf file. Postfix is supposed to be easy to
-configure. Listing all 300+ in main.cf defeats the purpose. It is an invitation
+all 400+ parameters in the main.cf file. Postfix is supposed to be easy to
+configure. Listing all 400+ in main.cf defeats the purpose. It is an invitation
for hobbyists to make random changes without understanding what they do, and
gets them into endless trouble.
@@ -39,7 +39,10 @@ You can build a pre-built Postfix package as an unprivileged user.
First compile Postfix. After successful compilation, execute:
- % sh postfix-install
+ % mmaakkee ppaacckkaaggee
+
+With Postfix versions before 2.2 you must invoke the post-install script
+directly (% sshh ppoosstt--iinnssttaallll).
You will be prompted for installation parameters. Specify an install_root
directory other than /. The mail_owner and setgid_group installation parameter
@@ -49,8 +52,10 @@ the package is unpacked and installed on the destination machine.
If you want to fully automate this process, specify all the non-default
installation parameters on the command line:
- % sh postfix-install -non-interactive
- install_root=/some/where ...
+ % mmaakkee nnoonn--iinntteerraaccttiivvee--ppaacckkaaggee iinnssttaallll__rroooott==//ssoommee//wwhheerree...
+
+With Postfix versions before 2.2 you must invoke the post-install script
+directly (% sshh ppoosstt--iinnssttaallll --nnoonn--iinntteerraaccttiivvee iinnssttaallll__rroooott......).
BBeeggiinn SSeeccuurriittyy AAlleerrtt
diff --git a/postfix/RELEASE_NOTES b/postfix/RELEASE_NOTES
index 5a1e813f7..b317fedbd 100644
--- a/postfix/RELEASE_NOTES
+++ b/postfix/RELEASE_NOTES
@@ -7,13 +7,34 @@ snapshot release). Patches are issued for the official release
and change the patchlevel and the release date. Patches are never
issued for snapshot releases.
-Incompatible changes with snapshot Postfix-2.2-20050131
+Incompatible changes with snapshot Postfix-2.2-20050202
=======================================================
Postfix rewrites message header addresses only in mail that originates
from the local machine. Specify "local_header_rewrite_clients =
static:all" to get the old behavior of Postfix 2.1 and earlier.
+Major changes with snapshot Postfix-2.2-20050202
+================================================
+
+To create a ready-to-install package for distribution to other
+systems use "make package" or "make non-interactive-package",
+instead of invoking the postfix-install script by hand (which is
+deprecated). See the PACKAGE_README file for details.
+
+New "permit_inet_interfaces" access restriction to allow access
+from local IP addresses only. This is used for the default, purist,
+setting of local_header_rewrite_clients.
+
+New "sleep time-in-seconds" pseudo access restriction to block
+zombie clients with reject_unauthorized_pipelining before the
+Postfix SMTP server sends the SMTP greeting. See postconf(5)
+for example.
+
+Safety: Postfix no longer tries to send mail to the fallback_relay
+when the local machine is MX host for the mail destination. See
+postconf(5) description of fallback_relay for details.
+
Incompatible changes with snapshot Postfix-2.2-20050117
=======================================================
diff --git a/postfix/conf/aliases b/postfix/conf/aliases
index a6690b232..c1f921eca 100644
--- a/postfix/conf/aliases
+++ b/postfix/conf/aliases
@@ -134,6 +134,21 @@ decode: root
# user+foo), the search is repeated for the unextended
# address (e.g., user).
#
+# The propagate_unmatched_extensions parameter controls
+# whether an unmatched address extension (+foo) is propa-
+# gated to the result of table lookup.
+#
+# SECURITY
+# The local(8) delivery agent disallows regular expression
+# substitution of $1 etc. in alias_maps, because that would
+# open a security hole.
+#
+# The local(8) delivery agent will silently ignore requests
+# to use the proxymap(8) server within alias_maps. Instead
+# it will open the table directly. Before Postfix version
+# 2.2, the local(8) delivery agent will terminate with a
+# fatal error.
+#
# CONFIGURATION PARAMETERS
# The following main.cf parameters are especially relevant.
# The text below provides only a parameter summary. See
@@ -161,6 +176,13 @@ decode: root
# the right-hand side of the owner alias, instead
# using of the left-hand side address.
#
+# propagate_unmatched_extensions
+# A list of address rewriting or forwarding mecha-
+# nisms that propagate an address extension from the
+# original address to the result. Specify zero or
+# more of canonical, virtual, alias, forward, or
+# include.
+#
# owner_request_special
# Give special treatment to owner-listname and list-
# name-request addresses.
@@ -169,11 +191,6 @@ decode: root
# Delimiter that separates recipients from address
# extensions.
#
-# BUGS
-# Regular expression alias lookup tables are allowed, but
-# substitution of $1 etc. is forbidden because that would
-# open a security loophole.
-#
# STANDARDS
# RFC 822 (ARPA Internet Text Messages)
#
diff --git a/postfix/html/PACKAGE_README.html b/postfix/html/PACKAGE_README.html
index 3aa2a9361..9d385cbfd 100644
--- a/postfix/html/PACKAGE_README.html
+++ b/postfix/html/PACKAGE_README.html
@@ -27,8 +27,8 @@ Postfix distributions for general use.
file
The installed main.cf file must be small. PLEASE resist the
-temptation to list all 300+ parameters in the main.cf file. Postfix
-is supposed to be easy to configure. Listing all 300+ in main.cf
+temptation to list all 400+ parameters in the main.cf file. Postfix
+is supposed to be easy to configure. Listing all 400+ in main.cf
defeats the purpose. It is an invitation for hobbyists to make
random changes without understanding what they do, and gets them
into endless trouble.
@@ -62,7 +62,11 @@ user.
First compile Postfix. After successful compilation, execute:
- % sh postfix-install
+ % make package
+
+
+ With Postfix versions before 2.2 you must invoke the post-install
+script directly (% sh post-install).
You will be prompted for installation parameters. Specify an
install_root directory other than /. The mail_owner and setgid_group
@@ -73,8 +77,13 @@ installed on the destination machine.
If you want to fully automate this process, specify all the
non-default installation parameters on the command line:
- % sh postfix-install -non-interactive
-install_root=/some/where ...
+
+ % make non-interactive-package install_root=/some/where...
+
+
+ With Postfix versions before 2.2 you must invoke the post-install
+script directly (% sh post-install -non-interactive
+install_root...).
Begin Security Alert
diff --git a/postfix/html/aliases.5.html b/postfix/html/aliases.5.html
index a884ccb0f..a3b2c84f7 100644
--- a/postfix/html/aliases.5.html
+++ b/postfix/html/aliases.5.html
@@ -102,6 +102,21 @@ ALIASES(5) ALIASES(5)
user+foo), the search is repeated for the unextended
address (e.g., user).
+ The propagate_unmatched_extensions parameter controls
+ whether an unmatched address extension (+foo) is propa-
+ gated to the result of table lookup.
+
+SECURITY
+ The local(8) delivery agent disallows regular expression
+ substitution of $1 etc. in alias_maps, because that would
+ open a security hole.
+
+ The local(8) delivery agent will silently ignore requests
+ to use the proxymap(8) server within alias_maps. Instead
+ it will open the table directly. Before Postfix version
+ 2.2, the local(8) delivery agent will terminate with a
+ fatal error.
+
CONFIGURATION PARAMETERS
The following main.cf parameters are especially relevant.
The text below provides only a parameter summary. See
@@ -109,10 +124,10 @@ ALIASES(5) ALIASES(5)
alias_database
List of alias databases that are updated by the
- newaliases(1) command.
+ newaliases(1) command.
alias_maps
- List of alias databases queried by the local(8)
+ List of alias databases queried by the local(8)
delivery agent.
allow_mail_to_commands
@@ -129,6 +144,13 @@ ALIASES(5) ALIASES(5)
the right-hand side of the owner alias, instead
using of the left-hand side address.
+ propagate_unmatched_extensions
+ A list of address rewriting or forwarding mecha-
+ nisms that propagate an address extension from the
+ original address to the result. Specify zero or
+ more of canonical, virtual, alias, forward, or
+ include.
+
owner_request_special
Give special treatment to owner-listname and list-
name-request addresses.
@@ -137,11 +159,6 @@ ALIASES(5) ALIASES(5)
Delimiter that separates recipients from address
extensions.
-BUGS
- Regular expression alias lookup tables are allowed, but
- substitution of $1 etc. is forbidden because that would
- open a security loophole.
-
STANDARDS
RFC 822 (ARPA Internet Text Messages)
diff --git a/postfix/html/local.8.html b/postfix/html/local.8.html
index 23b1e2e6b..125e39a71 100644
--- a/postfix/html/local.8.html
+++ b/postfix/html/local.8.html
@@ -313,6 +313,23 @@ LOCAL(8) LOCAL(8)
the postmaster is notified of bounces and of other trou-
ble.
+SECURITY
+ The local(8) delivery agent needs a dual personality 1) to
+ access the private Postfix queue and IPC mechanisms, 2) to
+ impersonate the recipient and deliver to recipient-speci-
+ fied files or commands. It is therefore security sensi-
+ tive.
+
+ The local(8) delivery agent disallows regular expression
+ substitution of $1 etc. in alias_maps, because that would
+ open a security hole.
+
+ The local(8) delivery agent will silently ignore requests
+ to use the proxymap(8) server within alias_maps. Instead
+ it will open the table directly. Before Postfix version
+ 2.2, the local(8) delivery agent will terminate with a
+ fatal error.
+
BUGS
For security reasons, the message delivery status of
external commands or of external files is never check-
@@ -326,7 +343,7 @@ LOCAL(8) LOCAL(8)
CONFIGURATION PARAMETERS
Changes to main.cf are picked up automatically, as
- local(8) processes run for only a limited amount of time.
+ local(8) processes run for only a limited amount of time.
Use the command "postfix reload" to speed up a change.
The text below provides only a parameter summary. See
@@ -352,7 +369,7 @@ LOCAL(8) LOCAL(8)
Obsolete SUN mailtool compatibility feature.
DELIVERY METHOD CONTROLS
- The precedence of local(8) delivery methods from high to
+ The precedence of local(8) delivery methods from high to
low is: aliases, .forward files, mailbox_transport, mail-
box_command_maps, mailbox_command, home_mailbox,
mail_spool_directory, fallback_transport and luser_relay.
diff --git a/postfix/html/postconf.5.html b/postfix/html/postconf.5.html
index 2fb6be1bf..6430c32f1 100644
--- a/postfix/html/postconf.5.html
+++ b/postfix/html/postconf.5.html
@@ -458,6 +458,18 @@ If you change the alias database, run "postalias /etc/aliases"
run "newaliases" to build the necessary DBM or DB file.
+
+The local(8) delivery agent disallows regular expression substitution
+of $1 etc. in alias_maps, because that would open a security hole.
+
+
+
+The local(8) delivery agent will silently ignore requests to use
+the proxymap(8) server within alias_maps. Instead it will open the
+table directly. Before Postfix version 2.2, the local(8) delivery
+agent will terminate with a fatal error.
+
+
Examples:
@@ -7157,6 +7169,21 @@ a restriction list, to make the default policy explicit. The
reject_code configuration parameter specifies the response code to
rejected requests (default: 554).
+sleep seconds
+
+Pause for the specified number of seconds and proceed with
+the next restriction in the list, if any. This may stop zombie
+mail when used as:
+
+
+
+/etc/postfix/main.cf:
+ smtpd_client_restrictions =
+ sleep 1, reject_unauth_pipelining
+ smtpd_delay_reject = no
+
+
+
warn_if_reject
Change the meaning of the next restriction, so that it logs
diff --git a/postfix/html/virtual.8.html b/postfix/html/virtual.8.html
index 8fb6cde38..0c241132a 100644
--- a/postfix/html/virtual.8.html
+++ b/postfix/html/virtual.8.html
@@ -116,6 +116,15 @@ VIRTUAL(8) VIRTUAL(8)
information are adequately protected. This program is not
designed to run chrooted.
+ The virtual delivery agent disallows regular expression
+ substitution of $1 etc. in regular expression lookup
+ tables, because that would open a security hole.
+
+ The virtual delivery agent will silently ignore requests
+ to use the proxymap(8) server. Instead it will open the
+ table directly. Before Postfix version 2.2, the virtual
+ delivery agent will terminate with a fatal error.
+
STANDARDS
RFC 822 (ARPA Internet Text Messages)
@@ -124,71 +133,71 @@ VIRTUAL(8) VIRTUAL(8)
recipient is over disk quota. In all other cases, mail for
an existing recipient is deferred and a warning is logged.
- Problems and transactions are logged to syslogd(8). Cor-
- rupted message files are marked so that the queue manager
+ Problems and transactions are logged to syslogd(8). Cor-
+ rupted message files are marked so that the queue manager
can move them to the corrupt queue afterwards.
- Depending on the setting of the notify_classes parameter,
- the postmaster is notified of bounces and of other trou-
+ Depending on the setting of the notify_classes parameter,
+ the postmaster is notified of bounces and of other trou-
ble.
BUGS
- This delivery agent supports address extensions in email
+ This delivery agent supports address extensions in email
addresses and in lookup table keys, but does not propagate
- address extension information to the result of table
+ address extension information to the result of table
lookup.
Postfix should have lookup tables that can return multiple
- result attributes. In order to avoid the inconvenience of
+ result attributes. In order to avoid the inconvenience of
maintaining three tables, use an LDAP or MYSQL database.
CONFIGURATION PARAMETERS
- Changes to main.cf are picked up automatically, as vir-
- tual(8) processes run for only a limited amount of time.
+ Changes to main.cf are picked up automatically, as vir-
+ tual(8) processes run for only a limited amount of time.
Use the command "postfix reload" to speed up a change.
- The text below provides only a parameter summary. See
+ The text below provides only a parameter summary. See
postconf(5) for more details including examples.
MAILBOX DELIVERY CONTROLS
virtual_mailbox_base (empty)
- A prefix that the virtual(8) delivery agent
- prepends to all pathname results from $vir-
+ A prefix that the virtual(8) delivery agent
+ prepends to all pathname results from $vir-
tual_mailbox_maps table lookups.
virtual_mailbox_maps (empty)
- Optional lookup tables with all valid addresses in
+ Optional lookup tables with all valid addresses in
the domains that match $virtual_mailbox_domains.
virtual_minimum_uid (100)
- The minimum user ID value that the virtual(8)
- delivery agent accepts as a result from $vir-
+ The minimum user ID value that the virtual(8)
+ delivery agent accepts as a result from $vir-
tual_uid_maps table lookup.
virtual_uid_maps (empty)
- Lookup tables with the per-recipient user ID that
+ Lookup tables with the per-recipient user ID that
the virtual(8) delivery agent uses while writing to
the recipient's mailbox.
virtual_gid_maps (empty)
- Lookup tables with the per-recipient group ID for
+ Lookup tables with the per-recipient group ID for
virtual(8) mailbox delivery.
Available in Postfix version 2.0 and later:
virtual_mailbox_domains ($virtual_mailbox_maps)
Postfix is final destination for the specified list
- of domains; mail is delivered via the $vir-
+ of domains; mail is delivered via the $vir-
tual_transport mail delivery transport.
virtual_transport (virtual)
- The default mail delivery transport for domains
- that match the $virtual_mailbox_domains parameter
+ The default mail delivery transport for domains
+ that match the $virtual_mailbox_domains parameter
value.
LOCKING CONTROLS
virtual_mailbox_lock (see 'postconf -d' output)
- How to lock a UNIX-style virtual(8) mailbox before
+ How to lock a UNIX-style virtual(8) mailbox before
attempting delivery.
deliver_lock_attempts (20)
@@ -196,37 +205,37 @@ VIRTUAL(8) VIRTUAL(8)
sive lock on a mailbox file or bounce(8) logfile.
deliver_lock_delay (1s)
- The time between attempts to acquire an exclusive
+ The time between attempts to acquire an exclusive
lock on a mailbox file or bounce(8) logfile.
stale_lock_time (500s)
- The time after which a stale exclusive mailbox
+ The time after which a stale exclusive mailbox
lockfile is removed.
RESOURCE AND RATE CONTROLS
virtual_destination_concurrency_limit ($default_destina-
tion_concurrency_limit)
- The maximal number of parallel deliveries to the
- same destination via the virtual message delivery
+ The maximal number of parallel deliveries to the
+ same destination via the virtual message delivery
transport.
virtual_destination_recipient_limit ($default_destina-
tion_recipient_limit)
- The maximal number of recipients per delivery via
+ The maximal number of recipients per delivery via
the virtual message delivery transport.
virtual_mailbox_limit (51200000)
- The maximal size in bytes of an individual mailbox
+ The maximal size in bytes of an individual mailbox
or maildir file, or zero (no limit).
MISCELLANEOUS CONTROLS
config_directory (see 'postconf -d' output)
- The default location of the Postfix main.cf and
+ The default location of the Postfix main.cf and
master.cf configuration files.
daemon_timeout (18000s)
- How much time a Postfix daemon process may take to
- handle a request before it is terminated by a
+ How much time a Postfix daemon process may take to
+ handle a request before it is terminated by a
built-in watchdog timer.
ipc_timeout (3600s)
@@ -234,31 +243,31 @@ VIRTUAL(8) VIRTUAL(8)
over an internal communication channel.
max_idle (100s)
- The maximum amount of time that an idle Postfix
- daemon process waits for the next service request
+ The maximum amount of time that an idle Postfix
+ daemon process waits for the next service request
before exiting.
max_use (100)
- The maximal number of connection requests before a
+ The maximal number of connection requests before a
Postfix daemon process terminates.
process_id (read-only)
- The process ID of a Postfix command or daemon pro-
+ The process ID of a Postfix command or daemon pro-
cess.
process_name (read-only)
- The process name of a Postfix command or daemon
+ The process name of a Postfix command or daemon
process.
queue_directory (see 'postconf -d' output)
- The location of the Postfix top-level queue direc-
+ The location of the Postfix top-level queue direc-
tory.
syslog_facility (mail)
The syslog facility of Postfix logging.
syslog_name (postfix)
- The mail system name that is prepended to the pro-
+ The mail system name that is prepended to the pro-
cess name in syslog records, so that "smtpd"
becomes, for example, "postfix/smtpd".
@@ -272,20 +281,20 @@ VIRTUAL(8) VIRTUAL(8)
VIRTUAL_README, domain hosting howto
LICENSE
- The Secure Mailer license must be distributed with this
+ The Secure Mailer license must be distributed with this
software.
HISTORY
- This delivery agent was originally based on the Postfix
- local delivery agent. Modifications mainly consisted of
- removing code that either was not applicable or that was
- not safe in this context: aliases, ~user/.forward files,
+ This delivery agent was originally based on the Postfix
+ local delivery agent. Modifications mainly consisted of
+ removing code that either was not applicable or that was
+ not safe in this context: aliases, ~user/.forward files,
delivery to "|command" or to /file/name.
The Delivered-To: message header appears in the qmail sys-
tem by Daniel Bernstein.
- The maildir structure appears in the qmail system by
+ The maildir structure appears in the qmail system by
Daniel Bernstein.
AUTHOR(S)
diff --git a/postfix/man/man5/aliases.5 b/postfix/man/man5/aliases.5
index a6a6561f7..ec1f5c539 100644
--- a/postfix/man/man5/aliases.5
+++ b/postfix/man/man5/aliases.5
@@ -94,6 +94,24 @@ configuration parameters.
When alias database search fails, and the recipient localpart
contains the optional recipient delimiter (e.g., \fIuser+foo\fR),
the search is repeated for the unextended address (e.g., \fIuser\fR).
+
+The \fBpropagate_unmatched_extensions\fR parameter controls
+whether an unmatched address extension (\fI+foo\fR) is
+propagated to the result of table lookup.
+.SH "SECURITY"
+.na
+.nf
+.ad
+.fi
+The \fBlocal\fR(8) delivery agent disallows regular expression
+substitution of $1 etc. in \fBalias_maps\fR, because that
+would open a security hole.
+
+The \fBlocal\fR(8) delivery agent will silently ignore
+requests to use the \fBproxymap\fR(8) server within
+\fBalias_maps\fR. Instead it will open the table directly.
+Before Postfix version 2.2, the \fBlocal\fR(8) delivery
+agent will terminate with a fatal error.
.SH "CONFIGURATION PARAMETERS"
.na
.nf
@@ -103,9 +121,10 @@ The following \fBmain.cf\fR parameters are especially relevant.
The text below provides only a parameter summary. See
postconf(5) for more details including examples.
.IP \fBalias_database\fR
-List of alias databases that are updated by the newaliases(1) command.
+List of alias databases that are updated by the
+\fBnewaliases\fR(1) command.
.IP \fBalias_maps\fR
-List of alias databases queried by the local(8) delivery agent.
+List of alias databases queried by the \fBlocal\fR(8) delivery agent.
.IP \fBallow_mail_to_commands\fR
Restrict the usage of mail delivery to external command.
.IP \fBallow_mail_to_files\fR
@@ -114,18 +133,17 @@ Restrict the usage of mail delivery to external file.
When delivering to an alias that has an \fBowner-\fR companion alias,
set the envelope sender address to the right-hand side of the
owner alias, instead using of the left-hand side address.
+.IP \fBpropagate_unmatched_extensions\fR
+A list of address rewriting or forwarding mechanisms that
+propagate an address extension from the original address
+to the result. Specify zero or more of \fBcanonical\fR,
+\fBvirtual\fR, \fBalias\fR, \fBforward\fR, or \fBinclude\fR.
.IP \fBowner_request_special\fR
Give special treatment to \fBowner-\fIlistname\fR and
\fIlistname\fB-request\fR
addresses.
.IP \fBrecipient_delimiter\fR
Delimiter that separates recipients from address extensions.
-.SH BUGS
-.ad
-.fi
-Regular expression alias lookup tables are allowed, but
-substitution of $1 etc. is forbidden because that would
-open a security loophole.
.SH "STANDARDS"
.na
.nf
diff --git a/postfix/man/man5/postconf.5 b/postfix/man/man5/postconf.5
index 548b89e9b..c8f05f879 100644
--- a/postfix/man/man5/postconf.5
+++ b/postfix/man/man5/postconf.5
@@ -238,6 +238,14 @@ If you change the alias database, run "\fBpostalias /etc/aliases\fR"
(or wherever your system stores the mail alias file), or simply
run "\fBnewaliases\fR" to build the necessary DBM or DB file.
.PP
+The local(8) delivery agent disallows regular expression substitution
+of $1 etc. in alias_maps, because that would open a security hole.
+.PP
+The local(8) delivery agent will silently ignore requests to use
+the proxymap(8) server within alias_maps. Instead it will open the
+table directly. Before Postfix version 2.2, the local(8) delivery
+agent will terminate with a fatal error.
+.PP
Examples:
.PP
.nf
@@ -704,7 +712,7 @@ debug_peer_list = some.domain
The external command to execute when a Postfix daemon program is
invoked with the -D option.
.PP
-Use "command .. & sleep 5" so that the debugger can attach before
+Use "command .. & sleep 5" so that the debugger can attach before
the process marches on. If you use an X-based debugger, be sure to
set up your XAUTHORITY environment variable before starting Postfix.
.PP
@@ -715,7 +723,7 @@ Example:
.ft C
debugger_command =
PATH=/usr/bin:/usr/X11R6/bin
- xxgdb $daemon_directory/$process_name $process_id & sleep 5
+ xxgdb $daemon_directory/$process_name $process_id & sleep 5
.fi
.ad
.ft R
@@ -4011,6 +4019,26 @@ Reject the request. This restriction is useful at the end of
a restriction list, to make the default policy explicit. The
reject_code configuration parameter specifies the response code to
rejected requests (default: 554).
+.IP "\fBsleep \fIseconds\fR\fR"
+Pause for the specified number of seconds and proceed with
+the next restriction in the list, if any. This may stop zombie
+mail when used as:
+.na
+.nf
+.in +4
+.nf
+.na
+.ft C
+/etc/postfix/main.cf:
+ smtpd_client_restrictions =
+ sleep 1, reject_unauth_pipelining
+ smtpd_delay_reject = no
+.fi
+.ad
+.ft R
+.in -4
+.fi
+.ad
.IP "\fBwarn_if_reject\fR"
Change the meaning of the next restriction, so that it logs
a warning instead of rejecting a request (look for logfile records
diff --git a/postfix/man/man8/local.8 b/postfix/man/man8/local.8
index 8eeb39e9a..a7ae4536f 100644
--- a/postfix/man/man8/local.8
+++ b/postfix/man/man8/local.8
@@ -326,6 +326,25 @@ manager can move them to the \fBcorrupt\fR queue afterwards.
Depending on the setting of the \fBnotify_classes\fR parameter,
the postmaster is notified of bounces and of other trouble.
+.SH "SECURITY"
+.na
+.nf
+.ad
+.fi
+The \fBlocal\fR(8) delivery agent needs a dual personality
+1) to access the private Postfix queue and IPC mechanisms,
+2) to impersonate the recipient and deliver to recipient-specified
+files or commands. It is therefore security sensitive.
+
+The \fBlocal\fR(8) delivery agent disallows regular expression
+substitution of $1 etc. in \fBalias_maps\fR, because that
+would open a security hole.
+
+The \fBlocal\fR(8) delivery agent will silently ignore
+requests to use the \fBproxymap\fR(8) server within
+\fBalias_maps\fR. Instead it will open the table directly.
+Before Postfix version 2.2, the \fBlocal\fR(8) delivery
+agent will terminate with a fatal error.
.SH BUGS
.ad
.fi
@@ -342,7 +361,7 @@ early. The resulting mail forwarding loop is broken by the use of the
.nf
.ad
.fi
-Changes to \fBmain.cf\fR are picked up automatically, as local(8)
+Changes to \fBmain.cf\fR are picked up automatically, as \fBlocal\fR(8)
processes run for only a limited amount of time. Use the command
"\fBpostfix reload\fR" to speed up a change.
@@ -370,7 +389,7 @@ Obsolete SUN mailtool compatibility feature.
.nf
.ad
.fi
-The precedence of local(8) delivery methods from high to low is:
+The precedence of \fBlocal\fR(8) delivery methods from high to low is:
aliases, .forward files, mailbox_transport, mailbox_command_maps,
mailbox_command, home_mailbox, mail_spool_directory, fallback_transport
and luser_relay.
diff --git a/postfix/man/man8/virtual.8 b/postfix/man/man8/virtual.8
index 34d466cbb..3ab976c78 100644
--- a/postfix/man/man8/virtual.8
+++ b/postfix/man/man8/virtual.8
@@ -127,6 +127,15 @@ map.
The virtual delivery agent is not security sensitive, provided
that the lookup tables with recipient user/group ID information are
adequately protected. This program is not designed to run chrooted.
+
+The virtual delivery agent disallows regular expression
+substitution of $1 etc. in regular expression lookup tables,
+because that would open a security hole.
+
+The virtual delivery agent will silently ignore requests
+to use the proxymap(8) server. Instead it will open the
+table directly. Before Postfix version 2.2, the virtual
+delivery agent will terminate with a fatal error.
.SH "STANDARDS"
.na
.nf
diff --git a/postfix/mantools/postconf2man b/postfix/mantools/postconf2man
index f9d32521e..bd4fe7aae 100755
--- a/postfix/mantools/postconf2man
+++ b/postfix/mantools/postconf2man
@@ -69,6 +69,7 @@ while(<>) {
$block =~ s/
\s*/\n.br\n/g;
$block =~ s/<//g;
+ $block =~ s/&/\&/g;
$block =~ s/\s+\n/\n/g;
$block =~ s/^\n//g;
print $block;
diff --git a/postfix/postfix-install b/postfix/postfix-install
index 196437f94..a955be13c 100644
--- a/postfix/postfix-install
+++ b/postfix/postfix-install
@@ -168,6 +168,7 @@ BACKUP_IFS="$IFS"
USAGE="Usage: $0 [name=value] [option]
-non-interactive Do not ask for installation parameters.
+ -package Build a ready-to-install package.
name=value Specify an installation parameter".
# Process command-line options and parameter settings. Work around
@@ -179,6 +180,7 @@ do
case $arg in
*=*) IFS= eval $arg; IFS="$BACKUP_IFS";;
-non-int*) non_interactive=1;;
+ -package) need_install_root=install_root;;
*) echo "$0: Error: $USAGE" 1>&2; exit 1;;
esac
shift
@@ -380,6 +382,11 @@ case $install_root in
/) install_root=
esac
+test -z "$need_install_root" || test -n "$install_root" || {
+ echo $0: Error: invalid package root directory: \"install_root=/\" 1>&2
+ exit 1
+}
+
CONFIG_DIRECTORY=$install_root$config_directory
# If a parameter is not set via the command line or environment,
diff --git a/postfix/proto/PACKAGE_README.html b/postfix/proto/PACKAGE_README.html
index ef14f6428..72bdf2663 100644
--- a/postfix/proto/PACKAGE_README.html
+++ b/postfix/proto/PACKAGE_README.html
@@ -27,8 +27,8 @@ Postfix distributions for general use.
file
The installed main.cf file must be small. PLEASE resist the
-temptation to list all 300+ parameters in the main.cf file. Postfix
-is supposed to be easy to configure. Listing all 300+ in main.cf
+temptation to list all 400+ parameters in the main.cf file. Postfix
+is supposed to be easy to configure. Listing all 400+ in main.cf
defeats the purpose. It is an invitation for hobbyists to make
random changes without understanding what they do, and gets them
into endless trouble.
@@ -62,7 +62,11 @@ user.
First compile Postfix. After successful compilation, execute:
- % sh postfix-install
+ % make package
+
+
+ With Postfix versions before 2.2 you must invoke the post-install
+script directly (% sh post-install).
You will be prompted for installation parameters. Specify an
install_root directory other than /. The mail_owner and setgid_group
@@ -73,8 +77,13 @@ installed on the destination machine.
If you want to fully automate this process, specify all the
non-default installation parameters on the command line:
- % sh postfix-install -non-interactive
-install_root=/some/where ...
+
+ % make non-interactive-package install_root=/some/where...
+
+
+ With Postfix versions before 2.2 you must invoke the post-install
+script directly (% sh post-install -non-interactive
+install_root...).
Begin Security Alert
diff --git a/postfix/proto/aliases b/postfix/proto/aliases
index 9743a6093..1abbddc13 100644
--- a/postfix/proto/aliases
+++ b/postfix/proto/aliases
@@ -86,6 +86,22 @@
# When alias database search fails, and the recipient localpart
# contains the optional recipient delimiter (e.g., \fIuser+foo\fR),
# the search is repeated for the unextended address (e.g., \fIuser\fR).
+#
+# The \fBpropagate_unmatched_extensions\fR parameter controls
+# whether an unmatched address extension (\fI+foo\fR) is
+# propagated to the result of table lookup.
+# SECURITY
+# .ad
+# .fi
+# The \fBlocal\fR(8) delivery agent disallows regular expression
+# substitution of $1 etc. in \fBalias_maps\fR, because that
+# would open a security hole.
+#
+# The \fBlocal\fR(8) delivery agent will silently ignore
+# requests to use the \fBproxymap\fR(8) server within
+# \fBalias_maps\fR. Instead it will open the table directly.
+# Before Postfix version 2.2, the \fBlocal\fR(8) delivery
+# agent will terminate with a fatal error.
# CONFIGURATION PARAMETERS
# .ad
# .fi
@@ -93,9 +109,10 @@
# The text below provides only a parameter summary. See
# postconf(5) for more details including examples.
# .IP \fBalias_database\fR
-# List of alias databases that are updated by the newaliases(1) command.
+# List of alias databases that are updated by the
+# \fBnewaliases\fR(1) command.
# .IP \fBalias_maps\fR
-# List of alias databases queried by the local(8) delivery agent.
+# List of alias databases queried by the \fBlocal\fR(8) delivery agent.
# .IP \fBallow_mail_to_commands\fR
# Restrict the usage of mail delivery to external command.
# .IP \fBallow_mail_to_files\fR
@@ -104,16 +121,17 @@
# When delivering to an alias that has an \fBowner-\fR companion alias,
# set the envelope sender address to the right-hand side of the
# owner alias, instead using of the left-hand side address.
+# .IP \fBpropagate_unmatched_extensions\fR
+# A list of address rewriting or forwarding mechanisms that
+# propagate an address extension from the original address
+# to the result. Specify zero or more of \fBcanonical\fR,
+# \fBvirtual\fR, \fBalias\fR, \fBforward\fR, or \fBinclude\fR.
# .IP \fBowner_request_special\fR
# Give special treatment to \fBowner-\fIlistname\fR and
# \fIlistname\fB-request\fR
# addresses.
# .IP \fBrecipient_delimiter\fR
# Delimiter that separates recipients from address extensions.
-# BUGS
-# Regular expression alias lookup tables are allowed, but
-# substitution of $1 etc. is forbidden because that would
-# open a security loophole.
# STANDARDS
# RFC 822 (ARPA Internet Text Messages)
# SEE ALSO
diff --git a/postfix/proto/postconf.proto b/postfix/proto/postconf.proto
index 61b2edb1b..9db5ca23d 100644
--- a/postfix/proto/postconf.proto
+++ b/postfix/proto/postconf.proto
@@ -427,6 +427,18 @@ If you change the alias database, run "postalias /etc/aliases"
(or wherever your system stores the mail alias file), or simply
run "newaliases" to build the necessary DBM or DB file.
+
+
+The local(8) delivery agent disallows regular expression substitution
+of $1 etc. in alias_maps, because that would open a security hole.
+
+
+
+The local(8) delivery agent will silently ignore requests to use
+the proxymap(8) server within alias_maps. Instead it will open the
+table directly. Before Postfix version 2.2, the local(8) delivery
+agent will terminate with a fatal error.
+
Examples:
@@ -4440,6 +4452,21 @@ a restriction list, to make the default policy explicit. The
reject_code configuration parameter specifies the response code to
rejected requests (default: 554).
+sleep seconds
+
+Pause for the specified number of seconds and proceed with
+the next restriction in the list, if any. This may stop zombie
+mail when used as:
+
+
+
+/etc/postfix/main.cf:
+ smtpd_client_restrictions =
+ sleep 1, reject_unauth_pipelining
+ smtpd_delay_reject = no
+
+
+
warn_if_reject
Change the meaning of the next restriction, so that it logs
diff --git a/postfix/src/anvil/anvil.c b/postfix/src/anvil/anvil.c
index 5aa6f35a7..40c00da10 100644
--- a/postfix/src/anvil/anvil.c
+++ b/postfix/src/anvil/anvil.c
@@ -272,6 +272,9 @@ static int max_rcpt;
static char *max_rcpt_user;
static time_t max_rcpt_time;
+static int max_cache;
+static time_t max_cache_time;
+
/*
* Remote connection state, one instance for each (service, client) pair.
*/
@@ -522,6 +525,10 @@ static ANVIL_REMOTE *anvil_remote_conn_update(VSTREAM *client_stream, const char
anvil_remote = (ANVIL_REMOTE *) mymalloc(sizeof(*anvil_remote));
ANVIL_REMOTE_FIRST(anvil_remote, ident);
htable_enter(anvil_remote_map, ident, (char *) anvil_remote);
+ if (max_cache < anvil_remote_map->used) {
+ max_cache = anvil_remote_map->used;
+ max_cache_time = event_time();
+ }
} else {
ANVIL_REMOTE_NEXT(anvil_remote);
}
@@ -809,29 +816,34 @@ static void post_jail_init(char *unused_name, char **unused_argv)
static void anvil_status_dump(char *unused_name, char **unused_argv)
{
- if (max_rate > 1) {
+ if (max_rate > 0) {
msg_info("statistics: max connection rate %d/%ds for (%s) at %.15s",
max_rate, var_anvil_time_unit,
max_rate_user, ctime(&max_rate_time) + 4);
max_rate = 0;
}
- if (max_count > 1) {
+ if (max_count > 0) {
msg_info("statistics: max connection count %d for (%s) at %.15s",
max_count, max_count_user, ctime(&max_count_time) + 4);
max_count = 0;
}
- if (max_mail > 1) {
+ if (max_mail > 0) {
msg_info("statistics: max message rate %d/%ds for (%s) at %.15s",
max_mail, var_anvil_time_unit,
max_mail_user, ctime(&max_mail_time) + 4);
max_mail = 0;
}
- if (max_rcpt > 1) {
+ if (max_rcpt > 0) {
msg_info("statistics: max recipient rate %d/%ds for (%s) at %.15s",
max_rcpt, var_anvil_time_unit,
max_rcpt_user, ctime(&max_rcpt_time) + 4);
max_rcpt = 0;
}
+ if (max_cache > 0) {
+ msg_info("statistics: max ident cache size %d at %.15s",
+ max_cache, ctime(&max_cache_time) + 4);
+ max_cache = 0;
+ }
}
/* anvil_status_update - log and reset extreme usage periodically */
diff --git a/postfix/src/global/mail_params.h b/postfix/src/global/mail_params.h
index 9b2bdfdde..bc147ae5d 100644
--- a/postfix/src/global/mail_params.h
+++ b/postfix/src/global/mail_params.h
@@ -1574,6 +1574,8 @@ extern int var_defer_code;
#define DEFER_IF_PERMIT "defer_if_permit"
#define DEFER_IF_REJECT "defer_if_reject"
+#define SLEEP "sleep"
+
#define REJECT_UNKNOWN_CLIENT "reject_unknown_client"
#define VAR_UNK_CLIENT_CODE "unknown_client_reject_code"
#define DEF_UNK_CLIENT_CODE 450
diff --git a/postfix/src/global/mail_version.h b/postfix/src/global/mail_version.h
index d69fd6ef3..432ec315d 100644
--- a/postfix/src/global/mail_version.h
+++ b/postfix/src/global/mail_version.h
@@ -20,7 +20,7 @@
* Patches change the patchlevel and the release date. Snapshots change the
* release date only.
*/
-#define MAIL_RELEASE_DATE "20050131"
+#define MAIL_RELEASE_DATE "20050202"
#define MAIL_VERSION_NUMBER "2.2"
#define VAR_MAIL_VERSION "mail_version"
diff --git a/postfix/src/local/local.c b/postfix/src/local/local.c
index 86337b919..226642742 100644
--- a/postfix/src/local/local.c
+++ b/postfix/src/local/local.c
@@ -302,6 +302,23 @@
/*
/* Depending on the setting of the \fBnotify_classes\fR parameter,
/* the postmaster is notified of bounces and of other trouble.
+/* SECURITY
+/* .ad
+/* .fi
+/* The \fBlocal\fR(8) delivery agent needs a dual personality
+/* 1) to access the private Postfix queue and IPC mechanisms,
+/* 2) to impersonate the recipient and deliver to recipient-specified
+/* files or commands. It is therefore security sensitive.
+/*
+/* The \fBlocal\fR(8) delivery agent disallows regular expression
+/* substitution of $1 etc. in \fBalias_maps\fR, because that
+/* would open a security hole.
+/*
+/* The \fBlocal\fR(8) delivery agent will silently ignore
+/* requests to use the \fBproxymap\fR(8) server within
+/* \fBalias_maps\fR. Instead it will open the table directly.
+/* Before Postfix version 2.2, the \fBlocal\fR(8) delivery
+/* agent will terminate with a fatal error.
/* BUGS
/* For security reasons, the message delivery status of external commands
/* or of external files is never checkpointed to file. As a result,
@@ -314,7 +331,7 @@
/* CONFIGURATION PARAMETERS
/* .ad
/* .fi
-/* Changes to \fBmain.cf\fR are picked up automatically, as local(8)
+/* Changes to \fBmain.cf\fR are picked up automatically, as \fBlocal\fR(8)
/* processes run for only a limited amount of time. Use the command
/* "\fBpostfix reload\fR" to speed up a change.
/*
@@ -338,7 +355,7 @@
/* DELIVERY METHOD CONTROLS
/* .ad
/* .fi
-/* The precedence of local(8) delivery methods from high to low is:
+/* The precedence of \fBlocal\fR(8) delivery methods from high to low is:
/* aliases, .forward files, mailbox_transport, mailbox_command_maps,
/* mailbox_command, home_mailbox, mail_spool_directory, fallback_transport
/* and luser_relay.
diff --git a/postfix/src/master/master.h b/postfix/src/master/master.h
index 95b5e491b..d6b2418f4 100644
--- a/postfix/src/master/master.h
+++ b/postfix/src/master/master.h
@@ -23,14 +23,17 @@ typedef struct MASTER_SERV {
int wakeup_time; /* wakeup interval */
int *listen_fd; /* incoming requests */
int listen_fd_count; /* nr of descriptors */
+#ifdef MASTER_SERV_TYPE_PASS
+ struct PASS_INFO *pass_info; /* descriptor passing state */
+#endif
union {
struct {
char *port; /* inet listen port */
struct INET_ADDR_LIST *addr;/* inet listen address */
- } inet_ep;
+ } inet_ep;
#define MASTER_INET_ADDRLIST(s) ((s)->endpoint.inet_ep.addr)
#define MASTER_INET_PORT(s) ((s)->endpoint.inet_ep.port)
- } endpoint;
+ } endpoint;
int max_proc; /* upper bound on # processes */
char *path; /* command pathname */
struct ARGV *args; /* argument vector */
@@ -62,6 +65,7 @@ typedef struct MASTER_SERV {
#define MASTER_SERV_TYPE_UNIX 1 /* AF_UNIX domain socket */
#define MASTER_SERV_TYPE_INET 2 /* AF_INET domain socket */
#define MASTER_SERV_TYPE_FIFO 3 /* fifo (named pipe) */
+/*#define MASTER_SERV_TYPE_PASS 4 /* AF_UNIX domain socket */
/*
* Default process management policy values. This is only the bare minimum.
diff --git a/postfix/src/master/master_ent.c b/postfix/src/master/master_ent.c
index adb6349a7..e2871d6d1 100644
--- a/postfix/src/master/master_ent.c
+++ b/postfix/src/master/master_ent.c
@@ -330,6 +330,11 @@ MASTER_SERV *get_master_ent()
} else if (STR_SAME(transport, MASTER_XPORT_NAME_FIFO)) {
serv->type = MASTER_SERV_TYPE_FIFO;
serv->listen_fd_count = 1;
+#ifdef MASTER_SERV_TYPE_PASS
+ } else if (STR_SAME(transport, MASTER_XPORT_NAME_PASS)) {
+ serv->type = MASTER_SERV_TYPE_PASS;
+ serv->listen_fd_count = 1;
+#endif
} else {
fatal_with_context("bad transport type: %s", transport);
}
@@ -353,6 +358,11 @@ MASTER_SERV *get_master_ent()
} else if (serv->type == MASTER_SERV_TYPE_FIFO) {
serv->name = mail_pathname(private ? MAIL_CLASS_PRIVATE :
MAIL_CLASS_PUBLIC, name);
+#ifdef MASTER_SERV_TYPE_PASS
+ } else if (serv->type == MASTER_SERV_TYPE_PASS) {
+ serv->name = mail_pathname(private ? MAIL_CLASS_PRIVATE :
+ MAIL_CLASS_PUBLIC, name);
+#endif
} else {
msg_panic("bad transport type: %d", serv->type);
}
@@ -474,6 +484,9 @@ void print_master_ent(MASTER_SERV *serv)
serv->type == MASTER_SERV_TYPE_UNIX ? MASTER_XPORT_NAME_UNIX :
serv->type == MASTER_SERV_TYPE_FIFO ? MASTER_XPORT_NAME_FIFO :
serv->type == MASTER_SERV_TYPE_INET ? MASTER_XPORT_NAME_INET :
+#ifdef MASTER_SERV_TYPE_PASS
+ serv->type == MASTER_SERV_TYPE_PASS ? MASTER_XPORT_NAME_PASS :
+#endif
"unknown transport type");
msg_info("listen_fd_count: %d", serv->listen_fd_count);
msg_info("wakeup: %d", serv->wakeup_time);
diff --git a/postfix/src/master/master_listen.c b/postfix/src/master/master_listen.c
index 49d16d9e1..0ff878389 100644
--- a/postfix/src/master/master_listen.c
+++ b/postfix/src/master/master_listen.c
@@ -127,6 +127,21 @@ void master_listen_init(MASTER_SERV *serv)
myfree(end_point);
}
break;
+
+ /*
+ * Descriptor passing endpoints always come as singlets.
+ */
+#ifdef MASTER_SERV_TYPE_PASS
+ case MASTER_SERV_TYPE_PASS:
+ set_eugid(var_owner_uid, var_owner_gid);
+ serv->listen_fd[0] =
+ PASS_LISTEN(serv->name, serv->max_proc > var_proc_limit ?
+ serv->max_proc : var_proc_limit, NON_BLOCKING,
+ &(serv->pass_info));
+ close_on_exec(serv->listen_fd[0], CLOSE_ON_EXEC);
+ set_ugid(getuid(), getgid());
+ break;
+#endif
default:
msg_panic("%s: unknown service type: %d", myname, serv->type);
}
@@ -146,6 +161,10 @@ void master_listen_cleanup(MASTER_SERV *serv)
* listener. The 4.4BSD shutdown(2) man page promises an ENOTCONN error
* when shutdown(2) is applied to a socket that is not connected.
*/
+#ifdef MASTER_SERV_TYPE_PASS
+ if (serv->type == MASTER_SERV_TYPE_PASS)
+ PASS_SHUTDOWN(&(serv->pass_info));
+#endif
for (n = 0; n < serv->listen_fd_count; n++) {
if (close(serv->listen_fd[n]) < 0)
msg_warn("%s: close listener socket %d: %m",
diff --git a/postfix/src/master/master_proto.h b/postfix/src/master/master_proto.h
index fc48fa092..ca6fe0b24 100644
--- a/postfix/src/master/master_proto.h
+++ b/postfix/src/master/master_proto.h
@@ -15,6 +15,7 @@
#define MASTER_XPORT_NAME_UNIX "unix" /* local IPC */
#define MASTER_XPORT_NAME_FIFO "fifo" /* local IPC */
#define MASTER_XPORT_NAME_INET "inet" /* non-local IPC */
+/*#define MASTER_XPORT_NAME_PASS "pass" /* local IPC */
/*
* Format of a status message sent by a child process to the process
diff --git a/postfix/src/master/master_wakeup.c b/postfix/src/master/master_wakeup.c
index d3052e688..7e7328a3f 100644
--- a/postfix/src/master/master_wakeup.c
+++ b/postfix/src/master/master_wakeup.c
@@ -104,6 +104,12 @@ static void master_wakeup_timer_event(int unused_event, char *context)
case MASTER_SERV_TYPE_UNIX:
status = LOCAL_TRIGGER(serv->name, &wakeup, sizeof(wakeup), BRIEFLY);
break;
+#ifdef MASTER_SERV_TYPE_PASS
+ case MASTER_SERV_TYPE_PASS:
+ /* Can't send data to a service that expects descriptors. */
+ status = 0;
+ break;
+#endif
/*
* If someone compromises the postfix account then this must not
diff --git a/postfix/src/master/multi_server.c b/postfix/src/master/multi_server.c
index 2ac116a11..e17df7203 100644
--- a/postfix/src/master/multi_server.c
+++ b/postfix/src/master/multi_server.c
@@ -347,6 +347,45 @@ static void multi_server_accept_local(int unused_event, char *context)
multi_server_wakeup(fd);
}
+#ifdef MASTER_XPORT_NAME_PASS
+
+/* multi_server_accept_pass - accept descriptor */
+
+static void multi_server_accept_pass(int unused_event, char *context)
+{
+ int listen_fd = CAST_CHAR_PTR_TO_INT(context);
+ int time_left = -1;
+ int fd;
+
+ /*
+ * Be prepared for accept() to fail because some other process already
+ * got the connection (the number of processes competing for clients is
+ * kept small, so this is not a "thundering herd" problem). If the
+ * accept() succeeds, be sure to disable non-blocking I/O, in order to
+ * minimize confusion.
+ */
+ if (client_count == 0 && var_idle_limit > 0)
+ time_left = event_cancel_timer(multi_server_timeout, (char *) 0);
+
+ if (multi_server_pre_accept)
+ multi_server_pre_accept(multi_server_name, multi_server_argv);
+ fd = PASS_ACCEPT(listen_fd);
+ if (multi_server_lock != 0
+ && myflock(vstream_fileno(multi_server_lock), INTERNAL_LOCK,
+ MYFLOCK_OP_NONE) < 0)
+ msg_fatal("select unlock: %m");
+ if (fd < 0) {
+ if (errno != EAGAIN)
+ msg_fatal("accept connection: %m");
+ if (time_left >= 0)
+ event_request_timer(multi_server_timeout, (char *) 0, time_left);
+ return;
+ }
+ multi_server_wakeup(fd);
+}
+
+#endif
+
/* multi_server_accept_inet - accept client connection request */
static void multi_server_accept_inet(int unused_event, char *context)
@@ -603,6 +642,10 @@ NORETURN multi_server_main(int argc, char **argv, MULTI_SERVER_FN service,...)
multi_server_accept = multi_server_accept_inet;
else if (strcasecmp(transport, MASTER_XPORT_NAME_UNIX) == 0)
multi_server_accept = multi_server_accept_local;
+#ifdef MASTER_XPORT_NAME_PASS
+ else if (strcasecmp(transport, MASTER_XPORT_NAME_PASS) == 0)
+ multi_server_accept = multi_server_accept_pass;
+#endif
else
msg_fatal("unsupported transport type: %s", transport);
}
diff --git a/postfix/src/master/single_server.c b/postfix/src/master/single_server.c
index 41efe9ad5..069b8c839 100644
--- a/postfix/src/master/single_server.c
+++ b/postfix/src/master/single_server.c
@@ -296,6 +296,44 @@ static void single_server_accept_local(int unused_event, char *context)
single_server_wakeup(fd);
}
+#ifdef MASTER_XPORT_NAME_PASS
+
+/* single_server_accept_pass - accept descriptor */
+
+static void single_server_accept_pass(int unused_event, char *context)
+{
+ int listen_fd = CAST_CHAR_PTR_TO_INT(context);
+ int time_left = -1;
+ int fd;
+
+ /*
+ * Be prepared for accept() to fail because some other process already
+ * got the connection. We use select() + accept(), instead of simply
+ * blocking in accept(), because we must be able to detect that the
+ * master process has gone away unexpectedly.
+ */
+ if (var_idle_limit > 0)
+ time_left = event_cancel_timer(single_server_timeout, (char *) 0);
+
+ if (single_server_pre_accept)
+ single_server_pre_accept(single_server_name, single_server_argv);
+ fd = PASS_ACCEPT(listen_fd);
+ if (single_server_lock != 0
+ && myflock(vstream_fileno(single_server_lock), INTERNAL_LOCK,
+ MYFLOCK_OP_NONE) < 0)
+ msg_fatal("select unlock: %m");
+ if (fd < 0) {
+ if (errno != EAGAIN)
+ msg_fatal("accept connection: %m");
+ if (time_left >= 0)
+ event_request_timer(single_server_timeout, (char *) 0, time_left);
+ return;
+ }
+ single_server_wakeup(fd);
+}
+
+#endif
+
/* single_server_accept_inet - accept client connection request */
static void single_server_accept_inet(int unused_event, char *context)
@@ -546,6 +584,10 @@ NORETURN single_server_main(int argc, char **argv, SINGLE_SERVER_FN service,...)
single_server_accept = single_server_accept_inet;
else if (strcasecmp(transport, MASTER_XPORT_NAME_UNIX) == 0)
single_server_accept = single_server_accept_local;
+#ifdef MASTER_XPORT_NAME_PASS
+ else if (strcasecmp(transport, MASTER_XPORT_NAME_PASS) == 0)
+ single_server_accept = single_server_accept_pass;
+#endif
else
msg_fatal("unsupported transport type: %s", transport);
}
diff --git a/postfix/src/master/trigger_server.c b/postfix/src/master/trigger_server.c
index ce6c5f225..047bf7e98 100644
--- a/postfix/src/master/trigger_server.c
+++ b/postfix/src/master/trigger_server.c
@@ -324,6 +324,54 @@ static void trigger_server_accept_local(int unused_event, char *context)
close(fd);
}
+#ifdef MASTER_XPORT_NAME_PASS
+
+/* trigger_server_accept_pass - accept descriptor */
+
+static void trigger_server_accept_pass(int unused_event, char *context)
+{
+ char *myname = "trigger_server_accept_pass";
+ int listen_fd = CAST_CHAR_PTR_TO_INT(context);
+ int time_left = 0;
+ int fd;
+
+ if (msg_verbose)
+ msg_info("%s: trigger arrived", myname);
+
+ /*
+ * Read a message from a socket. Be prepared for accept() to fail because
+ * some other process already got the connection. The socket is
+ * non-blocking so we won't get stuck when multiple processes wake up.
+ * Don't get stuck when the client connects but sends no data. Restart
+ * the idle timer if this was a false alarm.
+ */
+ if (var_idle_limit > 0)
+ time_left = event_cancel_timer(trigger_server_timeout, (char *) 0);
+
+ if (trigger_server_pre_accept)
+ trigger_server_pre_accept(trigger_server_name, trigger_server_argv);
+ fd = PASS_ACCEPT(listen_fd);
+ if (trigger_server_lock != 0
+ && myflock(vstream_fileno(trigger_server_lock), INTERNAL_LOCK,
+ MYFLOCK_OP_NONE) < 0)
+ msg_fatal("select unlock: %m");
+ if (fd < 0) {
+ if (errno != EAGAIN)
+ msg_fatal("accept connection: %m");
+ if (time_left >= 0)
+ event_request_timer(trigger_server_timeout, (char *) 0, time_left);
+ return;
+ }
+ close_on_exec(fd, CLOSE_ON_EXEC);
+ if (read_wait(fd, 10) == 0)
+ trigger_server_wakeup(fd);
+ else if (time_left >= 0)
+ event_request_timer(trigger_server_timeout, (char *) 0, time_left);
+ close(fd);
+}
+
+#endif
+
/* trigger_server_main - the real main program */
NORETURN trigger_server_main(int argc, char **argv, TRIGGER_SERVER_FN service,...)
@@ -556,6 +604,10 @@ NORETURN trigger_server_main(int argc, char **argv, TRIGGER_SERVER_FN service,..
trigger_server_accept = trigger_server_accept_local;
else if (strcasecmp(transport, MASTER_XPORT_NAME_FIFO) == 0)
trigger_server_accept = trigger_server_accept_fifo;
+#ifdef MASTER_XPORT_NAME_PASS
+ else if (strcasecmp(transport, MASTER_XPORT_NAME_PASS) == 0)
+ trigger_server_accept = trigger_server_accept_pass;
+#endif
else
msg_fatal("unsupported transport type: %s", transport);
}
diff --git a/postfix/src/oqmgr/qmgr.c b/postfix/src/oqmgr/qmgr.c
index 6335c8910..e17379eed 100644
--- a/postfix/src/oqmgr/qmgr.c
+++ b/postfix/src/oqmgr/qmgr.c
@@ -492,10 +492,15 @@ static void qmgr_post_init(char *unused_name, char **unused_argv)
* Sanity check.
*/
if (var_qmgr_rcpt_limit < var_qmgr_active_limit) {
- msg_warn("%s is smaller than %s",
- VAR_QMGR_RCPT_LIMIT, VAR_QMGR_ACT_LIMIT);
+ msg_warn("%s is smaller than %s - adjusting %s",
+ VAR_QMGR_RCPT_LIMIT, VAR_QMGR_ACT_LIMIT, VAR_QMGR_RCPT_LIMIT);
var_qmgr_rcpt_limit = var_qmgr_active_limit;
}
+ if (var_dsn_queue_time > var_max_queue_time) {
+ msg_warn("%s is larger than %s - adjusting %s",
+ VAR_DSN_QUEUE_TIME, VAR_MAX_QUEUE_TIME, VAR_DSN_QUEUE_TIME);
+ var_dsn_queue_time = var_max_queue_time;
+ }
/*
* This routine runs after the skeleton code has entered the chroot jail.
diff --git a/postfix/src/qmgr/qmgr.c b/postfix/src/qmgr/qmgr.c
index f9ef04b35..d590943ae 100644
--- a/postfix/src/qmgr/qmgr.c
+++ b/postfix/src/qmgr/qmgr.c
@@ -546,10 +546,15 @@ static void qmgr_post_init(char *name, char **unused_argv)
* Sanity check.
*/
if (var_qmgr_rcpt_limit < var_qmgr_active_limit) {
- msg_warn("%s is smaller than %s",
- VAR_QMGR_RCPT_LIMIT, VAR_QMGR_ACT_LIMIT);
+ msg_warn("%s is smaller than %s - adjusting %s",
+ VAR_QMGR_RCPT_LIMIT, VAR_QMGR_ACT_LIMIT, VAR_QMGR_RCPT_LIMIT);
var_qmgr_rcpt_limit = var_qmgr_active_limit;
}
+ if (var_dsn_queue_time > var_max_queue_time) {
+ msg_warn("%s is larger than %s - adjusting %s",
+ VAR_DSN_QUEUE_TIME, VAR_MAX_QUEUE_TIME, VAR_DSN_QUEUE_TIME);
+ var_dsn_queue_time = var_max_queue_time;
+ }
/*
* This routine runs after the skeleton code has entered the chroot jail.
diff --git a/postfix/src/smtpd/smtpd_check.c b/postfix/src/smtpd/smtpd_check.c
index 26c1f16bd..9b0718bf0 100644
--- a/postfix/src/smtpd/smtpd_check.c
+++ b/postfix/src/smtpd/smtpd_check.c
@@ -1285,7 +1285,8 @@ static int reject_unauth_pipelining(SMTPD_STATE *state,
if (state->client != 0
&& SMTPD_STAND_ALONE(state) == 0
- && vstream_peek(state->client) > 0
+ && (vstream_peek(state->client) > 0
+ || peekfd(vstream_fileno(state->client)) > 0)
&& (strcasecmp(state->protocol, MAIL_PROTO_ESMTP) != 0
|| strcasecmp(state->where, "DATA") == 0)) {
return (smtpd_check_reject(state, MAIL_ERROR_PROTOCOL,
@@ -3146,10 +3147,12 @@ static int generic_checks(SMTPD_STATE *state, ARGV *restrictions,
} else if (strcasecmp(name, REJECT_UNAUTH_PIPE) == 0) {
status = reject_unauth_pipelining(state, reply_name, reply_class);
} else if (strcasecmp(name, CHECK_POLICY_SERVICE) == 0) {
- if (cpp[1] == 0)
+ if (cpp[1] == 0 || strchr(cpp[1], ':') == 0) {
msg_warn("restriction %s must be followed by transport:server",
CHECK_POLICY_SERVICE);
- else
+ longjmp(smtpd_check_buf, smtpd_check_reject(state,
+ MAIL_ERROR_SOFTWARE, "451 Server configuration error"));
+ } else
status = check_policy_service(state, *++cpp, reply_name,
reply_class, def_acl);
} else if (strcasecmp(name, DEFER_IF_PERMIT) == 0) {
@@ -3160,6 +3163,13 @@ static int generic_checks(SMTPD_STATE *state, ARGV *restrictions,
DEFER_IF_REJECT2(state, MAIL_ERROR_POLICY,
"450 <%s>: %s rejected: defer_if_reject requested",
reply_name, reply_class);
+ } else if (strcasecmp(name, SLEEP) == 0) {
+ if (cpp[1] == 0 || alldig(cpp[1]) == 0) {
+ msg_warn("restriction %s must be followed by number", SLEEP);
+ longjmp(smtpd_check_buf, smtpd_check_reject(state,
+ MAIL_ERROR_SOFTWARE, "451 Server configuration error"));
+ } else
+ sleep(atoi(*++cpp));
}
/*
diff --git a/postfix/src/trivial-rewrite/trivial-rewrite.c b/postfix/src/trivial-rewrite/trivial-rewrite.c
index 182851f5b..9a869617d 100644
--- a/postfix/src/trivial-rewrite/trivial-rewrite.c
+++ b/postfix/src/trivial-rewrite/trivial-rewrite.c
@@ -333,6 +333,9 @@ RES_CONTEXT resolve_verify = {
static void rewrite_service(VSTREAM *stream, char *unused_service, char **argv)
{
int status = -1;
+ static time_t last;
+ time_t now = event_time();
+ const char *table;
/*
* Sanity check. This service takes no command-line arguments.
@@ -340,6 +343,17 @@ static void rewrite_service(VSTREAM *stream, char *unused_service, char **argv)
if (argv[0])
msg_fatal("unexpected command-line argument: %s", argv[0]);
+ /*
+ * Connections are persistent. Be sure to refesh timely.
+ */
+ if (now - last > 10) {
+ if ((table = dict_changed_name()) != 0) {
+ msg_info("table %s has changed -- restarting", table);
+ exit(0);
+ }
+ last = now;
+ }
+
/*
* This routine runs whenever a client connects to the UNIX-domain socket
* dedicated to address rewriting. All connection-management stuff is
@@ -362,18 +376,6 @@ static void rewrite_service(VSTREAM *stream, char *unused_service, char **argv)
multi_server_disconnect(stream);
}
-/* pre_accept - see if tables have changed */
-
-static void pre_accept(char *unused_name, char **unused_argv)
-{
- const char *table;
-
- if ((table = dict_changed_name()) != 0) {
- msg_info("table %s has changed -- restarting", table);
- exit(0);
- }
-}
-
/* pre_jail_init - initialize before entering chroot jail */
static void pre_jail_init(char *unused_name, char **unused_argv)
@@ -442,6 +444,5 @@ int main(int argc, char **argv)
MAIL_SERVER_BOOL_TABLE, bool_table,
MAIL_SERVER_PRE_INIT, pre_jail_init,
MAIL_SERVER_POST_INIT, post_jail_init,
- MAIL_SERVER_PRE_ACCEPT, pre_accept,
0);
}
diff --git a/postfix/src/util/listen.h b/postfix/src/util/listen.h
index 81c5389c0..f7e70db4c 100644
--- a/postfix/src/util/listen.h
+++ b/postfix/src/util/listen.h
@@ -24,9 +24,12 @@ extern int inet_listen(const char *, int, int);
extern int fifo_listen(const char *, int, int);
extern int stream_listen(const char *, int, int);
+#define upass_listen(path, mode, log) fifo_listen((path), (mode), (log))
+
extern int inet_accept(int);
extern int unix_accept(int);
extern int stream_accept(int);
+extern int upass_accept(int);
/* LICENSE
/* .ad
diff --git a/postfix/src/util/name_mask.c b/postfix/src/util/name_mask.c
index 2bd32ff54..49fce9f6b 100644
--- a/postfix/src/util/name_mask.c
+++ b/postfix/src/util/name_mask.c
@@ -87,8 +87,8 @@
#include
#include
-#ifdef STRCASECMP_IN_STRING_H
-#include
+#ifdef STRCASECMP_IN_STRINGS_H
+#include
#endif
/* Utility library. */
diff --git a/postfix/src/util/upass_listen.c b/postfix/src/util/upass_listen.c
new file mode 100644
index 000000000..22390949f
--- /dev/null
+++ b/postfix/src/util/upass_listen.c
@@ -0,0 +1,192 @@
+/*++
+/* NAME
+/* upass_listen 3
+/* SUMMARY
+/* start UNIX-domain file descriptor listener
+/* SYNOPSIS
+/* #include
+/*
+/* int upass_listen(path, backlog, block_mode)
+/* const char *path;
+/* int backlog;
+/* int block_mode;
+/*
+/* int upass_accept(fd)
+/* int fd;
+/* DESCRIPTION
+/* This module implements a listener that receives one file descriptor
+/* across each UNIX-domain connection that is made to it.
+/*
+/* upass_listen() creates a listener endpoint with the specified
+/* permissions, and returns a file descriptor to be used for accepting
+/* descriptors.
+/*
+/* upass_accept() accepts a descriptor.
+/*
+/* Arguments:
+/* .IP path
+/* Null-terminated string with connection destination.
+/* .IP backlog
+/* This argument exists for compatibility and is ignored.
+/* .IP block_mode
+/* Either NON_BLOCKING or BLOCKING. This does not affect the
+/* mode of accepted connections.
+/* .IP fd
+/* File descriptor returned by upass_listen().
+/* DIAGNOSTICS
+/* Fatal errors: upass_listen() aborts upon any system call failure.
+/* upass_accept() leaves all error handling up to the caller.
+/* LICENSE
+/* .ad
+/* .fi
+/* The Secure Mailer license must be distributed with this software.
+/* AUTHOR(S)
+/* Wietse Venema
+/* IBM T.J. Watson Research
+/* P.O. Box 704
+/* Yorktown Heights, NY 10598, USA
+/*--*/
+
+/* System library. */
+
+#include
+#include
+#include
+#include
+
+/* Utility library. */
+
+#include
+#include
+#include
+
+/* upass_accept - accept descriptor */
+
+int upass_accept(int listen_fd)
+{
+ const char *myname = "upass_accept";
+ int accept_fd;
+ int recv_fd;
+
+ accept_fd = sane_accept(listen_fd, (struct sockaddr *) 0, (int *) 0);
+ if (accept_fd < 0) {
+ if (errno != EAGAIN)
+ msg_warn("%s: accept connection: %m", myname);
+ return (-1);
+ } else {
+ if ((recv_fd = unix_recv_fd(accept_fd)) < 0)
+ msg_warn("%s: cannot receive file descriptor: %m", myname);
+ if (close(accept_fd) < 0)
+ msg_warn("%s: close: %m", myname);
+ return (recv_fd);
+ }
+}
+
+#if 0
+
+/* System library. */
+
+#include
+
+/* Utility library. */
+
+#include
+#include
+#include
+#include
+#include
+
+ /*
+ * It would be nice if a client could make one UNIX-domain connection to a
+ * Postfix master service, send multiple descriptors, and have each
+ * descriptor handled by the first available child process.
+ *
+ * Possible solutions:
+ *
+ * - Either the master process accepts the UNIX-domain connection and forwards
+ * each descriptor sent by the client to the first available child process.
+ * That's what the code below does. Unfortunately, this approach is
+ * inconsistent with the Postfix architecture which tries to eliminate the
+ * master from connection management as much as possible.
+ *
+ * - Or one child processes accepts the UNIX-domain connection and sends a
+ * shared socketpair half to the client. The other socketpair half is shared
+ * with the master and all the child's siblings. The client then sends its
+ * descriptors over the socketpair, and each descriptor is available to any
+ * child process that is waiting for work.
+ *
+ * If the second solution did not use a shared socketpair, then all the
+ * client's descriptors would be available only to the child process that
+ * accepted the UNIX-domain connection. That results in poor performance.
+ *
+ * Unfortunately, having to receive a descriptor before being able to send one
+ * or more descriptors is ugly from the client's point of view.
+ */
+
+#define upass_accept(fd) unix_recv_fd(fd)
+
+/* upass_plumbing - operate the hidden descriptor passing machinery */
+
+static void upass_plumbing(int unused_event, char *context)
+{
+ const char *myname = "upass_plumbing";
+ UPASS_INFO *info = (UNIX_UPASS_INFO *) context;
+ int fd;
+
+ /*
+ * Each time a client connects to the hidden UNIX-domain socket, call
+ * unix_send_fd() to send one half of the hidden socketpair across a
+ * short-lived UNIX-domain connection. Wait until the client closes the
+ * UNIX-domain connection before closing the connection. This wait needs
+ * to be time limited.
+ */
+ fd = sane_accept(info->unixsock, (struct sockaddr *) 0, (int *) 0);
+ if (fd < 0) {
+ if (errno != EAGAIN)
+ msg_fatal("%s: accept connection: %m", myname);
+ } else {
+ if (unix_send_fd(fd, info->halfpair) < 0)
+ msg_warn("%s: cannot send file descriptor: %m", myname);
+ if (read_wait(fd, 5) < 0)
+ msg_warn("%s: read timeout", myname);
+ if (close(fd) < 0)
+ msg_warn("%s: close: %m", myname);
+ }
+}
+
+/* upass_listen - set up hidden descriptor passing machinery */
+
+int upass_listen(const char *path, int backlog, int blocking, UPASS_INFO **ip)
+{
+ int pair[2];
+ UPASS_INFO *info;
+
+ /*
+ * Create a UNIX-domain socket with unix_listen() and create a
+ * socketpair. One socketpair half is returned to the caller. The other
+ * half is part of the hidden machinery, together with the UNIX-domain
+ * socket.
+ */
+ if (socketpair(AF_UNIX, SOCK_STREAM, 0, fds) < 0)
+ msg_fatal("socketpair: %m");
+ info = (UPASS_INFO *) mymalloc(sizeof(*info));
+ info->halfpair = pair[0];
+ info->unixsock = unix_listen(path, backlog, blocking);
+ event_request_read(info->unixsock, upass_plumbing, (char *) info);
+ *ip = info;
+ return (pair[1]);
+}
+
+/* upass_shutdown - tear down hidden descriptor passing machinery */
+
+void upass_shutdown(UPASS_INFO *info)
+{
+ event_disable_readwrite(upass_info->unixsock)
+ if (close(info->unixsock) < 0)
+ msg_warn("%s: close unixsock: %m", myname);
+ if (close(info->halfpair) < 0)
+ msg_warn("%s: close halfpair: %m", myname);
+ myfree((char *) info);
+}
+
+#endif
diff --git a/postfix/src/util/valid_hostname.c b/postfix/src/util/valid_hostname.c
index 32a8771cd..e79caad34 100644
--- a/postfix/src/util/valid_hostname.c
+++ b/postfix/src/util/valid_hostname.c
@@ -317,8 +317,8 @@ int valid_ipv6_hostaddr(const char *addr, int gripe)
break;
default:
/* Advance by at least 1 character position or terminate. */
- len = strspn(cp, "0123456789abcdefABCDEF");
- if (len /* - strspn(cp, "0") */ > 4) {
+ len = strspn((char *) cp, "0123456789abcdefABCDEF");
+ if (len /* - strspn((char *) cp, "0") */ > 4) {
if (gripe)
msg_warn("%s: malformed IPv6 address: %.100s",
myname, addr);
diff --git a/postfix/src/virtual/virtual.c b/postfix/src/virtual/virtual.c
index ca023fbb8..982ec322f 100644
--- a/postfix/src/virtual/virtual.c
+++ b/postfix/src/virtual/virtual.c
@@ -109,6 +109,15 @@
/* The virtual delivery agent is not security sensitive, provided
/* that the lookup tables with recipient user/group ID information are
/* adequately protected. This program is not designed to run chrooted.
+/*
+/* The virtual delivery agent disallows regular expression
+/* substitution of $1 etc. in regular expression lookup tables,
+/* because that would open a security hole.
+/*
+/* The virtual delivery agent will silently ignore requests
+/* to use the proxymap(8) server. Instead it will open the
+/* table directly. Before Postfix version 2.2, the virtual
+/* delivery agent will terminate with a fatal error.
/* STANDARDS
/* RFC 822 (ARPA Internet Text Messages)
/* DIAGNOSTICS