mail to be placed on the "hold" queue for manual inspection.
Files: global/hold_message.[hc], cleanup/cleanup_message.c.
+20020820
+
+ Bugfix: yesterday's HOLD pattern code did not update the
+ cleanup server's idea of the queue file name for error
+ recovery and for error reporting purposes, so that incomplete
+ or content rejected mail would not be deleted from the
+ queue, and so that the bouncer would not find the queue
+ file.
+
+ Feature: new header/body_checks DISCARD pattern that causes
+ mail to be silently discarded. Files: global/cleanup_user.h,
+ cleanup/cleanup_message.c.
+
+ Bugfix: the local delivery agent's mailbox duplicate delivery
+ eliminator was not updated when address extensions were
+ added to Postfix. The other local duplicate eliminators
+ may need revision as well. File: local/mailbox.c.
+
+20020821
+
+ Feature: HOLD and DISCARD actions in SMTPD access tables.
+ These requests are propagated to the cleanup daemon,
+ which required a bit of redesign of internal protocols.
+ Files: cleanup/cleanup.c pickup/pickup.c smtpd/smtpd.c
+ global/post_mail.c qmqpd/qmqpd.c local/forward.c.
+
Open problems:
- Medium: should permit_mx_backup defer delivery if DNS
- has some error of some kind?
+ Medium: should permit_mx_backup defer delivery if DNS has
+ some error of some kind?
Low: all table lookups should consistently use internalized
(unquoted) or externalized (quoted) forms as lookup keys.
Note: Postfix no longer supports the LDAP version 1 interface.
-You need to have LDAP libraries and include files installed somewhere on
-your system, and you need to configure the Postfix Makefiles
-accordingly.
+You need to have LDAP libraries and include files installed somewhere
+on your system, and you need to configure the Postfix Makefiles
+accordingly.
+
+For example, to build the OpenLDAP libraries for use with Postfix
+(i.e. LDAP client code only), you could use the following command:
+
+ % ./configure --without-kerberos --without-cyrus-sasl --without-tls \
+ --without-threads --disable-slapd --disable-slurpd \
+ --disable-debug --disable-shared
If you're using the libraries from the UM distribution
(http://www.umich.edu/~dirsvcs/ldap/ldap.html) or OpenLDAP
date. Snapshots change only the release date, unless they include
the same bugfixes as a patch release.
-Incompatible changes with Postfix snapshot 1.1.11-2002018
-=========================================================
+Incompatible changes with Postfix snapshot 1.1.11-20020821
+==========================================================
+
+After switching Postfix versions you need to "postfix reload"
+because internal protocols have changed.
+
+Incompatible changes with Postfix snapshot 1.1.11-20020818
+==========================================================
The qmgr_site_hog_factor feature is gone (this would defer mail
delivery for sites that occupy too much space in the active queue,
#
# OK Accept the address etc. that matches the pattern.
#
+# HOLD Place the message on the hold queue, where it will
+# sit until someone either deletes it or releases it
+# for delivery. Mail that is placed on hold can be
+# examined with the postcat(1) command, and can be
+# destroyed or released with the postsuper(1) com-
+# mand.
+#
+# DISCARD
+# Claim successful delivery and silently discard the
+# message.
+#
# all-numerical
# An all-numerical result is treated as OK. This for-
# mat is generated by address-based relay authoriza-
queue_directory = /var/spool/postfix
# The command_directory parameter specifies the location of all
-# postXXX commands. The default value is $program_directory.
+# postXXX commands.
#
command_directory = /usr/sbin
# The daemon_directory parameter specifies the location of all Postfix
-# daemon programs (i.e. programs listed in the master.cf file). The
-# default value is $program_directory. This directory must be owned
-# by root.
+# daemon programs (i.e. programs listed in the master.cf file). This
+# directory must be owned by root.
#
daemon_directory = /usr/libexec/postfix
# When a pattern matches, what happens next depends on the associated
# action that is specified in the right-hand side of the table:
#
-# REJECT the entire message is rejected.
-# REJECT text.... The text is sent to the originator.
-# IGNORE the header line is silently discarded.
-# WARN the header is logged (not rejected) with a warning message.
-# WARN text... as above, and the text is logged, too.
+# REJECT [optional text...]
+# Reject the entire message. The optional text is sent to the
+# originator and is logged to the maillog file.
+# IGNORE Silently discard the header line.
+# WARN [optional text...]
+# Log the message header and the optional text. This is useful
+# for testing. When the pattern is OK, change the WARN into a
+# REJECT or into a DISCARD.
+# HOLD [optional text...]
+# Place the message on the hold queue. Mail on hold can be
+# inspected with the postcat command, and can be destroyed or
+# taken off hold (i.e. delivered) with the postsuper command.
+# The matched header is logged with the optional text.
+# DISCARD [optional text...]
+# Claim successful delivery and silently discard the message.
+# The matched header is logged with the optional text.
# FILTER transport:nexthop
# after the message is queued, send the entire message through
# a content filter. This requires different cleanup servers
#
# Command + args: the command to be executed. The command name is
# relative to the Postfix program directory (pathname is controlled by
-# the program_directory configuration variable). Adding one or more
+# the daemon_directory configuration variable). Adding one or more
# -v options turns on verbose logging for that service; adding a -D
# option enables symbolic debugging (see the debugger_command variable
# in the main.cf configuration file). See individual command man pages
#
debugger_command =
PATH=/usr/bin:/usr/X11R6/bin
- xxgdb $program_directory/$process_name $process_id & sleep 5
+ xxgdb $daemon_directory/$process_name $process_id & sleep 5
# When a pattern matches, what happens next depends on the associated
# action that is specified in the right-hand side of the table:
#
-# REJECT the entire message is rejected.
-# REJECT text.... The text is sent to the originator.
-# IGNORE the header line is silently discarded.
-# WARN the header is logged (not rejected) with a warning message.
-# WARN text... as above, and the text is logged, too.
+# REJECT [optional text...]
+# Reject the entire message. The optional text is sent to the
+# originator and is logged to the maillog file.
+# IGNORE Silently discard the header line.
+# WARN [optional text...]
+# Log the message header and the optional text. This is useful
+# for testing. When the pattern is OK, change the WARN into a
+# REJECT or into a DISCARD.
+# HOLD [optional text...]
+# Place the message on the hold queue. Mail on hold can be
+# inspected with the postcat command, and can be destroyed or
+# taken off hold (i.e. delivered) with the postsuper command.
+# The matched header is logged with the optional text.
+# DISCARD [optional text...]
+# Claim successful delivery and silently discard the message.
+# The matched header is logged with the optional text.
# FILTER transport:nexthop
# after the message is queued, the message is sent through
# a content filter. This requires different cleanup servers
# depends on the associated action that is specified in the right-hand
# side of the table:
#
-# REJECT the entire message is rejected.
-# REJECT text.... The text is sent to the originator.
-# IGNORE the header line is silently discarded.
-# WARN the header is logged (not rejected) with a warning message.
-# WARN text... as above, and the text is logged, too.
+# REJECT [optional text...]
+# Reject the entire message. The optional text is sent to the
+# originator and is logged to the maillog file.
+# IGNORE Silently discard the body line
+# WARN [optional text...]
+# Log the body line and the optional text. This is useful
+# for testing. When the pattern is OK, change the WARN into a
+# REJECT or into a DISCARD.
+# HOLD [optional text...]
+# Place the message on the hold queue. Mail on hold can be
+# inspected with the postcat command, and can be destroyed or
+# taken off hold (i.e. delivered) with the postsuper command.
+# The matched body line is logged with the optional text.
+# DISCARD [optional text...]
+# Claim successful delivery and silently discard the message.
+# The matched body line is logged with the optional text.
# FILTER transport:nexthop
# after the message is queued, the message is sent through
# a content filter. This requires different cleanup servers
#
process_id_directory = pid
-# The program_directory parameter specifies the location of Postfix
+# The daemon_directory parameter specifies the location of Postfix
# support programs and daemons. This directory must be owned by root.
#
-program_directory = /usr/libexec/postfix
+daemon_directory = /usr/libexec/postfix
# The queue_directory specifies the location of the Postfix queue.
# This is also the root directory of Postfix daemons that run chrooted.
-#
+#
# Sample pcre (PERL-compatible regular expression) map file for
# mail body filtering. See pcre_table(5) for syntax description.
#
# info).
#
# The second field is the "replacement" string - the text
-# returned by the match.
+# returned by the match.
#
-# REJECT The entire message is rejected.
-# REJECT text.... The text is sent to the originator.
-# IGNORE The line is silently discarded.
-# WARN The line is logged (not rejected) with a warning.
-# WARN text.... As above, and the text is logged, too.
+# REJECT [optional text...]
+# Reject the entire message. The optional text is sent to
+# the originator and is logged to the maillog file.
+# IGNORE Silently discard the body line.
+# WARN [optional text...]
+# Log the body line and the optional text. This is
+# useful for testing. When the pattern is OK, change the
+# WARN into a REJECT or into a DISCARD.
+# HOLD [optional text...]
+# Place the message on the hold queue. Mail on hold can
+# be inspected with the postcat command, and can be
+# destroyed or taken off hold (i.e. delivered) with the
+# postsuper command. The matched body line is logged
+# together with the optional text.
+# DISCARD [optional text...]
+# Claim successful delivery and silently discard the
+# message. The matched body line is logged together
+# with the optional text.
# FILTER transport:nexthop
# After the message is queued, send the entire
# message through a content filter. This
# The second field is the "replacement" string - the text
# returned by the match.
#
-# REJECT The entire message is rejected.
-# REJECT text.... The text is sent to the originator.
-# IGNORE The header line is silently discarded.
-# WARN The header is logged (not rejected) with a warning.
-# WARN text.... As above, and the text is logged, too.
-# FILTER transport:nexthop
-# After the message is queued, send the entire
-# message through a content filter. This
-# requires different cleanup servers before
-# and after the filter, with header/body
-# checks turned off in the second cleanup
-# server. More information about content filters
-# is in the Postfix FILTER_README file.
+# REJECT [optional text...]
+# Reject the entire message. The optional text is sent to
+# the originator and is logged to the maillog file.
+# IGNORE Silently ignore the message header.
+# WARN [optional text...]
+# Log the message header and the optional text. This is
+# useful for testing. When the pattern is OK, change the
+# WARN into a REJECT or into a DISCARD.
+# HOLD [optional text...]
+# Place the message on the hold queue. Mail on hold can
+# be inspected with the postcat command, and can be
+# destroyed or taken off hold (i.e. delivered) with the
+# postsuper command. The matched header is logged
+# together with the optional text.
+# DISCARD [optional text...]
+# Claim successful delivery and silently discard the
+# message. The matched header is logged together with
+# the optional text.
+# FILTER transport:nexthop
+# After the message is queued, send the entire
+# message through a content filter. This
+# requires different cleanup servers before
+# and after the filter, with header/body
+# checks turned off in the second cleanup
+# server. More information about content filters
+# is in the Postfix FILTER_README file.
#
# Substitution of sub-strings from the matched expression is
# possible using the conventional perl syntax. The macros in the
# terminating processing of the ruleset.
#
# The result is one of the following:
-# REJECT The entire message is rejected.
-# REJECT text.... The text is sent to the originator.
-# IGNORE The header line is silently discarded.
-# WARN The header is logged (not rejected) with a warning.
-# WARN text.... As above, and the text is logged, too.
-# FILTER transport:nexthop
-# After the message is queued, send the entire
-# message through a content filter. This requires
-# different cleanup servers before and after the
-# filter, with header/body checks turned off in
-# the second cleanup server. More information about
-# content filters is in the Postfix FILTER_README file.
+# REJECT [optional text...]
+# Reject the entire message. The optional text is sent to the
+# originator and is logged to the maillog file.
+# IGNORE Silently ignore the body line.
+# WARN [optional text...]
+# Log the body line and the optional text. This is useful
+# for testing. When the pattern is OK, change the WARN into a
+# REJECT or into a DISCARD.
+# HOLD [optional text...]
+# Place the message on the hold queue. Mail on hold can be
+# inspected with the postcat command, and can be destroyed or
+# taken off hold (i.e. delivered) with the postsuper command.
+# The matched body line is logged together with the optional text.
+# DISCARD [optional text...]
+# Claim successful delivery and silently discard the message.
+# The matched body line is logged together with the optional text.
+# FILTER transport:nexthop
+# After the message is queued, send the entire message through
+# a content filter. This requires different cleanup servers
+# before and after the filter, with header/body checks turned
+# off in the second cleanup server.
# Skip over base 64 encoded blocks. This saves lots of CPU cycles.
# Expressions by Liviu Daia. Amended by Victor Duchovni.
# terminating processing of the ruleset.
#
# The result is one of the following:
-# REJECT the entire message is rejected.
-# REJECT text.... The text is sent to the originator.
-# IGNORE the header line is silently discarded.
-# WARN the header is logged (not rejected) with a warning.
-# WARN text... As above, and the text is logged, too.
-# FILTER transport:nexthop
-# After the message is queued, send the entire
-# message through a content filter. This requires
-# different cleanup servers before and after the
-# filter, with header/body checks turned off in
-# the second cleanup server. More information about
-# content filters is in the Postfix FILTER_README file.
+# REJECT [optional text...]
+# Reject the entire message. The optional text is sent to the
+# originator and is logged to the maillog file.
+# IGNORE Silently discard the message header.
+# WARN [optional text...]
+# Log the message header and the optional text. This is useful
+# for testing. When the pattern is OK, change the WARN into a
+# REJECT or into a DISCARD.
+# HOLD [optional text...]
+# Place the message on the hold queue. Mail on hold can be
+# inspected with the postcat command, and can be destroyed or
+# taken off hold (i.e. delivered) with the postsuper command.
+# The matched header is logged together with the optional text.
+# DISCARD [optional text...]
+# Claim successful delivery and silently discard the message.
+# The matched header is logged together with the optional text.
+# FILTER transport:nexthop
+# After the message is queued, send the entire message through
+# a content filter. This requires different cleanup servers
+# before and after the filter, with header/body checks turned
+# off in the second cleanup server.
/^Subject: Make Money Fast/ REJECT
/^To: friend@public.com/ REJECT
<b>OK</b> Accept the address etc. that matches the pattern.
+ <b>HOLD</b> Place the message on the <b>hold</b> queue, where it will
+ sit until someone either deletes it or releases it
+ for delivery. Mail that is placed on hold can be
+ examined with the <a href="postcat.1.html"><b>postcat</b>(1)</a> command, and can be
+ destroyed or released with the <a href="postsuper.1.html"><b>postsuper</b>(1)</a> com-
+ mand.
+
+ <b>DISCARD</b>
+ Claim successful delivery and silently discard the
+ message.
+
<i>all-numerical</i>
An all-numerical result is treated as OK. This for-
mat is generated by address-based relay authoriza-
<dl>
-<dt>REJECT <dd> Reject the message, and log the header.
+<dt>REJECT <dd>
-<dt>REJECT text... <dd> As above, and also send the text to
-the originator.
+<dt>REJECT text... <dd>
+
+Reject the message, log the header and the optional text,
+and send the optional text to the originator.
<dt>IGNORE <dd> Delete the header from the message.
-<dt>HOLD <dd> Place the message on the <b>hold</b> queue. Mail on
-hold can be inspected with the <a href="postcat.1.html">postcat</a>
-command, and can be destroyed or taken off hold with the <a
-href="postsuper.1.html">postsuper</a> command.
+<dt>WARN <dd>
+
+<dt>WARN text... <dd>
+
+Log (but do not reject) the header with a warning, and log the
+optional text.
+
+<dt>HOLD <dd>
-<dt>WARN <dd> Log (but do not reject) the header with a warning.
+<dt>HOLD text... <dd>
-<dt>WARN text... <dd> As above, and also log the text.
+Place the message on the <b>hold</b> queue. Mail on hold can be
+inspected with the <a href="postcat.1.html">postcat</a> command,
+and can be destroyed or taken off hold with the <a
+href="postsuper.1.html">postsuper</a> command.
+The optional text is logged together with the matched text.
+
+<dt>DISCARD <dd>
+
+<dt>DISCARD text... <dd>
+
+Claim successful delivery and silently discard the message.
+The optional text is logged together with the matched text.
<dt>FILTER <i>transport</i>:<i>nexthop</i> <dd>
After the message is queued, send the entire message through
<dl>
-<dt>REJECT <dd> Reject the message, and log the matched line.
+<dt>REJECT <dd>
+
+<dt>REJECT text... <dd>
+
+Reject the message, log the body line and the optional text,
+and send the optional text to the originator.
-<dt>REJECT text... <dd> As above, and also send the text to
-the originator.
+<dt>WARN <dd>
+
+<dt>WARN text... <dd>
+
+Log (but do not reject) the body line with a warning, and log the
+optional text.
<dt>IGNORE <dd> Delete the matched line from the message.
-<dt>HOLD <dd> Place the message on the <b>hold</b> queue. Mail on
-hold can be inspected with the <a href="postcat.1.html">postcat</a>
-command, and can be destroyed or taken off hold with the <a
+<dt>HOLD <dd>
+
+<dt>HOLD text... <dd>
+
+Place the message on the <b>hold</b> queue. Mail on hold can be
+inspected with the <a href="postcat.1.html">postcat</a> command,
+and can be destroyed or taken off hold with the <a
href="postsuper.1.html">postsuper</a> command.
+The optional text is logged together with the matched text.
+
+<dt>DISCARD <dd>
-<dt>WARN <dd> Log (but do not reject) the matched line with a warning.
+<dt>DISCARD text... <dd>
-<dt>WARN text... <dd> As above, and also log the text.
+Claim successful delivery and silently discard the message.
+The optional text is logged together with the matched text.
<dt>FILTER <i>transport</i>:<i>nexthop</i> <dd>
After the message is queued, send the entire message through
<dt> <i>maptype</i>:<i>mapname</i> <dd> Search the named <a
href="access.5.html">access database</a> for the client hostname, parent
domains, client IP address, or networks obtained by stripping least
-significant octets. Reject the request if the result is <b>REJECT</b>
-or "[<b>45</b>]<i>XX text</i>". Permit the request if the result
-is <b>OK</b> or <b>RELAY</b> or all-numerical. Otherwise, treat the
-result as another list of UCE restrictions. The
-<b>access_map_reject_code</b> parameter specifies the response code for
-<b>REJECT</b> results (default: <b>554</b>).
+significant octets.
+
+<p>
+
+<dl compact>
+
+<dt>REJECT
+<dd>Reject the request. The <b>access_map_reject_code</b> parameter
+specifies the response code (default: <b>554</b>).
+
+<p>
+
+<dt>[<b>45</b>]<i>XX text</i>
+<dd>Reject the request. Send the numerical code and text to the SMTP client.
+
+<p>
+
+<dt>OK
+<dt>RELAY
+<dt>all-numerical
+<dd>Permit the request.
+
+<p>
+
+<dt>HOLD
+<dd> Place the message on the <b>hold</b> queue. Mail on hold can
+be inspected with the <a href="postcat.1.html">postcat</a> command,
+and can be destroyed or taken off hold with the <a
+href="postsuper.1.html">postsuper</a> command.
+
+<p>
+
+<dt>DISCARD
+<dd> Claim successful delivery and silently discard the message.
+
+<p>
+
+<dt>Other<dd> Treat the result as another list of UCE restrictions.
+
+</dl>
<p>
error response message is generated.
.IP \fBOK\fR
Accept the address etc. that matches the pattern.
+.IP \fBHOLD\fR
+Place the message on the \fBhold\fR queue, where it will sit
+until someone either deletes it or releases it for delivery.
+Mail that is placed on hold can be examined with the
+\fBpostcat\fR(1) command, and can be destroyed or released with
+the \fBpostsuper\fR(1) command.
+.IP \fBDISCARD\fR
+Claim successful delivery and silently discard the message.
.IP \fIall-numerical\fR
An all-numerical result is treated as OK. This format is
generated by address-based relay authorization schemes.
# Note: lookup of the null sender address is not possible with
# some types of lookup table. By default, Postfix uses \fB<>\fR
# as the lookup key for such addresses. The value is specified with
-# the workaround is to specify \fBsmtpd_null_access_lookup_key\fR
+# the workaround is to specify \fBsmtpd_null_access_lookup_key\fR
# parameter in the Postfix \fBmain.cf\fR file.
# ADDRESS EXTENSION
# .fi
# .IP \fIall-numerical\fR
# An all-numerical result is treated as OK. This format is
# generated by address-based relay authorization schemes.
+# .IP \fBHOLD\fR
+# Place the message on the \fBhold\fR queue, where it will sit
+# until someone either deletes it or releases it for delivery.
+# Mail that is placed on hold can be examined with the
+# \fBpostcat\fR(1) command, and can be destroyed or released with
+# the \fBpostsuper\fR(1) command.
+# .IP \fBDISCARD\fR
+# Claim successful delivery and silently discard the message.
# .IP \fIrestriction...\fR
# Apply the named UCE restriction(s) (\fBpermit\fR, \fBreject\fR,
# \fBreject_unauth_destination\fR, and so on).
* Read the and validate the client request.
*/
if (mail_command_server(client,
- ATTR_TYPE_NUM, MAIL_ATTR_FLAGS, &flags,
+ ATTR_TYPE_NUM, MAIL_ATTR_BFLAGS, &flags,
ATTR_TYPE_STR, MAIL_ATTR_QUEUEID, queue_id,
ATTR_TYPE_STR, MAIL_ATTR_RECIP, recipient,
ATTR_TYPE_STR, MAIL_ATTR_WHY, why,
* Read and validate the client request.
*/
if (mail_command_server(client,
- ATTR_TYPE_NUM, MAIL_ATTR_FLAGS, &flags,
+ ATTR_TYPE_NUM, MAIL_ATTR_BFLAGS, &flags,
ATTR_TYPE_STR, MAIL_ATTR_QUEUE, queue_name,
ATTR_TYPE_STR, MAIL_ATTR_QUEUEID, queue_id,
ATTR_TYPE_STR, MAIL_ATTR_ENCODING, encoding,
* Read and validate the client request.
*/
if (mail_command_server(client,
- ATTR_TYPE_NUM, MAIL_ATTR_FLAGS, &flags,
+ ATTR_TYPE_NUM, MAIL_ATTR_BFLAGS, &flags,
ATTR_TYPE_STR, MAIL_ATTR_QUEUE, queue_name,
ATTR_TYPE_STR, MAIL_ATTR_QUEUEID, queue_id,
ATTR_TYPE_STR, MAIL_ATTR_ENCODING, encoding,
* Read and validate the client request.
*/
if (mail_command_server(client,
- ATTR_TYPE_NUM, MAIL_ATTR_FLAGS, &unused_flags,
+ ATTR_TYPE_NUM, MAIL_ATTR_BFLAGS, &unused_flags,
ATTR_TYPE_STR, MAIL_ATTR_QUEUE, queue_name,
ATTR_TYPE_STR, MAIL_ATTR_QUEUEID, queue_id,
ATTR_TYPE_STR, MAIL_ATTR_ENCODING, encoding,
cleanup_api.o: ../../include/bounce.h
cleanup_api.o: ../../include/mail_params.h
cleanup_api.o: ../../include/mail_stream.h
+cleanup_api.o: ../../include/hold_message.h
cleanup_api.o: cleanup.h
cleanup_api.o: ../../include/argv.h
cleanup_api.o: ../../include/nvtable.h
cleanup_message.o: ../../include/attr.h
cleanup_message.o: ../../include/mime_state.h
cleanup_message.o: ../../include/lex_822.h
-cleanup_message.o: ../../include/hold_message.h
cleanup_message.o: cleanup.h
cleanup_message.o: ../../include/maps.h
cleanup_message.o: ../../include/dict.h
state = cleanup_open();
/*
- * Send the queue id to the client. Read client processing options. If we
- * can't read the client processing options we can pretty much forget
- * about the whole operation.
+ * Send the queue id to the client.
*/
attr_print(src, ATTR_FLAG_NONE,
ATTR_TYPE_STR, MAIL_ATTR_QUEUEID, state->queue_id,
ATTR_TYPE_END);
- if (attr_scan(src, ATTR_FLAG_STRICT,
- ATTR_TYPE_NUM, MAIL_ATTR_FLAGS, &flags,
- ATTR_TYPE_END) != 1) {
- state->errs |= CLEANUP_STAT_BAD;
- flags = 0;
- }
- cleanup_control(state, flags);
/*
* XXX Rely on the front-end programs to enforce record size limits.
* our status report.
*/
if (CLEANUP_OUT_OK(state) == 0 && type > 0) {
- if ((state->errs & CLEANUP_STAT_CONT) == 0)
+ if ((state->errs & CLEANUP_STAT_CONT) == 0
+ && (state->flags & CLEANUP_FLAG_DISCARD) == 0)
msg_warn("%s: skipping further client input", state->queue_id);
while (type != REC_TYPE_END
&& (type = rec_get(src, buf, 0)) > 0)
#define CLEANUP_OUT_BUF(s, t, b) \
cleanup_out((s), (t), vstring_str((b)), VSTRING_LEN((b)))
-#define CLEANUP_OUT_OK(s) (((s)->errs & (s)->err_mask) == 0)
+#define CLEANUP_OUT_OK(s) \
+ (!((s)->errs & (s)->err_mask) && !((s)->flags & CLEANUP_FLAG_DISCARD))
/*
* cleanup_envelope.c
/* queue_id result structure member.
/*
/* cleanup_control() processes per-message flags specified by the caller.
-/* These flags control the handling of data errors, and must be set
-/* before processing the first message record.
+/* These flags control the storage of mail and the handling of errors.
+/* It is an error to any change error handling flags in the middle of
+/* a message.
/* .IP CLEANUP_FLAG_BOUNCE
/* The cleanup server is responsible for returning undeliverable
/* mail (too many hops, message too large) to the sender.
#include <bounce.h>
#include <mail_params.h>
#include <mail_stream.h>
+#include <hold_message.h>
/* Application-specific. */
* definition.
*/
if ((state->flags = flags) & CLEANUP_FLAG_BOUNCE) {
+ if (state->err_mask && state->err_mask != CLEANUP_STAT_MASK_INCOMPLETE)
+ msg_fatal("can't set CLEANUP_FLAG_BOUNCE after initializations");
state->err_mask = CLEANUP_STAT_MASK_INCOMPLETE;
} else {
state->err_mask = ~CLEANUP_STAT_MASK_EXTRACT_RCPT;
* If there are no errors, be very picky about queue file write errors
* because we are about to tell the sender that it can throw away its
* copy of the message.
+ *
+ * Optionally, place the message on hold, but only if the message was
+ * received successfully. This involves renaming the queue file before
+ * "finishing" it (or else the queue manager would open it for delivery)
+ * and updating our own idea of the queue file name for error recovery
+ * and for error reporting purposes.
*/
- if (state->errs == 0) {
+ if (state->errs == 0 && (state->flags & CLEANUP_FLAG_DISCARD) == 0) {
+ if ((state->flags & CLEANUP_FLAG_HOLD) != 0) {
+ hold_message(state->temp1, state->queue_name, state->queue_id);
+ junk = cleanup_path;
+ cleanup_path = mystrdup(vstring_str(state->temp1));
+ myfree(junk);
+ vstream_control(state->handle->stream,
+ VSTREAM_CTL_PATH, cleanup_path,
+ VSTREAM_CTL_END);
+ }
state->errs = mail_stream_finish(state->handle, (VSTRING *) 0);
} else {
mail_stream_cleanup(state->handle);
+ if ((state->flags & CLEANUP_FLAG_DISCARD) != 0)
+ state->errs = 0;
}
state->handle = 0;
state->dst = 0;
}
if (REMOVE(cleanup_path))
msg_warn("remove %s: %m", cleanup_path);
+ } else if ((state->flags & CLEANUP_FLAG_DISCARD) != 0) {
+ if (REMOVE(cleanup_path))
+ msg_warn("remove %s: %m", cleanup_path);
}
-
/*
* Make sure that our queue file will not be deleted by the error handler
* AFTER we have taken responsibility for delivery. Better to deliver
return;
}
nvtable_update(state->attr, attr_name, attr_value);
+ } else if (type == REC_TYPE_FLGS) {
+
+ /*
+ * For safety's sake, allow setting flags only. Even this sucks when
+ * people set the CLEANUP_FLAG_BOUNCE flag too late in the game.
+ */
+ cleanup_control(state, state->flags | atol(buf));
} else {
cleanup_out(state, type, buf, len);
}
#include <mail_proto.h>
#include <mime_state.h>
#include <lex_822.h>
-#include <hold_message.h>
/* Application-specific. */
return (CLEANUP_ACT_KEEP);
}
if (STREQUAL(value, "WARN", command_len)) {
- msg_info("%s: warning: %s %.200s; from=<%s> to=<%s>: %s",
+ msg_info("%s: warning: %s %.200s; from=<%s> to=<%s>%s%s",
state->queue_id, context, buf, state->sender,
state->recip ? state->recip : "unknown",
- *optional_text ? optional_text : "content matched");
+ *optional_text ? ": " : "",
+ *optional_text ? optional_text : "");
return (CLEANUP_ACT_KEEP);
}
if (STREQUAL(value, "FILTER", command_len)) {
}
return (CLEANUP_ACT_KEEP);
}
+ if (STREQUAL(value, "DISCARD", command_len)) {
+ msg_info("%s: discard: %s %.200s; from=<%s> to=<%s>%s%s",
+ state->queue_id, context, buf, state->sender,
+ state->recip ? state->recip : "unknown",
+ *optional_text ? ": " : "",
+ *optional_text ? optional_text : "");
+ state->flags |= CLEANUP_FLAG_DISCARD;
+ return (CLEANUP_ACT_KEEP);
+ }
+ if (STREQUAL(value, "HOLD", command_len)) {
+ msg_info("%s: hold: %s %.200s; from=<%s> to=<%s>%s%s",
+ state->queue_id, context, buf, state->sender,
+ state->recip ? state->recip : "unknown",
+ *optional_text ? ": " : "",
+ *optional_text ? optional_text : "");
+ state->flags |= CLEANUP_FLAG_HOLD;
+ return (CLEANUP_ACT_KEEP);
+ }
if (*optional_text)
msg_warn("unexpected text after command in %s map: %s",
map_class, value);
if (STREQUAL(value, "IGNORE", command_len))
return (CLEANUP_ACT_DROP);
- if (STREQUAL(value, "HOLD", command_len)) {
- hold_message(state->queue_name, state->queue_id);
- return (CLEANUP_ACT_KEEP);
- }
if (STREQUAL(value, "OK", command_len))
return (CLEANUP_ACT_KEEP);
if (attr_print(ap->fp, ATTR_FLAG_NONE,
ATTR_TYPE_NUM, MAIL_ATTR_NREQ, command,
- ATTR_TYPE_NUM, MAIL_ATTR_FLAGS, flags,
+ ATTR_TYPE_NUM, MAIL_ATTR_BFLAGS, flags,
ATTR_TYPE_STR, MAIL_ATTR_QUEUE, queue,
ATTR_TYPE_STR, MAIL_ATTR_QUEUEID, id,
ATTR_TYPE_STR, MAIL_ATTR_ENCODING, encoding,
if (attr_print(ap->fp, ATTR_FLAG_NONE,
ATTR_TYPE_NUM, MAIL_ATTR_NREQ, command,
- ATTR_TYPE_NUM, MAIL_ATTR_FLAGS, flags,
+ ATTR_TYPE_NUM, MAIL_ATTR_BFLAGS, flags,
ATTR_TYPE_STR, MAIL_ATTR_QUEUE, queue,
ATTR_TYPE_STR, MAIL_ATTR_QUEUEID, id,
ATTR_TYPE_STR, MAIL_ATTR_ENCODING, encoding,
if (mail_command_client(MAIL_CLASS_PRIVATE, var_soft_bounce ?
var_defer_service : var_bounce_service,
ATTR_TYPE_NUM, MAIL_ATTR_NREQ, BOUNCE_CMD_APPEND,
- ATTR_TYPE_NUM, MAIL_ATTR_FLAGS, flags,
+ ATTR_TYPE_NUM, MAIL_ATTR_BFLAGS, flags,
ATTR_TYPE_STR, MAIL_ATTR_QUEUEID, id,
ATTR_TYPE_STR, MAIL_ATTR_RECIP, recipient,
ATTR_TYPE_STR, MAIL_ATTR_WHY, vstring_str(why),
return (-1);
if (mail_command_client(MAIL_CLASS_PRIVATE, var_bounce_service,
ATTR_TYPE_NUM, MAIL_ATTR_NREQ, BOUNCE_CMD_FLUSH,
- ATTR_TYPE_NUM, MAIL_ATTR_FLAGS, flags,
+ ATTR_TYPE_NUM, MAIL_ATTR_BFLAGS, flags,
ATTR_TYPE_STR, MAIL_ATTR_QUEUE, queue,
ATTR_TYPE_STR, MAIL_ATTR_QUEUEID, id,
ATTR_TYPE_STR, MAIL_ATTR_ENCODING, encoding,
vstring_vsprintf(why, fmt, ap);
if (mail_command_client(MAIL_CLASS_PRIVATE, var_bounce_service,
ATTR_TYPE_NUM, MAIL_ATTR_NREQ, BOUNCE_CMD_ONE,
- ATTR_TYPE_NUM, MAIL_ATTR_FLAGS, flags,
+ ATTR_TYPE_NUM, MAIL_ATTR_BFLAGS, flags,
ATTR_TYPE_STR, MAIL_ATTR_QUEUE, queue,
ATTR_TYPE_STR, MAIL_ATTR_QUEUEID, id,
ATTR_TYPE_STR, MAIL_ATTR_ENCODING, encoding,
*/
#define CLEANUP_FLAG_NONE 0 /* No special features */
#define CLEANUP_FLAG_BOUNCE (1<<0) /* Bounce bad messages */
-#define CLEANUP_FLAG_FILTER (2<<0) /* Enable content filter */
+#define CLEANUP_FLAG_FILTER (1<<1) /* Enable content filter */
+#define CLEANUP_FLAG_HOLD (1<<2) /* Place message on hold */
+#define CLEANUP_FLAG_DISCARD (1<<3) /* Discard message */
/*
* Diagnostics.
vstring_vsprintf(why, fmt, ap);
if (mail_command_client(MAIL_CLASS_PRIVATE, var_defer_service,
ATTR_TYPE_NUM, MAIL_ATTR_NREQ, BOUNCE_CMD_APPEND,
- ATTR_TYPE_NUM, MAIL_ATTR_FLAGS, flags,
+ ATTR_TYPE_NUM, MAIL_ATTR_BFLAGS, flags,
ATTR_TYPE_STR, MAIL_ATTR_QUEUEID, id,
ATTR_TYPE_STR, MAIL_ATTR_RECIP, recipient,
ATTR_TYPE_STR, MAIL_ATTR_WHY, vstring_str(why),
{
if (mail_command_client(MAIL_CLASS_PRIVATE, var_defer_service,
ATTR_TYPE_NUM, MAIL_ATTR_NREQ, BOUNCE_CMD_FLUSH,
- ATTR_TYPE_NUM, MAIL_ATTR_FLAGS, flags,
+ ATTR_TYPE_NUM, MAIL_ATTR_BFLAGS, flags,
ATTR_TYPE_STR, MAIL_ATTR_QUEUE, queue,
ATTR_TYPE_STR, MAIL_ATTR_QUEUEID, id,
ATTR_TYPE_STR, MAIL_ATTR_ENCODING, encoding,
{
if (mail_command_client(MAIL_CLASS_PRIVATE, var_defer_service,
ATTR_TYPE_NUM, MAIL_ATTR_NREQ, BOUNCE_CMD_WARN,
- ATTR_TYPE_NUM, MAIL_ATTR_FLAGS, flags,
+ ATTR_TYPE_NUM, MAIL_ATTR_BFLAGS, flags,
ATTR_TYPE_STR, MAIL_ATTR_QUEUE, queue,
ATTR_TYPE_STR, MAIL_ATTR_QUEUEID, id,
ATTR_TYPE_STR, MAIL_ATTR_SENDER, sender,
int stat;
attr_print(stream, ATTR_FLAG_NONE,
- ATTR_TYPE_NUM, MAIL_ATTR_FLAGS, request->flags,
+ ATTR_TYPE_NUM, MAIL_ATTR_DFLAGS, request->flags,
ATTR_TYPE_STR, MAIL_ATTR_QUEUE, request->queue_name,
ATTR_TYPE_STR, MAIL_ATTR_QUEUEID, request->queue_id,
ATTR_TYPE_LONG, MAIL_ATTR_OFFSET, request->data_offset,
* the conversation when they send bad information.
*/
if (attr_scan(stream, ATTR_FLAG_STRICT | ATTR_FLAG_MORE,
- ATTR_TYPE_NUM, MAIL_ATTR_FLAGS, &request->flags,
+ ATTR_TYPE_NUM, MAIL_ATTR_DFLAGS, &request->flags,
ATTR_TYPE_STR, MAIL_ATTR_QUEUE, queue_name,
ATTR_TYPE_STR, MAIL_ATTR_QUEUEID, queue_id,
ATTR_TYPE_LONG, MAIL_ATTR_OFFSET, &request->data_offset,
/* SYNOPSIS
/* #include <hold_message.h>
/*
-/* void hold_message(queue_name, queue_id)
+/* void hold_message(path_buf, queue_name, queue_id)
+/* VSTRING *path_buf;
/* const char *queue_name;
/* const char *queue_id;
/* DESCRIPTION
/* The \fBhold_message\fR() routine moves the specified
/* queue file to the \fBhold\fR queue, where it will sit
/* until someone either destroys it or releases it.
+/*
+/* Arguments:
+/* .IP path_buf
+/* A null pointer, or storage for the new pathname.
+/* .IP queue_name
+/* Queue name with the message that needs to be placed on hold.
+/* .IP queue_id
+/* Queue file name with the message that needs to be placed on hold.
/* LICENSE
/* .ad
/* .fi
/* hold_message - move message to hold queue */
-void hold_message(const char *queue_name, const char *queue_id)
+void hold_message(VSTRING *path_buf, const char *queue_name,
+ const char *queue_id)
{
VSTRING *old_path = vstring_alloc(100);
- VSTRING *new_path = vstring_alloc(100);
+ VSTRING *new_path = 0;
uid_t saved_uid;
gid_t saved_gid;
set_eugid(var_owner_uid, var_owner_gid);
}
+ /*
+ * Your buffer or mine?
+ */
+ if (path_buf == 0)
+ new_path = path_buf = vstring_alloc(100);
+
/*
* Grr. Don't do stupid things when this function is called multiple
* times. sane_rename() would emit a bogus warning about spurious NFS
* problems.
*/
(void) mail_queue_path(old_path, queue_name, queue_id);
- (void) mail_queue_path(new_path, MAIL_QUEUE_HOLD, queue_id);
+ (void) mail_queue_path(path_buf, MAIL_QUEUE_HOLD, queue_id);
if (access(STR(old_path), F_OK) == 0) {
- if (rename(STR(old_path), STR(new_path)) == 0
- || access(STR(new_path), F_OK) == 0)
- msg_info("%s: placed on hold", queue_id);
- else
+ if (rename(STR(old_path), STR(path_buf)) == 0
+ || (access(STR(old_path), F_OK) < 0
+ && access(STR(path_buf), F_OK) == 0)) {
+ if (msg_verbose)
+ msg_info("%s: placed on hold", queue_id);
+ } else
msg_warn("%s: could not place message on hold: %m", queue_id);
}
* Cleanup.
*/
vstring_free(old_path);
- vstring_free(new_path);
+ if (new_path)
+ vstring_free(new_path);
}
/*
* External interface.
*/
-extern void hold_message(const char *, const char *);
+extern void hold_message(VSTRING *, const char *, const char *);
/* LICENSE
/* .ad
extern char *var_smtpd_sasl_opts;
#define VAR_SMTPD_SASL_REALM "smtpd_sasl_local_domain"
-#define DEF_SMTPD_SASL_REALM "$myhostname"
+#define DEF_SMTPD_SASL_REALM ""
extern char *var_smtpd_sasl_realm;
#define VAR_SMTPD_SND_AUTH_MAPS "smtpd_sender_login_maps"
#define MAIL_ATTR_NREQ "nrequest"
#define MAIL_ATTR_STATUS "status"
-#define MAIL_ATTR_FLAGS "flags"
+#define MAIL_ATTR_BFLAGS "bounce_flags"
+#define MAIL_ATTR_DFLAGS "delivery_flags"
+#define MAIL_ATTR_RFLAGS "resolve_flags"
#define MAIL_ATTR_QUEUE "queue_name"
#define MAIL_ATTR_QUEUEID "queue_id"
#define MAIL_ATTR_SENDER "sender"
/* command. mail_run_background() returns the process id in case
/* of success.
/* CONFIGURATION PARAMETERS
-/* program_directory: directory with Postfix executables;
/* fork_attempts: number of attempts to fork() a process;
/* fork_delay: delay in seconds between fork() attempts.
/* LICENSE
* Patches change the patchlevel and the release date. Snapshots change the
* release date only, unless they include the same bugfix as a patch release.
*/
-#define MAIL_RELEASE_DATE "20020819"
+#define MAIL_RELEASE_DATE "20020821"
#define VAR_MAIL_VERSION "mail_version"
#define DEF_MAIL_VERSION "1.1.11-" MAIL_RELEASE_DATE
*/
if (attr_scan(stream, ATTR_FLAG_STRICT,
ATTR_TYPE_STR, MAIL_ATTR_QUEUEID, id,
- ATTR_TYPE_END) != 1
- || attr_print(stream, ATTR_FLAG_NONE,
- ATTR_TYPE_NUM, MAIL_ATTR_FLAGS, flags,
- ATTR_TYPE_END) != 0)
+ ATTR_TYPE_END) != 1)
msg_fatal("unable to contact the %s service", var_cleanup_service);
/*
* Generate a minimal envelope section. The cleanup service will add a
* size record.
*/
+ rec_fprintf(stream, REC_TYPE_FLGS, "%d", flags);
rec_fprintf(stream, REC_TYPE_TIME, "%ld", (long) now);
rec_fprintf(stream, REC_TYPE_ATTR, "%s=%s",
MAIL_ATTR_ORIGIN, MAIL_ATTR_ORG_LOCAL);
#define REC_TYPE_ORCP 'O' /* original recipient, optional */
#define REC_TYPE_WARN 'W' /* warning message time */
#define REC_TYPE_ATTR 'A' /* named attribute for extensions */
+#define REC_TYPE_FLGS 'f' /* set processing flags */
#define REC_TYPE_MESG 'M' /* start message records */
* allow for the presence of A records in the extracted segment, because it
* can be requested to re-process already queued mail with `postsuper -r'.
*/
-#define REC_TYPE_ENVELOPE "MCTFILSDROWVA"
+#define REC_TYPE_ENVELOPE "MCTFILSDROWVAf"
#define REC_TYPE_CONTENT "XLN"
#define REC_TYPE_EXTRACT "EDROPreAFI"
ATTR_TYPE_STR, MAIL_ATTR_NEXTHOP, reply->nexthop,
ATTR_TYPE_STR, MAIL_ATTR_RECIP, reply->recipient,
- ATTR_TYPE_NUM, MAIL_ATTR_FLAGS, &reply->flags,
+ ATTR_TYPE_NUM, MAIL_ATTR_RFLAGS, &reply->flags,
ATTR_TYPE_END) != 4) {
if (msg_verbose || (errno != EPIPE && errno != ENOENT))
msg_warn("%s: bad read: %m", myname);
info->cleanup = cleanup;
info->queue_id = mystrdup(vstring_str(buffer));
info->posting_time = time((time_t *) 0);
- attr_print(cleanup, ATTR_FLAG_NONE,
- ATTR_TYPE_NUM, MAIL_ATTR_FLAGS, CLEANUP_FLAG_BOUNCE,
- ATTR_TYPE_END);
/*
* Send initial message envelope information. For bounces, set the
* designated sender: mailing list owner, posting user, whatever.
*/
+ rec_fprintf(cleanup, REC_TYPE_FLGS, "%d", CLEANUP_FLAG_BOUNCE);
rec_fprintf(cleanup, REC_TYPE_TIME, "%ld", (long) info->posting_time);
rec_fputs(cleanup, REC_TYPE_FROM, sender);
*
* Don't come here more than once, whether or not the recipient exists.
*/
- if (been_here(state.dup_filter, "mailbox %s", state.msg_attr.user))
+ if (been_here(state.dup_filter, "mailbox %s", state.msg_attr.local))
return (YES);
/*
nexthop = (cp = strrchr(entry->queue->name, '@')) != 0 && cp[1] ?
cp + 1 : entry->queue->name;
attr_print(stream, ATTR_FLAG_MORE,
- ATTR_TYPE_NUM, MAIL_ATTR_FLAGS, flags,
+ ATTR_TYPE_NUM, MAIL_ATTR_DFLAGS, flags,
ATTR_TYPE_STR, MAIL_ATTR_QUEUE, message->queue_name,
ATTR_TYPE_STR, MAIL_ATTR_QUEUEID, message->queue_id,
ATTR_TYPE_LONG, MAIL_ATTR_OFFSET, message->data_offset,
info->rcpt = mystrdup(vstring_str(buf));
if (type == REC_TYPE_TIME)
continue;
+ if (type == REC_TYPE_FLGS)
+ continue;
if (type == REC_TYPE_ATTR) {
if ((error_text = split_nameval(vstring_str(buf), &attr_name,
&attr_value)) != 0) {
info->id, (int) (now - info->st.st_mtime) / DAY_SECONDS);
}
+ /*
+ * Send our processing options. In case of trouble, request that the
+ * cleanup service bounces its copy of the message. because the original
+ * input file is not readable by the bounce service.
+ */
+#define PICKUP_CLEANUP_FLAGS (CLEANUP_FLAG_BOUNCE | CLEANUP_FLAG_FILTER)
+
+ rec_fprintf(cleanup, REC_TYPE_FLGS, "%d", PICKUP_CLEANUP_FLAGS);
+
/*
* Make sure the message has a posting-time record.
*/
/*
* Contact the cleanup service and read the queue ID that it has
- * allocated. In case of trouble, request that the cleanup service
- * bounces its copy of the message. because the original input file is
- * not readable by the bounce service.
+ * allocated.
*
* The actual message copying code is in a separate routine, so that it is
* easier to implement the many possible error exits without forgetting
* to close files, or to release memory.
*/
-#define PICKUP_CLEANUP_FLAGS (CLEANUP_FLAG_BOUNCE | CLEANUP_FLAG_FILTER)
cleanup = mail_connect_wait(MAIL_CLASS_PUBLIC, var_cleanup_service);
if (attr_scan(cleanup, ATTR_FLAG_STRICT,
ATTR_TYPE_STR, MAIL_ATTR_QUEUEID, buf,
- ATTR_TYPE_END) != 1
- || attr_print(cleanup, ATTR_FLAG_NONE,
- ATTR_TYPE_NUM, MAIL_ATTR_FLAGS, PICKUP_CLEANUP_FLAGS,
- ATTR_TYPE_END) != 0) {
+ ATTR_TYPE_END) != 1) {
status = KEEP_MESSAGE_FILE;
} else {
info->id = mystrdup(vstring_str(buf));
*
* If something goes wrong, slurp up the input before responding to the
* client, otherwise the client will give up after detecting SIGPIPE.
+ *
+ * XXX Need to add REC_TYPE_ATTR filtering code before we can talk directly
+ * to the cleanup daemon.
*/
vstream_control(VSTREAM_IN, VSTREAM_CTL_PATH, "stdin", VSTREAM_CTL_END);
buf = vstring_alloc(100);
}
if (rec_type == REC_TYPE_ERROR)
msg_fatal("uid=%ld: malformed input", (long) uid);
- if (rec_type == REC_TYPE_TIME)
- rec_fprintf(dst->stream, REC_TYPE_TIME, "%ld",
- (long) time((time_t *) 0));
if (strchr(*expected, rec_type) == 0)
msg_fatal("uid=%ld: unexpected record type: %d", (long) uid, rec_type);
if (rec_type == **expected)
expected++;
+ if (rec_type == REC_TYPE_TIME) {
+ rec_fprintf(dst->stream, REC_TYPE_TIME, "%ld",
+ (long) time((time_t *) 0));
+ continue;
+ }
+ if (rec_type == REC_TYPE_FLGS)
+ continue;
if (REC_PUT_BUF(dst->stream, rec_type, buf) < 0) {
while ((rec_type = rec_get(VSTREAM_IN, buf, var_line_limit)) > 0
&& rec_type != REC_TYPE_END)
nexthop = (cp = strrchr(entry->queue->name, '@')) != 0 && cp[1] ?
cp + 1 : entry->queue->name;
attr_print(stream, ATTR_FLAG_MORE,
- ATTR_TYPE_NUM, MAIL_ATTR_FLAGS, flags,
+ ATTR_TYPE_NUM, MAIL_ATTR_DFLAGS, flags,
ATTR_TYPE_STR, MAIL_ATTR_QUEUE, message->queue_name,
ATTR_TYPE_STR, MAIL_ATTR_QUEUEID, message->queue_id,
ATTR_TYPE_LONG, MAIL_ATTR_OFFSET, message->data_offset,
* Connect to the cleanup server. Log client name/address with queue ID.
*/
state->dest = mail_stream_service(MAIL_CLASS_PUBLIC, var_cleanup_service);
- if (state->dest == 0
- || attr_print(state->dest->stream, ATTR_FLAG_NONE,
- ATTR_TYPE_NUM, MAIL_ATTR_FLAGS, CLEANUP_FLAG_FILTER,
- ATTR_TYPE_END) != 0)
+ if (state->dest == 0)
msg_fatal("unable to connect to the %s %s service",
MAIL_CLASS_PUBLIC, var_cleanup_service);
state->cleanup = state->dest->stream;
* bloody likely, but present for the sake of consistency with all other
* Postfix points of entrance).
*/
+ rec_fprintf(state->cleanup, REC_TYPE_FLGS, "%d", CLEANUP_FLAG_FILTER);
rec_fprintf(state->cleanup, REC_TYPE_TIME, "%ld", (long) state->time);
if (*var_filter_xport)
rec_fprintf(state->cleanup, REC_TYPE_FILT, "%s", var_filter_xport);
/* .IP \fBmail_owner\fR
/* The owner of the mail queue and of most Postfix processes.
/* .IP \fBcommand_directory\fR
-/* Directory with Postfix support commands (default:
-/* \fB$program_directory\fR).
+/* Directory with Postfix support commands.
/* .IP \fBdaemon_directory\fR
-/* Directory with Postfix daemon programs (default:
-/* \fB$program_directory\fR).
+/* Directory with Postfix daemon programs.
/* .IP \fBqueue_directory\fR
/* Top-level directory of the Postfix queue. This is also the root
/* directory of Postfix daemons that run chrooted.
smtpd_check.o: ../../include/match_parent_style.h
smtpd_check.o: ../../include/strip_addr.h
smtpd_check.o: ../../include/virtual8.h
+smtpd_check.o: ../../include/cleanup_user.h
+smtpd_check.o: ../../include/record.h
+smtpd_check.o: ../../include/rec_type.h
smtpd_check.o: smtpd.h
smtpd_check.o: ../../include/mail_stream.h
smtpd_check.o: smtpd_sasl_glue.h
/* .IP \fBalways_bcc\fR
/* Address to send a copy of each message that enters the system.
/* .IP \fBcommand_directory\fR
-/* Location of Postfix support commands (default:
-/* \fB$program_directory\fR).
+/* Location of Postfix support commands.
/* .IP \fBdebug_peer_level\fR
/* Increment in verbose logging level when a remote host matches a
/* pattern in the \fBdebug_peer_list\fR parameter.
if (SMTPD_STAND_ALONE(state) == 0) {
state->dest = mail_stream_service(MAIL_CLASS_PUBLIC,
var_cleanup_service);
- if (state->dest == 0
- || attr_print(state->dest->stream, ATTR_FLAG_NONE,
- ATTR_TYPE_NUM, MAIL_ATTR_FLAGS, CLEANUP_FLAG_FILTER,
- ATTR_TYPE_END) != 0)
+ if (state->dest == 0)
msg_fatal("unable to connect to the %s %s service",
MAIL_CLASS_PUBLIC, var_cleanup_service);
+ rec_fprintf(state->dest->stream, REC_TYPE_FLGS, "%d",
+ CLEANUP_FLAG_FILTER);
}
/*
#include <match_parent_style.h>
#include <strip_addr.h>
#include <virtual8.h>
+#include <cleanup_user.h>
+#include <record.h>
+#include <rec_type.h>
/* Application-specific. */
#endif
}
+/* log_whatsup - log as much context as we have */
+
+static void log_whatsup(SMTPD_STATE *state, const char *whatsup,
+ const char *text)
+{
+ if (state->recipient && state->sender) {
+ msg_info("%s: %s from %s: %s; from=<%s> to=<%s>",
+ whatsup, state->where, state->namaddr, text,
+ state->sender, state->recipient);
+ } else if (state->recipient) {
+ msg_info("%s: %s from %s: %s; to=<%s>",
+ whatsup, state->where, state->namaddr, text,
+ state->recipient);
+ } else if (state->sender) {
+ msg_info("%s: %s from %s: %s; from=<%s>",
+ whatsup, state->where, state->namaddr, text,
+ state->sender);
+ } else {
+ msg_info("%s: %s from %s: %s",
+ whatsup, state->where, state->namaddr, text);
+ }
+}
+
/* smtpd_check_reject - do the boring things that must be done */
static int smtpd_check_reject(SMTPD_STATE *state, int error_class,
* postmaster notices, this may be the only trace left that service was
* rejected. Print the request, client name/address, and response.
*/
- if (state->recipient && state->sender) {
- msg_info("%s: %s from %s: %s; from=<%s> to=<%s>",
- whatsup, state->where, state->namaddr, STR(error_text),
- state->sender, state->recipient);
- } else if (state->recipient) {
- msg_info("%s: %s from %s: %s; to=<%s>",
- whatsup, state->where, state->namaddr, STR(error_text),
- state->recipient);
- } else if (state->sender) {
- msg_info("%s: %s from %s: %s; from=<%s>",
- whatsup, state->where, state->namaddr, STR(error_text),
- state->sender);
- } else {
- msg_info("%s: %s from %s: %s",
- whatsup, state->where, state->namaddr, STR(error_text));
- }
+ log_whatsup(state, whatsup, STR(error_text));
+
return (warn_if_reject ? 0 : SMTPD_CHECK_REJECT);
}
"%d <%s>: %s rejected: Access denied",
var_access_map_code, reply_name, reply_class));
+ /*
+ * HOLD means deliver later.
+ */
+ if (strcasecmp(value, "HOLD") == 0) {
+ vstring_sprintf(error_text, "<%s>: %s triggers HOLD action",
+ reply_name, reply_class);
+ log_whatsup(state, "hold", STR(error_text));
+ rec_fprintf(state->dest->stream, REC_TYPE_FLGS, "%d",
+ CLEANUP_FLAG_HOLD);
+ }
+
+ /*
+ * DISCARD means silently discard and claim successful delivery.
+ */
+ if (strcasecmp(value, "DISCARD") == 0) {
+ vstring_sprintf(error_text, "<%s>: %s triggers DISCARD action",
+ reply_name, reply_class);
+ log_whatsup(state, "discard", STR(error_text));
+ rec_fprintf(state->dest->stream, REC_TYPE_FLGS, "%d",
+ CLEANUP_FLAG_DISCARD);
+ }
+
/*
* All-numeric result probably means OK - some out-of-band authentication
* mechanism uses this as time stamp.
ATTR_TYPE_STR, MAIL_ATTR_TRANSPORT, STR(channel),
ATTR_TYPE_STR, MAIL_ATTR_NEXTHOP, STR(nexthop),
ATTR_TYPE_STR, MAIL_ATTR_RECIP, STR(nextrcpt),
- ATTR_TYPE_NUM, MAIL_ATTR_FLAGS, flags,
+ ATTR_TYPE_NUM, MAIL_ATTR_RFLAGS, flags,
ATTR_TYPE_END);
if (vstream_fflush(stream) != 0) {
#ifdef HAS_LDAP
- /*
- * Older APIs have weird memory freeing behavior.
- */
-#if !defined(LDAP_API_VERSION) || (LDAP_API_VERSION < 2000)
-#error "Your LDAP version is too old"
-#endif
-
#include <sys/time.h>
#include <stdio.h>
#include <signal.h>
#include <ldap.h>
#include <string.h>
+ /*
+ * Older APIs have weird memory freeing behavior.
+ */
+#if !defined(LDAP_API_VERSION) || (LDAP_API_VERSION < 2000)
+#error "Your LDAP version is too old"
+#endif
+
/* Handle differences between LDAP SDK's constant definitions */
#ifndef LDAP_CONST
#define LDAP_CONST const
{
int rc;
-#if (LDAP_API_VERSION >= 2000)
if (ldap_get_option(ld, LDAP_OPT_ERROR_NUMBER, &rc) != LDAP_OPT_SUCCESS)
rc = LDAP_OTHER;
-#else
- rc = dict_ldap->ld->ld_errno;
-#endif
return rc;
}
static int dict_ldap_set_errno(LDAP * ld, int rc)
{
-#if (LDAP_API_VERSION >= 2000)
(void) ldap_set_option(ld, LDAP_OPT_ERROR_NUMBER, &rc);
-#else
- ld->ld_errno = rc;
-#endif
return rc;
}
* Configure alias dereferencing for this connection. Thanks to Mike
* Mattice for this, and to Hery Rakotoarisoa for the v3 update.
*/
-#if (LDAP_API_VERSION >= 2000)
if (ldap_set_option(dict_ldap->ld, LDAP_OPT_DEREF,
&(dict_ldap->dereference)) != LDAP_OPT_SUCCESS)
msg_warn("%s: Unable to set dereference option.", myname);
-#else
- dict_ldap->ld->ld_deref = dict_ldap->dereference;
-#endif
#if defined(LDAP_OPT_DEBUG_LEVEL) && defined(LBER_OPT_LOG_PRINT_FN)
if (dict_ldap->debuglevel > 0 &&