From eb8dcde50badf578b245f1c171b01da4b5700c12 Mon Sep 17 00:00:00 2001 From: Wietse Venema Date: Mon, 19 May 2003 00:00:00 -0500 Subject: [PATCH] postfix-2.0.9-20030519 --- postfix/HISTORY | 37 +++++++++++++ postfix/README_FILES/ADDRESS_CLASS_README | 65 +++++++++++------------ postfix/README_FILES/FILTER_README | 11 ++-- postfix/README_FILES/SCHEDULER_README | 11 ++-- postfix/README_FILES/VIRTUAL_README | 2 +- postfix/conf/master.cf | 20 +++---- postfix/conf/pcre_table | 2 +- postfix/conf/sample-mime.cf | 2 +- postfix/conf/sample-pcre-access.cf | 2 +- postfix/conf/sample-regexp-access.cf | 4 +- postfix/html/pcre_table.5.html | 2 +- postfix/man/man5/pcre_table.5 | 2 +- postfix/man/man8/cleanup.8 | 2 +- postfix/proto/pcre_table | 2 +- postfix/src/cleanup/cleanup.c | 3 -- postfix/src/cleanup/cleanup_envelope.c | 2 + postfix/src/cleanup/cleanup_message.c | 44 +++++++++++++++ postfix/src/global/cleanup_strerror.c | 1 + postfix/src/global/cleanup_user.h | 9 +++- postfix/src/global/mail_params.h | 5 ++ postfix/src/global/mail_version.h | 2 +- postfix/src/lmtp/lmtp_proto.c | 2 +- postfix/src/lmtp/lmtp_sasl_glue.c | 2 +- postfix/src/local/token.c | 5 ++ postfix/src/proxymap/proxymap.c | 2 +- postfix/src/qmqpd/qmqpd.c | 3 ++ postfix/src/smtpd/smtpd.c | 3 ++ postfix/src/smtpd/smtpd_check.c | 27 ++++++++++ postfix/src/util/sys_defs.h | 1 + postfix/src/util/vstream.c | 12 +++++ 30 files changed, 217 insertions(+), 70 deletions(-) diff --git a/postfix/HISTORY b/postfix/HISTORY index 68140df75..4d4512d4e 100644 --- a/postfix/HISTORY +++ b/postfix/HISTORY @@ -8047,6 +8047,43 @@ Apologies for any names omitted. Patrik Rak's clever queue manager scheduler (nqmgr). Files: conf/sample-scheduler.cf, README_FILES/SCHEDULER_README. +20030429 + + Bugfix: while verifying an address, the LMTP client entered + a forbidden "next" sender state after the last recipient. + Fix by Vladimir Davydoff. File: lmtp/lmtp_proto.c. + + Bugfix: proxymap server did not parse "," as space. + Leandro Santi. File: proxymap/proxymap.c. + +20030502 + + Bugfix: defer delivery after .forward etc. file read error. + File: local/token.c. + +20030503 + + Bugfix: the Postfix LMTP client used the wrong service + name, causing trouble with SASL 2.1.13. Daniel Schales, + Louisiana Tech. File: lmtp/lmtp_sasl_glue.c. + +20030518 + + Workaround: IRIX select() reports that a non-blocking file + descriptor is writable while write() transfers zero bytes. + File: util/vstream.c. + +20030519 + + Feature: new require_{date,from,message_id,received}_header + restriction to reject SMTP mail when some message header + is missing. Only the From: and Date: headers are actually + required by Internet mail standards; the Received: and + Message-ID: headers are optional, but these are often + missing from SPAM email. Files: global/cleanup_user.h, + global/cleanup_strerror.c, smtpd/smtpd_check.c, + cleanup/cleanup_message.c. + Open problems: Low: smtp-source may block when sending large test messages. diff --git a/postfix/README_FILES/ADDRESS_CLASS_README b/postfix/README_FILES/ADDRESS_CLASS_README index 8a77dae12..07658ccba 100644 --- a/postfix/README_FILES/ADDRESS_CLASS_README +++ b/postfix/README_FILES/ADDRESS_CLASS_README @@ -28,43 +28,43 @@ Initially the list of address classes is hard coded, but this is meant to become extensible: ------------------------------------------------------------------- -Class Description +Class Description ------------------------------------------------------------------- -local For UNIX accounts and for traditional /etc/aliases - Domain names are listed in $mydestination (or match the IP - address listed with $inet_interfaces) - Known recipients are listed in $local_recipient_maps (this - information is currently used by the Postfix SMTP server - only; if $local_recipient_maps is empty, the Postfix - SMTP server accepts all recipients) - Default delivery agent: local +local For UNIX accounts and for traditional /etc/aliases + Domain names are listed in $mydestination (or match the IP + address listed with $inet_interfaces) + Known recipients are listed in $local_recipient_maps (this + information is currently used by the Postfix SMTP server + only; if $local_recipient_maps is empty, the Postfix + SMTP server accepts all recipients) + Default delivery agent: local virtual For hosted domains that are aliased to mailboxes in other -alias domains - Known recipients are listed in $virtual_alias_maps (default - is $virtual_maps for Postfix 1.1 compatibility) - Domain names are listed in $virtual_alias_domains (default - is $virtual_alias_maps for Postfix 1.1 compatibility) +alias domains + Known recipients are listed in $virtual_alias_maps (default + is $virtual_maps for Postfix 1.1 compatibility) + Domain names are listed in $virtual_alias_domains (default + is $virtual_alias_maps for Postfix 1.1 compatibility) -virtual For hosted domains with their own mailboxes -mailbox Known recipients are listed in $virtual_mailbox_maps (if - this parameter is empty, the Postfix SMTP server accepts - all recipients for domains listed in $virtual_mailbox_domains) - Domain names are listed in $virtual_mailbox_domains (default - is $virtual_mailbox_maps for Postfix 1.1 compatibility) - Default delivery agent: virtual +virtual For hosted domains with their own mailboxes +mailbox Known recipients are listed in $virtual_mailbox_maps (if + this parameter is empty, the Postfix SMTP server accepts + all recipients for domains listed in $virtual_mailbox_domains) + Domain names are listed in $virtual_mailbox_domains (default + is $virtual_mailbox_maps for Postfix 1.1 compatibility) + Default delivery agent: virtual -relay For remote destinations that list your system as MX host - Domain names are listed in $relay_domains - Known recipients are listed in $relay_recipient_maps (if - this parameter is empty, the Postfix SMTP server accepts - all recipients for domains listed in $relay_domains) - Default delivery agent: relay (clone of default smtp agent) +relay For remote destinations that list your system as MX host + Domain names are listed in $relay_domains + Known recipients are listed in $relay_recipient_maps (if + this parameter is empty, the Postfix SMTP server accepts + all recipients for domains listed in $relay_domains) + Default delivery agent: relay (clone of default smtp agent) -other Restricted to mail from authorized clients - Default delivery agent: smtp - No domain table - No recipient table +other Restricted to mail from authorized clients + Default delivery agent: smtp + No domain table + No recipient table ------------------------------------------------------------------- Incompatibilities with Postfix 1.1 @@ -92,8 +92,7 @@ Incompatibilities with Postfix 1.1 - The local_recipient_maps feature is now turned on by default, so that the Postfix SMTP server rejects mail for unknown local - recipients. This is enabled by default. See the LOCAL_RECIPIENT_README - file hints and tips. + recipients. See the LOCAL_RECIPIENT_README file hints and tips. - Introduction of relay delivery transport in master.cf. This helps to avoid mail delivery scheduling problems on inbound mail relays, diff --git a/postfix/README_FILES/FILTER_README b/postfix/README_FILES/FILTER_README index e59ccfa51..ecdf61d71 100644 --- a/postfix/README_FILES/FILTER_README +++ b/postfix/README_FILES/FILTER_README @@ -236,8 +236,9 @@ program. Note: the localhost port 10025 SMTP server filter should announce itself as "220 localhost...". Postfix aborts delivery when it -connects to an SMTP server that uses the same hostname, because -that normally means you have a mail delivery loop problem. +connects to an SMTP server that uses the same hostname as Postfix +("host greeted me with my own hostname"), because that +normally means you have a mail delivery loop problem. The example here assumes that the /some/where/filter command is a PERL script. PERL has modules that make talking SMTP easy. The @@ -280,9 +281,9 @@ mail. The "-o local_recipient_maps=" and "-o relay_recipient_maps=" avoid unnecessary table lookups. -The "-o myhostname=localhost.domain.tld" avoids a possible problem -if your content filter is based on a proxy that simply relays SMTP -commands. +The "-o myhostname=localhost.domain.tld" avoids false alarms ("host + greeted me with my own hostname") if your content +filter is based on a proxy that simply relays SMTP commands. The "-o smtpd_xxx_restrictions" and "-o mynetworks=127.0.0.0/8" turn off UCE controls that would only waste time here. diff --git a/postfix/README_FILES/SCHEDULER_README b/postfix/README_FILES/SCHEDULER_README index 457ea9ebe..ebfff51e6 100644 --- a/postfix/README_FILES/SCHEDULER_README +++ b/postfix/README_FILES/SCHEDULER_README @@ -13,10 +13,11 @@ The old Postfix scheduler had several limitations due to unfortunate choices in its design. 1 - Round-robin selection by destination for mail that is delivered - via the same message delivery transport. That strategy broke - down when one single destination (say, inbound mail) had to - compete with multiple other destinations (say, outbound mail). - The poor suffering destination would be selected only + via the same message delivery transport. The round-robin strategy + was chosen with the intention to prevent a single (destination) + site from using up too many mail delivery resources. However, + that strategy penalized inbound mail on bi-directional gateways. + The poor suffering inbound destination would be selected only 1/number-of-destinations of the time, even when it had more mail than other destinations, and thus mail could be delayed. @@ -62,7 +63,7 @@ However, even from programmer's point of view, there is nothing more to add to the message scheduling idea itself. There are few things which make it look more complicated than it is, but the algorithm is the same as the user percieves it. The summary of the -changes from the user's view: +differences of the programmer's view from the user's view are: 1) Simplification of terms for users: The user knows about messages and recipients. The program itself works with jobs (one message is diff --git a/postfix/README_FILES/VIRTUAL_README b/postfix/README_FILES/VIRTUAL_README index d4c9ab19c..5c9df7613 100644 --- a/postfix/README_FILES/VIRTUAL_README +++ b/postfix/README_FILES/VIRTUAL_README @@ -68,7 +68,7 @@ virtual_mailbox_domains Specifies the list of domains that should be delivered to the $virtual_transport delivery agent (default: virtual). As of - version 1.2, Postfix is smart enough that you don't have to + version 2.0, Postfix is smart enough that you don't have to list every virtual domain in a Postfix transport map. virtual_mailbox_maps diff --git a/postfix/conf/master.cf b/postfix/conf/master.cf index a8f973721..141866760 100644 --- a/postfix/conf/master.cf +++ b/postfix/conf/master.cf @@ -1,8 +1,14 @@ # -# Postfix master process configuration file. Each line describes how -# a mailer component program should be run. The fields that make up -# each line are described below. A "-" field value requests that a -# default value be used for that field. +# Postfix master process configuration file. Each logical line +# describes how a Postfix daemon program should be run. +# +# A logical line starts with non-whitespace, non-comment text. +# Empty lines and whitespace-only lines are ignored, as are comment +# lines whose first non-whitespace character is a `#'. +# A line that starts with whitespace continues a logical line. +# +# The fields that make up each line are described below. A "-" field +# value requests that a default value be used for that field. # # Service: any name that is valid for the specified transport type # (the next field). With INET transports, a service is specified as @@ -59,12 +65,6 @@ # SPECIFY ONLY PROGRAMS THAT ARE WRITTEN TO RUN AS POSTFIX DAEMONS. # ALL DAEMONS SPECIFIED HERE MUST SPEAK A POSTFIX-INTERNAL PROTOCOL. # -# DO NOT CHANGE THE ZERO PROCESS LIMIT FOR CLEANUP/BOUNCE/DEFER OR -# POSTFIX WILL BECOME STUCK UP UNDER HEAVY LOAD -# -# DO NOT CHANGE THE ONE PROCESS LIMIT FOR PICKUP/QMGR OR POSTFIX WILL -# DELIVER MAIL MULTIPLE TIMES. -# # DO NOT SHARE THE POSTFIX QUEUE BETWEEN MULTIPLE POSTFIX INSTANCES. # # ========================================================================== diff --git a/postfix/conf/pcre_table b/postfix/conf/pcre_table index c8db65bac..ad5bd0bc9 100644 --- a/postfix/conf/pcre_table +++ b/postfix/conf/pcre_table @@ -135,7 +135,7 @@ # # EXAMPLE SMTPD ACCESS MAP # # Protect your outgoing majordomo exploders -# /^(?!owner-)(.*)-outgoing@/ 550 Use ${1}@${2} instead +# /^(?!owner-)(.*)-outgoing@(.*)/ 550 Use ${1}@${2} instead # # # Bounce friend@whatever, except when whatever is our domain (you would # # be better just bouncing all friend@ mail - this is just an example). diff --git a/postfix/conf/sample-mime.cf b/postfix/conf/sample-mime.cf index 67aa22800..ac4d9f241 100644 --- a/postfix/conf/sample-mime.cf +++ b/postfix/conf/sample-mime.cf @@ -66,4 +66,4 @@ strict_8bitmime = no # # This blocks mail from poorly written mail software. # -strict_mime_domain_encoding = no +strict_mime_encoding_domain = no diff --git a/postfix/conf/sample-pcre-access.cf b/postfix/conf/sample-pcre-access.cf index c9735698f..03aa27a8c 100644 --- a/postfix/conf/sample-pcre-access.cf +++ b/postfix/conf/sample-pcre-access.cf @@ -45,7 +45,7 @@ # Protect your outgoing majordomo exploders # -/^(?!owner-)(.*)-outgoing@/ 550 Use ${1}@${2} instead +/^(?!owner-)(.*)-outgoing@(.*)/ 550 Use ${1}@${2} instead # Bounce friend@whatever, except when whatever is our domain (you would diff --git a/postfix/conf/sample-regexp-access.cf b/postfix/conf/sample-regexp-access.cf index 6d6d1c27e..10df2529d 100644 --- a/postfix/conf/sample-regexp-access.cf +++ b/postfix/conf/sample-regexp-access.cf @@ -30,4 +30,6 @@ /^postmaster@/ OK # Protect your outgoing majordomo exploders -/^(.*)-outgoing@(.*)$/!/^owner-.*/ 550 Use ${1}@${2} instead +if !/^owner-.*/ +/^(.*)-outgoing@(.*)$/ 550 Use ${1}@${2} instead +endif diff --git a/postfix/html/pcre_table.5.html b/postfix/html/pcre_table.5.html index 31da45f43..6be1fd8c7 100644 --- a/postfix/html/pcre_table.5.html +++ b/postfix/html/pcre_table.5.html @@ -136,7 +136,7 @@ PCRE_TABLE(5) PCRE_TABLE(5) EXAMPLE SMTPD ACCESS MAP # Protect your outgoing majordomo exploders - /^(?!owner-)(.*)-outgoing@/ 550 Use ${1}@${2} instead + /^(?!owner-)(.*)-outgoing@(.*)/ 550 Use ${1}@${2} instead # Bounce friend@whatever, except when whatever is our domain (you would # be better just bouncing all friend@ mail - this is just an example). diff --git a/postfix/man/man5/pcre_table.5 b/postfix/man/man5/pcre_table.5 index 6293ed4a8..7fcedcb88 100644 --- a/postfix/man/man5/pcre_table.5 +++ b/postfix/man/man5/pcre_table.5 @@ -119,7 +119,7 @@ or $(n) if they aren't followed by whitespace. .na .nf # Protect your outgoing majordomo exploders -/^(?!owner-)(.*)-outgoing@/ 550 Use ${1}@${2} instead +/^(?!owner-)(.*)-outgoing@(.*)/ 550 Use ${1}@${2} instead # Bounce friend@whatever, except when whatever is our domain (you would # be better just bouncing all friend@ mail - this is just an example). diff --git a/postfix/man/man8/cleanup.8 b/postfix/man/man8/cleanup.8 index fdadfa4a8..67420bea3 100644 --- a/postfix/man/man8/cleanup.8 +++ b/postfix/man/man8/cleanup.8 @@ -121,7 +121,7 @@ this also breaks majordomo approval requests when the included request contains valid 8-bit MIME mail, and it breaks bounces from mailers that do not properly encapsulate 8-bit content (for example, bounces from qmail or from old versions of Postfix). -.IP \fBstrict_mime_domain_encoding\fR +.IP \fBstrict_mime_encoding_domain\fR Reject mail with invalid \fBContent-Transfer-Encoding:\fR information for message/* or multipart/*. This blocks mail from poorly written software. diff --git a/postfix/proto/pcre_table b/postfix/proto/pcre_table index c8512c70c..eab2ebbee 100644 --- a/postfix/proto/pcre_table +++ b/postfix/proto/pcre_table @@ -111,7 +111,7 @@ # or $(n) if they aren't followed by whitespace. # EXAMPLE SMTPD ACCESS MAP # # Protect your outgoing majordomo exploders -# /^(?!owner-)(.*)-outgoing@/ 550 Use ${1}@${2} instead +# /^(?!owner-)(.*)-outgoing@(.*)/ 550 Use ${1}@${2} instead # # # Bounce friend@whatever, except when whatever is our domain (you would # # be better just bouncing all friend@ mail - this is just an example). diff --git a/postfix/src/cleanup/cleanup.c b/postfix/src/cleanup/cleanup.c index 2b19a902e..1e988f22e 100644 --- a/postfix/src/cleanup/cleanup.c +++ b/postfix/src/cleanup/cleanup.c @@ -277,9 +277,6 @@ static void cleanup_service(VSTREAM *src, char *unused_service, char **argv) * our status report. */ if (CLEANUP_OUT_OK(state) == 0 && type > 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) /* void */ ; diff --git a/postfix/src/cleanup/cleanup_envelope.c b/postfix/src/cleanup/cleanup_envelope.c index 226a673d6..b26ccc7ed 100644 --- a/postfix/src/cleanup/cleanup_envelope.c +++ b/postfix/src/cleanup/cleanup_envelope.c @@ -132,6 +132,8 @@ static void cleanup_envelope_process(CLEANUP_STATE *state, int type, return; } if (type == REC_TYPE_FLGS) { + if (msg_verbose) + msg_info("envelope %c %.*s", type, len, buf); extra_flags = atol(buf); if (extra_flags & ~CLEANUP_FLAG_MASK_EXTRA) msg_warn("%s: bad extra flags: 0x%x", state->queue_id, extra_flags); diff --git a/postfix/src/cleanup/cleanup_message.c b/postfix/src/cleanup/cleanup_message.c index 72a562703..f77801565 100644 --- a/postfix/src/cleanup/cleanup_message.c +++ b/postfix/src/cleanup/cleanup_message.c @@ -493,6 +493,29 @@ static void cleanup_header_callback(void *context, int header_class, } } +/* cleanup_missing - handle missing message header */ + +static void cleanup_missing(CLEANUP_STATE *state, const char *resent, + const char *header) +{ + const char *attr; + + if ((attr = nvtable_find(state->attr, MAIL_ATTR_ORIGIN)) == 0) + attr = "unknown"; + vstring_sprintf(state->temp1, "%s: reject: missing %s%s header from %s;", + state->queue_id, resent, header, attr); + if (state->sender) + vstring_sprintf_append(state->temp1, " from=<%s>", state->sender); + if (state->recip) + vstring_sprintf_append(state->temp1, " to=<%s>", state->recip); + if ((attr = nvtable_find(state->attr, MAIL_ATTR_PROTO_NAME)) != 0) + vstring_sprintf_append(state->temp1, " proto=%s", attr); + if ((attr = nvtable_find(state->attr, MAIL_ATTR_HELO_NAME)) != 0) + vstring_sprintf_append(state->temp1, " helo=<%s>", attr); + msg_info("%s", vstring_str(state->temp1)); + state->errs |= CLEANUP_STAT_MISS_HDR; +} + /* cleanup_header_done_callback - insert missing message headers */ static void cleanup_header_done_callback(void *context) @@ -502,6 +525,15 @@ static void cleanup_header_done_callback(void *context) struct tm *tp; TOK822 *token; + /* + * Postfix prepends a Received: message header, so we should see two when + * one is required. + */ + if ((state->flags & CLEANUP_FLAG_NEED_RCVD) && state->hop_count < 2) { + cleanup_missing(state, "", "Received"); + return; + } + /* * Add a missing (Resent-)Message-Id: header. The message ID gives the * time in GMT units, plus the local queue ID. @@ -513,6 +545,10 @@ static void cleanup_header_done_callback(void *context) */ if ((state->headers_seen & (1 << (state->resent[0] ? HDR_RESENT_MESSAGE_ID : HDR_MESSAGE_ID))) == 0) { + if (state->flags & CLEANUP_FLAG_NEED_MSGID) { + cleanup_missing(state, state->resent, "Message-Id"); + return; + } tp = gmtime(&state->time); strftime(time_stamp, sizeof(time_stamp), "%Y%m%d%H%M%S", tp); cleanup_out_format(state, REC_TYPE_NORM, "%sMessage-Id: <%s.%s@%s>", @@ -528,6 +564,10 @@ static void cleanup_header_done_callback(void *context) */ if ((state->headers_seen & (1 << (state->resent[0] ? HDR_RESENT_DATE : HDR_DATE))) == 0) { + if (state->flags & CLEANUP_FLAG_NEED_DATE) { + cleanup_missing(state, state->resent, "Date"); + return; + } cleanup_out_format(state, REC_TYPE_NORM, "%sDate: %s", state->resent, mail_date(state->time)); } @@ -537,6 +577,10 @@ static void cleanup_header_done_callback(void *context) */ if ((state->headers_seen & (1 << (state->resent[0] ? HDR_RESENT_FROM : HDR_FROM))) == 0) { + if (state->flags & CLEANUP_FLAG_NEED_FROM) { + cleanup_missing(state, state->resent, "From"); + return; + } quote_822_local(state->temp1, *state->sender ? state->sender : MAIL_ADDR_MAIL_DAEMON); vstring_sprintf(state->temp2, "%sFrom: %s", diff --git a/postfix/src/global/cleanup_strerror.c b/postfix/src/global/cleanup_strerror.c index 489093ed9..e763ce950 100644 --- a/postfix/src/global/cleanup_strerror.c +++ b/postfix/src/global/cleanup_strerror.c @@ -51,6 +51,7 @@ static struct cleanup_stat_map cleanup_stat_map[] = { CLEANUP_STAT_BAD, "Internal protocol error", CLEANUP_STAT_RCPT, "No recipients specified", CLEANUP_STAT_HOPS, "Too many hops", + CLEANUP_STAT_MISS_HDR, "Missing message header", CLEANUP_STAT_SIZE, "Message file too big", CLEANUP_STAT_CONT, "Message content rejected", CLEANUP_STAT_WRITE, "Error writing message file", diff --git a/postfix/src/global/cleanup_user.h b/postfix/src/global/cleanup_user.h index ce4af5851..8c988251b 100644 --- a/postfix/src/global/cleanup_user.h +++ b/postfix/src/global/cleanup_user.h @@ -20,13 +20,19 @@ #define CLEANUP_FLAG_HOLD (1<<2) /* Place message on hold */ #define CLEANUP_FLAG_DISCARD (1<<3) /* Discard message silently */ #define CLEANUP_FLAG_BCC_OK (1<<4) /* Ok to add auto-BCC addresses */ +#define CLEANUP_FLAG_NEED_DATE (1<<5) /* Require (Resent:-)Date: */ +#define CLEANUP_FLAG_NEED_FROM (1<<6) /* Require (Resent:-)From: */ +#define CLEANUP_FLAG_NEED_MSGID (1<<7) /* Require (Resent:-)Message-Id: */ +#define CLEANUP_FLAG_NEED_RCVD (1<<8) /* Require two Received: headers */ /* * These are set on the fly while processing SMTP envelopes or message * content. */ #define CLEANUP_FLAG_MASK_EXTRA \ - (CLEANUP_FLAG_HOLD | CLEANUP_FLAG_DISCARD) + (CLEANUP_FLAG_HOLD | CLEANUP_FLAG_DISCARD | CLEANUP_FLAG_NEED_DATE | \ + CLEANUP_FLAG_NEED_FROM | CLEANUP_FLAG_NEED_MSGID | \ + CLEANUP_FLAG_NEED_RCVD) /* * Diagnostics. @@ -39,6 +45,7 @@ #define CLEANUP_STAT_SIZE (1<<2) /* Message file too big */ #define CLEANUP_STAT_CONT (1<<3) /* Message content rejected */ #define CLEANUP_STAT_HOPS (1<<4) /* Too many hops */ +#define CLEANUP_STAT_MISS_HDR (1<<5) /* Some missing header */ #define CLEANUP_STAT_RCPT (1<<6) /* No recipients found */ /* diff --git a/postfix/src/global/mail_params.h b/postfix/src/global/mail_params.h index 3c8021d5d..4b968416c 100644 --- a/postfix/src/global/mail_params.h +++ b/postfix/src/global/mail_params.h @@ -1337,6 +1337,11 @@ ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\\\]^_`\ abcdefghijklmnopqrstuvwxyz{|}~" extern char *var_smtpd_exp_filter; +#define REQUIRE_DATE_HDR "require_date_header" +#define REQUIRE_FROM_HDR "require_from_header" +#define REQUIRE_MSGID_HDR "require_message_id_header" +#define REQUIRE_RCVD_HDR "require_received_header" + /* * Heuristic to reject unknown local recipients at the SMTP port. */ diff --git a/postfix/src/global/mail_version.h b/postfix/src/global/mail_version.h index 302e68189..744414eff 100644 --- a/postfix/src/global/mail_version.h +++ b/postfix/src/global/mail_version.h @@ -20,7 +20,7 @@ * 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 "20030424" +#define MAIL_RELEASE_DATE "20030519" #define VAR_MAIL_VERSION "mail_version" #define DEF_MAIL_VERSION "2.0.9-" MAIL_RELEASE_DATE diff --git a/postfix/src/lmtp/lmtp_proto.c b/postfix/src/lmtp/lmtp_proto.c index b4afc37d0..e17d7b0aa 100644 --- a/postfix/src/lmtp/lmtp_proto.c +++ b/postfix/src/lmtp/lmtp_proto.c @@ -396,7 +396,7 @@ static int lmtp_loop(LMTP_STATE *state, int send_state, int recv_state) vstring_str(state->scratch)); if ((next_rcpt = send_rcpt + 1) == request->rcpt_list.len) next_state = DEL_REQ_TRACE_ONLY(request->flags) ? - LMTP_STATE_ABORT : LMTP_STATE_DATA; + LMTP_STATE_RSET : LMTP_STATE_DATA; break; /* diff --git a/postfix/src/lmtp/lmtp_sasl_glue.c b/postfix/src/lmtp/lmtp_sasl_glue.c index a53c19f9a..60e622fca 100644 --- a/postfix/src/lmtp/lmtp_sasl_glue.c +++ b/postfix/src/lmtp/lmtp_sasl_glue.c @@ -369,7 +369,7 @@ void lmtp_sasl_start(LMTP_STATE *state) #define NULL_SERVER_ADDR ((char *) 0) #define NULL_CLIENT_ADDR ((char *) 0) - if (SASL_CLIENT_NEW("smtp", state->session->host, + if (SASL_CLIENT_NEW("lmtp", state->session->host, NULL_CLIENT_ADDR, NULL_SERVER_ADDR, state->sasl_callbacks, NULL_SECFLAGS, (sasl_conn_t **) &state->sasl_conn) != SASL_OK) diff --git a/postfix/src/local/token.c b/postfix/src/local/token.c index 1da680c01..7954c39ac 100644 --- a/postfix/src/local/token.c +++ b/postfix/src/local/token.c @@ -98,6 +98,7 @@ #include #include #include +#include /* Application-specific. */ @@ -207,6 +208,10 @@ int deliver_token_stream(LOCAL_STATE state, USER_ATTR usr_attr, break; } } + if (vstream_ferror(fp)) + status = defer_append(BOUNCE_FLAGS(state.request), + BOUNCE_ATTR(state.msg_attr), + "error reading .forward file: %m"); vstring_free(buf); return (status); } diff --git a/postfix/src/proxymap/proxymap.c b/postfix/src/proxymap/proxymap.c index 22d070f3a..83279127c 100644 --- a/postfix/src/proxymap/proxymap.c +++ b/postfix/src/proxymap/proxymap.c @@ -350,7 +350,7 @@ DICT *dict_proxy_open(const char *map, int open_flags, int dict_flags) static void post_jail_init(char *unused_name, char **unused_argv) { - const char *sep = " \t\r\n"; + const char *sep = ", \t\r\n"; char *saved_filter; char *bp; char *type_name; diff --git a/postfix/src/qmqpd/qmqpd.c b/postfix/src/qmqpd/qmqpd.c index 28cbbcd68..2e676001e 100644 --- a/postfix/src/qmqpd/qmqpd.c +++ b/postfix/src/qmqpd/qmqpd.c @@ -482,6 +482,9 @@ static void qmqpd_send_status(QMQPD_STATE *state) } else if ((state->err & CLEANUP_STAT_RCPT) != 0) { qmqpd_reply(state, DO_LOG, QMQPD_STAT_HARD, "Error: no recipients specified"); + } else if ((state->err & CLEANUP_STAT_MISS_HDR) != 0) { + qmqpd_reply(state, DO_LOG, QMQPD_STAT_HARD, + "Error: missing message header"); } else { qmqpd_reply(state, DO_LOG, QMQPD_STAT_RETRY, "Error: internal error %d", state->err); diff --git a/postfix/src/smtpd/smtpd.c b/postfix/src/smtpd/smtpd.c index 96147559d..9c93fd0e3 100644 --- a/postfix/src/smtpd/smtpd.c +++ b/postfix/src/smtpd/smtpd.c @@ -1141,6 +1141,9 @@ static int data_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *unused_argv) } else if ((state->err & CLEANUP_STAT_WRITE) != 0) { state->error_mask |= MAIL_ERROR_RESOURCE; smtpd_chat_reply(state, "451 Error: queue file write error"); + } else if ((state->err & CLEANUP_STAT_MISS_HDR) != 0) { + state->error_mask |= MAIL_ERROR_POLICY; + smtpd_chat_reply(state, "550 Error: missing message header"); } else { state->error_mask |= MAIL_ERROR_SOFTWARE; smtpd_chat_reply(state, "451 Error: internal error %d", state->err); diff --git a/postfix/src/smtpd/smtpd_check.c b/postfix/src/smtpd/smtpd_check.c index f3ef3fe4f..ee56be523 100644 --- a/postfix/src/smtpd/smtpd_check.c +++ b/postfix/src/smtpd/smtpd_check.c @@ -57,6 +57,13 @@ /* Reject, defer or permit the request unconditionally. This is to be used /* at the end of a restriction list in order to make the default /* action explicit. +/* .IP require_date_header +/* .IP require_from_header +/* .IP require_message_id_header +/* .IP require_received_header +/* Reject the message when it does not contain a Date: etc. +/* message header. Only the Date: header is required by mail +/* standards. The other headers are usually added by MTAs. /* .IP reject_unknown_client /* Reject the request when the client hostname could not be found. /* The \fIunknown_client_reject_code\fR configuration parameter @@ -2750,6 +2757,26 @@ static int generic_checks(SMTPD_STATE *state, ARGV *restrictions, DEFER_IF_REJECT2(state, MAIL_ERROR_POLICY, "450 <%s>: %s rejected: defer_if_reject requested", reply_name, reply_class); + } else if (strcasecmp(name, REQUIRE_DATE_HDR) == 0) { +#ifndef TEST + rec_fprintf(state->dest->stream, REC_TYPE_FLGS, "%d", + CLEANUP_FLAG_NEED_DATE); +#endif + } else if (strcasecmp(name, REQUIRE_FROM_HDR) == 0) { +#ifndef TEST + rec_fprintf(state->dest->stream, REC_TYPE_FLGS, "%d", + CLEANUP_FLAG_NEED_FROM); +#endif + } else if (strcasecmp(name, REQUIRE_MSGID_HDR) == 0) { +#ifndef TEST + rec_fprintf(state->dest->stream, REC_TYPE_FLGS, "%d", + CLEANUP_FLAG_NEED_MSGID); +#endif + } else if (strcasecmp(name, REQUIRE_RCVD_HDR) == 0) { +#ifndef TEST + rec_fprintf(state->dest->stream, REC_TYPE_FLGS, "%d", + CLEANUP_FLAG_NEED_RCVD); +#endif } /* diff --git a/postfix/src/util/sys_defs.h b/postfix/src/util/sys_defs.h index e084d5cfb..17120a0c9 100644 --- a/postfix/src/util/sys_defs.h +++ b/postfix/src/util/sys_defs.h @@ -470,6 +470,7 @@ extern int initgroups(const char *, int); #define DBM_NO_TRAILING_NULL /* XXX check */ #define USE_STATVFS #define STATVFS_IN_SYS_STATVFS_H +#define BROKEN_NON_BLOCKING_WRITE_SELECT #endif #if defined(IRIX5) diff --git a/postfix/src/util/vstream.c b/postfix/src/util/vstream.c index 5cff45140..b0176b13a 100644 --- a/postfix/src/util/vstream.c +++ b/postfix/src/util/vstream.c @@ -535,11 +535,23 @@ static int vstream_fflush_some(VSTREAM *stream, int to_flush) * When flushing a buffer, allow for partial writes. These can happen * while talking to a network. Update the cached file seek position, if * any. + * + * XXX Workaround for IRIX brain damage: select() indicates that a pipe is + * writable, but write() transfers zero bytes on non-blocking pipes. This + * means that there is no reasonable way to enforce write timeouts. */ for (data = (char *) bp->data, len = to_flush; len > 0; len -= n, data += n) { if (stream->timeout) stream->iotime = time((time_t *) 0); if ((n = stream->write_fn(stream->fd, data, len, stream->timeout, stream->context)) <= 0) { +#ifdef BROKEN_NON_BLOCKING_WRITE_SELECT + if (n == 0) { + msg_warn("%s: write() transfers 0 bytes on a writable descriptor!", + myname); + sleep(1); + continue; + } +#endif bp->flags |= VSTREAM_FLAG_ERR; if (errno == ETIMEDOUT) bp->flags |= VSTREAM_FLAG_TIMEOUT;