diff --git a/postfix/HISTORY b/postfix/HISTORY index 7ab7c2bd2..73768300a 100644 --- a/postfix/HISTORY +++ b/postfix/HISTORY @@ -5702,8 +5702,23 @@ Apologies for any names omitted. local/maildir.c, local/mailbox.c, local/command.c, pipe/pipe.c, virtual/mailbox.c, virtual/maildir.c. - Bugfix: the bounce daemon broke in case of a non-existing - message queue file. File: bounce/bounce_notify_util.c. + Bugfix: the bounce daemon broke in the unlikely case of a + non-existing queue file. File: bounce/bounce_notify_util.c. + +20011127 + + Feature: added WARN command to header/body_checks files as + proposed by Michael Tokarev. File: cleanup/cleanup_message.c. + + Bugfix: the postdrop program was broken after the change + of Postfix internal protocols. This broke "sendmail -bs" + mail submissions with "secure" maildrop directory. Reported + by Craig Loomis, apo.nmsu.edu. File: postdrop/postdrop.c. + + Feature: a first start at fault injection for testing + unlikely error scenarios (such as corrupt queue files). + Parameter: fault_injection_code, must be left at zero for + production use. Open problems: @@ -5716,6 +5731,9 @@ Open problems: Medium: smtpd access maps don't understand the recipient delimiter setting. + Low: generic showq protocol, to allow for more intelligent + processing than just mailq. Maybe marry this with postsuper. + Low: default domain for appending to unqualified recipients. Low: The $process_id_directory setting is not used anywhere diff --git a/postfix/LMTP_README b/postfix/LMTP_README index 36ea8ea36..d88b72c5a 100644 --- a/postfix/LMTP_README +++ b/postfix/LMTP_README @@ -200,6 +200,10 @@ look something like this: mailbox_transport = lmtp:unix:/var/imap/socket/lmtp +/etc/postfix/master.cf: + + lmtp unix - - n - - lmtp + In this case, the Postfix local delivery agent expands aliases and .forward files, and delegates mailbox delivery to the Cyrus lmtpd server via the socket "/var/imap/socket/lmtp". @@ -228,13 +232,13 @@ thusly: lmtp_sasl_auth_enable = yes lmtp_sasl_password_maps = hash:/etc/postfix/lmtp_sasl_pass +/etc/postfix/lmtp_sasl_pass: + localhost.my.domain username:password + /etc/postfix/master.cf: lmtp unix - - n - - lmtp -/etc/postfix/lmtp_sasl_pass: - localhost.my.domain username:password - Instead of "hash", use the map type of your choice. Some systems use "dbm" instead. Use "postconf -m" to find out what map types are supported. diff --git a/postfix/RELEASE_NOTES b/postfix/RELEASE_NOTES index 88152f1b4..6e8734ad4 100644 --- a/postfix/RELEASE_NOTES +++ b/postfix/RELEASE_NOTES @@ -1,3 +1,14 @@ +Major changes with snapshot-20011127 +==================================== + +New parameter smtpd_noop_commands to specify a list of commands +that the Postfix SMTP server treats as NOOP commands (no syntax +check, no state change). This is a workaround for misbehaving +clients that send unsupported commands such as ONEX. + +New header/body_check result "WARN" to make Postfix log a warning +about a header/body line without rejecting the content. + Major changes with snapshot-20011125 ==================================== diff --git a/postfix/conf/main.cf b/postfix/conf/main.cf index cc39b935b..7bb85611c 100644 --- a/postfix/conf/main.cf +++ b/postfix/conf/main.cf @@ -408,16 +408,23 @@ mail_owner = postfix # The controls listed here are only a very small subset. See the file # sample-smtpd.cf for an elaborate list of anti-UCE controls. -# The header_checks parameter restricts what may appear in message -# headers. This requires that POSIX or PCRE regular expression support -# is built-in. Specify "/^header-name: stuff you do not want/ REJECT" -# in the pattern file. Patterns are case-insensitive by default. Note: -# specify only patterns ending in REJECT (reject entire message) or -# IGNORE (silently discard this header). Patterns ending in OK are -# mostly a waste of cycles. +# The header_checks parameter specifies an optional table with patterns +# that each logical message header is matched against, including +# headers that span multiple physical lines. Patterns are matched +# in the specified order, and the search stops upon the first match. +# When a pattern matches, what happens next depends on the associated +# action that is specified in the right-hand side of the table: # -#header_checks = regexp:/etc/postfix/filename -#header_checks = pcre:/etc/postfix/filename +# 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. +# +# These patterns do not apply to MIME headers in the message body. +# +# See also the body_checks example in the sample-filter.cf file. +# +#header_checks = regexp:/etc/postfix/header_checks # FAST ETRN SERVICE # diff --git a/postfix/conf/sample-filter.cf b/postfix/conf/sample-filter.cf index a52671e13..8b9c96038 100644 --- a/postfix/conf/sample-filter.cf +++ b/postfix/conf/sample-filter.cf @@ -9,16 +9,12 @@ # headers that span multiple physical lines. Patterns are matched # in the specified order, and the search stops upon the first match. # When a pattern matches, what happens next depends on the associated -# action: +# 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. -# -# OK Nothing happens. the message will still be rejected when some -# other header line matches a REJECT pattern. +# WARN the header is logged (not rejected) with a warning message. # # These patterns do not apply to MIME headers in the message body. # @@ -27,19 +23,16 @@ header_checks = regexp:/etc/postfix/header_checks # The body_checks parameter specifies an optional table with patterns # that each physical line in the message body is matched against # (including MIME headers inside the message body - Postfix does not -# recognize multi-line MIME headers). Lines are matched one at a -# time. Long lines are matched in chunks of at most $line_length_limit -# characters. Patterns are matched in the specified order, and the -# search stops upon the first match. When a pattern matches, what -# happens next depends on the associated action: +# recognize multi-line MIME headers in the message body). +# Lines are matched one at a time. Long lines are matched in chunks +# of at most $line_length_limit characters. Patterns are matched in +# the specified order, and the search stops upon the first match. +# 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 body line is silently discarded. -# -# OK Nothing happens. The message will still be rejected when some -# other body line matches a REJECT pattern. +# WARN the body line is logged (not rejected) with a warning message. # body_checks = regexp:/etc/postfix/body_checks diff --git a/postfix/html/uce.html b/postfix/html/uce.html index 663dfe392..902aa6ad2 100644 --- a/postfix/html/uce.html +++ b/postfix/html/uce.html @@ -109,8 +109,22 @@ is allowed in message headers.
Syntax:
Specify a list of zero or more lookup tables. Whenever a header -matches a table, a REJECT result means reject the message, and an -IGNORE result means delete the header from the message. +matches a table, the action depends on the lookup result: + +

+ +

+ +
REJECT
Reject the message, and log the header. + +
REJECT text...
As above, and also send the text to +the originator. + +
IGNORE
Delete the header from the message. + +
WARN
Log (but do not reject) the header with a warning. + +

@@ -133,7 +147,7 @@ mail still to be rejected.

Example (header_checks): -
/^to: *friend@public\.com$/ REJECT +
/^to: *friend@public\.com$/ REJECT

diff --git a/postfix/src/cleanup/cleanup_message.c b/postfix/src/cleanup/cleanup_message.c index 875ebb16b..fca690451 100644 --- a/postfix/src/cleanup/cleanup_message.c +++ b/postfix/src/cleanup/cleanup_message.c @@ -303,6 +303,10 @@ static void cleanup_header(CLEANUP_STATE *state) state->reason); } else if (strcasecmp(value, "IGNORE") == 0) { return; + } else if (strcasecmp(value, "WARN") == 0) { + msg_info("%s: warning: header %.200s; from=<%s> to=<%s>", + state->queue_id, header, state->sender, + state->recip ? state->recip : "unknown"); } } } @@ -583,6 +587,10 @@ static void cleanup_message_body(CLEANUP_STATE *state, int type, char *buf, int state->reason); } else if (strcasecmp(value, "IGNORE") == 0) { return; + } else if (strcasecmp(value, "WARN") == 0) { + msg_info("%s: warning: body %.200s; from=<%s> to=<%s>", + state->queue_id, buf, state->sender, + state->recip ? state->recip : "unknown"); } } } diff --git a/postfix/src/global/deliver_request.h b/postfix/src/global/deliver_request.h index e7cb43356..45c205523 100644 --- a/postfix/src/global/deliver_request.h +++ b/postfix/src/global/deliver_request.h @@ -41,14 +41,21 @@ typedef struct DELIVER_REQUEST { char *hop_status; /* reason if unavailable */ } DELIVER_REQUEST; -#define DEL_STAT_OK (0) /* success including bounced */ -#define DEL_STAT_DEFER (-1) /* deferred */ -#define DEL_STAT_CORRUPT (-1) /* corrupt */ - #define DEL_REQ_FLAG_DEFLT (DEL_REQ_FLAG_SUCCESS | DEL_REQ_FLAG_BOUNCE) #define DEL_REQ_FLAG_SUCCESS (1<<0) /* delete successful recipients */ #define DEL_REQ_FLAG_BOUNCE (1<<1) /* unimplemented */ + /* + * Delivery status. Note that there are only FINAL and DEFER. This is + * because delivery status information can be lost when a delivery agent or + * queue manager process terminates prematurely. The only distinctions we + * can rely on are "final delivery completed" and "everything else". In the + * absence of a definitive statement the queue manager will always have to + * be prepared for all possibilities. + */ +#define DEL_STAT_FINAL 0 /* delivered or bounced */ +#define DEL_STAT_DEFER (-1) /* not delivered or bounced */ + typedef struct VSTREAM _deliver_vstream_; extern DELIVER_REQUEST *deliver_request_read(_deliver_vstream_ *); extern int deliver_request_done(_deliver_vstream_ *, DELIVER_REQUEST *, int); diff --git a/postfix/src/global/mail_copy.c b/postfix/src/global/mail_copy.c index 8156cd88e..c2d328981 100644 --- a/postfix/src/global/mail_copy.c +++ b/postfix/src/global/mail_copy.c @@ -107,8 +107,9 @@ #include "rec_type.h" #include "mail_queue.h" #include "mail_addr.h" -#include "mail_copy.h" #include "mark_corrupt.h" +#include "mail_params.h" +#include "mail_copy.h" /* mail_copy - copy message with extreme prejudice */ @@ -192,6 +193,8 @@ int mail_copy(const char *sender, const char *delivered, prev_type = type; } if (vstream_ferror(dst) == 0) { + if (var_fault_inj_code == 1) + type = 0; if (type != REC_TYPE_XTRA) corrupt_error = mark_corrupt(src); if (prev_type != REC_TYPE_NORM) @@ -217,6 +220,14 @@ int mail_copy(const char *sender, const char *delivered, if ((flags & MAIL_COPY_TOFILE) != 0) write_error |= fsync(vstream_fileno(dst)); #endif + if (var_fault_inj_code == 2) { + read_error = 1; + errno = ENOENT; + } + if (var_fault_inj_code == 3) { + write_error = 1; + errno = ENOENT; + } #ifndef NO_TRUNCATE if ((flags & MAIL_COPY_TOFILE) != 0) if (corrupt_error || read_error || write_error) diff --git a/postfix/src/global/mail_params.c b/postfix/src/global/mail_params.c index 803996ffc..9e517fc92 100644 --- a/postfix/src/global/mail_params.c +++ b/postfix/src/global/mail_params.c @@ -71,6 +71,7 @@ /* char *var_debug_peer_list; /* int var_debug_peer_level; /* int var_in_flow_delay; +/* int var_fault_inj_code; /* /* void mail_params_init() /* DESCRIPTION @@ -194,6 +195,7 @@ char *var_import_environ; char *var_export_environ; char *var_debug_peer_list; int var_debug_peer_level; +int var_fault_inj_code; /* check_myhostname - lookup hostname and validate */ @@ -330,6 +332,7 @@ void mail_params_init() VAR_FORK_TRIES, DEF_FORK_TRIES, &var_fork_tries, 1, 0, VAR_FLOCK_TRIES, DEF_FLOCK_TRIES, &var_flock_tries, 1, 0, VAR_DEBUG_PEER_LEVEL, DEF_DEBUG_PEER_LEVEL, &var_debug_peer_level, 1, 0, + VAR_FAULT_INJ_CODE, DEF_FAULT_INJ_CODE, &var_fault_inj_code, 0, 0, 0, }; static CONFIG_TIME_TABLE time_defaults[] = { diff --git a/postfix/src/global/mail_params.h b/postfix/src/global/mail_params.h index 26248bdf7..30bb8c7d3 100644 --- a/postfix/src/global/mail_params.h +++ b/postfix/src/global/mail_params.h @@ -1346,6 +1346,13 @@ extern char *var_par_dom_match; #define SMTPD_ACCESS_MAPS "smtpd_access_maps" + /* + * Run-time fault injection. + */ +#define VAR_FAULT_INJ_CODE "fault_injection_code" +#define DEF_FAULT_INJ_CODE 0 +extern int var_fault_inj_code; + /* LICENSE /* .ad /* .fi diff --git a/postfix/src/global/mail_version.h b/postfix/src/global/mail_version.h index 9fa31ea5e..928f94824 100644 --- a/postfix/src/global/mail_version.h +++ b/postfix/src/global/mail_version.h @@ -15,7 +15,7 @@ * Version of this program. */ #define VAR_MAIL_VERSION "mail_version" -#define DEF_MAIL_VERSION "Snapshot-20011126" +#define DEF_MAIL_VERSION "Snapshot-20011127" extern char *var_mail_version; /* LICENSE diff --git a/postfix/src/global/mark_corrupt.c b/postfix/src/global/mark_corrupt.c index e27cc1e3b..bcffef8dd 100644 --- a/postfix/src/global/mark_corrupt.c +++ b/postfix/src/global/mark_corrupt.c @@ -73,5 +73,5 @@ int mark_corrupt(VSTREAM *src) if (saved_uid != var_owner_uid) set_eugid(saved_uid, saved_gid); - return (DEL_STAT_CORRUPT); + return (DEL_STAT_DEFER); } diff --git a/postfix/src/local/command.c b/postfix/src/local/command.c index 56e9bace8..8a86ac63a 100644 --- a/postfix/src/local/command.c +++ b/postfix/src/local/command.c @@ -196,7 +196,7 @@ int deliver_command(LOCAL_STATE state, USER_ATTR usr_attr, const char *comma "%s", vstring_str(why)); break; case PIPE_STAT_CORRUPT: - deliver_status = DEL_STAT_CORRUPT; + deliver_status = DEL_STAT_DEFER; break; default: msg_panic("%s: bad status %d", myname, cmd_status); diff --git a/postfix/src/local/file.c b/postfix/src/local/file.c index 3f1f7f1d9..96663d3c4 100644 --- a/postfix/src/local/file.c +++ b/postfix/src/local/file.c @@ -171,7 +171,7 @@ int deliver_file(LOCAL_STATE state, USER_ATTR usr_attr, char *path) * As the mail system, bounce, defer delivery, or report success. */ if (mail_copy_status & MAIL_COPY_STAT_CORRUPT) { - deliver_status = DEL_STAT_CORRUPT; + deliver_status = DEL_STAT_DEFER; } else if (mail_copy_status != 0) { deliver_status = (errno == EAGAIN || errno == ENOSPC || errno == ESTALE ? defer_append : bounce_append) diff --git a/postfix/src/local/mailbox.c b/postfix/src/local/mailbox.c index f92394533..45d24d8d2 100644 --- a/postfix/src/local/mailbox.c +++ b/postfix/src/local/mailbox.c @@ -204,7 +204,7 @@ static int deliver_mailbox_file(LOCAL_STATE state, USER_ATTR usr_attr) * As the mail system, bounce, defer delivery, or report success. */ if (mail_copy_status & MAIL_COPY_STAT_CORRUPT) { - deliver_status = DEL_STAT_CORRUPT; + deliver_status = DEL_STAT_DEFER; } else if (mail_copy_status != 0) { deliver_status = (errno == EAGAIN || errno == ENOSPC || errno == ESTALE ? defer_append : bounce_append) diff --git a/postfix/src/local/maildir.c b/postfix/src/local/maildir.c index 12128cd02..b2ccef3ce 100644 --- a/postfix/src/local/maildir.c +++ b/postfix/src/local/maildir.c @@ -157,7 +157,7 @@ int deliver_maildir(LOCAL_STATE state, USER_ATTR usr_attr, char *path) * As the mail system, bounce or defer delivery. */ if (mail_copy_status & MAIL_COPY_STAT_CORRUPT) { - deliver_status = DEL_STAT_CORRUPT; + deliver_status = DEL_STAT_DEFER; } else if (mail_copy_status != 0) { deliver_status = (errno == ENOSPC || errno == ESTALE ? defer_append : bounce_append) diff --git a/postfix/src/pipe/pipe.c b/postfix/src/pipe/pipe.c index 53cb7363d..9794c697c 100644 --- a/postfix/src/pipe/pipe.c +++ b/postfix/src/pipe/pipe.c @@ -718,7 +718,7 @@ static int eval_command_status(int command_status, char *service, } break; case PIPE_STAT_CORRUPT: - result |= DEL_STAT_CORRUPT; + result |= DEL_STAT_DEFER; break; default: msg_panic("eval_command_status: bad status %d", command_status); diff --git a/postfix/src/postdrop/postdrop.c b/postfix/src/postdrop/postdrop.c index 07475df6b..928f46c41 100644 --- a/postfix/src/postdrop/postdrop.c +++ b/postfix/src/postdrop/postdrop.c @@ -306,6 +306,7 @@ int main(int argc, char **argv) */ attr_print(VSTREAM_OUT, ATTR_FLAG_NONE, ATTR_TYPE_NUM, MAIL_ATTR_STATUS, status, + ATTR_TYPE_STR, MAIL_ATTR_WHY, "", ATTR_TYPE_END); vstream_fflush(VSTREAM_OUT); exit(status); diff --git a/postfix/src/smtpd/smtpd.c b/postfix/src/smtpd/smtpd.c index ca5f0d6c5..eb00514bc 100644 --- a/postfix/src/smtpd/smtpd.c +++ b/postfix/src/smtpd/smtpd.c @@ -69,9 +69,9 @@ /* This parameter uses the same syntax as the right-hand side of /* a Postfix transport table. /* .IP \fBsmtpd_noop_commands\fR -/* List of commands that are treated as NOOP (no operation) commands -/* without any parameter syntax checking. This list overrides built-in -/* command definitions. +/* List of commands that are treated as NOOP (no operation) commands, +/* without any parameter syntax checking and without any state change. +/* This list overrides built-in command definitions. /* .SH "Authentication controls" /* .IP \fBenable_sasl_authentication\fR /* Enable per-session authentication as per RFC 2554 (SASL). diff --git a/postfix/src/virtual/mailbox.c b/postfix/src/virtual/mailbox.c index 4f65f8025..cff9239ec 100644 --- a/postfix/src/virtual/mailbox.c +++ b/postfix/src/virtual/mailbox.c @@ -131,7 +131,7 @@ static int deliver_mailbox_file(LOCAL_STATE state, USER_ATTR usr_attr) * As the mail system, bounce, defer delivery, or report success. */ if (mail_copy_status & MAIL_COPY_STAT_CORRUPT) { - deliver_status = DEL_STAT_CORRUPT; + deliver_status = DEL_STAT_DEFER; } else if (mail_copy_status != 0) { deliver_status = (errno == EDQUOT || errno == EFBIG ? bounce_append : defer_append) diff --git a/postfix/src/virtual/maildir.c b/postfix/src/virtual/maildir.c index 19738c5e4..2db413002 100644 --- a/postfix/src/virtual/maildir.c +++ b/postfix/src/virtual/maildir.c @@ -155,7 +155,7 @@ int deliver_maildir(LOCAL_STATE state, USER_ATTR usr_attr) * location possibly under user control. */ if (mail_copy_status & MAIL_COPY_STAT_CORRUPT) { - deliver_status = DEL_STAT_CORRUPT; + deliver_status = DEL_STAT_DEFER; } else if (mail_copy_status != 0) { deliver_status = (errno == EDQUOT || errno == EFBIG ? bounce_append : defer_append)