at the time that the SMTP client could suffer from a similar
problem.
+20020516
+
+ Updated the FILTER_README file to turn off DNS lookups in
+ the SMTP client that feeds mail into a content filter.
+
20020517
Cleanup: Mailbox-Line: message header labels should be
20020515-21
- Feature: new MIME parser, written from scratch, that recognizes
- the structure of MIME encapsulated mail. MIME header scanning
- now happens in header_checks, and are is faster than
- body_checks could ever be. Thus also eliminates the problem
- with multi-line MIME headers being matched one line at a
- time. Files: global/mime_state.[hc], cleanup/cleanup_message.c.
+ Feature: new MIME parser, written from scratch, that
+ recognizes the structure of MIME encapsulated mail. Influenced
+ by comments from Victor Duchovny. This code can detect but
+ will not fix illegal MIME encapsulations that Liviu Daia
+ expresses concern about. MIME header scanning now happens
+ in header_checks, and is faster than body_checks could ever
+ be. Thus also eliminates the problem with multi-line MIME
+ headers being matched one line at a time. Files:
+ global/mime_state.[hc], cleanup/cleanup_message.c.
20020521-22
the Postfix SMTP client. File: smtp/smtp_proto.c.
Logging: the Postfix SMTP and LMTP clients now report the
- stage of the protocol when it reports a server reply.
+ stage of the protocol when they report a server reply.
File: smtp/smtp_proto.c, lmtp/lmtp_proto.c.
- Bugfix: the SMTP server complained about ignored client
- attributes in mail submitted with "sendmail -bs".
- File: smtpd/smtpd.c.
+ Bugfix: the SMTP server warned about ignored client
+ attributes (introduced in 20020510) in mail submitted with
+ "sendmail -bs". File: smtpd/smtpd.c.
20020525
+ Feature: separation of header checks into header_checks
+ (all primary headers except MIME related headers),
+ mime_header_checks (all MIME headers including MIME headers
+ at the start of messages) and nested_header_checks (headers
+ of attached messages, except MIME related headers).
+
Cleanup: broke out the header value parser from the MIME
- processor so it can be used elsewhere. File:
+ processor so that the code can be reused elsewhere. File:
global/header_token.c.
- Cleanup needs an option to revert to old non-MIME
- aware behavior - this must override the MIME header
- match override.
+ Compatibility: Postfix now recognizes "name :" as a valid
+ message header, but normalizes it to "name:" form or else
+ lots of things would break all over the place. Files:
+ global/is_header.c, global/mime_state.c.
+
+20020526
+
+ Bugfix: the SMTP server now disallows RCPT TO:<"">, just
+ like it disallows RCPT TO:<>. File: smtpd/smtpd.c.
+
+ Feature: disable_mime_input_processing=yes/no controls
+ whether Postfix recognizes (and optionally enforces) MIME
+ formats while receiving mail. Default is NO.
+
+ Feature: disable_mime_output_conversion=yes/no controls
+ whether Postfix will convert 8BITMIME to 7BIT mail when
+ delivering to an SMTP server that does not announce 8BITMIME.
+ Default is NO.
+
+ Feature: strict_8bitmime=yes/no controls whether Postfix
+ rejects 8-bit characters in headers and 7-bit body parts.
+ This blocks mail from poorly written software, as well as
+ mail that is piped into ancient /bin/mail implementations
+ that do not MIME format 8-bit content. Default is NO.
+
+ Feature: strict_mime_encoding_domain=yes/no controls whether
+ Postfix rejects illegal content transfer encodings for
+ multipart/* and message/*. This blocks mail from poorly
+ written software. Default is NO.
Open problems:
filtering software that can receive and deliver mail via SMTP.
You can expect to lose about a factor of two in Postfix performance
-for transit mail (not delivered on the same machine) that arrives
-and leaves via SMTP; and each temporary file created by the content
-filter adds another factor to the performance loss.
+for transit mail that arrives and leaves via SMTP, provided that
+the content filter creates no temporary files. Each temporary file
+created by the content filter adds another factor to the performance
+loss.
We will set up a content filtering program that receives SMTP mail
via localhost port 10025, and that submits SMTP mail back into
#
cleanup2 unix n - n - 0 cleanup
-o header_checks=
+ -o mime_header_checks=
+ -o nested_header_checks=
-o body_checks=
#
# The normal "smtp" delivery agent for contrast with "scan".
date. Snapshots change only the release date, unless they include
the same bugfixes as a patch release.
-Incompatible changes with Postfix snapshot 1.1.10-200205XX
+Incompatible changes with Postfix snapshot 1.1.10-20020526
==========================================================
-Message headers in MIME attachments etc. are now matched by
-header_checks instead of body_checks. Multi-line headers in MIME
-attachments are now properly recognized.
+Message headers in MIME attachments etc. are no longer matched by
+body_checks, one input line at a time. They are now by default
+matched by header_checks, one multi-line header at a time. To get
+the old behavior, specify "disable_mime_input_processing = yes".
+
+Postfix rejects mail if the MIME multipart structure is nested more
+than mime_nesting_limit levels (default: 20) while receiving mail,
+or when Postfix is performing 8BITMIME to 7BIT conversion while
+delivering mail.
+
+Postfix now recognizes "name :" as a valid message header, but
+normalizes it to "name:" for consistency (actually, there is so
+much code in Postfix that would break with "name :" that there
+is little choice, except to not recognize "name :" headers).
+
+Major changes with Postfix snapshot 1.1.10-20020526
+===================================================
+
+Postfix now properly recognizes MIME headers in attachments, which
+is much more efficient than recognizing them via body_checks. In
+fact, Postfix now has three classes of header patterns: header_checks
+(for primary message headers except MIME headers), mime_header_checks
+(for MIME headers), and nested_header_checks (for headers of attached
+email messages except MIME headers). By default, all headers are
+matched with header_checks. To revert to the the old behavior,
+specify "disable_mime_input_processing = yes". More details in
+conf/sample-filter.cf.
+
+The Postfix SMTP client will now convert 8BITMIME mail to 7BIT when
+delivering to an SMTP server that does not announce 8BITMIME support.
+To disable, specify "disable_mime_output_conversion = yes". However,
+this conversion is required by RFC standards.
+
+Postfix can enforce some aspects of the MIME standards while
+receiving mail. Specify "strict_8bitmime = yes" to disallow 8-bit
+characters except where allowed by the MIME standard, and specify
+"strict_mime_encoding_domain = yes" to block mail from poorly
+written mail software. More details in conf/sample-mime.cf.
Incompatible changes with Postfix snapshot 1.1.10-20020514
==========================================================
# WARN the header is logged (not rejected) with a warning message.
# WARN text... as above, and the text is logged, too.
#
-# These patterns do not apply to MIME headers in the message body.
+# By default, these patterns also apply to MIME headers and to the
+# headers of attached messages. With older Postfix versions, MIME and
+# attached message headers were treated as body text.
#
# See also the body_checks example in the sample-filter.cf file.
#
$sample_directory/sample-ldap.cf:f:root:-:644
$sample_directory/sample-lmtp.cf:f:root:-:644
$sample_directory/sample-local.cf:f:root:-:644
+$sample_directory/sample-mime.cf:f:root:-:644
$sample_directory/sample-misc.cf:f:root:-:644
$sample_directory/sample-pcre-access.cf:f:root:-:644
$sample_directory/sample-pcre-body.cf:f:root:-:644
# WARN the header is logged (not rejected) with a warning message.
# WARN text... as above, and the text is logged, too.
#
-# These patterns do not apply to MIME headers in the message body.
+# By default, these patterns apply the primary message headers, to
+# MIME headers, and to the headers of attached messages. With older
+# Postfix versions, MIME and attached message headers were treated
+# as body text.
#
header_checks = regexp:/etc/postfix/header_checks
+# The mime_header_checks specifies an optional table with patterns
+# that each MIME header is matched against. This applies to MIME
+# related headers in message headers, and to the headers that follow
+# multipart boundary strings. Headers may 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:
+#
+# 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.
+#
+# By default, the same patterns are applied as for header_checks.
+#
+mime_header_checks = $header_checks
+
+# The nested_header_checks specifies an optional table with patterns
+# that each attached message header is matched against (except for
+# MIME related headers). Headers may 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:
+#
+# 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.
+#
+# By default, the same patterns are applied as for header_checks.
+#
+nested_header_checks = $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
--- /dev/null
+# DO NOT EDIT THIS FILE. EDIT THE MAIN.CF FILE INSTEAD. THE STUFF
+# HERE JUST SERVES AS AN EXAMPLE.
+#
+# This file contains example settings of Postfix configuration
+# parameters that control MIME processing.
+
+# Specify "yes" to disable special processing of Content-Type: headers
+# while receiving mail. This treats all text after the primary mail
+# headers as message body text, and disables the optional features
+# below that enforce some aspects of MIME standards.
+#
+disable_mime_input_processing = no
+
+# Specify "yes" to disable special processing of Content-Type: headers
+# while delivering mail. This treats all text after the primary mail
+# headers as message body text, and disables 8BITMIME to 7BIT conversion
+# when delivering mail to an SMTP server that does not announce
+# 8BITMIME support.
+#
+disable_mime_output_conversion = no
+
+# Specify the amount of space that will be allocated for MIME multipart
+# boundary strings. The MIME processor is unable to distinguish
+# between boundary strings that are identical in the first
+# $mime_boundary_length_limit characters. The default limit is the
+# input line length limit.
+#
+mime_boundary_length_limit = 2048
+
+# Specify the maximal nesting level of multipart mail that the MIME
+# processor can handle. Refuse mail that is nested deeper while
+# receiving mail, or when converting 8BITMIME to 7BIT while delivering
+# mail.
+#
+mime_nesting_limit = 20
+
+# Specify "yes" to reject mail with 8-bit text in message headers,
+# and with 8-bit text in message bodies that either claim to be 7-bit
+# format or that default to 7-bit format. This optional restriction
+# is enforced while receiving mail.
+#
+# This blocks mail from poorly written mail software. Unfortunately,
+# this also blocks approval requests from Majordomo when the included
+# request contains valid 8-bit MIME mail, and it may block 8-bit mail
+# that is piped into /bin/mail or other MIME challenged software.
+#
+strict_8bitmime = no
+
+# Specify "yes" to reject mail with invalid Content-Transfer-Encoding:
+# information for multipart/* or message/* content (in general, only
+# the unity transformations 7bin, 8bit or binary are allowed at those
+# levels in the message structure). This optional restriction is
+# enforced while receiving mail.
+#
+# This blocks mail from poorly written mail software.
+#
+strict_mime_domain_encoding = no
sages. These filters see logical headers one at a
time, including headers that span multiple lines.
+<b>MIME</b> <b>Processing</b>
+ <b>disable</b><i>_</i><b>mime</b><i>_</i><b>input</b><i>_</i><b>processing</b>
+ While receiving, give no special treatment to <b>Con-</b>
+ <b>tent-Type:</b> message headers; all text after the ini-
+ tial message headers is considered to be part of
+ the message body.
+
+ <b>mime</b><i>_</i><b>boundary</b><i>_</i><b>length</b><i>_</i><b>limit</b>
+ The amount of space that will be allocated for MIME
+ multipart boundary strings. The MIME processor is
+ unable to distinguish between boundary strings that
+ do not differ in the first <b>$mime</b><i>_</i><b>bound-</b>
+ <b>ary</b><i>_</i><b>length</b><i>_</i><b>limit</b> characters.
+
+ <b>mime</b><i>_</i><b>nesting</b><i>_</i><b>limit</b>
+ The maximal nesting level of multipart mail that
+ the MIME processor can handle. Refuse mail that is
+ nested deeper.
+
+ <b>strict</b><i>_</i><b>8bitmime</b>
+ Reject mail with 8-bit text in message headers, and
+ with 8-bit text in content that claims to be 7-bit,
+ or that has no explicit content encoding informa-
+ tion. This blocks mail mail poorly written mail
+ software. Unfortunately, this also breaks majordomo
+ approval requests when the included request con-
+ tains valid 8-bit MIME mail.
+
+ <b>strict</b><i>_</i><b>mime</b><i>_</i><b>domain</b><i>_</i><b>encoding</b>
+ Reject mail with invalid <b>Content-Transfer-Encoding:</b>
+ information for message/* or multipart/*. This
+ blocks mail from poorly written software.
+
<b>Miscellaneous</b>
<b>always</b><i>_</i><b>bcc</b>
- Address to send a copy of each message that enters
+ Address to send a copy of each message that enters
the system.
<b>hopcount</b><i>_</i><b>limit</b>
<b>Address</b> <b>transformations</b>
<b>empty</b><i>_</i><b>address</b><i>_</i><b>recipient</b>
- The destination for undeliverable mail from <>.
- This substitution is done before all other address
+ The destination for undeliverable mail from <>.
+ This substitution is done before all other address
rewriting.
<b>canonical</b><i>_</i><b>maps</b>
header sender addresses.
<b>masquerade</b><i>_</i><b>classes</b>
- List of address classes subject to masquerading:
- zero or more of <b>envelope</b><i>_</i><b>sender</b>, <b>envelope</b><i>_</i><b>recipi-</b>
+ List of address classes subject to masquerading:
+ zero or more of <b>envelope</b><i>_</i><b>sender</b>, <b>envelope</b><i>_</i><b>recipi-</b>
<b>ent</b>, <b>header</b><i>_</i><b>sender</b>, <b>header</b><i>_</i><b>recipient</b>.
<b>masquerade</b><i>_</i><b>domains</b>
- List of domains that hide their subdomain struc-
+ List of domains that hide their subdomain struc-
ture.
<b>masquerade</b><i>_</i><b>exceptions</b>
- List of user names that are not subject to address
+ List of user names that are not subject to address
masquerading.
<b>virtual</b><i>_</i><b>maps</b>
<b>Resource</b> <b>controls</b>
<b>duplicate</b><i>_</i><b>filter</b><i>_</i><b>limit</b>
- Limit the number of envelope recipients that are
+ Limit the number of envelope recipients that are
remembered.
<b>header</b><i>_</i><b>size</b><i>_</i><b>limit</b>
<b>in</b><i>_</i><b>flow</b><i>_</i><b>delay</b>
Amount of time to pause before accepting a message,
- when the message arrival rate exceeds the message
+ when the message arrival rate exceeds the message
delivery rate.
<b>extract</b><i>_</i><b>recipient</b><i>_</i><b>limit</b>
- Limit the amount of recipients extracted from mes-
+ Limit the amount of recipients extracted from mes-
sage headers.
<b>SEE</b> <b>ALSO</b>
/etc/postfix/virtual*, virtual mapping table
<b>LICENSE</b>
- The Secure Mailer license must be distributed with this
+ The Secure Mailer license must be distributed with this
software.
<b>AUTHOR(S)</b>
PIX firewall <CR><LF>.<CR><LF> bug workaround is
turned on.
+<b>MIME</b> <b>Conversion</b>
+ <b>disable</b><i>_</i><b>mime</b><i>_</i><b>output</b><i>_</i><b>conversion</b>
+ Disable the conversion of 8BITMIME format to 7BIT
+ format when the remote system does not advertise
+ 8BITMIME support.
+
+ <b>mime</b><i>_</i><b>boundary</b><i>_</i><b>length</b><i>_</i><b>limit</b>
+ The amount of space that will be allocated for MIME
+ multipart boundary strings. The MIME processor is
+ unable to distinguish between boundary strings that
+ do not differ in the first <b>$mime</b><i>_</i><b>bound-</b>
+ <b>ary</b><i>_</i><b>length</b><i>_</i><b>limit</b> characters.
+
+ <b>mime</b><i>_</i><b>nesting</b><i>_</i><b>limit</b>
+ The maximal nesting level of multipart mail that
+ the MIME processor can handle. Refuse mail that is
+ nested deeper, when converting from 8BITMIME format
+ to 7BIT format.
+
<b>Authentication</b> <b>controls</b>
<b>smtp</b><i>_</i><b>sasl</b><i>_</i><b>auth</b><i>_</i><b>enable</b>
- Enable per-session authentication as per <a href="http://www.faqs.org/rfcs/rfc2554.html">RFC 2554</a>
- (SASL). By default, Postfix is built without SASL
+ Enable per-session authentication as per <a href="http://www.faqs.org/rfcs/rfc2554.html">RFC 2554</a>
+ (SASL). By default, Postfix is built without SASL
support.
<b>smtp</b><i>_</i><b>sasl</b><i>_</i><b>password</b><i>_</i><b>maps</b>
Lookup tables with per-host or domain <i>name</i>:<i>password</i>
- entries. No entry for a host means no attempt to
+ entries. No entry for a host means no attempt to
authenticate.
<b>smtp</b><i>_</i><b>sasl</b><i>_</i><b>security</b><i>_</i><b>options</b>
<b>Resource</b> <b>controls</b>
<b>smtp</b><i>_</i><b>destination</b><i>_</i><b>concurrency</b><i>_</i><b>limit</b>
Limit the number of parallel deliveries to the same
- destination. The default limit is taken from the
+ destination. The default limit is taken from the
<b>default</b><i>_</i><b>destination</b><i>_</i><b>concurrency</b><i>_</i><b>limit</b> parameter.
<b>smtp</b><i>_</i><b>destination</b><i>_</i><b>recipient</b><i>_</i><b>limit</b>
- Limit the number of recipients per message deliv-
- ery. The default limit is taken from the
+ Limit the number of recipients per message deliv-
+ ery. The default limit is taken from the
<b>default</b><i>_</i><b>destination</b><i>_</i><b>recipient</b><i>_</i><b>limit</b> parameter.
<b>Timeout</b> <b>controls</b>
- The default time unit is seconds; an explicit time unit
- can be specified by appending a one-letter suffix to the
- value: s (seconds), m (minutes), h (hours), d (days) or w
+ The default time unit is seconds; an explicit time unit
+ can be specified by appending a one-letter suffix to the
+ value: s (seconds), m (minutes), h (hours), d (days) or w
(weeks).
<b>smtp</b><i>_</i><b>connect</b><i>_</i><b>timeout</b>
- Timeout for completing a TCP connection. When no
- connection can be made within the deadline, the
- SMTP client tries the next address on the mail
+ Timeout for completing a TCP connection. When no
+ connection can be made within the deadline, the
+ SMTP client tries the next address on the mail
exchanger list.
<b>smtp</b><i>_</i><b>helo</b><i>_</i><b>timeout</b>
- Timeout for receiving the SMTP greeting banner.
- When the server drops the connection without send-
+ Timeout for receiving the SMTP greeting banner.
+ When the server drops the connection without send-
ing a greeting banner, or when it sends no greeting
- banner within the deadline, the SMTP client tries
+ banner within the deadline, the SMTP client tries
the next address on the mail exchanger list.
<b>smtp</b><i>_</i><b>helo</b><i>_</i><b>timeout</b>
- Timeout for sending the <b>HELO</b> command, and for
+ Timeout for sending the <b>HELO</b> command, and for
receiving the server response.
<b>smtp</b><i>_</i><b>mail</b><i>_</i><b>timeout</b>
- Timeout for sending the <b>MAIL</b> <b>FROM</b> command, and for
+ Timeout for sending the <b>MAIL</b> <b>FROM</b> command, and for
receiving the server response.
<b>smtp</b><i>_</i><b>rcpt</b><i>_</i><b>timeout</b>
- Timeout for sending the <b>RCPT</b> <b>TO</b> command, and for
+ Timeout for sending the <b>RCPT</b> <b>TO</b> command, and for
receiving the server response.
<b>smtp</b><i>_</i><b>data</b><i>_</i><b>init</b><i>_</i><b>timeout</b>
- Timeout for sending the <b>DATA</b> command, and for
+ Timeout for sending the <b>DATA</b> command, and for
receiving the server response.
<b>smtp</b><i>_</i><b>data</b><i>_</i><b>xfer</b><i>_</i><b>timeout</b>
<b>smtp</b><i>_</i><b>data</b><i>_</i><b>done</b><i>_</i><b>timeout</b>
Timeout for sending the "<b>.</b>" command, and for
- receiving the server response. When no response is
- received, a warning is logged that the mail may be
+ receiving the server response. When no response is
+ received, a warning is logged that the mail may be
delivered multiple times.
<b>smtp</b><i>_</i><b>quit</b><i>_</i><b>timeout</b>
- Timeout for sending the <b>QUIT</b> command, and for
+ Timeout for sending the <b>QUIT</b> command, and for
receiving the server response.
<b>SEE</b> <b>ALSO</b>
syslogd(8) system logging
<b>LICENSE</b>
- The Secure Mailer license must be distributed with this
+ The Secure Mailer license must be distributed with this
software.
<b>AUTHOR(S)</b>
The <b>header_checks</b> parameter restricts what is allowed in
message headers. Patterns are applied to entire logical message
-headers, even when a header spans multiple lines of text.
+headers, even when a header spans multiple lines of text.
+
+<p>
+
+By default, the same <b>header_checks</b> patterns are used for
+primary message headers, for MIME headers (including headers at
+the start of multipart body parts), and for the headers at the
+beginning of attached email messages.
<p>
<h2> Body filtering</h2>
The <b>body_checks</b> parameter restricts what text is
-is allowed in message body lines (including MIME headers
-within the message body).
+is allowed in message body lines.
<p>
the message, and to the initial headers of attached messages.
These filters see logical headers one at a time, including headers
that span multiple lines.
+.SH MIME Processing
+.ad
+.fi
+.IP \fBdisable_mime_input_processing\fR
+While receiving, give no special treatment to \fBContent-Type:\fR
+message headers; all text after the initial message headers is
+considered to be part of the message body.
+.IP \fBmime_boundary_length_limit\fR
+The amount of space that will be allocated for MIME multipart
+boundary strings. The MIME processor is unable to distinguish
+between boundary strings that do not differ in the first
+\fB$mime_boundary_length_limit\fR characters.
+.IP \fBmime_nesting_limit\fR
+The maximal nesting level of multipart mail that the MIME
+processor can handle. Refuse mail that is nested deeper.
+.IP \fBstrict_8bitmime\fR
+Reject mail with 8-bit text in message headers, and with
+8-bit text in content that claims to be 7-bit, or that has
+no explicit content encoding information. This blocks mail
+mail poorly written mail software. Unfortunately, this also
+breaks majordomo approval requests when the included request
+contains valid 8-bit MIME mail.
+.IP \fBstrict_mime_domain_encoding\fR
+Reject mail with invalid \fBContent-Transfer-Encoding:\fR
+information for message/* or multipart/*. This blocks mail
+from poorly written software.
.SH Miscellaneous
.ad
.fi
.IP \fBsmtp_pix_workaround_threshold_time\fR
The time a message must be queued before the CISCO PIX firewall
<CR><LF>.<CR><LF> bug workaround is turned on.
+.SH "MIME Conversion"
+.IP \fBdisable_mime_output_conversion\fR
+Disable the conversion of 8BITMIME format to 7BIT format when
+the remote system does not advertise 8BITMIME support.
+.IP \fBmime_boundary_length_limit\fR
+The amount of space that will be allocated for MIME multipart
+boundary strings. The MIME processor is unable to distinguish
+between boundary strings that do not differ in the first
+\fB$mime_boundary_length_limit\fR characters.
+.IP \fBmime_nesting_limit\fR
+The maximal nesting level of multipart mail that the MIME
+processor can handle. Refuse mail that is nested deeper,
+when converting from 8BITMIME format to 7BIT format.
.SH "Authentication controls"
.IP \fBsmtp_sasl_auth_enable\fR
Enable per-session authentication as per RFC 2554 (SASL).
/* the message, and to the initial headers of attached messages.
/* These filters see logical headers one at a time, including headers
/* that span multiple lines.
+/* .SH MIME Processing
+/* .ad
+/* .fi
+/* .IP \fBdisable_mime_input_processing\fR
+/* While receiving, give no special treatment to \fBContent-Type:\fR
+/* message headers; all text after the initial message headers is
+/* considered to be part of the message body.
+/* .IP \fBmime_boundary_length_limit\fR
+/* The amount of space that will be allocated for MIME multipart
+/* boundary strings. The MIME processor is unable to distinguish
+/* between boundary strings that do not differ in the first
+/* \fB$mime_boundary_length_limit\fR characters.
+/* .IP \fBmime_nesting_limit\fR
+/* The maximal nesting level of multipart mail that the MIME
+/* processor can handle. Refuse mail that is nested deeper.
+/* .IP \fBstrict_8bitmime\fR
+/* Reject mail with 8-bit text in message headers, and with
+/* 8-bit text in content that claims to be 7-bit, or that has
+/* no explicit content encoding information. This blocks mail
+/* mail poorly written mail software. Unfortunately, this also
+/* breaks majordomo approval requests when the included request
+/* contains valid 8-bit MIME mail.
+/* .IP \fBstrict_mime_domain_encoding\fR
+/* Reject mail with invalid \fBContent-Transfer-Encoding:\fR
+/* information for message/* or multipart/*. This blocks mail
+/* from poorly written software.
/* .SH Miscellaneous
/* .ad
/* .fi
int mime_errs; /* MIME error flags */
} CLEANUP_STATE;
-#define CLEANUP_CURR_HEADERS (1<<0) /* in main headers section */
-
/*
* Mappings.
*/
TOK822 *tree;
TOK822 **addr_list;
TOK822 **tpp;
- char *addr;
if (msg_verbose)
msg_info("rewrite_sender: %s", hdr_opts->name);
* sender addresses, and regenerate the header line. Finally, pipe the
* result through the header line folding routine.
*/
-#define SKIP_HEADER_THRASH(cp) { while (ISSPACE(*cp)) cp++; cp++; }
-
- addr = vstring_str(header_buf) + strlen(hdr_opts->name);
- SKIP_HEADER_THRASH(addr);
- tree = tok822_parse(addr);
+ tree = tok822_parse(vstring_str(header_buf)
+ + strlen(hdr_opts->name) + 1);
addr_list = tok822_grep(tree, TOK822_ADDR);
for (tpp = addr_list; *tpp; tpp++) {
cleanup_rewrite_tree(*tpp);
TOK822 **addr_list;
TOK822 **tpp;
ARGV *rcpt;
- char *addr;
if (msg_verbose)
msg_info("rewrite_recip: %s", hdr_opts->name);
* recipient addresses, and regenerate the header line. Finally, pipe the
* result through the header line folding routine.
*/
- addr = vstring_str(header_buf) + strlen(hdr_opts->name);
- SKIP_HEADER_THRASH(addr);
- tree = tok822_parse(addr);
+ tree = tok822_parse(vstring_str(header_buf)
+ + strlen(hdr_opts->name) + 1);
addr_list = tok822_grep(tree, TOK822_ADDR);
for (tpp = addr_list; *tpp; tpp++) {
cleanup_rewrite_tree(*tpp);
header_class = MIME_HDR_MULTIPART;
if ((state->flags & CLEANUP_FLAG_FILTER)
- && (CHECK(MIME_HDR_PRIMARY, cleanup_header_checks, VAR_HEADER_CHECKS)
+ && (CHECK(MIME_HDR_PRIMARY, cleanup_header_checks, VAR_HEADER_CHECKS)
|| CHECK(MIME_HDR_MULTIPART, cleanup_mimehdr_checks, VAR_MIMEHDR_CHECKS)
|| CHECK(MIME_HDR_NESTED, cleanup_nesthdr_checks, VAR_NESTHDR_CHECKS))) {
char *header = vstring_str(header_buf);
* Allow 8-bit type info to override 7-bit type info. XXX Should reuse
* the effort that went into MIME header parsing.
*/
- hdrval = vstring_str(header_buf) + strlen(hdr_opts->name);
- SKIP_HEADER_THRASH(hdrval);
+ hdrval = vstring_str(header_buf) + strlen(hdr_opts->name) + 1;
+ while (ISSPACE(*hdrval))
+ hdrval++;
/* trimblanks(hdrval, 0)[0] = 0; */
if (hdr_opts->type == HDR_CONTENT_TRANSFER_ENCODING) {
for (cmp = code_map; cmp->name != 0; cmp++) {
if (strcasecmp(hdrval, cmp->name) == 0) {
- if (nvtable_find(state->attr, MAIL_ATTR_ENCODING) == 0
- || strcmp(cmp->encoding, MAIL_ATTR_ENC_8BIT) == 0)
+ if (strcmp(cmp->encoding, MAIL_ATTR_ENC_8BIT) == 0)
nvtable_update(state->attr, MAIL_ATTR_ENCODING,
cmp->encoding);
break;
}
/*
- * To avoid complications elsewhere, text must not end in REC_TYPE_CONT.
- *
* If we have reached the end of the message content segment, record the
* current file position so we can compute the message size lateron.
*/
else if (type == REC_TYPE_XTRA) {
state->mime_errs = mime_state_update(state->mime_state, type, buf, len);
+ /* Ignore header truncation after primary message headers. */
+ state->mime_errs &= ~MIME_ERR_TRUNC_HEADER;
+ /* Ignore MIME nesting error if bouncing or forwarding mail. */
+ /* XXX Also: ignore if not header checking. */
+ if ((state->flags & CLEANUP_FLAG_FILTER) == 0)
+ state->mime_errs &= ~MIME_ERR_NESTING;
+ if (state->mime_errs && state->reason == 0) {
+ state->errs |= CLEANUP_STAT_CONT;
+ state->reason = mystrdup(mime_state_error(state->mime_errs));
+ }
state->mime_state = mime_state_free(state->mime_state);
if ((state->xtra_offset = vstream_ftell(state->dst)) < 0)
msg_fatal("%s: vstream_ftell %s: %m", myname, cleanup_path);
void cleanup_message(CLEANUP_STATE *state, int type, char *buf, int len)
{
char *myname = "cleanup_message";
+ int mime_options;
/*
* Write a dummy start-of-content segment marker. We'll update it with
msg_fatal("%s: vstream_ftell %s: %m", myname, cleanup_path);
/*
- * Pass control to the header processing routine.
+ * Set up MIME processing options, if any. MIME_OPT_DISABLE_MIME disables
+ * special processing of Content-Type: headers, and thus, causes all text
+ * after the primary headers to be treated as the message body.
*/
- state->mime_state = mime_state_alloc(MIME_OPT_REPORT_TRUNC_HEADER,
+ mime_options = MIME_OPT_REPORT_TRUNC_HEADER;
+ if (var_disable_mime_input) {
+ mime_options |= MIME_OPT_DISABLE_MIME;
+ } else {
+ /* Turn off strict MIME checks if bouncing or forwarding mail. */
+ if (state->flags & CLEANUP_FLAG_FILTER) {
+ if (var_strict_8bitmime)
+ mime_options |= (MIME_OPT_REPORT_8BIT_IN_HEADER
+ | MIME_OPT_REPORT_8BIT_IN_7BIT_BODY);
+ if (var_strict_encoding)
+ mime_options |= MIME_OPT_REPORT_ENCODING_DOMAIN;
+ }
+ }
+ state->mime_state = mime_state_alloc(mime_options,
cleanup_header_callback,
cleanup_header_done_callback,
cleanup_body_callback,
(MIME_STATE_ANY_END) 0,
(void *) state);
+
+ /*
+ * Pass control to the header processing routine.
+ */
state->action = cleanup_message_headerbody;
cleanup_message_headerbody(state, type, buf, len);
}
+++ /dev/null
-Delivered-To: wietse@porcupine.watson.ibm.com
-Received: from mailhub.watson.ibm.com (mailhub.watson.ibm.com [9.2.250.97])
- by porcupine.watson.ibm.com (Postfix) with ESMTP for <wietse@porcupine.watson.ibm.com>
- id 2F0FC188CE; Tue, 12 Jan 1999 15:08:46 -0500 (EST)
-Received: from wzv.watson.ibm.com (wzv.watson.ibm.com [9.2.84.53]) by mailhub.watson.ibm.com (8.8.7/Feb-20-98) with ESMTP id PAA07748 for <wietse@porcupine.watson.ibm.com>; Tue, 12 Jan 1999 15:08:45 -0500
-Received: by wzv.watson.ibm.com (Postfix, from userid 309)
- id 9AC44827; Tue, 12 Jan 1999 15:08:45 -0500 (EST)
-Delivered-To: wietse@[9.2.84.53]
-From: wietse
-To: wietse
-Subject: testje
-MIME-Version: 1.0
-Content-Type: "multipart" ; boundary = "abcdef" foobar
-Status: RO
-
-prolog
-
---abcdef
-
-part01
-
---abcdef
-
-part02
-
---abcdef
-
-part03
-
---abcdef--
-
-epilog
/* quoted-string, comment, control characters, and a set of
/* user-specified special characters.
/*
-/* A token type is one of the following:
+/* A result token type is one of the following:
/* .IP HEADER_TOK_QSTRING
/* Quoted string as per RFC 822.
/* .IP HEADER_TOK_TOKEN
/*
/* Arguments:
/* .IP token
-/* Result array of HEADER_TOKEN structures.
+/* Result array of HEADER_TOKEN structures. Token string values
+/* are pointers to null-terminated substrings in the token_buffer.
/* .IP token_len
/* Length of the array of HEADER_TOKEN structures.
/* .IP token_buffer
-/* Storage for result token values.
+/* Storage for result token string values.
/* .IP ptr
/* Input/output read position. The input is a null-terminated string.
/* .IP specials
+++ /dev/null
-/*++
-/* NAME
-/* is_header 3
-/* SUMMARY
-/* message header classification
-/* SYNOPSIS
-/* #include <is_header.h>
-/*
-/* int is_header(string)
-/* const char *string;
-/* DESCRIPTION
-/* is_header() examines the given string and returns non-zero (true)
-/* when it begins with a mail header name + colon. This routine
-/* permits 8-bit data in header labels.
-/* STANDARDS
-/* RFC 822 (ARPA Internet Text Messages)
-/* LICENSE
-/* .ad
-/* .fi
-/* The Secure Mailer license must be distributed with this software.
-/* AUTHOR(S)
-/* Wietse Venema
-/* IBM T.J. Watson Research
-/* P.O. Box 704
-/* Yorktown Heights, NY 10598, USA
-/*--*/
-
-/* System library. */
-
-#include "sys_defs.h"
-#include <ctype.h>
-
-/* Global library. */
-
-#include "is_header.h"
-
-/* is_header - determine if this can be a header line */
-
-int is_header(const char *str)
-{
- const char *cp;
- int state;
- int c;
-
-#define INITIAL 0
-#define IN_CHAR 1
-#define IN_CHAR_SPACE 2
-
- /*
- * XXX RFC 2822 Section 4.5, Obsolete header fields: whitespace may
- * appear between header label and ":" (see: RFC 822, Section 3.4.2.).
- *
- * The code below allows no such whitespace. This has never been a problem,
- * and therefore we're not inclined to add code for it.
- *
- * XXX It may, however, present another ambiguity with respect to finding
- * attachment message headers. Sendmail rewrites obsolete forms.
- */
- for (state = INITIAL, cp = str; (c = *(unsigned char *) cp) != 0; cp++) {
- if (c == ':')
- return (state == IN_CHAR || state == IN_CHAR_SPACE);
- if (c == ' ') {
- if (state == IN_CHAR)
- state = IN_CHAR_SPACE;
- if (state != IN_CHAR_SPACE)
- break;
- }
- if (!ISASCII(c) || ISCNTRL(c))
- break;
- if (state == INITIAL) state = IN_CHAR
- }
- return (0);
-}
/* int var_mime_maxdepth;
/* int var_mime_bound_len;
/* int var_header_limit;
+/* int var_disable_mime_input;
+/* int var_disable_mime_oconv;
+/* int var_strict_8bitmime;
+/* int var_strict_encoding;
/*
/* void mail_params_init()
/* DESCRIPTION
int var_mime_maxdepth;
int var_mime_bound_len;
int var_header_limit;
+int var_disable_mime_input;
+int var_disable_mime_oconv;
+int var_strict_8bitmime;
+int var_strict_encoding;
#define MAIN_CONF_FILE "main.cf"
VAR_DISABLE_DNS, DEF_DISABLE_DNS, &var_disable_dns,
VAR_SOFT_BOUNCE, DEF_SOFT_BOUNCE, &var_soft_bounce,
VAR_OWNREQ_SPECIAL, DEF_OWNREQ_SPECIAL, &var_ownreq_special,
+ VAR_STRICT_8BITMIME, DEF_STRICT_8BITMIME, &var_strict_8bitmime,
+ VAR_STRICT_ENCODING, DEF_STRICT_ENCODING, &var_strict_encoding,
+ VAR_DISABLE_MIME_INPUT, DEF_DISABLE_MIME_INPUT, &var_disable_mime_input,
+ VAR_DISABLE_MIME_OCONV, DEF_DISABLE_MIME_OCONV, &var_disable_mime_oconv,
0,
};
const char *cp;
extern int var_smtpd_hard_erlim;
#define VAR_SMTPD_ERR_SLEEP "smtpd_error_sleep_time"
-#define DEF_SMTPD_ERR_SLEEP "5s"
+#define DEF_SMTPD_ERR_SLEEP "1s"
extern int var_smtpd_err_sleep;
#define VAR_SMTPD_JUNK_CMD "smtpd_junk_command_limit"
* MIME support.
*/
#define VAR_MIME_MAXDEPTH "mime_nesting_limit"
-#define DEF_MIME_MAXDEPTH 100
+#define DEF_MIME_MAXDEPTH 20
extern int var_mime_maxdepth;
#define VAR_MIME_BOUND_LEN "mime_boundary_length_limit"
-#define DEF_MIME_BOUND_LEN 100
+#define DEF_MIME_BOUND_LEN 2048
extern int var_mime_bound_len;
+#define VAR_DISABLE_MIME_INPUT "disable_mime_input_processing"
+#define DEF_DISABLE_MIME_INPUT 0
+extern bool var_disable_mime_input;
+
+#define VAR_DISABLE_MIME_OCONV "disable_mime_output_conversion"
+#define DEF_DISABLE_MIME_OCONV 0
+extern bool var_disable_mime_oconv;
+
+#define VAR_STRICT_8BITMIME "strict_8bitmime"
+#define DEF_STRICT_8BITMIME 0
+extern bool var_strict_8bitmime;
+
+#define VAR_STRICT_ENCODING "strict_mime_encoding_domain"
+#define DEF_STRICT_ENCODING 0
+extern bool var_strict_encoding;
+
/* LICENSE
/* .ad
/* .fi
* 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 "20020524"
+#define MAIL_RELEASE_DATE "20020526"
#define VAR_MAIL_VERSION "mail_version"
#define DEF_MAIL_VERSION "1.1.10-" MAIL_RELEASE_DATE
/*
/* In order to fend off denial of service attacks, message headers
/* are truncated at or above var_header_limit bytes, message boundary
-/* strings are truncated at var_boundary_len bytes, and the message
+/* strings are truncated at var_boundary_len bytes, and the multipart
/* nesting level is limited to var_mime_maxdepth levels.
/*
/* mime_state_alloc() creates a MIME state machine. The machine
/* .IP MIME_ERR_8BIT_IN_7BIT_BODY
/* A MIME header specifies (or defaults to) 7-bit content, but the
/* correspnding message body or body parts contain 8-bit content.
-/* .IP MIME_ERR_DOMAIN_ENCODING
+/* .IP MIME_ERR_ENCODING_DOMAIN
/* An entity of type "message" or "multipart" specifies the wrong
/* content transfer encoding domain, or specifies a transformation
/* (quoted-printable, base64) instead of a domain (7bit, 8bit,
/* .IP enc_type
/* The content encoding: MIME_ENC_7BIT or MIME_ENC_8BIT.
/* .IP flags
-/* Processing options. Specify the bit-wise OR of zero or more
-/* of the following:
+/* Special processing options. Specify the bit-wise OR of zero or
+/* more of the following:
/* .RS
/* .IP MIME_OPT_DISABLE_MIME
/* Pay no attention to Content-* message headers, and switch to
/* forwarded for approval, because Majordomo does not propagate
/* MIME type information from the enclosed message to the message
/* headers of the request for approval.
-/* .IP MIME_OPT_REPORT_DOMAIN_ENCODING
-/* Report errors that set the MIME_ERR_DOMAIN_ENCODING error
+/* .IP MIME_OPT_REPORT_ENCODING_DOMAIN
+/* Report errors that set the MIME_ERR_ENCODING_DOMAIN error
/* flag (see above).
/* .IP MIME_OPT_RECURSE_ALL_MESSAGE
/* Recurse into message/anything types other than message/rfc822.
/*
/* This module will not glue together RFC 2231 formatted (boundary)
/* parameter values. RFC 2231 says claims compatibility with existing
-/* MIME processors.
+/* MIME processors. Splitting boundary strings is not backwards
+/* compatible.
/*
/* The "8-bit data inside 7-bit body" test is myopic. It is not aware
-/* of the enclosing message or multipart encoding information.
+/* of any enclosing (message or multipart) encoding information.
/*
/* If the input ends in data other than a hard line break, this module
-/* will add a hard line break. No line break is added to empty input.
+/* will add a hard line break of its own. No line break is added to
+/* empty input.
+/*
+/* This code recognizes the obsolete form "headername :" but will
+/* normalize it to the canonical form "headername:". Leaving the
+/* obsolete form alone would cause too much trouble with existing code
+/* that expects only the normalized form.
/* SEE ALSO
/* msg(3) diagnostics interface
/* header_opts(3) header information lookup
#define TOKEN_MATCH(tok, text) \
((tok).type == HEADER_TOK_TOKEN && strcasecmp((tok).u.value, (text)) == 0)
-#define SKIP_HEADER_THRASH(cp) { while (ISSPACE(*cp)) cp++; cp++; }
-
#define RFC2045_TSPECIALS "()<>@,;:\\\"/[]?="
#define PARSE_CONTENT_TYPE_HEADER(state, ptr) \
header_token(state->token, MIME_MAX_TOKEN, \
state->token_buffer, ptr, RFC2045_TSPECIALS, ';')
- cp = STR(state->output_buffer) + strlen(header_info->name);
- SKIP_HEADER_THRASH(cp);
+ cp = STR(state->output_buffer) + strlen(header_info->name) + 1;
if ((tok_count = PARSE_CONTENT_TYPE_HEADER(state, &cp)) > 0) {
/*
* something other than 7bit, 8bit or binary, even if we don't recognize
* the input.
*/
- cp = STR(state->output_buffer) + strlen(header_info->name);
- SKIP_HEADER_THRASH(cp);
+ cp = STR(state->output_buffer) + strlen(header_info->name) + 1;
if (PARSE_CONTENT_ENCODING_HEADER(state, &cp) > 0
&& state->token[0].type == HEADER_TOK_TOKEN) {
for (cmp = code_map; cmp->name != 0; cmp++) {
/*
* This message state machine is kept simple for the sake of robustness.
* Standards evolve over time, and we want to be able to correctly
- * processes messages that are not yet defined. This state machine knows
+ * process messages that are not yet defined. This state machine knows
* about headers and bodies, understands that multipart/whatever has
* multiple body parts with a header and body, and that message/whatever
* has message headers at the start of a body part.
* clean slate.
*/
if (input_is_text) {
+ int header_len;
/*
* See if this input is (the beginning of) a message header.
* Normalize obsolete "name space colon" syntax to "name colon".
* Things would be too confusing otherwise.
*/
- if ((len = is_header(text)) > 0) {
- vstring_strncpy(state->output_buffer, text, len);
- for (text += len; ISSPACE(*text); text++)
+ if ((header_len = is_header(text)) > 0) {
+ vstring_strncpy(state->output_buffer, text, header_len);
+ for (text += header_len; ISSPACE(*text); text++)
/* void */ ;
vstring_strcat(state->output_buffer, text);
SAVE_PREV_REC_TYPE_AND_RETURN_ERR_FLAGS(state, rec_type);
/* .IP \fBsmtp_pix_workaround_threshold_time\fR
/* The time a message must be queued before the CISCO PIX firewall
/* <CR><LF>.<CR><LF> bug workaround is turned on.
+/* .SH "MIME Conversion"
+/* .IP \fBdisable_mime_output_conversion\fR
+/* Disable the conversion of 8BITMIME format to 7BIT format when
+/* the remote system does not advertise 8BITMIME support.
+/* .IP \fBmime_boundary_length_limit\fR
+/* The amount of space that will be allocated for MIME multipart
+/* boundary strings. The MIME processor is unable to distinguish
+/* between boundary strings that do not differ in the first
+/* \fB$mime_boundary_length_limit\fR characters.
+/* .IP \fBmime_nesting_limit\fR
+/* The maximal nesting level of multipart mail that the MIME
+/* processor can handle. Refuse mail that is nested deeper,
+/* when converting from 8BITMIME format to 7BIT format.
/* .SH "Authentication controls"
/* .IP \fBsmtp_sasl_auth_enable\fR
/* Enable per-session authentication as per RFC 2554 (SASL).
} \
} while (0)
-#define RETURN(x) do { vstring_free(next_command); return (x); } while (0)
+#define RETURN(x) do { \
+ vstring_free(next_command); \
+ if (state->mime_state) \
+ state->mime_state = mime_state_free(state->mime_state); \
+ return (x); \
+ } while (0)
#define SENDER_IS_AHEAD \
(recv_state < send_state || recv_rcpt != send_rcpt)
* transaction in progress.
*/
if (send_state == SMTP_STATE_DOT && nrcpt > 0) {
- downgrading = ((state->features & SMTP_FEATURE_8BITMIME) == 0
- && strcmp(request->encoding, MAIL_ATTR_ENC_7BIT) != 0);
+ downgrading =
+ (var_disable_mime_oconv == 0
+ && (state->features & SMTP_FEATURE_8BITMIME) == 0
+ && strcmp(request->encoding, MAIL_ATTR_ENC_7BIT) != 0);
if (downgrading)
- state->mime_state = mime_state_alloc(MIME_OPT_DOWNGRADE
- | MIME_OPT_REPORT_8BIT_IN_7BIT_BODY
- | MIME_OPT_REPORT_8BIT_IN_HEADER,
+ state->mime_state = mime_state_alloc(MIME_OPT_DOWNGRADE,
smtp_header_out,
(MIME_STATE_ANY_END) 0,
smtp_text_out,
/*
* Report trouble. Log a warning only if we are going to sleep+reject so
* that attackers can't flood our logfiles.
- *
- * XXX !allow_empty_addr should also reject <"">.
*/
- if ((naddr < 1 && !allow_empty_addr)
- || naddr > 1
+ if (naddr > 1
|| (strict_rfc821 && (non_addr || *STR(arg->vstrval) != '<'))) {
msg_warn("Illegal address syntax from %s in %s command: %s",
state->namaddr, state->where, STR(arg->vstrval));
vstring_strcpy(arg->vstrval, "");
arg->strval = STR(arg->vstrval);
+ /*
+ * Report trouble. Log a warning only if we are going to sleep+reject so
+ * that attackers can't flood our logfiles.
+ */
+ if (arg->strval[0] == 0 && !allow_empty_addr) {
+ msg_warn("Illegal address syntax from %s in %s command: %s",
+ state->namaddr, state->where, STR(arg->vstrval));
+ err = "501 Bad address syntax";
+ }
+
/*
* Cleanup.
*/