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