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
+
+
+-
+
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.
@@ -260,6 +270,35 @@ mail to a user on such a host.
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:
+
+
+
+Message-ID: <!&! ...very long string... ==@example.com>
+
+
+
+ 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:.* <!&!" 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.
+
+
+
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
+
+
+-
+
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.
@@ -260,6 +270,35 @@ mail to a user on such a host.
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:
+
+
+
+Message-ID: <!&! ...very long string... ==@example.com>
+
+
+
+ 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:.* <!&!" 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.
+
+
+
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,