From 4be2bc6036cd9f044703a0f1df5066a248ab8de0 Mon Sep 17 00:00:00 2001 From: Wietse Venema Date: Sun, 17 Dec 2006 00:00:00 -0500 Subject: [PATCH] postfix-2.4-20061217 --- postfix/HISTORY | 62 ++++++-- postfix/README_FILES/BACKSCATTER_README | 60 ++++++-- postfix/RELEASE_NOTES | 8 + postfix/html/BACKSCATTER_README.html | 39 +++++ postfix/html/flush.8.html | 63 ++++---- postfix/html/postconf.5.html | 7 +- postfix/html/postqueue.1.html | 85 +++++----- postfix/html/sendmail.1.html | 136 ++++++++-------- postfix/man/man1/postqueue.1 | 6 + postfix/man/man1/sendmail.1 | 5 + postfix/man/man5/postconf.5 | 7 +- postfix/man/man8/flush.8 | 4 +- postfix/proto/BACKSCATTER_README.html | 39 +++++ postfix/proto/postconf.proto | 7 +- postfix/src/flush/Makefile.in | 1 + postfix/src/flush/flush.c | 197 ++++++++++++++++++++---- postfix/src/global/flush_clnt.c | 42 ++++- postfix/src/global/flush_clnt.h | 6 +- postfix/src/global/mail_queue.h | 8 + postfix/src/global/mail_version.h | 2 +- postfix/src/oqmgr/qmgr.c | 6 +- postfix/src/oqmgr/qmgr.h | 6 +- postfix/src/oqmgr/qmgr_active.c | 9 +- postfix/src/oqmgr/qmgr_message.c | 36 ++++- postfix/src/oqmgr/qmgr_scan.c | 48 ++++-- postfix/src/postconf/postconf.c | 15 +- postfix/src/postqueue/Makefile.in | 1 + postfix/src/postqueue/postqueue.c | 67 +++++++- postfix/src/qmgr/qmgr.c | 6 +- postfix/src/qmgr/qmgr.h | 6 +- postfix/src/qmgr/qmgr_active.c | 9 +- postfix/src/qmgr/qmgr_message.c | 50 ++++-- postfix/src/qmgr/qmgr_scan.c | 48 ++++-- postfix/src/sendmail/sendmail.c | 53 +++++-- postfix/src/smtpd/smtpd.c | 7 +- postfix/src/smtpd/smtpd_check.c | 30 +++- 36 files changed, 878 insertions(+), 303 deletions(-) diff --git a/postfix/HISTORY b/postfix/HISTORY index 952176f91..8c1e6ede6 100644 --- a/postfix/HISTORY +++ b/postfix/HISTORY @@ -12935,7 +12935,8 @@ Apologies for any names omitted. after-the-fact consistency of the thread that was interrupted. File: util/msg_output.c. - Robustness: replace exit() calls by _exit(). File: util/msg.c. + Robustness: replace exit() calls by _exit(). File: util/msg.c, + bounce/bounce_cleanup.c. 20061207 @@ -12982,7 +12983,47 @@ Apologies for any names omitted. Cleanup: streamline the signal handler reentrancy protections, and document under what conditions these protections work, with REENTRANCY sections in the relevant man pages. Files: - util/vbuf.c. util/msg.c, util/msg_output.c. + util/vbuf_print.c. util/msg.c, util/msg_output.c. + +20061211 + + When doing server access control by the TLS client fingerprint, + do not require client certificate verification. Victor + Duchovni. File: smtpd/smtpd_check.c. + + When the remote SMTP client certificate isn't verified, + don't send ccert_subject and ccert_issuer attributes in + check_policy_service requests. Victor Duchovni. File: + smtpd/smtpd_check.c. + + Bugfix: the postconf command still complained about an + unqualified machine name, because it was not updated with + the 20050513 change that introduced a default "mydomain = + localdomain". File: postconf/postconf.c. + +20061213 + + Bugfix: race condition in "ETRN site", "sendmail -qRsite" + and "postqueue -s site". When the command arrived while an + incoming queue scan was already in progress, mail could + stay deferred instead of being flushed. The fix was to + unthrottle the queue manager before moving files from the + deferred queue to the incoming queue. Files: flush/flush.c, + qmgr/qmgr_scan.c. + + Feature: "sendmail -qIqueueid" and "postqueue -i queueid" + to flush a specific queue file. Files: sendmail/sendmail.c, + postqueue/postqueue.c, global/flush_clnt.c, flush/flush.c. + +20061214 + + Performance: "sendmail -qIqueueid" and "postqueue -i queueid" + unthrottle only the necessary message delivery transports + and queues. The unthrottle request now is propagated to the + queue manager via queue file group read permission bits. + Based on initial implementation by Victor Duchovni. Files: + flush/flush.c, *qmgr/qmgr.c, *qmgr/qmgr_scan.c, + *qmgr/qmgr_active.c, *qmgr/qmgr_message.c. Wish list: @@ -13037,9 +13078,6 @@ Wish list: Are transport:nexthop null fields the same as in the case of default_transport etc. parameters? - Introduce structured API for tls_server_mumble() just like - with smtp(8): this eliminates ever-growing lists of arguments. - Don't lose bits when converting st_dev into maildir file name. It's 64 bits on Linux. Found with the BEAM source code analyzer. Is this really a problem, or are they just @@ -13054,9 +13092,6 @@ Wish list: while it is configured in an SMTP server that runs before the smtpd_proxy filter. - The sendmail command should not return non-std exit status - after fatal error in some internal library routine. - Log DSN original recipient when rejecting mail. Keep whitespace between label and ":"? @@ -13190,20 +13225,13 @@ Wish list: would allow correlation of rejected RCPT TO requests with accepted requests for the same mail transaction. - Med: silly queue file bit so that the queue manager doesn't - skip files when fast flush is requested while a queue scan - is in progress. The bit is set by the flush server and is - reset when the mail is deferred, so that it survives queue - manager restart. It's not clear, however, how one would - unthrottle disabled transports or queues. - Med: postsuper -r should do something with recipients in bounce logfiles, to make sure the sender will be notified. To be perfectly safe, no process other than the queue manager should move a queue file away from the active queue. This could involve tagging a queue file, and use up another - permission bit. + permission bit (postsuper tags a "hot" file, qmgr requeues it). Low: postsuper re-run after renaming files, but only a limited number of times. @@ -13222,7 +13250,7 @@ Wish list: Low: have a configurable list of errno values for mailbox or maildir delivery that result in deferral rather than - bouncing mail. + bouncing mail. What about "killed by signal" exits? Low: after reorganizing configuration parameters, add flags to all parameters whose value can be read from file. diff --git a/postfix/README_FILES/BACKSCATTER_README b/postfix/README_FILES/BACKSCATTER_README index e5dc8f9f3..a7a82c02a 100644 --- a/postfix/README_FILES/BACKSCATTER_README +++ b/postfix/README_FILES/BACKSCATTER_README @@ -110,6 +110,7 @@ this: /^Received:.* +by +(porcupine\.org)[[:>:]]/ reject forged mail server name in Received: header: $1 endif + /^Message-ID:.* ]*Received:.* +by +(porcupine\.org)[[:>:]]/ reject forged mail server name in Received: header: $1 endif + /^[> ]*Message-ID:.* ]*Message-ID:.*@(porcupine\.org)/ reject forged domain name in Message-ID: header: $1 @@ -143,30 +145,54 @@ Notes: * The "if /pattern/" and "endif" eliminate unnecessary matching attempts. DO NOT indent lines starting with /pattern/ between the "if" and "endif"! + * The two "Message-ID:.* + + where example.com is the domain name part of the email address specified in + Outlook's account settings for the user. Since many users configure their + email addresses as username@example.com, messages with DSN turned on will + trigger the REJECT action in the previous section. + + If you have such clients then you can to exclude their Message-ID strings + with the two "Message-ID:.* /^Received:.* +by +(porcupine\.org)[[:>:]]/ reject forged mail server name in Received: header: $1 endif + /^Message-ID:.* <!&!/ DUNNO /^Message-ID:.*@(porcupine\.org)/ reject forged domain name in Message-ID: header: $1 @@ -198,6 +199,7 @@ patterns like this:

/^[> ]*Received:.* +by +(porcupine\.org)[[:>:]]/ reject forged mail server name in Received: header: $1 endif + /^[> ]*Message-ID:.* <!&!/ DUNNO /^[> ]*Message-ID:.*@(porcupine\.org)/ reject forged domain name in Message-ID: header: $1 @@ -226,10 +228,18 @@ see your system documentation.

matching attempts. DO NOT indent lines starting with /pattern/ between the "if" and "endif"!

+
  • The two "Message-ID:.* <!&!" rules are +workarounds for some versions of Outlook express, as described in +the caveats section below. +

    Caveats

    + +

    Blocking backscatter mail with forged sender information

    diff --git a/postfix/html/flush.8.html b/postfix/html/flush.8.html index 5a81f4161..cba373e9e 100644 --- a/postfix/html/flush.8.html +++ b/postfix/html/flush.8.html @@ -38,10 +38,13 @@ FLUSH(8) FLUSH(8) the specified queue ID is queued for the specified destination. - send sitename + send_site sitename Request delivery of mail that is queued for the specified destination. + send_file queueid + Request delivery of the specified deferred message. + refresh Refresh non-empty per-destination logfiles that were not read in $fast_flush_refresh_time hours, by @@ -57,7 +60,7 @@ FLUSH(8) FLUSH(8) SECURITY The flush(8) server is not security-sensitive. It does not - talk to the network, and it does not talk to local users. + talk to the network, and it does not talk to local users. The fast flush server can run chrooted at fixed low privi- lege. @@ -65,46 +68,46 @@ FLUSH(8) FLUSH(8) Problems and transactions are logged to syslogd(8). BUGS - Fast flush logfiles are truncated only after a "send" - request, not when mail is actually delivered, and there- - fore can accumulate outdated or redundant data. In order - to maintain sanity, "refresh" must be executed periodi- - cally. This can be automated with a suitable wakeup timer + Fast flush logfiles are truncated only after a "send" + request, not when mail is actually delivered, and there- + fore can accumulate outdated or redundant data. In order + to maintain sanity, "refresh" must be executed periodi- + cally. This can be automated with a suitable wakeup timer setting in the master.cf configuration file. - Upon receipt of a request to deliver mail for an eligible - destination, the flush(8) server requests delivery of all - messages that are listed in that destination's logfile, - regardless of the recipients of those messages. This is + Upon receipt of a request to deliver mail for an eligible + destination, the flush(8) server requests delivery of all + messages that are listed in that destination's logfile, + regardless of the recipients of those messages. This is not an issue for mail that is sent to a relay_domains des- - tination because such mail typically only has recipients + tination because such mail typically only has recipients in one domain. CONFIGURATION PARAMETERS Changes to main.cf are picked up automatically as flush(8) - processes run for only a limited amount of time. Use the + 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. 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. fast_flush_domains ($relay_domains) Optional list of destinations that are eligible for - per-destination logfiles with mail that is queued + per-destination logfiles with mail that is queued to those destinations. fast_flush_refresh_time (12h) - The time after which a non-empty but unread per- - destination "fast flush" logfile needs to be + The time after which a non-empty but unread per- + destination "fast flush" logfile needs to be refreshed. fast_flush_purge_time (7d) @@ -116,38 +119,38 @@ FLUSH(8) FLUSH(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. - parent_domain_matches_subdomains (see 'postconf -d' out- + parent_domain_matches_subdomains (see 'postconf -d' out- put) What Postfix features match subdomains of "domain.tld" automatically, instead of requiring an explicit ".domain.tld" pattern. process_id (read-only) - The process ID of a Postfix command or daemon + The process ID of a Postfix command or daemon process. 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 - process name in syslog records, so that "smtpd" + The mail system name that is prepended to the + process name in syslog records, so that "smtpd" becomes, for example, "postfix/smtpd". FILES @@ -165,7 +168,7 @@ FLUSH(8) FLUSH(8) ETRN_README, Postfix ETRN howto LICENSE - The Secure Mailer license must be distributed with this + The Secure Mailer license must be distributed with this software. HISTORY diff --git a/postfix/html/postconf.5.html b/postfix/html/postconf.5.html index 0468636f9..c1e0f2b4c 100644 --- a/postfix/html/postconf.5.html +++ b/postfix/html/postconf.5.html @@ -9190,9 +9190,10 @@ client network address information.
    check_ccert_access type:table
    -
    When the remote SMTP client certificate is verified successfully, -use the client certificate fingerprint as lookup key for the specified -access(5) database. This feature is available with Postfix version 2.2.
    +
    Use the client certificate fingerprint as lookup key for the +specified access(5) database; with Postfix version 2.2, also require +that the SMTP client certificate is verified successfully. This +feature is available with Postfix version 2.2 and later.
    check_client_access type:table
    diff --git a/postfix/html/postqueue.1.html b/postfix/html/postqueue.1.html index b18850100..0a96c5486 100644 --- a/postfix/html/postqueue.1.html +++ b/postfix/html/postqueue.1.html @@ -11,6 +11,7 @@ POSTQUEUE(1) POSTQUEUE(1) SYNOPSIS postqueue [-v] [-c config_dir] -f + postqueue [-v] [-c config_dir] -i queue_id postqueue [-v] [-c config_dir] -p postqueue [-v] [-c config_dir] -s site @@ -41,115 +42,121 @@ POSTQUEUE(1) POSTQUEUE(1) will result in poor delivery performance of all other mail. + -i queue_id + Schedule immediate delivery of mail with the speci- + fied queue ID. This feature uses the flush(8) + server, and is available with Postfix 2.4 and + later. + -p Produce a traditional sendmail-style queue listing. - This option implements the traditional mailq com- + This option implements the traditional mailq com- mand, by contacting the Postfix showq(8) daemon. - Each queue entry shows the queue file ID, message + Each queue entry shows the queue file ID, message size, arrival time, sender, and the recipients that - still need to be delivered. If mail could not be - delivered upon the last attempt, the reason for - failure is shown. This mode of operation is imple- - mented by executing the postqueue(1) command. The - queue ID string is followed by an optional status + still need to be delivered. If mail could not be + delivered upon the last attempt, the reason for + failure is shown. This mode of operation is imple- + mented by executing the postqueue(1) command. The + queue ID string is followed by an optional status character: * The message is in the active queue, i.e. the message is selected for delivery. - ! The message is in the hold queue, i.e. no - further delivery attempt will be made until + ! The message is in the hold queue, i.e. no + further delivery attempt will be made until the mail is taken off hold. -s site - Schedule immediate delivery of all mail that is + Schedule immediate delivery of all mail that is queued for the named site. A numerical site must be - specified as a valid RFC 2821 address literal - enclosed in [], just like in email addresses. The + specified as a valid RFC 2821 address literal + enclosed in [], just like in email addresses. The site must be eligible for the "fast flush" service. - See flush(8) for more information about the "fast + See flush(8) for more information about the "fast flush" service. - This option implements the traditional "sendmail - -qRsite" command, by contacting the Postfix + This option implements the traditional "sendmail + -qRsite" command, by contacting the Postfix flush(8) daemon. -v Enable verbose logging for debugging purposes. Mul- - tiple -v options make the software increasingly - verbose. As of Postfix 2.3, this option is avail- + tiple -v options make the software increasingly + verbose. As of Postfix 2.3, this option is avail- able for the super-user only. SECURITY - This program is designed to run with set-group ID privi- + This program is designed to run with set-group ID privi- leges, so that it can connect to Postfix daemon processes. DIAGNOSTICS - Problems are logged to syslogd(8) and to the standard + Problems are logged to syslogd(8) and to the standard error stream. ENVIRONMENT MAIL_CONFIG - Directory with the main.cf file. In order to avoid - exploitation of set-group ID privileges, a non- + Directory with the main.cf file. In order to avoid + exploitation of set-group ID privileges, a non- standard directory is allowed only if: - o The name is listed in the standard main.cf - file with the alternate_config_directories + o The name is listed in the standard main.cf + file with the alternate_config_directories configuration parameter. o The command is invoked by the super-user. CONFIGURATION PARAMETERS - The following main.cf parameters are especially relevant + The following main.cf parameters are especially relevant to this program. The text below provides only a parameter - summary. See postconf(5) for more details including exam- + summary. See postconf(5) for more details including exam- ples. alternate_config_directories (empty) - A list of non-default Postfix configuration direc- + A list of non-default Postfix configuration direc- tories that may be specified with "-c config_direc- - tory" on the command line, or via the MAIL_CONFIG + tory" on the command line, or via the MAIL_CONFIG environment parameter. 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. command_directory (see 'postconf -d' output) - The location of all postfix administrative com- + The location of all postfix administrative com- mands. fast_flush_domains ($relay_domains) Optional list of destinations that are eligible for - per-destination logfiles with mail that is queued + per-destination logfiles with mail that is queued to those destinations. import_environment (see 'postconf -d' output) - The list of environment parameters that a Postfix + The list of environment parameters that a Postfix process will import from a non-Postfix parent 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 - process name in syslog records, so that "smtpd" + The mail system name that is prepended to the + process name in syslog records, so that "smtpd" becomes, for example, "postfix/smtpd". trigger_timeout (10s) - The time limit for sending a trigger to a Postfix - daemon (for example, the pickup(8) or qmgr(8) dae- + The time limit for sending a trigger to a Postfix + daemon (for example, the pickup(8) or qmgr(8) dae- mon). Available in Postfix version 2.2 and later: authorized_flush_users (static:anyone) - List of users who are authorized to flush the + List of users who are authorized to flush the queue. authorized_mailq_users (static:anyone) @@ -169,11 +176,11 @@ POSTQUEUE(1) POSTQUEUE(1) ETRN_README, Postfix ETRN howto LICENSE - The Secure Mailer license must be distributed with this + The Secure Mailer license must be distributed with this software. HISTORY - The postqueue command was introduced with Postfix version + The postqueue command was introduced with Postfix version 1.1. AUTHOR(S) diff --git a/postfix/html/sendmail.1.html b/postfix/html/sendmail.1.html index c79578d8e..527edee80 100644 --- a/postfix/html/sendmail.1.html +++ b/postfix/html/sendmail.1.html @@ -217,24 +217,30 @@ SENDMAIL(1) SENDMAIL(1) The interval between queue runs. Use the queue_run_delay configuration parameter instead. + -qIqueueid + Schedule immediate delivery of mail with the speci- + fied queue ID. This option is implemented by exe- + cuting the postqueue(1) command, and is available + with Postfix version 2.4 and later. + -qRsite - Schedule immediate delivery of all mail that is + Schedule immediate delivery of all mail that is queued for the named site. This option accepts only - site names that are eligible for the "fast flush" - service, and is implemented by executing the + site names that are eligible for the "fast flush" + service, and is implemented by executing the postqueue(1) command. See flush(8) for more infor- mation about the "fast flush" service. -qSsite - This command is not implemented. Use the slower + This command is not implemented. Use the slower "sendmail -q" command instead. - -t Extract recipients from message headers. These are - added to any recipients specified on the command + -t Extract recipients from message headers. These are + added to any recipients specified on the command line. - With Postfix versions prior to 2.1, this option - requires that no recipient addresses are specified + With Postfix versions prior to 2.1, this option + requires that no recipient addresses are specified on the command line. -U (ignored) @@ -247,41 +253,41 @@ SENDMAIL(1) SENDMAIL(1) This feature is available in Postfix 2.3 and later. -XV (Postfix 2.2 and earlier: -V) - Variable Envelope Return Path. Given an envelope - sender address of the form owner-listname@origin, - each recipient user@domain receives mail with a + Variable Envelope Return Path. Given an envelope + sender address of the form owner-listname@origin, + each recipient user@domain receives mail with a personalized envelope sender address. - By default, the personalized envelope sender - address is owner-listname+user=domain@origin. The - default + and = characters are configurable with - the default_verp_delimiters configuration parame- + By default, the personalized envelope sender + address is owner-listname+user=domain@origin. The + default + and = characters are configurable with + the default_verp_delimiters configuration parame- ter. -XVxy (Postfix 2.2 and earlier: -Vxy) - As -XV, but uses x and y as the VERP delimiter - characters, instead of the characters specified - with the default_verp_delimiters configuration + As -XV, but uses x and y as the VERP delimiter + characters, instead of the characters specified + with the default_verp_delimiters configuration parameter. - -v Send an email report of the first delivery attempt - (Postfix versions 2.1 and later). Mail delivery - always happens in the background. When multiple -v + -v Send an email report of the first delivery attempt + (Postfix versions 2.1 and later). Mail delivery + always happens in the background. When multiple -v options are given, enable verbose logging for debugging purposes. -X log_file (ignored) - Log mailer traffic. Use the debug_peer_list and - debug_peer_level configuration parameters instead. + Log mailer traffic. Use the debug_peer_list and + debug_peer_level configuration parameters instead. SECURITY - By design, this program is not set-user (or group) id. - However, it must handle data from untrusted users or - untrusted machines. Thus, the usual precautions need to + By design, this program is not set-user (or group) id. + However, it must handle data from untrusted users or + untrusted machines. Thus, the usual precautions need to be taken against malicious inputs. DIAGNOSTICS - Problems are logged to syslogd(8) and to the standard + Problems are logged to syslogd(8) and to the standard error stream. ENVIRONMENT @@ -293,21 +299,21 @@ SENDMAIL(1) SENDMAIL(1) MAIL_DEBUG (value does not matter) Enable debugging with an external command, as spec- - ified with the debugger_command configuration + ified with the debugger_command configuration parameter. - NAME The sender full name. This is used only with mes- - sages that have no From: message header. See also + NAME The sender full name. This is used only with mes- + sages that have no From: message header. See also the -F option above. CONFIGURATION PARAMETERS - The following main.cf parameters are especially relevant + The following main.cf parameters are especially relevant to this program. The text below provides only a parameter - summary. See postconf(5) for more details including exam- + summary. See postconf(5) for more details including exam- ples. TROUBLE SHOOTING CONTROLS - The DEBUG_README file gives examples of how to trouble + The DEBUG_README file gives examples of how to trouble shoot a Postfix system. debugger_command (empty) @@ -315,29 +321,29 @@ SENDMAIL(1) SENDMAIL(1) mon program is invoked with the -D option. debug_peer_level (2) - The increment in verbose logging level when a - remote client or server matches a pattern in the + The increment in verbose logging level when a + remote client or server matches a pattern in the debug_peer_list parameter. debug_peer_list (empty) - Optional list of remote client or server hostname - or network address patterns that cause the verbose - logging level to increase by the amount specified + Optional list of remote client or server hostname + or network address patterns that cause the verbose + logging level to increase by the amount specified in $debug_peer_level. ACCESS CONTROLS Available in Postfix version 2.2 and later: authorized_flush_users (static:anyone) - List of users who are authorized to flush the + List of users who are authorized to flush the queue. authorized_mailq_users (static:anyone) List of users who are authorized to view the queue. authorized_submit_users (static:anyone) - List of users who are authorized to submit mail - with the sendmail(1) command (and with the privi- + List of users who are authorized to submit mail + with the sendmail(1) command (and with the privi- leged postdrop(1) helper command). RESOURCE AND RATE CONTROLS @@ -346,7 +352,7 @@ SENDMAIL(1) SENDMAIL(1) sent in a non-delivery notification. fork_attempts (5) - The maximal number of attempts to fork() a child + The maximal number of attempts to fork() a child process. fork_delay (1s) @@ -354,11 +360,11 @@ SENDMAIL(1) SENDMAIL(1) process. hopcount_limit (50) - The maximal number of Received: message headers + The maximal number of Received: message headers that is allowed in the primary message headers. queue_run_delay (1000s) - The time between deferred queue scans by the queue + The time between deferred queue scans by the queue manager. FAST FLUSH CONTROLS @@ -367,37 +373,37 @@ SENDMAIL(1) SENDMAIL(1) fast_flush_domains ($relay_domains) Optional list of destinations that are eligible for - per-destination logfiles with mail that is queued + per-destination logfiles with mail that is queued to those destinations. VERP CONTROLS The VERP_README file describes configuration and operation - details of Postfix support for variable envelope return + details of Postfix support for variable envelope return path addresses. default_verp_delimiters (+=) The two default VERP delimiter characters. verp_delimiter_filter (-=+) - The characters Postfix accepts as VERP delimiter - characters on the Postfix sendmail(1) command line + The characters Postfix accepts as VERP delimiter + characters on the Postfix sendmail(1) command line and in SMTP commands. MISCELLANEOUS CONTROLS alias_database (see 'postconf -d' output) - The alias databases for local(8) delivery that are + The alias databases for local(8) delivery that are updated with "newaliases" or with "sendmail -bi". command_directory (see 'postconf -d' output) - The location of all postfix administrative com- + The location of all postfix administrative com- mands. 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_directory (see 'postconf -d' output) - The directory with Postfix support programs and + The directory with Postfix support programs and daemon programs. default_database_type (see 'postconf -d' output) @@ -405,16 +411,16 @@ SENDMAIL(1) SENDMAIL(1) postalias(1) and postmap(1) commands. delay_warning_time (0h) - The time after which the sender receives the mes- + The time after which the sender receives the mes- sage headers of mail that is still queued. enable_errors_to (no) - Report mail delivery errors to the address speci- - fied with the non-standard Errors-To: message - header, instead of the envelope sender address - (this feature is removed with Postfix version 2.2, - is turned off by default with Postfix version 2.1, - and is always turned on with older Postfix ver- + Report mail delivery errors to the address speci- + fied with the non-standard Errors-To: message + header, instead of the envelope sender address + (this feature is removed with Postfix version 2.2, + is turned off by default with Postfix version 2.1, + and is always turned on with older Postfix ver- sions). mail_owner (postfix) @@ -422,21 +428,21 @@ SENDMAIL(1) SENDMAIL(1) and most Postfix daemon processes. 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. remote_header_rewrite_domain (empty) - Don't rewrite message headers from remote clients + Don't rewrite message headers from remote clients at all when this parameter is empty; otherwise, re- - write message headers and append the specified + write message headers and append the specified domain name to incomplete addresses. syslog_facility (mail) The syslog facility of Postfix logging. syslog_name (postfix) - The mail system name that is prepended to the - process name in syslog records, so that "smtpd" + The mail system name that is prepended to the + process name in syslog records, so that "smtpd" becomes, for example, "postfix/smtpd". FILES @@ -461,7 +467,7 @@ SENDMAIL(1) SENDMAIL(1) VERP_README, Postfix VERP howto LICENSE - The Secure Mailer license must be distributed with this + The Secure Mailer license must be distributed with this software. AUTHOR(S) diff --git a/postfix/man/man1/postqueue.1 b/postfix/man/man1/postqueue.1 index b3a126c73..79a49f6af 100644 --- a/postfix/man/man1/postqueue.1 +++ b/postfix/man/man1/postqueue.1 @@ -10,6 +10,8 @@ Postfix queue control .nf \fBpostqueue\fR [\fB-v\fR] [\fB-c \fIconfig_dir\fR] \fB-f\fR .br +\fBpostqueue\fR [\fB-v\fR] [\fB-c \fIconfig_dir\fR] \fB-i \fIqueue_id\fR +.br \fBpostqueue\fR [\fB-v\fR] [\fB-c \fIconfig_dir\fR] \fB-p\fR .br \fBpostqueue\fR [\fB-v\fR] [\fB-c \fIconfig_dir\fR] \fB-s \fIsite\fR @@ -36,6 +38,10 @@ by contacting the Postfix \fBqmgr\fR(8) daemon. Warning: flushing undeliverable mail frequently will result in poor delivery performance of all other mail. +.IP "\fB-i \fIqueue_id\fR" +Schedule immediate delivery of mail with the specified queue ID. +This feature uses the \fBflush\fR(8) server, and is available +with Postfix 2.4 and later. .IP \fB-p\fR Produce a traditional sendmail-style queue listing. This option implements the traditional \fBmailq\fR command, diff --git a/postfix/man/man1/sendmail.1 b/postfix/man/man1/sendmail.1 index a4e99359d..43f34a0f3 100644 --- a/postfix/man/man1/sendmail.1 +++ b/postfix/man/man1/sendmail.1 @@ -174,6 +174,11 @@ poor delivery performance of all other mail. .IP "\fB-q\fIinterval\fR (ignored)" The interval between queue runs. Use the \fBqueue_run_delay\fR configuration parameter instead. +.IP \fB-qI\fIqueueid\fR +Schedule immediate delivery of mail with the specified queue +ID. This option is implemented by executing the +\fBpostqueue\fR(1) command, and is available with Postfix +version 2.4 and later. .IP \fB-qR\fIsite\fR Schedule immediate delivery of all mail that is queued for the named \fIsite\fR. This option accepts only \fIsite\fR names that are diff --git a/postfix/man/man5/postconf.5 b/postfix/man/man5/postconf.5 index 4ae39dea1..22a49f1bb 100644 --- a/postfix/man/man5/postconf.5 +++ b/postfix/man/man5/postconf.5 @@ -5408,9 +5408,10 @@ restriction that matches wins. The following restrictions are specific to client hostname or client network address information. .IP "\fBcheck_ccert_access \fItype:table\fR\fR" -When the remote SMTP client certificate is verified successfully, -use the client certificate fingerprint as lookup key for the specified -\fBaccess\fR(5) database. This feature is available with Postfix version 2.2. +Use the client certificate fingerprint as lookup key for the +specified \fBaccess\fR(5) database; with Postfix version 2.2, also require +that the SMTP client certificate is verified successfully. This +feature is available with Postfix version 2.2 and later. .IP "\fBcheck_client_access \fItype:table\fR\fR" Search the specified access database for the client hostname, parent domains, client IP address, or networks obtained by stripping diff --git a/postfix/man/man8/flush.8 b/postfix/man/man8/flush.8 index c71950cdf..c85d6eb44 100644 --- a/postfix/man/man8/flush.8 +++ b/postfix/man/man8/flush.8 @@ -36,9 +36,11 @@ This server implements the following requests: .IP "\fBadd\fI sitename queueid\fR" Inform the \fBflush\fR(8) server that the message with the specified queue ID is queued for the specified destination. -.IP "\fBsend\fI sitename\fR" +.IP "\fBsend_site\fI sitename\fR" Request delivery of mail that is queued for the specified destination. +.IP "\fBsend_file\fI queueid\fR" +Request delivery of the specified deferred message. .IP \fBrefresh\fR Refresh non-empty per-destination logfiles that were not read in \fB$fast_flush_refresh_time\fR hours, by simulating diff --git a/postfix/proto/BACKSCATTER_README.html b/postfix/proto/BACKSCATTER_README.html index af7659d24..c93add454 100644 --- a/postfix/proto/BACKSCATTER_README.html +++ b/postfix/proto/BACKSCATTER_README.html @@ -186,6 +186,7 @@ patterns like this:

    /^Received:.* +by +(porcupine\.org)[[:>:]]/ reject forged mail server name in Received: header: $1 endif + /^Message-ID:.* <!&!/ DUNNO /^Message-ID:.*@(porcupine\.org)/ reject forged domain name in Message-ID: header: $1 @@ -198,6 +199,7 @@ patterns like this:

    /^[> ]*Received:.* +by +(porcupine\.org)[[:>:]]/ reject forged mail server name in Received: header: $1 endif + /^[> ]*Message-ID:.* <!&!/ DUNNO /^[> ]*Message-ID:.*@(porcupine\.org)/ reject forged domain name in Message-ID: header: $1 @@ -226,10 +228,18 @@ see your system documentation.

    matching attempts. DO NOT indent lines starting with /pattern/ between the "if" and "endif"!

    +
  • The two "Message-ID:.* <!&!" rules are +workarounds for some versions of Outlook express, as described in +the caveats section below. +

    Caveats

    + +

    Blocking backscatter mail with forged sender information

    diff --git a/postfix/proto/postconf.proto b/postfix/proto/postconf.proto index 3d395e3f0..e73e49847 100644 --- a/postfix/proto/postconf.proto +++ b/postfix/proto/postconf.proto @@ -4577,9 +4577,10 @@ client network address information.
    check_ccert_access type:table
    -
    When the remote SMTP client certificate is verified successfully, -use the client certificate fingerprint as lookup key for the specified -access(5) database. This feature is available with Postfix version 2.2.
    +
    Use the client certificate fingerprint as lookup key for the +specified access(5) database; with Postfix version 2.2, also require +that the SMTP client certificate is verified successfully. This +feature is available with Postfix version 2.2 and later.
    check_client_access type:table
    diff --git a/postfix/src/flush/Makefile.in b/postfix/src/flush/Makefile.in index b83c38529..8144eabbf 100644 --- a/postfix/src/flush/Makefile.in +++ b/postfix/src/flush/Makefile.in @@ -78,6 +78,7 @@ flush.o: ../../include/match_ops.h flush.o: ../../include/match_parent_style.h flush.o: ../../include/msg.h flush.o: ../../include/myflock.h +flush.o: ../../include/safe_open.h flush.o: ../../include/scan_dir.h flush.o: ../../include/stringops.h flush.o: ../../include/sys_defs.h diff --git a/postfix/src/flush/flush.c b/postfix/src/flush/flush.c index 4b47e30a7..06f19f15b 100644 --- a/postfix/src/flush/flush.c +++ b/postfix/src/flush/flush.c @@ -30,9 +30,11 @@ /* .IP "\fBadd\fI sitename queueid\fR" /* Inform the \fBflush\fR(8) server that the message with the specified /* queue ID is queued for the specified destination. -/* .IP "\fBsend\fI sitename\fR" +/* .IP "\fBsend_site\fI sitename\fR" /* Request delivery of mail that is queued for the specified /* destination. +/* .IP "\fBsend_file\fI queueid\fR" +/* Request delivery of the specified deferred message. /* .IP \fBrefresh\fR /* Refresh non-empty per-destination logfiles that were not read in /* \fB$fast_flush_refresh_time\fR hours, by simulating @@ -166,6 +168,7 @@ #include #include #include +#include /* Global library. */ @@ -210,7 +213,7 @@ static DOMAIN_LIST *flush_domains; * Silly little macros. */ #define STR(x) vstring_str(x) -#define STREQ(x,y) (strcmp(x,y) == 0) +#define STREQ(x,y) ((x) == (y) || strcmp(x,y) == 0) /* * Forward declarations resulting from breaking up routines according to @@ -223,9 +226,24 @@ static int flush_send_path(const char *, int); * Do we only refresh the per-destination logfile, or do we really request * mail delivery as if someone sent ETRN? If the latter, we must override * information about unavailable hosts or unavailable transports. + * + * When selectively flushing deferred mail, we need to override the queue + * manager's "dead destination" information and unthrottle transports and + * queues. There are two options: + * + * - Unthrottle all transports and queues before we move mail to the incoming + * queue. This is less accurate, but has the advantage when flushing lots of + * mail, because Postfix can skip delivery of flushed messages after it + * discovers that a destination is (still) unavailable. + * + * - Unthrottle some transports and queues after the queue manager moves mail + * to the active queue. This is more accurate, but has the disadvantage when + * flushing lots of mail, because Postfix cannot skip delivery of flushed + * messages after it discovers that a destination is (still) unavailable. */ #define REFRESH_ONLY 0 -#define REFRESH_AND_DELIVER 1 +#define UNTHROTTLE_BEFORE (1<<0) +#define UNTHROTTLE_AFTER (1<<1) /* flush_site_to_path - convert domain or [addr] to harmless string */ @@ -366,6 +384,86 @@ static int flush_send_service(const char *site, int how) return (status); } +/* flush_one_file - move one queue file to incoming queue */ + +static int flush_one_file(const char *queue_id, VSTRING *queue_file, + struct utimbuf * tbuf, int how) +{ + const char *myname = "flush_one_file"; + const char *queue_name; + const char *path; + + /* + * Some other instance of this program may flush some logfile and may + * just have moved this queue file to the incoming queue. + */ + for (queue_name = MAIL_QUEUE_DEFERRED; /* see below */ ; + queue_name = MAIL_QUEUE_INCOMING) { + path = mail_queue_path(queue_file, queue_name, queue_id); + if (utime(path, tbuf) == 0) + break; + if (errno != ENOENT) + msg_warn("%s: update %s time stamps: %m", myname, path); + if (STREQ(queue_name, MAIL_QUEUE_INCOMING)) + return (0); + } + + /* + * With the UNTHROTTLE_AFTER strategy, we leave it up to the queue + * manager to unthrottle transports and queues as it reads recipients + * from a queue file. We request this unthrottle operation by setting the + * group read permission bit. + * + * Note: we must avoid using chmod(). It is not only slower than fchmod() + * but it is also less secure. With chmod(), an attacker could repeatedly + * send requests to the flush server and trick it into changing + * permissions of non-queue files, by exploiting a race condition. + * + * We use safe_open() because we don't validate the file content before + * modifying the file status. + */ + if (how & UNTHROTTLE_AFTER) { + VSTRING *why; + struct stat st; + VSTREAM *fp; + + for (why = vstring_alloc(1); /* see below */ ; + queue_name = MAIL_QUEUE_INCOMING, + path = mail_queue_path(queue_file, queue_name, queue_id)) { + if ((fp = safe_open(path, O_RDWR, 0, &st, -1, -1, why)) != 0) + break; + if (errno != ENOENT) + msg_warn("%s: open %s: %s", myname, path, STR(why)); + if (errno != ENOENT || STREQ(queue_name, MAIL_QUEUE_INCOMING)) { + vstring_free(why); + return (0); + } + } + vstring_free(why); + if ((st.st_mode & MAIL_QUEUE_STAT_READY) != MAIL_QUEUE_STAT_READY) { + (void) vstream_fclose(fp); + return (0); + } + if (fchmod(vstream_fileno(fp), st.st_mode | MAIL_QUEUE_STAT_UNTHROTTLE) < 0) + msg_warn("%s: fchmod %s: %m", myname, path); + (void) vstream_fclose(fp); + } + + /* + * Move the file to the incoming queue, if it isn't already there. + */ + if (STREQ(queue_name, MAIL_QUEUE_INCOMING) == 0 + && mail_queue_rename(queue_id, queue_name, MAIL_QUEUE_INCOMING) < 0 + && errno != ENOENT) + msg_warn("%s: rename from %s to %s: %m", + path, queue_name, MAIL_QUEUE_INCOMING); + + /* + * If we got here, we achieved something, so let's claim succes. + */ + return (1); +} + /* flush_send_path - flush logfile file */ static int flush_send_path(const char *path, int how) @@ -375,11 +473,10 @@ static int flush_send_path(const char *path, int how) VSTRING *queue_file; VSTREAM *log; struct utimbuf tbuf; - static char qmgr_deliver_trigger[] = { - QMGR_REQ_SCAN_INCOMING, /* scan incoming queue */ + static char qmgr_flush_trigger[] = { QMGR_REQ_FLUSH_DEAD, /* flush dead site/transport cache */ }; - static char qmgr_refresh_trigger[] = { + static char qmgr_scan_trigger[] = { QMGR_REQ_SCAN_INCOMING, /* scan incoming queue */ }; HTABLE *dup_filter; @@ -410,6 +507,23 @@ static int flush_send_path(const char *path, int how) if (myflock(vstream_fileno(log), INTERNAL_LOCK, MYFLOCK_OP_EXCLUSIVE) < 0) msg_fatal("%s: lock fast flush logfile %s: %m", myname, path); + /* + * With the UNTHROTTLE_BEFORE strategy, we ask the queue manager to + * unthrottle all transports and queues before we move a deferred queue + * file to the incoming queue. This minimizes a race condition where the + * queue manager seizes a queue file before it knows that we want to + * flush that message. + * + * This reduces the race condition time window to a very small amount (the + * flush server does not really know when the queue manager reads its + * command fifo). But there is a worse race, where the queue manager + * moves a deferred queue file to the active queue before we have a + * chance to expedite its delivery. + */ + if (how & UNTHROTTLE_BEFORE) + mail_trigger(MAIL_CLASS_PUBLIC, var_queue_service, + qmgr_flush_trigger, sizeof(qmgr_flush_trigger)); + /* * This is the part that dominates running time: schedule the listed * queue files for delivery by updating their file time stamps and by @@ -444,25 +558,7 @@ static int flush_send_path(const char *path, int how) myname, path, STR(queue_id)); if (dup_filter->used <= FLUSH_DUP_FILTER_SIZE) htable_enter(dup_filter, STR(queue_id), 0); - - mail_queue_path(queue_file, MAIL_QUEUE_DEFERRED, STR(queue_id)); - if (utime(STR(queue_file), &tbuf) < 0) { - if (errno != ENOENT) - msg_warn("%s: update %s time stamps: %m", - myname, STR(queue_file)); - /* XXX Wart... */ - mail_queue_path(queue_file, MAIL_QUEUE_INCOMING, STR(queue_id)); - if (utime(STR(queue_file), &tbuf) < 0) - if (errno != ENOENT) - msg_warn("%s: update %s time stamps: %m", - myname, STR(queue_file)); - } else if (mail_queue_rename(STR(queue_id), MAIL_QUEUE_DEFERRED, - MAIL_QUEUE_INCOMING) < 0) { - if (errno != ENOENT) - msg_warn("%s: rename from %s to %s: %m", - STR(queue_file), MAIL_QUEUE_DEFERRED, - MAIL_QUEUE_INCOMING); - } + count += flush_one_file(STR(queue_id), queue_file, &tbuf, how); } else { if (msg_verbose) msg_info("%s: logfile %s: skip queue file %s as duplicate", @@ -489,16 +585,42 @@ static int flush_send_path(const char *path, int how) if (count > 0) { if (msg_verbose) msg_info("%s: requesting delivery for logfile %s", myname, path); - if (how == REFRESH_ONLY) - mail_trigger(MAIL_CLASS_PUBLIC, var_queue_service, - qmgr_refresh_trigger, sizeof(qmgr_refresh_trigger)); - else - mail_trigger(MAIL_CLASS_PUBLIC, var_queue_service, - qmgr_deliver_trigger, sizeof(qmgr_deliver_trigger)); + mail_trigger(MAIL_CLASS_PUBLIC, var_queue_service, + qmgr_scan_trigger, sizeof(qmgr_scan_trigger)); } return (FLUSH_STAT_OK); } +/* flush_send_file_service - flush one queue file */ + +static int flush_send_file_service(const char *queue_id) +{ + const char *myname = "flush_send_file_service"; + VSTRING *queue_file; + struct utimbuf tbuf; + static char qmgr_scan_trigger[] = { + QMGR_REQ_SCAN_INCOMING, /* scan incoming queue */ + }; + + /* + * Sanity check. + */ + if (!mail_queue_id_ok(queue_id)) + return (FLUSH_STAT_BAD); + + if (msg_verbose) + msg_info("%s: requesting delivery for queue_id %s", myname, queue_id); + + queue_file = vstring_alloc(30); + tbuf.actime = tbuf.modtime = event_time(); + if (flush_one_file(queue_id, queue_file, &tbuf, UNTHROTTLE_AFTER) > 0) + mail_trigger(MAIL_CLASS_PUBLIC, var_queue_service, + qmgr_scan_trigger, sizeof(qmgr_scan_trigger)); + vstring_free(queue_file); + + return (FLUSH_STAT_OK); +} + /* flush_refresh_service - refresh logfiles beyond some age */ static int flush_refresh_service(int max_age) @@ -633,13 +755,22 @@ static void flush_service(VSTREAM *client_stream, char *unused_service, attr_print(client_stream, ATTR_FLAG_NONE, ATTR_TYPE_INT, MAIL_ATTR_STATUS, status, ATTR_TYPE_END); - } else if (STREQ(STR(request), FLUSH_REQ_SEND)) { + } else if (STREQ(STR(request), FLUSH_REQ_SEND_SITE)) { site = vstring_alloc(10); if (attr_scan(client_stream, ATTR_FLAG_STRICT, ATTR_TYPE_STR, MAIL_ATTR_SITE, site, ATTR_TYPE_END) == 1) status = flush_send_service(lowercase(STR(site)), - REFRESH_AND_DELIVER); + UNTHROTTLE_BEFORE); + attr_print(client_stream, ATTR_FLAG_NONE, + ATTR_TYPE_INT, MAIL_ATTR_STATUS, status, + ATTR_TYPE_END); + } else if (STREQ(STR(request), FLUSH_REQ_SEND_FILE)) { + queue_id = vstring_alloc(10); + if (attr_scan(client_stream, ATTR_FLAG_STRICT, + ATTR_TYPE_STR, MAIL_ATTR_QUEUEID, queue_id, + ATTR_TYPE_END) == 1) + status = flush_send_file_service(STR(queue_id)); attr_print(client_stream, ATTR_FLAG_NONE, ATTR_TYPE_INT, MAIL_ATTR_STATUS, status, ATTR_TYPE_END); diff --git a/postfix/src/global/flush_clnt.c b/postfix/src/global/flush_clnt.c index 7f7e65d36..043754f9b 100644 --- a/postfix/src/global/flush_clnt.c +++ b/postfix/src/global/flush_clnt.c @@ -12,9 +12,12 @@ /* const char *site; /* const char *queue_id; /* -/* int flush_send(site) +/* int flush_send_site(site) /* const char *site; /* +/* int flush_send_file(queue_id) +/* const char *queue_id; +/* /* int flush_refresh() /* /* int flush_purge() @@ -30,9 +33,12 @@ /* flush_add() informs the "fast flush" cache manager that mail is /* queued for the specified site with the specified queue ID. /* -/* flush_send() requests delivery of all mail that is queued for +/* flush_send_site() requests delivery of all mail that is queued for /* the specified destination. /* +/* flush_send_file() requests delivery of mail with the specified +/* queue ID. +/* /* flush_refresh() requests the "fast flush" cache manager to refresh /* cached information that was not used for some configurable amount /* time. @@ -153,11 +159,11 @@ int flush_refresh(void) return (status); } -/* flush_send - deliver mail queued for site */ +/* flush_send_site - deliver mail queued for site */ -int flush_send(const char *site) +int flush_send_site(const char *site) { - const char *myname = "flush_send"; + const char *myname = "flush_send_site"; int status; if (msg_verbose) @@ -173,7 +179,7 @@ int flush_send(const char *site) status = FLUSH_STAT_DENY; else status = mail_command_client(MAIL_CLASS_PUBLIC, var_flush_service, - ATTR_TYPE_STR, MAIL_ATTR_REQ, FLUSH_REQ_SEND, + ATTR_TYPE_STR, MAIL_ATTR_REQ, FLUSH_REQ_SEND_SITE, ATTR_TYPE_STR, MAIL_ATTR_SITE, site, ATTR_TYPE_END); @@ -183,6 +189,30 @@ int flush_send(const char *site) return (status); } +/* flush_send_file - deliver specific message */ + +int flush_send_file(const char *queue_id) +{ + const char *myname = "flush_send_file"; + int status; + + if (msg_verbose) + msg_info("%s: queue_id %s", myname, queue_id); + + /* + * Require that the service is turned on. + */ + status = mail_command_client(MAIL_CLASS_PUBLIC, var_flush_service, + ATTR_TYPE_STR, MAIL_ATTR_REQ, FLUSH_REQ_SEND_FILE, + ATTR_TYPE_STR, MAIL_ATTR_QUEUEID, queue_id, + ATTR_TYPE_END); + + if (msg_verbose) + msg_info("%s: queue_id %s status %d", myname, queue_id, status); + + return (status); +} + /* flush_add - inform "fast flush" cache manager */ int flush_add(const char *site, const char *queue_id) diff --git a/postfix/src/global/flush_clnt.h b/postfix/src/global/flush_clnt.h index 2846fb377..6b891b216 100644 --- a/postfix/src/global/flush_clnt.h +++ b/postfix/src/global/flush_clnt.h @@ -16,7 +16,8 @@ */ extern void flush_init(void); extern int flush_add(const char *, const char *); -extern int flush_send(const char *); +extern int flush_send_site(const char *); +extern int flush_send_file(const char *); extern int flush_refresh(void); extern int flush_purge(void); @@ -24,7 +25,8 @@ extern int flush_purge(void); * Mail flush server requests. */ #define FLUSH_REQ_ADD "add" /* append queue ID to site log */ -#define FLUSH_REQ_SEND "send" /* flush mail queued for site */ +#define FLUSH_REQ_SEND_SITE "send_site" /* flush mail for site */ +#define FLUSH_REQ_SEND_FILE "send_file" /* flush one queue file */ #define FLUSH_REQ_REFRESH "rfrsh" /* refresh old logfiles */ #define FLUSH_REQ_PURGE "purge" /* refresh all logfiles */ diff --git a/postfix/src/global/mail_queue.h b/postfix/src/global/mail_queue.h index 8c4e3b898..f1c2389d9 100644 --- a/postfix/src/global/mail_queue.h +++ b/postfix/src/global/mail_queue.h @@ -38,9 +38,17 @@ /* * Queue file modes. + * + * 4.4BSD-like systems don't allow (sticky AND executable) together, so we use + * group read permission bits instead. These are more portable, but they + * also are more likely to be turned on by accident. It would not be the end + * of the world. */ #define MAIL_QUEUE_STAT_READY (S_IRUSR | S_IWUSR | S_IXUSR) #define MAIL_QUEUE_STAT_CORRUPT (S_IRUSR) +#ifndef MAIL_QUEUE_STAT_UNTHROTTLE +#define MAIL_QUEUE_STAT_UNTHROTTLE (S_IRGRP) +#endif extern struct VSTREAM *mail_queue_enter(const char *, mode_t, struct timeval *); extern struct VSTREAM *mail_queue_open(const char *, const char *, int, mode_t); diff --git a/postfix/src/global/mail_version.h b/postfix/src/global/mail_version.h index ff1b9d834..98879f1e0 100644 --- a/postfix/src/global/mail_version.h +++ b/postfix/src/global/mail_version.h @@ -20,7 +20,7 @@ * Patches change both the patchlevel and the release date. Snapshots have no * patchlevel; they change the release date only. */ -#define MAIL_RELEASE_DATE "20061210" +#define MAIL_RELEASE_DATE "20061217" #define MAIL_VERSION_NUMBER "2.4" #ifdef SNAPSHOT diff --git a/postfix/src/oqmgr/qmgr.c b/postfix/src/oqmgr/qmgr.c index d666d3381..927f1be2f 100644 --- a/postfix/src/oqmgr/qmgr.c +++ b/postfix/src/oqmgr/qmgr.c @@ -367,6 +367,8 @@ static void qmgr_trigger_event(char *buf, int len, * request in order. And as long as we don't have conflicting requests we * are free to sort them into the most suitable order. */ +#define QMGR_FLUSH_BEFORE (QMGR_FLUSH_ONCE | QMGR_FLUSH_DFXP) + for (i = 0; i < len; i++) { if (msg_verbose) msg_info("request: %d (%c)", @@ -380,8 +382,8 @@ static void qmgr_trigger_event(char *buf, int len, deferred_flag |= QMGR_SCAN_START; break; case QMGR_REQ_FLUSH_DEAD: - deferred_flag |= QMGR_FLUSH_DEAD; - incoming_flag |= QMGR_FLUSH_DEAD; + deferred_flag |= QMGR_FLUSH_BEFORE; + incoming_flag |= QMGR_FLUSH_BEFORE; break; case QMGR_REQ_SCAN_ALL: deferred_flag |= QMGR_SCAN_ALL; diff --git a/postfix/src/oqmgr/qmgr.h b/postfix/src/oqmgr/qmgr.h index 19f54b33c..c28430c00 100644 --- a/postfix/src/oqmgr/qmgr.h +++ b/postfix/src/oqmgr/qmgr.h @@ -256,7 +256,7 @@ extern int qmgr_recipient_count; extern void qmgr_message_free(QMGR_MESSAGE *); extern void qmgr_message_update_warn(QMGR_MESSAGE *); extern void qmgr_message_kill_record(QMGR_MESSAGE *, long); -extern QMGR_MESSAGE *qmgr_message_alloc(const char *, const char *, int); +extern QMGR_MESSAGE *qmgr_message_alloc(const char *, const char *, int, mode_t); extern QMGR_MESSAGE *qmgr_message_realloc(QMGR_MESSAGE *); #define QMGR_MSG_STATS(stats, message) \ @@ -317,7 +317,9 @@ struct QMGR_SCAN { */ #define QMGR_SCAN_START (1<<0) /* start now/restart when done */ #define QMGR_SCAN_ALL (1<<1) /* all queue file time stamps */ -#define QMGR_FLUSH_DEAD (1<<2) /* all sites, all transports */ +#define QMGR_FLUSH_ONCE (1<<2) /* unthrottle once */ +#define QMGR_FLUSH_DFXP (1<<3) /* override defer_transports */ +#define QMGR_FLUSH_EACH (1<<4) /* unthrottle per message */ /* * qmgr_scan.c diff --git a/postfix/src/oqmgr/qmgr_active.c b/postfix/src/oqmgr/qmgr_active.c index 46a9cfdcd..59bae9af8 100644 --- a/postfix/src/oqmgr/qmgr_active.c +++ b/postfix/src/oqmgr/qmgr_active.c @@ -226,8 +226,15 @@ int qmgr_active_feed(QMGR_SCAN *scan_info, const char *queue_id) * being delivered. In that case (the file is locked), defer delivery by * a minimal amount of time. */ +#define QMGR_FLUSH_AFTER (QMGR_FLUSH_EACH | QMGR_FLUSH_DFXP) + if ((message = qmgr_message_alloc(MAIL_QUEUE_ACTIVE, queue_id, - scan_info->flags)) == 0) { + (st.st_mode & MAIL_QUEUE_STAT_UNTHROTTLE) ? + scan_info->flags | QMGR_FLUSH_AFTER : + scan_info->flags, + (st.st_mode & MAIL_QUEUE_STAT_UNTHROTTLE) ? + st.st_mode & ~MAIL_QUEUE_STAT_UNTHROTTLE : + 0)) == 0) { qmgr_active_corrupt(queue_id); return (0); } else if (message == QMGR_MESSAGE_LOCKED) { diff --git a/postfix/src/oqmgr/qmgr_message.c b/postfix/src/oqmgr/qmgr_message.c index cf1bb6f7e..8e56e56e4 100644 --- a/postfix/src/oqmgr/qmgr_message.c +++ b/postfix/src/oqmgr/qmgr_message.c @@ -9,10 +9,11 @@ /* int qmgr_message_count; /* int qmgr_recipient_count; /* -/* QMGR_MESSAGE *qmgr_message_alloc(class, name, qflags) +/* QMGR_MESSAGE *qmgr_message_alloc(class, name, qflags, mode) /* const char *class; /* const char *name; /* int qflags; +/* mode_t mode; /* /* QMGR_MESSAGE *qmgr_message_realloc(message) /* QMGR_MESSAGE *message; @@ -49,6 +50,7 @@ /* run through the resolver, and are assigned to destination /* queues. Recipients that cannot be assigned are deferred or /* bounced. Mail that has bounced twice is silently absorbed. +/* A non-zero mode means change the queue file permissions. /* /* qmgr_message_realloc() resumes reading recipients from the queue /* file, and updates the recipient list and \fIrcpt_offset\fR message @@ -929,9 +931,9 @@ static void qmgr_message_resolve(QMGR_MESSAGE *message) for (recipient = list.info; recipient < list.info + list.len; recipient++) { /* - * Redirect overrides all else. But only once (per entire - * message). For consistency with the remainder of Postfix, - * rewrite the address to canonical form before resolving it. + * Redirect overrides all else. But only once (per entire message). + * For consistency with the remainder of Postfix, rewrite the address + * to canonical form before resolving it. */ if (message->redirect_addr) { if (recipient > list.info) { @@ -1040,7 +1042,7 @@ static void qmgr_message_resolve(QMGR_MESSAGE *message) * Optionally defer deliveries over specific transports, unless the * restriction is lifted temporarily. */ - if (*var_defer_xports && (message->qflags & QMGR_FLUSH_DEAD) == 0) { + if (*var_defer_xports && (message->qflags & QMGR_FLUSH_DFXP) == 0) { if (defer_xport_argv == 0) defer_xport_argv = argv_split(var_defer_xports, " \t\r\n,"); for (cpp = defer_xport_argv->argv; *cpp; cpp++) @@ -1061,6 +1063,14 @@ static void qmgr_message_resolve(QMGR_MESSAGE *message) queue = 0; } + /* + * This message is being flushed. If need-be unthrottle the + * transport. + */ + if ((message->qflags & QMGR_FLUSH_EACH) != 0 + && QMGR_TRANSPORT_THROTTLED(transport)) + qmgr_transport_unthrottle(transport); + /* * This transport is dead. Defer delivery to this recipient. */ @@ -1137,6 +1147,13 @@ static void qmgr_message_resolve(QMGR_MESSAGE *message) STR(reply.nexthop)); } + /* + * This message is being flushed. If need-be unthrottle the queue. + */ + if ((message->qflags & QMGR_FLUSH_EACH) != 0 + && QMGR_QUEUE_THROTTLED(queue)) + qmgr_queue_unthrottle(queue); + /* * This queue is dead. Defer delivery to this recipient. */ @@ -1242,7 +1259,7 @@ void qmgr_message_free(QMGR_MESSAGE *message) /* qmgr_message_alloc - create in-core message structure */ QMGR_MESSAGE *qmgr_message_alloc(const char *queue_name, const char *queue_id, - int qflags) + int qflags, mode_t mode) { const char *myname = "qmgr_message_alloc"; QMGR_MESSAGE *message; @@ -1277,6 +1294,13 @@ QMGR_MESSAGE *qmgr_message_alloc(const char *queue_name, const char *queue_id, return (0); } else { + /* + * We have validated the queue file content, so it is safe to modify + * the file properties now. + */ + if (mode != 0 && fchmod(vstream_fileno(message->fp), mode) < 0) + msg_fatal("fchmod %s: %m", VSTREAM_PATH(message->fp)); + /* * Reset the defer log. This code should not be here, but we must * reset the defer log *after* acquiring the exclusive lock on the diff --git a/postfix/src/oqmgr/qmgr_scan.c b/postfix/src/oqmgr/qmgr_scan.c index 37a3ce8de..0665a23ce 100644 --- a/postfix/src/oqmgr/qmgr_scan.c +++ b/postfix/src/oqmgr/qmgr_scan.c @@ -31,12 +31,17 @@ /* qmgr_scan_request() records a request for the next queue scan. The /* flags argument is the bit-wise OR of zero or more of the following, /* unrecognized flags being ignored: -/* .IP QMGR_FLUSH_DEAD -/* Forget state information about dead hosts or transports. This -/* request takes effect upon the next queue scan. +/* .IP QMGR_FLUSH_ONCE +/* Forget state information about dead hosts or transports. +/* This request takes effect immediately. +/* .IP QMGR_FLUSH_DFXP +/* Override the defer_transports setting. This takes effect +/* immediately when a queue scan is in progress, and affects +/* the next queue scan. /* .IP QMGR_SCAN_ALL -/* Ignore queue file time stamps. -/* This flag is passed on to the qmgr_active_feed() routine. +/* Ignore queue file time stamps. This takes effect immediately +/* when a queue scan is in progress, and affects the next queue +/* scan. /* .IP QMGR_SCAN_START /* Start a queue scan when none is in progress, or restart the /* current scan upon completion. @@ -94,12 +99,6 @@ static void qmgr_scan_start(QMGR_SCAN *scan_info) scan_info->nflags & QMGR_SCAN_START ? "re" : "", scan_info->queue); - /* - * Optionally forget all dead host information. - */ - if (scan_info->nflags & QMGR_FLUSH_DEAD) - qmgr_enable_all(); - /* * Start or restart the scan. */ @@ -113,6 +112,33 @@ static void qmgr_scan_start(QMGR_SCAN *scan_info) void qmgr_scan_request(QMGR_SCAN *scan_info, int flags) { + /* + * Apply "forget all dead destinations" requests immediately. Throttle + * dead transports and queues at the earliest opportunity: preferably + * during an already ongoing queue scan, otherwise the throttling will + * have to wait until a "start scan" trigger arrives. + * + * The QMGR_FLUSH_ONCE request always comes with QMGR_FLUSH_DFXP, and + * sometimes it also comes with QMGR_SCAN_ALL. It becomes a completely + * different story when a flush request is encoded in file permissions. + */ + if (flags & QMGR_FLUSH_ONCE) + qmgr_enable_all(); + + /* + * Apply "ignore time stamp" requests also towards the scan that is + * already in progress. + */ + if (scan_info->handle != 0 && (flags & QMGR_SCAN_ALL)) + scan_info->flags |= QMGR_SCAN_ALL; + + /* + * Apply "override defer_transports" requests also towards the scan that + * is already in progress. + */ + if (scan_info->handle != 0 && (flags & QMGR_FLUSH_DFXP)) + scan_info->flags |= QMGR_FLUSH_DFXP; + /* * If a scan is in progress, just record the request. */ diff --git a/postfix/src/postconf/postconf.c b/postfix/src/postconf/postconf.c index 960861406..376644fe9 100644 --- a/postfix/src/postconf/postconf.c +++ b/postfix/src/postconf/postconf.c @@ -381,17 +381,12 @@ static const char *check_myhostname(void) /* * If the local machine name is not in FQDN form, try to append the * contents of $mydomain. - * - * XXX Do not complain when running as "postconf -d". */ name = get_hostname(); - if ((cmd_mode & SHOW_DEFS) == 0 && (dot = strchr(name, '.')) == 0) { - if ((domain = mail_conf_lookup_eval(VAR_MYDOMAIN)) == 0) { - msg_warn("My hostname %s is not a fully qualified name - set %s or %s in %s/main.cf", - name, VAR_MYHOSTNAME, VAR_MYDOMAIN, var_config_dir); - } else { - name = concatenate(name, ".", domain, (char *) 0); - } + if ((dot = strchr(name, '.')) == 0) { + if ((domain = mail_conf_lookup_eval(VAR_MYDOMAIN)) == 0) + domain = DEF_MYDOMAIN; + name = concatenate(name, ".", domain, (char *) 0); } return (name); } @@ -420,7 +415,7 @@ static const char *check_mydomainname(void) if (var_myhostname == 0) get_myhostname(); if ((dot = strchr(var_myhostname, '.')) == 0 || strchr(dot + 1, '.') == 0) - return (var_myhostname); + return (DEF_MYDOMAIN); return (dot + 1); } diff --git a/postfix/src/postqueue/Makefile.in b/postfix/src/postqueue/Makefile.in index 51894330c..7a0a39ca9 100644 --- a/postfix/src/postqueue/Makefile.in +++ b/postfix/src/postqueue/Makefile.in @@ -68,6 +68,7 @@ postqueue.o: ../../include/mail_dict.h postqueue.o: ../../include/mail_flush.h postqueue.o: ../../include/mail_params.h postqueue.o: ../../include/mail_proto.h +postqueue.o: ../../include/mail_queue.h postqueue.o: ../../include/mail_run.h postqueue.o: ../../include/mail_task.h postqueue.o: ../../include/msg.h diff --git a/postfix/src/postqueue/postqueue.c b/postfix/src/postqueue/postqueue.c index 9bfd2a265..c8fa2d870 100644 --- a/postfix/src/postqueue/postqueue.c +++ b/postfix/src/postqueue/postqueue.c @@ -6,6 +6,8 @@ /* SYNOPSIS /* \fBpostqueue\fR [\fB-v\fR] [\fB-c \fIconfig_dir\fR] \fB-f\fR /* .br +/* \fBpostqueue\fR [\fB-v\fR] [\fB-c \fIconfig_dir\fR] \fB-i \fIqueue_id\fR +/* .br /* \fBpostqueue\fR [\fB-v\fR] [\fB-c \fIconfig_dir\fR] \fB-p\fR /* .br /* \fBpostqueue\fR [\fB-v\fR] [\fB-c \fIconfig_dir\fR] \fB-s \fIsite\fR @@ -30,6 +32,10 @@ /* /* Warning: flushing undeliverable mail frequently will result in /* poor delivery performance of all other mail. +/* .IP "\fB-i \fIqueue_id\fR" +/* Schedule immediate delivery of mail with the specified queue ID. +/* This feature uses the \fBflush\fR(8) server, and is available +/* with Postfix 2.4 and later. /* .IP \fB-p\fR /* Produce a traditional sendmail-style queue listing. /* This option implements the traditional \fBmailq\fR command, @@ -186,6 +192,7 @@ #include #include #include +#include #include #include #include @@ -214,6 +221,7 @@ #define PQ_MODE_MAILQ_LIST 1 /* list mail queue */ #define PQ_MODE_FLUSH_QUEUE 2 /* flush queue */ #define PQ_MODE_FLUSH_SITE 3 /* flush site */ +#define PQ_MODE_FLUSH_FILE 4 /* flush message */ /* * Silly little macros (SLMs). @@ -345,7 +353,7 @@ static void flush_site(const char *site) flush_init(); - switch (status = flush_send(site)) { + switch (status = flush_send_site(site)) { case FLUSH_STAT_OK: exit(0); case FLUSH_STAT_BAD: @@ -363,11 +371,46 @@ static void flush_site(const char *site) } } +/* flush_file - flush mail with specific queue ID */ + +static void flush_file(const char *queue_id) +{ + int status; + const char *errstr; + uid_t uid = getuid(); + + if (uid != 0 && uid != var_owner_uid + && (errstr = check_user_acl_byuid(var_flush_acl, uid)) != 0) + msg_fatal_status(EX_NOPERM, + "User %s(%ld) is not allowed to flush the mail queue", + errstr, (long) uid); + + switch (status = flush_send_file(queue_id)) { + case FLUSH_STAT_OK: + exit(0); + case FLUSH_STAT_BAD: + msg_fatal_status(EX_USAGE, "Invalid request: \"%s\"", queue_id); + case FLUSH_STAT_FAIL: + msg_fatal_status(EX_UNAVAILABLE, + "Cannot flush mail queue - mail system is down"); + default: + msg_fatal_status(EX_SOFTWARE, + "Unexpected flush server reply status %d", status); + } +} + +/* unavailable - sanitize exit status from library run-time errors */ + +static void unavailable(void) +{ + exit(EX_UNAVAILABLE); +} + /* usage - scream and die */ static NORETURN usage(void) { - msg_fatal_status(EX_USAGE, "usage: postqueue -f | postqueue -p | postqueue -s site"); + msg_fatal_status(EX_USAGE, "usage: postqueue -f | postqueue -i queueid | postqueue -p | postqueue -s site"); } /* main - the main program */ @@ -380,6 +423,7 @@ int main(int argc, char **argv) int fd; int mode = PQ_MODE_DEFAULT; char *site_to_flush = 0; + char *id_to_flush = 0; ARGV *import_env; int bad_site; @@ -406,6 +450,7 @@ int main(int argc, char **argv) if ((slash = strrchr(argv[0], '/')) != 0 && slash[1]) argv[0] = slash + 1; msg_vstream_init(argv[0], VSTREAM_ERR); + msg_cleanup(unavailable); msg_syslog_init(mail_task("postqueue"), LOG_PID, LOG_FACILITY); set_mail_conf_str(VAR_PROCNAME, var_procname = mystrdup(argv[0])); @@ -415,7 +460,7 @@ int main(int argc, char **argv) * mail configuration read routine. Don't do complex things until we have * completed initializations. */ - while ((c = GETOPT(argc, argv, "c:fps:v")) > 0) { + while ((c = GETOPT(argc, argv, "c:fi:ps:v")) > 0) { switch (c) { case 'c': /* non-default configuration */ if (setenv(CONF_ENV_PATH, optarg, 1) < 0) @@ -426,6 +471,12 @@ int main(int argc, char **argv) usage(); mode = PQ_MODE_FLUSH_QUEUE; break; + case 'i': /* flush queue file */ + if (mode != PQ_MODE_DEFAULT) + usage(); + mode = PQ_MODE_FLUSH_FILE; + id_to_flush = optarg; + break; case 'p': /* traditional mailq */ if (mode != PQ_MODE_DEFAULT) usage(); @@ -489,6 +540,12 @@ int main(int argc, char **argv) "Cannot flush mail queue - invalid destination: \"%.100s%s\"", site_to_flush, strlen(site_to_flush) > 100 ? "..." : ""); } + if (id_to_flush != 0) { + if (!mail_queue_id_ok(id_to_flush)) + msg_fatal_status(EX_USAGE, + "Cannot flush queue ID - invalid name: \"%.100s%s\"", + id_to_flush, strlen(id_to_flush) > 100 ? "..." : ""); + } /* * Start processing. @@ -505,6 +562,10 @@ int main(int argc, char **argv) flush_site(site_to_flush); exit(0); break; + case PQ_MODE_FLUSH_FILE: + flush_file(id_to_flush); + exit(0); + break; case PQ_MODE_FLUSH_QUEUE: flush_queue(); exit(0); diff --git a/postfix/src/qmgr/qmgr.c b/postfix/src/qmgr/qmgr.c index 7a386f6a2..4641f4cb8 100644 --- a/postfix/src/qmgr/qmgr.c +++ b/postfix/src/qmgr/qmgr.c @@ -427,6 +427,8 @@ static void qmgr_trigger_event(char *buf, int len, * request in order. And as long as we don't have conflicting requests we * are free to sort them into the most suitable order. */ +#define QMGR_FLUSH_BEFORE (QMGR_FLUSH_ONCE | QMGR_FLUSH_DFXP) + for (i = 0; i < len; i++) { if (msg_verbose) msg_info("request: %d (%c)", @@ -440,8 +442,8 @@ static void qmgr_trigger_event(char *buf, int len, deferred_flag |= QMGR_SCAN_START; break; case QMGR_REQ_FLUSH_DEAD: - deferred_flag |= QMGR_FLUSH_DEAD; - incoming_flag |= QMGR_FLUSH_DEAD; + deferred_flag |= QMGR_FLUSH_BEFORE; + incoming_flag |= QMGR_FLUSH_BEFORE; break; case QMGR_REQ_SCAN_ALL: deferred_flag |= QMGR_SCAN_ALL; diff --git a/postfix/src/qmgr/qmgr.h b/postfix/src/qmgr/qmgr.h index 03e1fa5cc..d791a9ef0 100644 --- a/postfix/src/qmgr/qmgr.h +++ b/postfix/src/qmgr/qmgr.h @@ -304,7 +304,7 @@ extern int qmgr_recipient_count; extern void qmgr_message_free(QMGR_MESSAGE *); extern void qmgr_message_update_warn(QMGR_MESSAGE *); extern void qmgr_message_kill_record(QMGR_MESSAGE *, long); -extern QMGR_MESSAGE *qmgr_message_alloc(const char *, const char *, int); +extern QMGR_MESSAGE *qmgr_message_alloc(const char *, const char *, int, mode_t); extern QMGR_MESSAGE *qmgr_message_realloc(QMGR_MESSAGE *); #define QMGR_MSG_STATS(stats, message) \ @@ -423,7 +423,9 @@ struct QMGR_SCAN { */ #define QMGR_SCAN_START (1<<0) /* start now/restart when done */ #define QMGR_SCAN_ALL (1<<1) /* all queue file time stamps */ -#define QMGR_FLUSH_DEAD (1<<2) /* all sites, all transports */ +#define QMGR_FLUSH_ONCE (1<<2) /* unthrottle once */ +#define QMGR_FLUSH_DFXP (1<<3) /* override defer_transports */ +#define QMGR_FLUSH_EACH (1<<4) /* unthrottle per message */ /* * qmgr_scan.c diff --git a/postfix/src/qmgr/qmgr_active.c b/postfix/src/qmgr/qmgr_active.c index 46a9cfdcd..59bae9af8 100644 --- a/postfix/src/qmgr/qmgr_active.c +++ b/postfix/src/qmgr/qmgr_active.c @@ -226,8 +226,15 @@ int qmgr_active_feed(QMGR_SCAN *scan_info, const char *queue_id) * being delivered. In that case (the file is locked), defer delivery by * a minimal amount of time. */ +#define QMGR_FLUSH_AFTER (QMGR_FLUSH_EACH | QMGR_FLUSH_DFXP) + if ((message = qmgr_message_alloc(MAIL_QUEUE_ACTIVE, queue_id, - scan_info->flags)) == 0) { + (st.st_mode & MAIL_QUEUE_STAT_UNTHROTTLE) ? + scan_info->flags | QMGR_FLUSH_AFTER : + scan_info->flags, + (st.st_mode & MAIL_QUEUE_STAT_UNTHROTTLE) ? + st.st_mode & ~MAIL_QUEUE_STAT_UNTHROTTLE : + 0)) == 0) { qmgr_active_corrupt(queue_id); return (0); } else if (message == QMGR_MESSAGE_LOCKED) { diff --git a/postfix/src/qmgr/qmgr_message.c b/postfix/src/qmgr/qmgr_message.c index b2567460d..ae0dd174d 100644 --- a/postfix/src/qmgr/qmgr_message.c +++ b/postfix/src/qmgr/qmgr_message.c @@ -9,10 +9,11 @@ /* int qmgr_message_count; /* int qmgr_recipient_count; /* -/* QMGR_MESSAGE *qmgr_message_alloc(class, name, qflags) +/* QMGR_MESSAGE *qmgr_message_alloc(class, name, qflags, mode) /* const char *class; /* const char *name; /* int qflags; +/* mode_t mode; /* /* QMGR_MESSAGE *qmgr_message_realloc(message) /* QMGR_MESSAGE *message; @@ -49,6 +50,7 @@ /* run through the resolver, and are assigned to destination /* queues. Recipients that cannot be assigned are deferred or /* bounced. Mail that has bounced twice is silently absorbed. +/* A non-zero mode means change the queue file permissions. /* /* qmgr_message_realloc() resumes reading recipients from the queue /* file, and updates the recipient list and \fIrcpt_offset\fR message @@ -749,10 +751,11 @@ static int qmgr_message_read(QMGR_MESSAGE *message) message->queue_id, orig_rcpt); myfree(orig_rcpt); } - + /* * Remember when we have read the last recipient batch. Note that we do - * it here after reading as reading might have used considerable amount of time. + * it here after reading as reading might have used considerable amount + * of time. */ message->refill_time = sane_time(); @@ -985,16 +988,15 @@ static void qmgr_message_resolve(QMGR_MESSAGE *message) for (recipient = list.info; recipient < list.info + list.len; recipient++) { /* - * Redirect overrides all else. But only once (per entire - * message). For consistency with the remainder of Postfix, - * rewrite the address to canonical form before resolving it. + * Redirect overrides all else. But only once (per entire message). + * For consistency with the remainder of Postfix, rewrite the address + * to canonical form before resolving it. */ if (message->redirect_addr) { if (recipient > list.info) { recipient->u.queue = 0; continue; } - message->rcpt_offset = 0; message->rcpt_unread = 0; @@ -1099,7 +1101,7 @@ static void qmgr_message_resolve(QMGR_MESSAGE *message) * Optionally defer deliveries over specific transports, unless the * restriction is lifted temporarily. */ - if (*var_defer_xports && (message->qflags & QMGR_FLUSH_DEAD) == 0) { + if (*var_defer_xports && (message->qflags & QMGR_FLUSH_DFXP) == 0) { if (defer_xport_argv == 0) defer_xport_argv = argv_split(var_defer_xports, " \t\r\n,"); for (cpp = defer_xport_argv->argv; *cpp; cpp++) @@ -1120,6 +1122,14 @@ static void qmgr_message_resolve(QMGR_MESSAGE *message) queue = 0; } + /* + * This message is being flushed. If need-be unthrottle the + * transport. + */ + if ((message->qflags & QMGR_FLUSH_EACH) != 0 + && QMGR_TRANSPORT_THROTTLED(transport)) + qmgr_transport_unthrottle(transport); + /* * This transport is dead. Defer delivery to this recipient. */ @@ -1196,6 +1206,13 @@ static void qmgr_message_resolve(QMGR_MESSAGE *message) STR(reply.nexthop)); } + /* + * This message is being flushed. If need-be unthrottle the queue. + */ + if ((message->qflags & QMGR_FLUSH_EACH) != 0 + && QMGR_QUEUE_THROTTLED(queue)) + qmgr_queue_unthrottle(queue); + /* * This queue is dead. Defer delivery to this recipient. */ @@ -1244,7 +1261,7 @@ static void qmgr_message_assign(QMGR_MESSAGE *message) */ if ((queue = recipient->u.queue) == 0) continue; - + /* * Lookup or instantiate the message job if necessary. */ @@ -1258,10 +1275,10 @@ static void qmgr_message_assign(QMGR_MESSAGE *message) */ if (peer == 0 || queue != peer->queue) peer = qmgr_peer_obtain(job, queue); - + /* - * Lookup old or instantiate new recipient entry. We try to reuse - * the last existing entry whenever the recipient limit permits. + * Lookup old or instantiate new recipient entry. We try to reuse the + * last existing entry whenever the recipient limit permits. */ entry = peer->entry_list.prev; if (message->single_rcpt || entry == 0 @@ -1363,7 +1380,7 @@ void qmgr_message_free(QMGR_MESSAGE *message) /* qmgr_message_alloc - create in-core message structure */ QMGR_MESSAGE *qmgr_message_alloc(const char *queue_name, const char *queue_id, - int qflags) + int qflags, mode_t mode) { const char *myname = "qmgr_message_alloc"; QMGR_MESSAGE *message; @@ -1398,6 +1415,13 @@ QMGR_MESSAGE *qmgr_message_alloc(const char *queue_name, const char *queue_id, return (0); } else { + /* + * We have validated the queue file content, so it is safe to modify + * the file properties now. + */ + if (mode != 0 && fchmod(vstream_fileno(message->fp), mode) < 0) + msg_fatal("fchmod %s: %m", VSTREAM_PATH(message->fp)); + /* * Reset the defer log. This code should not be here, but we must * reset the defer log *after* acquiring the exclusive lock on the diff --git a/postfix/src/qmgr/qmgr_scan.c b/postfix/src/qmgr/qmgr_scan.c index 37a3ce8de..0665a23ce 100644 --- a/postfix/src/qmgr/qmgr_scan.c +++ b/postfix/src/qmgr/qmgr_scan.c @@ -31,12 +31,17 @@ /* qmgr_scan_request() records a request for the next queue scan. The /* flags argument is the bit-wise OR of zero or more of the following, /* unrecognized flags being ignored: -/* .IP QMGR_FLUSH_DEAD -/* Forget state information about dead hosts or transports. This -/* request takes effect upon the next queue scan. +/* .IP QMGR_FLUSH_ONCE +/* Forget state information about dead hosts or transports. +/* This request takes effect immediately. +/* .IP QMGR_FLUSH_DFXP +/* Override the defer_transports setting. This takes effect +/* immediately when a queue scan is in progress, and affects +/* the next queue scan. /* .IP QMGR_SCAN_ALL -/* Ignore queue file time stamps. -/* This flag is passed on to the qmgr_active_feed() routine. +/* Ignore queue file time stamps. This takes effect immediately +/* when a queue scan is in progress, and affects the next queue +/* scan. /* .IP QMGR_SCAN_START /* Start a queue scan when none is in progress, or restart the /* current scan upon completion. @@ -94,12 +99,6 @@ static void qmgr_scan_start(QMGR_SCAN *scan_info) scan_info->nflags & QMGR_SCAN_START ? "re" : "", scan_info->queue); - /* - * Optionally forget all dead host information. - */ - if (scan_info->nflags & QMGR_FLUSH_DEAD) - qmgr_enable_all(); - /* * Start or restart the scan. */ @@ -113,6 +112,33 @@ static void qmgr_scan_start(QMGR_SCAN *scan_info) void qmgr_scan_request(QMGR_SCAN *scan_info, int flags) { + /* + * Apply "forget all dead destinations" requests immediately. Throttle + * dead transports and queues at the earliest opportunity: preferably + * during an already ongoing queue scan, otherwise the throttling will + * have to wait until a "start scan" trigger arrives. + * + * The QMGR_FLUSH_ONCE request always comes with QMGR_FLUSH_DFXP, and + * sometimes it also comes with QMGR_SCAN_ALL. It becomes a completely + * different story when a flush request is encoded in file permissions. + */ + if (flags & QMGR_FLUSH_ONCE) + qmgr_enable_all(); + + /* + * Apply "ignore time stamp" requests also towards the scan that is + * already in progress. + */ + if (scan_info->handle != 0 && (flags & QMGR_SCAN_ALL)) + scan_info->flags |= QMGR_SCAN_ALL; + + /* + * Apply "override defer_transports" requests also towards the scan that + * is already in progress. + */ + if (scan_info->handle != 0 && (flags & QMGR_FLUSH_DFXP)) + scan_info->flags |= QMGR_FLUSH_DFXP; + /* * If a scan is in progress, just record the request. */ diff --git a/postfix/src/sendmail/sendmail.c b/postfix/src/sendmail/sendmail.c index da88542b1..6e2d284e7 100644 --- a/postfix/src/sendmail/sendmail.c +++ b/postfix/src/sendmail/sendmail.c @@ -168,6 +168,11 @@ /* .IP "\fB-q\fIinterval\fR (ignored)" /* The interval between queue runs. Use the \fBqueue_run_delay\fR /* configuration parameter instead. +/* .IP \fB-qI\fIqueueid\fR +/* Schedule immediate delivery of mail with the specified queue +/* ID. This option is implemented by executing the +/* \fBpostqueue\fR(1) command, and is available with Postfix +/* version 2.4 and later. /* .IP \fB-qR\fIsite\fR /* Schedule immediate delivery of all mail that is queued for the named /* \fIsite\fR. This option accepts only \fIsite\fR names that are @@ -885,6 +890,13 @@ static void enqueue(const int flags, const char *encoding, myfree(saved_sender); } +/* tempfail - sanitize exit status after library run-time error */ + +static void tempfail(void) +{ + exit(EX_TEMPFAIL); +} + /* main - the main program */ int main(int argc, char **argv) @@ -902,6 +914,7 @@ int main(int argc, char **argv) int n; int flags = SM_FLAG_DEFAULT; char *site_to_flush = 0; + char *id_to_flush = 0; char *encoding = 0; char *qtime = 0; const char *errstr; @@ -952,6 +965,7 @@ int main(int argc, char **argv) if ((slash = strrchr(argv[0], '/')) != 0 && slash[1]) argv[0] = slash + 1; msg_vstream_init(argv[0], VSTREAM_ERR); + msg_cleanup(tempfail); msg_syslog_init(mail_task("sendmail"), LOG_PID, LOG_FACILITY); set_mail_conf_str(VAR_PROCNAME, var_procname = mystrdup(argv[0])); @@ -1175,6 +1189,10 @@ int main(int argc, char **argv) site_to_flush = optarg + 1; if (*site_to_flush == 0) msg_fatal_status(EX_USAGE, "specify: -qRsitename"); + } else if (optarg[0] == 'I') { + id_to_flush = optarg + 1; + if (*id_to_flush == 0) + msg_fatal_status(EX_USAGE, "specify: -qIqueueid"); } else { msg_fatal_status(EX_USAGE, "-q%c is not implemented", optarg[0]); @@ -1200,6 +1218,9 @@ int main(int argc, char **argv) if (site_to_flush && mode != SM_MODE_ENQUEUE) msg_fatal_status(EX_USAGE, "-qR can be used only in delivery mode"); + if (id_to_flush && mode != SM_MODE_ENQUEUE) + msg_fatal_status(EX_USAGE, "-qI can be used only in delivery mode"); + if (flags & DEL_REQ_FLAG_USR_VRFY) { if (flags & SM_FLAG_XRCPT) msg_fatal_status(EX_USAGE, "-t option cannot be used with -bv"); @@ -1228,20 +1249,32 @@ int main(int argc, char **argv) msg_panic("unknown operation mode: %d", mode); /* NOTREACHED */ case SM_MODE_ENQUEUE: - if (site_to_flush == 0) { + if (site_to_flush) { + if (argv[OPTIND]) + msg_fatal_status(EX_USAGE, "flush site requires no recipient"); + ext_argv = argv_alloc(2); + argv_add(ext_argv, "postqueue", "-s", site_to_flush, (char *) 0); + for (n = 0; n < msg_verbose; n++) + argv_add(ext_argv, "-v", (char *) 0); + argv_terminate(ext_argv); + mail_run_replace(var_command_dir, ext_argv->argv); + /* NOTREACHED */ + } else if (id_to_flush) { + if (argv[OPTIND]) + msg_fatal_status(EX_USAGE, "flush queue_id requires no recipient"); + ext_argv = argv_alloc(2); + argv_add(ext_argv, "postqueue", "-i", id_to_flush, (char *) 0); + for (n = 0; n < msg_verbose; n++) + argv_add(ext_argv, "-v", (char *) 0); + argv_terminate(ext_argv); + mail_run_replace(var_command_dir, ext_argv->argv); + /* NOTREACHED */ + } else { enqueue(flags, encoding, dsn_envid, dsn_notify, rewrite_context, sender, full_name, argv + OPTIND); exit(0); + /* NOTREACHED */ } - if (argv[OPTIND]) - msg_fatal_status(EX_USAGE, "flush site requires no recipient"); - ext_argv = argv_alloc(2); - argv_add(ext_argv, "postqueue", "-s", site_to_flush, (char *) 0); - for (n = 0; n < msg_verbose; n++) - argv_add(ext_argv, "-v", (char *) 0); - argv_terminate(ext_argv); - mail_run_replace(var_command_dir, ext_argv->argv); - /* NOTREACHED */ break; case SM_MODE_MAILQ: if (argv[OPTIND]) diff --git a/postfix/src/smtpd/smtpd.c b/postfix/src/smtpd/smtpd.c index 4a19510d2..cce5136cc 100644 --- a/postfix/src/smtpd/smtpd.c +++ b/postfix/src/smtpd/smtpd.c @@ -1708,6 +1708,11 @@ static int mail_open_stream(SMTPD_STATE *state) MAIL_ATTR_ACT_HELO_NAME, state->helo_name); rec_fprintf(state->cleanup, REC_TYPE_ATTR, "%s=%u", MAIL_ATTR_ACT_CLIENT_AF, state->addr_family); + + /* + * Don't send client certificate down the pipeline unless it is + * a) verified or b) just a fingerprint. + */ } if (state->verp_delims) rec_fputs(state->cleanup, REC_TYPE_VERP, state->verp_delims); @@ -2994,7 +2999,7 @@ static int etrn_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *argv) smtpd_chat_reply(state, "%s", err); return (-1); } - switch (flush_send(argv[1].strval)) { + switch (flush_send_site(argv[1].strval)) { case FLUSH_STAT_OK: smtpd_chat_reply(state, "250 Queuing started"); return (0); diff --git a/postfix/src/smtpd/smtpd_check.c b/postfix/src/smtpd/smtpd_check.c index 865930d24..80d41ac25 100644 --- a/postfix/src/smtpd/smtpd_check.c +++ b/postfix/src/smtpd/smtpd_check.c @@ -1221,8 +1221,12 @@ static int permit_tls_clientcerts(SMTPD_STATE *state, int permit_all_certs) msg_info("Relaying allowed for all verified client certificates"); return (SMTPD_CHECK_OK); } - if (state->tls_context->peer_verified - && state->tls_context->peer_fingerprint) { + + /* + * When directly checking the fingerprint, it is OK if the issuing CA is + * not trusted. + */ + if (state->tls_context->peer_fingerprint) { found = maps_find(relay_ccerts, state->tls_context->peer_fingerprint, DICT_FLAG_NONE); if (found) { @@ -2578,8 +2582,11 @@ static int check_ccert_access(SMTPD_STATE *state, const char *table, if (!state->tls_context) return SMTPD_CHECK_DUNNO; - if (state->tls_context->peer_verified - && state->tls_context->peer_fingerprint) { + /* + * When directly checking the fingerprint, it is OK if the issuing CA is + * not trusted. + */ + if (state->tls_context->peer_fingerprint) { if (msg_verbose) msg_info("%s: %s", myname, state->tls_context->peer_fingerprint); @@ -3335,11 +3342,18 @@ static int check_policy_service(SMTPD_STATE *state, const char *server, #define IF_VERIFIED(x) \ ((state->tls_context && \ state->tls_context->peer_verified && ((x) != 0)) ? (x) : "") - ATTR_TYPE_STR, MAIL_ATTR_CCERT_SUBJECT, subject, - ATTR_TYPE_STR, MAIL_ATTR_CCERT_ISSUER, issuer, - ATTR_TYPE_STR, MAIL_ATTR_CCERT_FINGERPRINT, - IF_VERIFIED(state->tls_context->peer_fingerprint), #define IF_ENCRYPTED(x, y) ((state->tls_context && ((x) != 0)) ? (x) : (y)) + ATTR_TYPE_STR, MAIL_ATTR_CCERT_SUBJECT, + IF_VERIFIED(subject), + ATTR_TYPE_STR, MAIL_ATTR_CCERT_ISSUER, + IF_VERIFIED(issuer), + + /* + * When directly checking the fingerprint, it is OK if the issuing CA is + * not trusted. + */ + ATTR_TYPE_STR, MAIL_ATTR_CCERT_FINGERPRINT, + IF_ENCRYPTED(state->tls_context->peer_fingerprint, ""), ATTR_TYPE_STR, MAIL_ATTR_CRYPTO_PROTOCOL, IF_ENCRYPTED(state->tls_context->protocol, ""), ATTR_TYPE_STR, MAIL_ATTR_CRYPTO_CIPHER,