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
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:
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
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 ":"?
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.
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.
/^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
/^[> ]*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
* 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:.* <!&!" rules are workarounds for some versions of
+ Outlook express, as described in the caveats section below.
+
C\bCa\bav\bve\bea\bat\bts\bs
-Netscape Messenger (and reportedly, Mozilla) sends a HELO name that is
-identical to the sender address domain part. If you have such clients then the
-above patterns would block legitimate email.
+ * Netscape Messenger (and reportedly, Mozilla) sends a HELO name that is
+ identical to the sender address domain part. If you have such clients then
+ the above patterns would block legitimate email.
-My network has only one such machine, and to prevent its mail from being
-blocked I have configured it to send mail as user@hostname.porcupine.org. On
-the Postfix server, a canonical mapping translates this temporary address into
-user@porcupine.org.
+ My network has only one such machine, and to prevent its mail from being
+ blocked I have configured it to send mail as user@hostname.porcupine.org.
+ On the Postfix server, a canonical mapping translates this temporary
+ address into user@porcupine.org.
- /etc/postfix/main.cf:
- canonical_maps = hash:/etc/postfix/canonical
+ /etc/postfix/main.cf:
+ canonical_maps = hash:/etc/postfix/canonical
+
+ /etc/postfix/canonical:
+ @hostname.porcupine.org @porcupine.org
+
+ This is of course practical only when you have very few systems that send
+ HELO commands like this, and when you never have to send mail to a user on
+ such a host.
+
+ An alternative would be to remove the hostname from
+ "hostname.porcupine.org" with address masquerading, as described in the
+ ADDRESS_REWRITING_README document.
+
+ * Reportedly, Outlook 2003 (perhaps Outlook Express, and other versions as
+ well) present substantially different Message-ID headers depending upon
+ whether or not a DSN is requested (via Options "Request a delivery receipt
+ for this message").
+
+ When a DSN is requested, Outlook 2003 uses a Message-ID string that ends in
+ the sender's domain name:
- /etc/postfix/canonical:
- @hostname.porcupine.org @porcupine.org
+ Message-ID: <!&! ...very long string... ==@example.com>
-This is of course practical only when you have very few systems that send HELO
-commands like this, and when you never have to send mail to a user on such a
-host.
+ 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.
-An alternative would be to remove the hostname from "hostname.porcupine.org"
-with address masquerading, as described in the ADDRESS_REWRITING_README
-document.
+ If you have such clients then you can to exclude their Message-ID strings
+ with the two "Message-ID:.* <!&!" patterns that are shown in the previous
+ section. Otherwise you will not be able to use the two backscatter rules to
+ stop forged Message ID strings. Of course this workaround may break the
+ next time Outlook is changed.
B\bBl\blo\boc\bck\bki\bin\bng\bg b\bba\bac\bck\bks\bsc\bca\bat\btt\bte\ber\br m\bma\bai\bil\bl w\bwi\bit\bth\bh f\bfo\bor\brg\bge\bed\bd s\bse\ben\bnd\bde\ber\br i\bin\bnf\bfo\bor\brm\bma\bat\bti\bio\bon\bn
If you upgrade from Postfix 2.2 or earlier, read RELEASE_NOTES-2.3
before proceeding.
+Incompatible changes with Postfix snapshot 20061217
+===================================================
+
+Postfix no longer requires a domain name. It uses "localdomain" as
+the default Internet domain name when no domain is specified in
+main.cf, and when the machine hostname does not include domain name
+information.
+
Incompatible changes with Postfix snapshot 20061209
===================================================
/^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
/^[> ]*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
</pre>
matching attempts. DO NOT indent lines starting with /pattern/
between the "if" and "endif"! </p>
+<li> <p> The two "<tt>Message-ID:.* <!&!</tt>" rules are
+workarounds for some versions of Outlook express, as described in
+the <a href="#caveats"> caveats </a> section below.
+
</ul>
<p><a name="caveats"><strong>Caveats</strong></a></p>
+<ul>
+
+<li>
+
<p> Netscape Messenger (and reportedly, Mozilla) sends a HELO name
that is identical to the sender address domain part. If you have
such clients then the above patterns would block legitimate email.
masquerading, as described in the <a href="ADDRESS_REWRITING_README.html">ADDRESS_REWRITING_README</a> document.
</p>
+<li> <p> Reportedly, Outlook 2003 (perhaps Outlook Express, and
+other versions as well) present substantially different Message-ID
+headers depending upon whether or not a DSN is requested (via Options
+"Request a delivery receipt for this message"). </p>
+
+<p> When a DSN is requested, Outlook 2003 uses a Message-ID string
+that ends in the sender's domain name: </p>
+
+<blockquote>
+<pre>
+Message-ID: <!&! ...very long string... ==@example.com>
+</pre>
+</blockquote>
+
+<p> where <i>example.com</i> 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 <i>username@example.com</i>,
+messages with DSN turned on will trigger the REJECT action in the
+previous section. </p>
+
+<p> If you have such clients then you can to exclude their Message-ID
+strings with the two "<tt>Message-ID:.* <!&!</tt>" patterns
+that are shown in the previous section. Otherwise you will not be
+able to use the two backscatter rules to stop forged Message ID
+strings. Of course this workaround may break the next time Outlook
+is changed. </p>
+
+</ul>
+
<h3><a name="forged_sender">Blocking backscatter mail with forged
sender information</a></h3>
the specified queue ID is queued for the specified
destination.
- <b>send</b> <i>sitename</i>
+ <b>send_site</b> <i>sitename</i>
Request delivery of mail that is queued for the
specified destination.
+ <b>send_file</b> <i>queueid</i>
+ Request delivery of the specified deferred message.
+
<b>refresh</b>
Refresh non-empty per-destination logfiles that
were not read in <b>$<a href="postconf.5.html#fast_flush_refresh_time">fast_flush_refresh_time</a></b> hours, by
<b>SECURITY</b>
The <a href="flush.8.html"><b>flush</b>(8)</a> 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.
Problems and transactions are logged to <b>syslogd</b>(8).
<b>BUGS</b>
- 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 <a href="master.5.html"><b>master.cf</b></a> configuration file.
- Upon receipt of a request to deliver mail for an eligible
- destination, the <a href="flush.8.html"><b>flush</b>(8)</a> 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 <a href="flush.8.html"><b>flush</b>(8)</a> 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 <b><a href="postconf.5.html#relay_domains">relay_domains</a></b> des-
- tination because such mail typically only has recipients
+ tination because such mail typically only has recipients
in one domain.
<b>CONFIGURATION PARAMETERS</b>
Changes to <a href="postconf.5.html"><b>main.cf</b></a> are picked up automatically as <a href="flush.8.html"><b>flush</b>(8)</a>
- processes run for only a limited amount of time. Use the
+ processes run for only a limited amount of time. Use the
command "<b>postfix reload</b>" to speed up a change.
- The text below provides only a parameter summary. See
+ The text below provides only a parameter summary. See
<a href="postconf.5.html"><b>postconf</b>(5)</a> for more details including examples.
<b><a href="postconf.5.html#config_directory">config_directory</a> (see 'postconf -d' output)</b>
- The default location of the Postfix <a href="postconf.5.html">main.cf</a> and
+ The default location of the Postfix <a href="postconf.5.html">main.cf</a> and
<a href="master.5.html">master.cf</a> configuration files.
<b><a href="postconf.5.html#daemon_timeout">daemon_timeout</a> (18000s)</b>
- 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.
<b><a href="postconf.5.html#fast_flush_domains">fast_flush_domains</a> ($<a href="postconf.5.html#relay_domains">relay_domains</a>)</b>
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.
<b><a href="postconf.5.html#fast_flush_refresh_time">fast_flush_refresh_time</a> (12h)</b>
- 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.
<b><a href="postconf.5.html#fast_flush_purge_time">fast_flush_purge_time</a> (7d)</b>
over an internal communication channel.
<b><a href="postconf.5.html#max_idle">max_idle</a> (100s)</b>
- 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.
<b><a href="postconf.5.html#max_use">max_use</a> (100)</b>
- The maximal number of connection requests before a
+ The maximal number of connection requests before a
Postfix daemon process terminates.
- <b><a href="postconf.5.html#parent_domain_matches_subdomains">parent_domain_matches_subdomains</a> (see 'postconf -d' out-</b>
+ <b><a href="postconf.5.html#parent_domain_matches_subdomains">parent_domain_matches_subdomains</a> (see 'postconf -d' out-</b>
<b>put)</b>
What Postfix features match subdomains of
"domain.tld" automatically, instead of requiring an
explicit ".domain.tld" pattern.
<b><a href="postconf.5.html#process_id">process_id</a> (read-only)</b>
- The process ID of a Postfix command or daemon
+ The process ID of a Postfix command or daemon
process.
<b><a href="postconf.5.html#process_name">process_name</a> (read-only)</b>
- The process name of a Postfix command or daemon
+ The process name of a Postfix command or daemon
process.
<b><a href="postconf.5.html#queue_directory">queue_directory</a> (see 'postconf -d' output)</b>
- The location of the Postfix top-level queue direc-
+ The location of the Postfix top-level queue direc-
tory.
<b><a href="postconf.5.html#syslog_facility">syslog_facility</a> (mail)</b>
The syslog facility of Postfix logging.
<b><a href="postconf.5.html#syslog_name">syslog_name</a> (postfix)</b>
- 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".
<b>FILES</b>
<a href="ETRN_README.html">ETRN_README</a>, Postfix ETRN howto
<b>LICENSE</b>
- The Secure Mailer license must be distributed with this
+ The Secure Mailer license must be distributed with this
software.
<b>HISTORY</b>
<dt><b><a name="check_ccert_access">check_ccert_access</a> <i><a href="DATABASE_README.html">type:table</a></i></b></dt>
-<dd>When the remote SMTP client certificate is verified successfully,
-use the client certificate fingerprint as lookup key for the specified
-<a href="access.5.html">access(5)</a> database. This feature is available with Postfix version 2.2.</dd>
+<dd> Use the client certificate fingerprint as lookup key for the
+specified <a href="access.5.html">access(5)</a> 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.</dd>
<dt><b><a name="check_client_access">check_client_access</a> <i><a href="DATABASE_README.html">type:table</a></i></b></dt>
<b>SYNOPSIS</b>
<b>postqueue</b> [<b>-v</b>] [<b>-c</b> <i>config</i><b>_</b><i>dir</i>] <b>-f</b>
+ <b>postqueue</b> [<b>-v</b>] [<b>-c</b> <i>config</i><b>_</b><i>dir</i>] <b>-i</b> <i>queue</i><b>_</b><i>id</i>
<b>postqueue</b> [<b>-v</b>] [<b>-c</b> <i>config</i><b>_</b><i>dir</i>] <b>-p</b>
<b>postqueue</b> [<b>-v</b>] [<b>-c</b> <i>config</i><b>_</b><i>dir</i>] <b>-s</b> <i>site</i>
will result in poor delivery performance of all
other mail.
+ <b>-i</b> <i>queue</i><b>_</b><i>id</i>
+ Schedule immediate delivery of mail with the speci-
+ fied queue ID. This feature uses the <a href="flush.8.html"><b>flush</b>(8)</a>
+ server, and is available with Postfix 2.4 and
+ later.
+
<b>-p</b> Produce a traditional sendmail-style queue listing.
- This option implements the traditional <b>mailq</b> com-
+ This option implements the traditional <b>mailq</b> com-
mand, by contacting the Postfix <a href="showq.8.html"><b>showq</b>(8)</a> 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 <a href="postqueue.1.html"><b>postqueue</b>(1)</a> 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 <a href="postqueue.1.html"><b>postqueue</b>(1)</a> command. The
+ queue ID string is followed by an optional status
character:
<b>*</b> The message is in the <b>active</b> queue, i.e. the
message is selected for delivery.
- <b>!</b> The message is in the <b>hold</b> queue, i.e. no
- further delivery attempt will be made until
+ <b>!</b> The message is in the <b>hold</b> queue, i.e. no
+ further delivery attempt will be made until
the mail is taken off hold.
<b>-s</b> <i>site</i>
- Schedule immediate delivery of all mail that is
+ Schedule immediate delivery of all mail that is
queued for the named <i>site</i>. A numerical site must be
- specified as a valid <a href="http://www.faqs.org/rfcs/rfc2821.html">RFC 2821</a> address literal
- enclosed in [], just like in email addresses. The
+ specified as a valid <a href="http://www.faqs.org/rfcs/rfc2821.html">RFC 2821</a> address literal
+ enclosed in [], just like in email addresses. The
site must be eligible for the "fast flush" service.
- See <a href="flush.8.html"><b>flush</b>(8)</a> for more information about the "fast
+ See <a href="flush.8.html"><b>flush</b>(8)</a> for more information about the "fast
flush" service.
- This option implements the traditional "<b>sendmail</b>
- <b>-qR</b><i>site</i>" command, by contacting the Postfix
+ This option implements the traditional "<b>sendmail</b>
+ <b>-qR</b><i>site</i>" command, by contacting the Postfix
<a href="flush.8.html"><b>flush</b>(8)</a> daemon.
<b>-v</b> Enable verbose logging for debugging purposes. Mul-
- tiple <b>-v</b> options make the software increasingly
- verbose. As of Postfix 2.3, this option is avail-
+ tiple <b>-v</b> options make the software increasingly
+ verbose. As of Postfix 2.3, this option is avail-
able for the super-user only.
<b>SECURITY</b>
- 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.
<b>DIAGNOSTICS</b>
- Problems are logged to <b>syslogd</b>(8) and to the standard
+ Problems are logged to <b>syslogd</b>(8) and to the standard
error stream.
<b>ENVIRONMENT</b>
MAIL_CONFIG
- Directory with the <a href="postconf.5.html"><b>main.cf</b></a> file. In order to avoid
- exploitation of set-group ID privileges, a non-
+ Directory with the <a href="postconf.5.html"><b>main.cf</b></a> file. In order to avoid
+ exploitation of set-group ID privileges, a non-
standard directory is allowed only if:
- <b>o</b> The name is listed in the standard <a href="postconf.5.html"><b>main.cf</b></a>
- file with the <b><a href="postconf.5.html#alternate_config_directories">alternate_config_directories</a></b>
+ <b>o</b> The name is listed in the standard <a href="postconf.5.html"><b>main.cf</b></a>
+ file with the <b><a href="postconf.5.html#alternate_config_directories">alternate_config_directories</a></b>
configuration parameter.
<b>o</b> The command is invoked by the super-user.
<b>CONFIGURATION PARAMETERS</b>
- The following <a href="postconf.5.html"><b>main.cf</b></a> parameters are especially relevant
+ The following <a href="postconf.5.html"><b>main.cf</b></a> parameters are especially relevant
to this program. The text below provides only a parameter
- summary. See <a href="postconf.5.html"><b>postconf</b>(5)</a> for more details including exam-
+ summary. See <a href="postconf.5.html"><b>postconf</b>(5)</a> for more details including exam-
ples.
<b><a href="postconf.5.html#alternate_config_directories">alternate_config_directories</a> (empty)</b>
- A list of non-default Postfix configuration direc-
+ A list of non-default Postfix configuration direc-
tories that may be specified with "-c <a href="postconf.5.html#config_directory">config_direc</a>-
- <a href="postconf.5.html#config_directory">tory</a>" on the command line, or via the MAIL_CONFIG
+ <a href="postconf.5.html#config_directory">tory</a>" on the command line, or via the MAIL_CONFIG
environment parameter.
<b><a href="postconf.5.html#config_directory">config_directory</a> (see 'postconf -d' output)</b>
- The default location of the Postfix <a href="postconf.5.html">main.cf</a> and
+ The default location of the Postfix <a href="postconf.5.html">main.cf</a> and
<a href="master.5.html">master.cf</a> configuration files.
<b><a href="postconf.5.html#command_directory">command_directory</a> (see 'postconf -d' output)</b>
- The location of all postfix administrative com-
+ The location of all postfix administrative com-
mands.
<b><a href="postconf.5.html#fast_flush_domains">fast_flush_domains</a> ($<a href="postconf.5.html#relay_domains">relay_domains</a>)</b>
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.
<b><a href="postconf.5.html#import_environment">import_environment</a> (see 'postconf -d' output)</b>
- 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.
<b><a href="postconf.5.html#queue_directory">queue_directory</a> (see 'postconf -d' output)</b>
- The location of the Postfix top-level queue direc-
+ The location of the Postfix top-level queue direc-
tory.
<b><a href="postconf.5.html#syslog_facility">syslog_facility</a> (mail)</b>
The syslog facility of Postfix logging.
<b><a href="postconf.5.html#syslog_name">syslog_name</a> (postfix)</b>
- 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".
<b><a href="postconf.5.html#trigger_timeout">trigger_timeout</a> (10s)</b>
- The time limit for sending a trigger to a Postfix
- daemon (for example, the <a href="pickup.8.html"><b>pickup</b>(8)</a> or <a href="qmgr.8.html"><b>qmgr</b>(8)</a> dae-
+ The time limit for sending a trigger to a Postfix
+ daemon (for example, the <a href="pickup.8.html"><b>pickup</b>(8)</a> or <a href="qmgr.8.html"><b>qmgr</b>(8)</a> dae-
mon).
Available in Postfix version 2.2 and later:
<b><a href="postconf.5.html#authorized_flush_users">authorized_flush_users</a> (static:anyone)</b>
- List of users who are authorized to flush the
+ List of users who are authorized to flush the
queue.
<b><a href="postconf.5.html#authorized_mailq_users">authorized_mailq_users</a> (static:anyone)</b>
<a href="ETRN_README.html">ETRN_README</a>, Postfix ETRN howto
<b>LICENSE</b>
- The Secure Mailer license must be distributed with this
+ The Secure Mailer license must be distributed with this
software.
<b>HISTORY</b>
- The postqueue command was introduced with Postfix version
+ The postqueue command was introduced with Postfix version
1.1.
<b>AUTHOR(S)</b>
The interval between queue runs. Use the
<b><a href="postconf.5.html#queue_run_delay">queue_run_delay</a></b> configuration parameter instead.
+ <b>-qI</b><i>queueid</i>
+ Schedule immediate delivery of mail with the speci-
+ fied queue ID. This option is implemented by exe-
+ cuting the <a href="postqueue.1.html"><b>postqueue</b>(1)</a> command, and is available
+ with Postfix version 2.4 and later.
+
<b>-qR</b><i>site</i>
- Schedule immediate delivery of all mail that is
+ Schedule immediate delivery of all mail that is
queued for the named <i>site</i>. This option accepts only
- <i>site</i> names that are eligible for the "fast flush"
- service, and is implemented by executing the
+ <i>site</i> names that are eligible for the "fast flush"
+ service, and is implemented by executing the
<a href="postqueue.1.html"><b>postqueue</b>(1)</a> command. See <a href="flush.8.html"><b>flush</b>(8)</a> for more infor-
mation about the "fast flush" service.
<b>-qS</b><i>site</i>
- This command is not implemented. Use the slower
+ This command is not implemented. Use the slower
"<b>sendmail -q</b>" command instead.
- <b>-t</b> Extract recipients from message headers. These are
- added to any recipients specified on the command
+ <b>-t</b> 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.
<b>-U</b> (ignored)
This feature is available in Postfix 2.3 and later.
<b>-XV</b> (Postfix 2.2 and earlier: <b>-V</b>)
- Variable Envelope Return Path. Given an envelope
- sender address of the form <i>owner-listname</i>@<i>origin</i>,
- each recipient <i>user</i>@<i>domain</i> receives mail with a
+ Variable Envelope Return Path. Given an envelope
+ sender address of the form <i>owner-listname</i>@<i>origin</i>,
+ each recipient <i>user</i>@<i>domain</i> receives mail with a
personalized envelope sender address.
- By default, the personalized envelope sender
- address is <i>owner-listname</i><b>+</b><i>user</i><b>=</b><i>domain</i>@<i>origin</i>. The
- default <b>+</b> and <b>=</b> characters are configurable with
- the <b><a href="postconf.5.html#default_verp_delimiters">default_verp_delimiters</a></b> configuration parame-
+ By default, the personalized envelope sender
+ address is <i>owner-listname</i><b>+</b><i>user</i><b>=</b><i>domain</i>@<i>origin</i>. The
+ default <b>+</b> and <b>=</b> characters are configurable with
+ the <b><a href="postconf.5.html#default_verp_delimiters">default_verp_delimiters</a></b> configuration parame-
ter.
<b>-XV</b><i>xy</i> (Postfix 2.2 and earlier: <b>-V</b><i>xy</i>)
- As <b>-XV</b>, but uses <i>x</i> and <i>y</i> as the VERP delimiter
- characters, instead of the characters specified
- with the <b><a href="postconf.5.html#default_verp_delimiters">default_verp_delimiters</a></b> configuration
+ As <b>-XV</b>, but uses <i>x</i> and <i>y</i> as the VERP delimiter
+ characters, instead of the characters specified
+ with the <b><a href="postconf.5.html#default_verp_delimiters">default_verp_delimiters</a></b> configuration
parameter.
- <b>-v</b> Send an email report of the first delivery attempt
- (Postfix versions 2.1 and later). Mail delivery
- always happens in the background. When multiple <b>-v</b>
+ <b>-v</b> Send an email report of the first delivery attempt
+ (Postfix versions 2.1 and later). Mail delivery
+ always happens in the background. When multiple <b>-v</b>
options are given, enable verbose logging for
debugging purposes.
<b>-X</b> <i>log</i><b>_</b><i>file</i> (ignored)
- Log mailer traffic. Use the <b><a href="postconf.5.html#debug_peer_list">debug_peer_list</a></b> and
- <b><a href="postconf.5.html#debug_peer_level">debug_peer_level</a></b> configuration parameters instead.
+ Log mailer traffic. Use the <b><a href="postconf.5.html#debug_peer_list">debug_peer_list</a></b> and
+ <b><a href="postconf.5.html#debug_peer_level">debug_peer_level</a></b> configuration parameters instead.
<b>SECURITY</b>
- 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.
<b>DIAGNOSTICS</b>
- Problems are logged to <b>syslogd</b>(8) and to the standard
+ Problems are logged to <b>syslogd</b>(8) and to the standard
error stream.
<b>ENVIRONMENT</b>
<b>MAIL_DEBUG</b> (value does not matter)
Enable debugging with an external command, as spec-
- ified with the <b><a href="postconf.5.html#debugger_command">debugger_command</a></b> configuration
+ ified with the <b><a href="postconf.5.html#debugger_command">debugger_command</a></b> configuration
parameter.
- <b>NAME</b> The sender full name. This is used only with mes-
- sages that have no <b>From:</b> message header. See also
+ <b>NAME</b> The sender full name. This is used only with mes-
+ sages that have no <b>From:</b> message header. See also
the <b>-F</b> option above.
<b>CONFIGURATION PARAMETERS</b>
- The following <a href="postconf.5.html"><b>main.cf</b></a> parameters are especially relevant
+ The following <a href="postconf.5.html"><b>main.cf</b></a> parameters are especially relevant
to this program. The text below provides only a parameter
- summary. See <a href="postconf.5.html"><b>postconf</b>(5)</a> for more details including exam-
+ summary. See <a href="postconf.5.html"><b>postconf</b>(5)</a> for more details including exam-
ples.
<b>TROUBLE SHOOTING CONTROLS</b>
- The <a href="DEBUG_README.html">DEBUG_README</a> file gives examples of how to trouble
+ The <a href="DEBUG_README.html">DEBUG_README</a> file gives examples of how to trouble
shoot a Postfix system.
<b><a href="postconf.5.html#debugger_command">debugger_command</a> (empty)</b>
mon program is invoked with the -D option.
<b><a href="postconf.5.html#debug_peer_level">debug_peer_level</a> (2)</b>
- 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
<a href="postconf.5.html#debug_peer_list">debug_peer_list</a> parameter.
<b><a href="postconf.5.html#debug_peer_list">debug_peer_list</a> (empty)</b>
- 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 $<a href="postconf.5.html#debug_peer_level">debug_peer_level</a>.
<b>ACCESS CONTROLS</b>
Available in Postfix version 2.2 and later:
<b><a href="postconf.5.html#authorized_flush_users">authorized_flush_users</a> (static:anyone)</b>
- List of users who are authorized to flush the
+ List of users who are authorized to flush the
queue.
<b><a href="postconf.5.html#authorized_mailq_users">authorized_mailq_users</a> (static:anyone)</b>
List of users who are authorized to view the queue.
<b><a href="postconf.5.html#authorized_submit_users">authorized_submit_users</a> (static:anyone)</b>
- List of users who are authorized to submit mail
- with the <a href="sendmail.1.html"><b>sendmail</b>(1)</a> command (and with the privi-
+ List of users who are authorized to submit mail
+ with the <a href="sendmail.1.html"><b>sendmail</b>(1)</a> command (and with the privi-
leged <a href="postdrop.1.html"><b>postdrop</b>(1)</a> helper command).
<b>RESOURCE AND RATE CONTROLS</b>
sent in a non-delivery notification.
<b><a href="postconf.5.html#fork_attempts">fork_attempts</a> (5)</b>
- The maximal number of attempts to fork() a child
+ The maximal number of attempts to fork() a child
process.
<b><a href="postconf.5.html#fork_delay">fork_delay</a> (1s)</b>
process.
<b><a href="postconf.5.html#hopcount_limit">hopcount_limit</a> (50)</b>
- The maximal number of Received: message headers
+ The maximal number of Received: message headers
that is allowed in the primary message headers.
<b><a href="postconf.5.html#queue_run_delay">queue_run_delay</a> (1000s)</b>
- The time between <a href="QSHAPE_README.html#deferred_queue">deferred queue</a> scans by the queue
+ The time between <a href="QSHAPE_README.html#deferred_queue">deferred queue</a> scans by the queue
manager.
<b>FAST FLUSH CONTROLS</b>
<b><a href="postconf.5.html#fast_flush_domains">fast_flush_domains</a> ($<a href="postconf.5.html#relay_domains">relay_domains</a>)</b>
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.
<b>VERP CONTROLS</b>
The <a href="VERP_README.html">VERP_README</a> file describes configuration and operation
- details of Postfix support for variable envelope return
+ details of Postfix support for variable envelope return
path addresses.
<b><a href="postconf.5.html#default_verp_delimiters">default_verp_delimiters</a> (+=)</b>
The two default VERP delimiter characters.
<b><a href="postconf.5.html#verp_delimiter_filter">verp_delimiter_filter</a> (-=+)</b>
- The characters Postfix accepts as VERP delimiter
- characters on the Postfix <a href="sendmail.1.html"><b>sendmail</b>(1)</a> command line
+ The characters Postfix accepts as VERP delimiter
+ characters on the Postfix <a href="sendmail.1.html"><b>sendmail</b>(1)</a> command line
and in SMTP commands.
<b>MISCELLANEOUS CONTROLS</b>
<b><a href="postconf.5.html#alias_database">alias_database</a> (see 'postconf -d' output)</b>
- The alias databases for <a href="local.8.html"><b>local</b>(8)</a> delivery that are
+ The alias databases for <a href="local.8.html"><b>local</b>(8)</a> delivery that are
updated with "<b>newaliases</b>" or with "<b>sendmail -bi</b>".
<b><a href="postconf.5.html#command_directory">command_directory</a> (see 'postconf -d' output)</b>
- The location of all postfix administrative com-
+ The location of all postfix administrative com-
mands.
<b><a href="postconf.5.html#config_directory">config_directory</a> (see 'postconf -d' output)</b>
- The default location of the Postfix <a href="postconf.5.html">main.cf</a> and
+ The default location of the Postfix <a href="postconf.5.html">main.cf</a> and
<a href="master.5.html">master.cf</a> configuration files.
<b><a href="postconf.5.html#daemon_directory">daemon_directory</a> (see 'postconf -d' output)</b>
- The directory with Postfix support programs and
+ The directory with Postfix support programs and
daemon programs.
<b><a href="postconf.5.html#default_database_type">default_database_type</a> (see 'postconf -d' output)</b>
<a href="postalias.1.html"><b>postalias</b>(1)</a> and <a href="postmap.1.html"><b>postmap</b>(1)</a> commands.
<b><a href="postconf.5.html#delay_warning_time">delay_warning_time</a> (0h)</b>
- 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.
<b><a href="postconf.5.html#enable_errors_to">enable_errors_to</a> (no)</b>
- 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).
<b><a href="postconf.5.html#mail_owner">mail_owner</a> (postfix)</b>
and most Postfix daemon processes.
<b><a href="postconf.5.html#queue_directory">queue_directory</a> (see 'postconf -d' output)</b>
- The location of the Postfix top-level queue direc-
+ The location of the Postfix top-level queue direc-
tory.
<b><a href="postconf.5.html#remote_header_rewrite_domain">remote_header_rewrite_domain</a> (empty)</b>
- 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.
<b><a href="postconf.5.html#syslog_facility">syslog_facility</a> (mail)</b>
The syslog facility of Postfix logging.
<b><a href="postconf.5.html#syslog_name">syslog_name</a> (postfix)</b>
- 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".
<b>FILES</b>
<a href="VERP_README.html">VERP_README</a>, Postfix VERP howto
<b>LICENSE</b>
- The Secure Mailer license must be distributed with this
+ The Secure Mailer license must be distributed with this
software.
<b>AUTHOR(S)</b>
.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
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,
.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
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
.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
/^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
/^[> ]*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
</pre>
matching attempts. DO NOT indent lines starting with /pattern/
between the "if" and "endif"! </p>
+<li> <p> The two "<tt>Message-ID:.* <!&!</tt>" rules are
+workarounds for some versions of Outlook express, as described in
+the <a href="#caveats"> caveats </a> section below.
+
</ul>
<p><a name="caveats"><strong>Caveats</strong></a></p>
+<ul>
+
+<li>
+
<p> Netscape Messenger (and reportedly, Mozilla) sends a HELO name
that is identical to the sender address domain part. If you have
such clients then the above patterns would block legitimate email.
masquerading, as described in the ADDRESS_REWRITING_README document.
</p>
+<li> <p> Reportedly, Outlook 2003 (perhaps Outlook Express, and
+other versions as well) present substantially different Message-ID
+headers depending upon whether or not a DSN is requested (via Options
+"Request a delivery receipt for this message"). </p>
+
+<p> When a DSN is requested, Outlook 2003 uses a Message-ID string
+that ends in the sender's domain name: </p>
+
+<blockquote>
+<pre>
+Message-ID: <!&! ...very long string... ==@example.com>
+</pre>
+</blockquote>
+
+<p> where <i>example.com</i> 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 <i>username@example.com</i>,
+messages with DSN turned on will trigger the REJECT action in the
+previous section. </p>
+
+<p> If you have such clients then you can to exclude their Message-ID
+strings with the two "<tt>Message-ID:.* <!&!</tt>" patterns
+that are shown in the previous section. Otherwise you will not be
+able to use the two backscatter rules to stop forged Message ID
+strings. Of course this workaround may break the next time Outlook
+is changed. </p>
+
+</ul>
+
<h3><a name="forged_sender">Blocking backscatter mail with forged
sender information</a></h3>
<dt><b><a name="check_ccert_access">check_ccert_access</a> <i><a href="DATABASE_README.html">type:table</a></i></b></dt>
-<dd>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.</dd>
+<dd> 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.</dd>
<dt><b><a name="check_client_access">check_client_access</a> <i><a href="DATABASE_README.html">type:table</a></i></b></dt>
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
/* .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
#include <dict.h>
#include <scan_dir.h>
#include <stringops.h>
+#include <safe_open.h>
/* Global library. */
* 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
* 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 */
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)
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;
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
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",
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)
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);
/* 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()
/* 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.
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)
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);
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)
*/
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);
* 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 */
/*
* 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);
* 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
* 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)",
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;
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) \
*/
#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
* 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) {
/* 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;
/* 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
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) {
* 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++)
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.
*/
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.
*/
/* 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;
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
/* 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.
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.
*/
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.
*/
/*
* 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);
}
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);
}
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
/* 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
/*
/* 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,
#include <mail_task.h>
#include <mail_run.h>
#include <mail_flush.h>
+#include <mail_queue.h>
#include <flush_clnt.h>
#include <smtp_stream.h>
#include <user_acl.h>
#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).
flush_init();
- switch (status = flush_send(site)) {
+ switch (status = flush_send_site(site)) {
case FLUSH_STAT_OK:
exit(0);
case FLUSH_STAT_BAD:
}
}
+/* 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 */
int fd;
int mode = PQ_MODE_DEFAULT;
char *site_to_flush = 0;
+ char *id_to_flush = 0;
ARGV *import_env;
int bad_site;
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]));
* 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)
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();
"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.
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);
* 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)",
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;
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) \
*/
#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
* 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) {
/* 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;
/* 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
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();
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;
* 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++)
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.
*/
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.
*/
*/
if ((queue = recipient->u.queue) == 0)
continue;
-
+
/*
* Lookup or instantiate the message job if necessary.
*/
*/
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
/* 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;
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
/* 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.
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.
*/
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.
*/
/* .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
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)
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;
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]));
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]);
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");
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])
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);
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);
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) {
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);
#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,