2
0
mirror of https://github.com/vdukhovni/postfix synced 2025-08-31 14:17:41 +00:00

postfix-1.1.10-20020524

This commit is contained in:
Wietse Venema
2002-05-24 00:00:00 -05:00
committed by Viktor Dukhovni
parent f0d9a4857f
commit 5eb74275bf
52 changed files with 2490 additions and 324 deletions

6
postfix/.indent.pro vendored
View File

@@ -51,6 +51,7 @@
-TFILE
-TFORWARD_INFO
-THEADER_OPTS
-THEADER_TOKEN
-THOST
-THTABLE
-THTABLE_INFO
@@ -75,6 +76,11 @@
-TMASTER_STATUS
-TMBLOCK
-TMBOX
-TMIME_ENCODING
-TMIME_INFO
-TMIME_STACK
-TMIME_STATE
-TMIME_TOKEN
-TMKMAP
-TMKMAP_OPEN_INFO
-TMULTI_SERVER

View File

@@ -6447,8 +6447,59 @@ Apologies for any names omitted.
with "resolve_dequoted_address = no"). Victor Duchovny,
Morgan Stanley. File: smtpd/smtpd_check.c.
20020515
Workaround: flush the SMTP client output buffer when no
output has happened for 10+ seconds. This prevents the
socket from timing out, in case DNS CNAME expansion is
slow. Problem experienced by Alex Erdelyi, peregrine.com.
File: smtp/smtp_chat.c. We did the same thing for the SMTP
server years ago, and one wonders why the coin didn't drop
at the time that the SMTP client could suffer from a similar
problem.
20020517
Cleanup: Mailbox-Line: message header labels should be
X-Mailbox-Line: labels. Files: smtpd/smtpd.c, qmqpd/qmqpd.c.
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.
20020521-22
Feature: 8-bit to quoted-printable conversion. First use in
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.
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.
20020525
Cleanup: broke out the header value parser from the MIME
processor so it can be used 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.
Open problems:
Medium: old maildrop files are no longer readable by the
pickup service. Log a message that suggests a fix.
Low: all table lookups should consistently use internalized
(unquoted) or externalized (quoted) forms as lookup keys.
smtpd, qmgr, local, etc. use internalized forms as keys.

View File

@@ -128,10 +128,11 @@ The second example is considerably more complex, but can give much
better performance, and is less likely to bounce mail when the
machine runs into a resource problem. This approach uses content
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 that arrives and leaves via SMTP, provided that
you create no temporary files. Each temporary file adds another
factor to the performance loss.
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.
We will set up a content filtering program that receives SMTP mail
via localhost port 10025, and that submits SMTP mail back into
@@ -158,18 +159,33 @@ To enable content filtering in this manner, specify in main.cf a
new parameter:
/etc/postfix/main.cf:
content_filter = smtp:localhost:10025
content_filter = scan:localhost:10025
This causes Postfix to add one extra content filtering record to
each incoming mail message, with content smtp:localhost:10025.
You can use the same syntax as in the right-hand side of a Postfix
transport table. The content filtering records are added by the
smtpd and pickup servers.
each incoming mail message, with content scan:localhost:10025.
The content filtering records are added by the smtpd and pickup
servers.
When a queue file has content filtering information, the queue
manager will deliver the mail to the specified content filter
regardless of its final destination.
In this example, "scan" is an instance of the Postfix SMTP client
with slightly different configuration parameters. This is how
one would set up the service in the Postfix master.cf file:
/etc/postfix/master.cf:
scan unix - - n - 10 smtp
-o disable_dns_lookups=yes
Turning off DNS lookups at this point can make a great difference
in content filtering performance. It also isolates the content
filtering process from temporary outages in DNS service.
Instead of 10, use whatever limit is feasible for your machine.
Content inspection software can gobble up a lot of system resources,
so you don't want to have too much of it running at the same time.
The content filter can be set up with the Postfix spawn service,
which is the Postfix equivalent of inetd. For example, to instantiate
up to 10 content filtering processes on demand:
@@ -263,7 +279,7 @@ into Postfix via localhost port 10026.
: cleanup2/ | \smtp----->
: ^ v :
: | v :
: smtpd smtp :
: smtpd scan :
: 10026 | :
.......................|...........
^ |

View File

@@ -12,6 +12,13 @@ snapshot release). Patches change the patchlevel and the release
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
==========================================================
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.
Incompatible changes with Postfix snapshot 1.1.10-20020514
==========================================================

View File

@@ -55,6 +55,8 @@ CLEANUP(8) CLEANUP(8)
<b>STANDARDS</b>
<a href="http://www.faqs.org/rfcs/rfc822.html">RFC 822</a> (ARPA Internet Text Messages)
<a href="http://www.faqs.org/rfcs/rfc2045.html">RFC 2045</a> (MIME: Format of Internet Message Bodies)
<a href="http://www.faqs.org/rfcs/rfc2046.html">RFC 2046</a> (MIME: Media Types)
<b>DIAGNOSTICS</b>
Problems and transactions are logged to <b>syslogd</b>(8).
@@ -76,14 +78,21 @@ CLEANUP(8) CLEANUP(8)
time, in chunks of at most line_length_limit bytes.
<b>header</b><i>_</i><b>checks</b>
<b>mime</b><i>_</i><b>header</b><i>_</i><b>checks</b> (default: <b>$header</b><i>_</i><b>checks</b>)
<b>nested</b><i>_</i><b>header</b><i>_</i><b>checks</b> (default: <b>$header</b><i>_</i><b>checks</b>)
Lookup tables with content filters for message
header lines. These filters see logical headers
one at a time, including headers that span multiple
lines.
header lines: respectively, these are applied to
the primary message headers (not including MIME
headers), to the MIME headers anywhere in the mes-
sage, and to the initial headers of attached mes-
sages. These filters see logical headers one at a
time, including headers that span multiple lines.
<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>
@@ -96,8 +105,8 @@ CLEANUP(8) CLEANUP(8)
<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 &lt;&gt;.
This substitution is done before all other address
The destination for undeliverable mail from &lt;&gt;.
This substitution is done before all other address
rewriting.
<b>canonical</b><i>_</i><b>maps</b>
@@ -113,16 +122,16 @@ CLEANUP(8) CLEANUP(8)
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>
@@ -131,7 +140,7 @@ CLEANUP(8) CLEANUP(8)
<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>
@@ -140,11 +149,11 @@ CLEANUP(8) CLEANUP(8)
<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>
@@ -159,7 +168,7 @@ CLEANUP(8) CLEANUP(8)
/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>

View File

@@ -102,6 +102,9 @@ POSTALIAS(1) POSTALIAS(1)
<i>file_name</i><b>.db</b>. This is available only on
systems with support for <b>db</b> databases.
Use the command <b>postconf</b> <b>-m</b> to find out what types
of database your Postfix installation can support.
When no <i>file_type</i> is specified, the software uses
the database type specified via the <b>database</b><i>_</i><b>type</b>
configuration parameter. The default value for

View File

@@ -55,17 +55,69 @@ POSTCONF(1) POSTCONF(1)
<b>-m</b> List the names of all supported lookup table types.
<b>btree</b> A sorted, balanced tree structure. This is
available only on systems with support for
Berkeley DB databases.
<b>dbm</b> An indexed file type based on hashing. This
is available only on systems with support
for DBM databases.
<b>environ</b>
The UNIX process environment array. The
lookup key is the variable name. Originally
implemented for testing, someone may find
this useful someday.
<b>hash</b> An indexed file type based on hashing. This
is available only on systems with support
for Berkeley DB databases.
<b>ldap</b> Perform lookups using the LDAP protocol.
This is described in an LDAP_README file.
<b>pcre</b> A lookup table based on Perl Compatible Reg-
ular Expressions. The file format is
described in <a href="pcre_table.5.html"><b>pcre</b><i>_</i><b>table</b>(5)</a>.
<b>regexp</b> A lookup table based on regular expressions.
The file format is described in <b>reg-</b>
<b>exp</b><i>_</i><b>table</b>(5).
<b>static</b> A table that always returns the same result.
For example, <b>static:foobar</b> always returns
the string <b>foobar</b>.
<b>unix</b> A limited way to query the UNIX authentica-
tion database. The following tables are
implemented:
<b>unix:passwd.byname</b>
The table is the UNIX password
database. The key is a login name.
The result is a password file entry
in passwd(5) format.
<b>unix:group.byname</b>
The table is the UNIX group
database. The key is a group name.
The result is a group file entry in
group(5) format.
Other table types may exist depending on how Postfix was
built.
<b>-n</b> Print non-default parameter settings only.
<b>-v</b> Enable verbose logging for debugging purposes. Mul-
tiple <b>-v</b> options make the software increasingly
tiple <b>-v</b> options make the software increasingly
verbose.
<b>DIAGNOSTICS</b>
Problems are reported to the standard error stream.
<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>

View File

@@ -123,6 +123,9 @@ POSTMAP(1) POSTMAP(1)
<i>file_name</i><b>.db</b>. This is available only on
systems with support for <b>db</b> databases.
Use the command <b>postconf</b> <b>-m</b> to find out what types
of database your Postfix installation can support.
When no <i>file_type</i> is specified, the software uses
the database type specified via the <b>database</b><i>_</i><b>type</b>
configuration parameter.

View File

@@ -42,9 +42,12 @@ SMTP(8) SMTP(8)
<b>STANDARDS</b>
<a href="http://www.faqs.org/rfcs/rfc821.html">RFC 821</a> (SMTP protocol)
<a href="http://www.faqs.org/rfcs/rfc822.html">RFC 822</a> (ARPA Internet Text Messages)
<a href="http://www.faqs.org/rfcs/rfc1651.html">RFC 1651</a> (SMTP service extensions)
<a href="http://www.faqs.org/rfcs/rfc1652.html">RFC 1652</a> (8bit-MIME transport)
<a href="http://www.faqs.org/rfcs/rfc1870.html">RFC 1870</a> (Message Size Declaration)
<a href="http://www.faqs.org/rfcs/rfc2045.html">RFC 2045</a> (MIME: Format of Internet Message Bodies)
<a href="http://www.faqs.org/rfcs/rfc2046.html">RFC 2046</a> (MIME: Media Types)
<a href="http://www.faqs.org/rfcs/rfc2197.html">RFC 2197</a> (Pipelining)
<a href="http://www.faqs.org/rfcs/rfc2554.html">RFC 2554</a> (AUTH command)
<a href="http://www.faqs.org/rfcs/rfc2821.html">RFC 2821</a> (SMTP protocol)

View File

@@ -92,6 +92,9 @@ This is available only on systems with support for \fBdbm\fR databases.
The output is a hashed file, named \fIfile_name\fB.db\fR.
This is available only on systems with support for \fBdb\fR databases.
.PP
Use the command \fBpostconf -m\fR to find out what types of database
your Postfix installation can support.
When no \fIfile_type\fR is specified, the software uses the database
type specified via the \fBdatabase_type\fR configuration parameter.
The default value for this parameter depends on the host environment.

View File

@@ -54,6 +54,48 @@ stale lock files that were left behind after abnormal termination.
.RE
.IP \fB-m\fR
List the names of all supported lookup table types.
.RS
.IP \fBbtree\fR
A sorted, balanced tree structure.
This is available only on systems with support for Berkeley DB
databases.
.IP \fBdbm\fR
An indexed file type based on hashing.
This is available only on systems with support for DBM databases.
.IP \fBenviron\fR
The UNIX process environment array. The lookup key is the variable
name. Originally implemented for testing, someone may find this
useful someday.
.IP \fBhash\fR
An indexed file type based on hashing.
This is available only on systems with support for Berkeley DB
databases.
.IP \fBldap\fR
Perform lookups using the LDAP protocol. This is described
in an LDAP_README file.
.IP \fBpcre\fR
A lookup table based on Perl Compatible Regular Expressions. The
file format is described in \fBpcre_table\fR(5).
.IP \fBregexp\fR
A lookup table based on regular expressions. The file format is
described in \fBregexp_table\fR(5).
.IP \fBstatic\fR
A table that always returns the same result. For example,
\fBstatic:foobar\fR always returns the string \fBfoobar\fR.
.IP \fBunix\fR
A limited way to query the UNIX authentication database. The
following tables are implemented:
.RS
. IP \fBunix:passwd.byname\fR
The table is the UNIX password database. The key is a login name.
The result is a password file entry in passwd(5) format.
.IP \fBunix:group.byname\fR
The table is the UNIX group database. The key is a group name.
The result is a group file entry in group(5) format.
.RE
.RE
.sp
Other table types may exist depending on how Postfix was built.
.IP \fB-n\fR
Print non-default parameter settings only.
.IP \fB-v\fR

View File

@@ -113,6 +113,9 @@ This is available only on systems with support for \fBdbm\fR databases.
The output file is a hashed file, named \fIfile_name\fB.db\fR.
This is available only on systems with support for \fBdb\fR databases.
.PP
Use the command \fBpostconf -m\fR to find out what types of database
your Postfix installation can support.
When no \fIfile_type\fR is specified, the software uses the database
type specified via the \fBdatabase_type\fR configuration parameter.
.RE

View File

@@ -56,6 +56,8 @@ in case of trouble.
.na
.nf
RFC 822 (ARPA Internet Text Messages)
RFC 2045 (MIME: Format of Internet Message Bodies)
RFC 2046 (MIME: Media Types)
.SH DIAGNOSTICS
.ad
.fi
@@ -80,7 +82,12 @@ Lookup tables with content filters for message body lines.
These filters see physical lines one at a time, in chunks of
at most line_length_limit bytes.
.IP \fBheader_checks\fR
Lookup tables with content filters for message header lines.
.IP "\fBmime_header_checks\fR (default: \fB$header_checks\fR)"
.IP "\fBnested_header_checks\fR (default: \fB$header_checks\fR)"
Lookup tables with content filters for message header lines:
respectively, these are applied to the primary message headers
(not including MIME headers), to the MIME headers anywhere in
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 Miscellaneous

View File

@@ -47,9 +47,12 @@ run chrooted at fixed low privilege.
.na
.nf
RFC 821 (SMTP protocol)
RFC 822 (ARPA Internet Text Messages)
RFC 1651 (SMTP service extensions)
RFC 1652 (8bit-MIME transport)
RFC 1870 (Message Size Declaration)
RFC 2045 (MIME: Format of Internet Message Bodies)
RFC 2046 (MIME: Media Types)
RFC 2197 (Pipelining)
RFC 2554 (AUTH command)
RFC 2821 (SMTP protocol)

View File

@@ -86,6 +86,8 @@ cleanup.o: ../../include/tok822.h
cleanup.o: ../../include/resolve_clnt.h
cleanup.o: ../../include/been_here.h
cleanup.o: ../../include/mail_stream.h
cleanup.o: ../../include/mime_state.h
cleanup.o: ../../include/header_opts.h
cleanup_api.o: cleanup_api.c
cleanup_api.o: ../../include/sys_defs.h
cleanup_api.o: ../../include/msg.h
@@ -111,6 +113,8 @@ cleanup_api.o: ../../include/tok822.h
cleanup_api.o: ../../include/resolve_clnt.h
cleanup_api.o: ../../include/been_here.h
cleanup_api.o: ../../include/mail_conf.h
cleanup_api.o: ../../include/mime_state.h
cleanup_api.o: ../../include/header_opts.h
cleanup_envelope.o: cleanup_envelope.c
cleanup_envelope.o: ../../include/sys_defs.h
cleanup_envelope.o: ../../include/msg.h
@@ -138,6 +142,8 @@ cleanup_envelope.o: ../../include/dict.h
cleanup_envelope.o: ../../include/been_here.h
cleanup_envelope.o: ../../include/mail_stream.h
cleanup_envelope.o: ../../include/mail_conf.h
cleanup_envelope.o: ../../include/mime_state.h
cleanup_envelope.o: ../../include/header_opts.h
cleanup_extracted.o: cleanup_extracted.c
cleanup_extracted.o: ../../include/sys_defs.h
cleanup_extracted.o: ../../include/msg.h
@@ -164,6 +170,8 @@ cleanup_extracted.o: ../../include/resolve_clnt.h
cleanup_extracted.o: ../../include/been_here.h
cleanup_extracted.o: ../../include/mail_stream.h
cleanup_extracted.o: ../../include/mail_conf.h
cleanup_extracted.o: ../../include/mime_state.h
cleanup_extracted.o: ../../include/header_opts.h
cleanup_init.o: cleanup_init.c
cleanup_init.o: ../../include/sys_defs.h
cleanup_init.o: ../../include/msg.h
@@ -187,6 +195,8 @@ cleanup_init.o: ../../include/resolve_clnt.h
cleanup_init.o: ../../include/been_here.h
cleanup_init.o: ../../include/mail_stream.h
cleanup_init.o: ../../include/mail_conf.h
cleanup_init.o: ../../include/mime_state.h
cleanup_init.o: ../../include/header_opts.h
cleanup_map11.o: cleanup_map11.c
cleanup_map11.o: ../../include/sys_defs.h
cleanup_map11.o: ../../include/msg.h
@@ -209,6 +219,8 @@ cleanup_map11.o: ../../include/resolve_clnt.h
cleanup_map11.o: ../../include/been_here.h
cleanup_map11.o: ../../include/mail_stream.h
cleanup_map11.o: ../../include/mail_conf.h
cleanup_map11.o: ../../include/mime_state.h
cleanup_map11.o: ../../include/header_opts.h
cleanup_map1n.o: cleanup_map1n.c
cleanup_map1n.o: ../../include/sys_defs.h
cleanup_map1n.o: ../../include/mymalloc.h
@@ -231,6 +243,8 @@ cleanup_map1n.o: ../../include/tok822.h
cleanup_map1n.o: ../../include/resolve_clnt.h
cleanup_map1n.o: ../../include/mail_stream.h
cleanup_map1n.o: ../../include/mail_conf.h
cleanup_map1n.o: ../../include/mime_state.h
cleanup_map1n.o: ../../include/header_opts.h
cleanup_masquerade.o: cleanup_masquerade.c
cleanup_masquerade.o: ../../include/sys_defs.h
cleanup_masquerade.o: ../../include/msg.h
@@ -253,6 +267,8 @@ cleanup_masquerade.o: ../../include/dict.h
cleanup_masquerade.o: ../../include/been_here.h
cleanup_masquerade.o: ../../include/mail_stream.h
cleanup_masquerade.o: ../../include/mail_conf.h
cleanup_masquerade.o: ../../include/mime_state.h
cleanup_masquerade.o: ../../include/header_opts.h
cleanup_message.o: cleanup_message.c
cleanup_message.o: ../../include/sys_defs.h
cleanup_message.o: ../../include/msg.h
@@ -281,6 +297,7 @@ cleanup_message.o: ../../include/ext_prop.h
cleanup_message.o: ../../include/mail_proto.h
cleanup_message.o: ../../include/iostuff.h
cleanup_message.o: ../../include/attr.h
cleanup_message.o: ../../include/mime_state.h
cleanup_message.o: cleanup.h
cleanup_message.o: ../../include/maps.h
cleanup_message.o: ../../include/dict.h
@@ -309,6 +326,8 @@ cleanup_out.o: ../../include/resolve_clnt.h
cleanup_out.o: ../../include/been_here.h
cleanup_out.o: ../../include/mail_stream.h
cleanup_out.o: ../../include/mail_conf.h
cleanup_out.o: ../../include/mime_state.h
cleanup_out.o: ../../include/header_opts.h
cleanup_out_recipient.o: cleanup_out_recipient.c
cleanup_out_recipient.o: ../../include/sys_defs.h
cleanup_out_recipient.o: ../../include/argv.h
@@ -329,6 +348,8 @@ cleanup_out_recipient.o: ../../include/tok822.h
cleanup_out_recipient.o: ../../include/resolve_clnt.h
cleanup_out_recipient.o: ../../include/mail_stream.h
cleanup_out_recipient.o: ../../include/mail_conf.h
cleanup_out_recipient.o: ../../include/mime_state.h
cleanup_out_recipient.o: ../../include/header_opts.h
cleanup_rewrite.o: cleanup_rewrite.c
cleanup_rewrite.o: ../../include/sys_defs.h
cleanup_rewrite.o: ../../include/msg.h
@@ -350,6 +371,8 @@ cleanup_rewrite.o: ../../include/dict.h
cleanup_rewrite.o: ../../include/been_here.h
cleanup_rewrite.o: ../../include/mail_stream.h
cleanup_rewrite.o: ../../include/mail_conf.h
cleanup_rewrite.o: ../../include/mime_state.h
cleanup_rewrite.o: ../../include/header_opts.h
cleanup_state.o: cleanup_state.c
cleanup_state.o: ../../include/sys_defs.h
cleanup_state.o: ../../include/mymalloc.h
@@ -359,6 +382,8 @@ cleanup_state.o: ../../include/argv.h
cleanup_state.o: ../../include/htable.h
cleanup_state.o: ../../include/been_here.h
cleanup_state.o: ../../include/mail_params.h
cleanup_state.o: ../../include/mime_state.h
cleanup_state.o: ../../include/header_opts.h
cleanup_state.o: cleanup.h
cleanup_state.o: ../../include/vstream.h
cleanup_state.o: ../../include/nvtable.h

View File

@@ -48,6 +48,8 @@
/* in case of trouble.
/* STANDARDS
/* RFC 822 (ARPA Internet Text Messages)
/* RFC 2045 (MIME: Format of Internet Message Bodies)
/* RFC 2046 (MIME: Media Types)
/* DIAGNOSTICS
/* Problems and transactions are logged to \fBsyslogd\fR(8).
/* BUGS
@@ -66,7 +68,12 @@
/* These filters see physical lines one at a time, in chunks of
/* at most line_length_limit bytes.
/* .IP \fBheader_checks\fR
/* Lookup tables with content filters for message header lines.
/* .IP "\fBmime_header_checks\fR (default: \fB$header_checks\fR)"
/* .IP "\fBnested_header_checks\fR (default: \fB$header_checks\fR)"
/* Lookup tables with content filters for message header lines:
/* respectively, these are applied to the primary message headers
/* (not including MIME headers), to the MIME headers anywhere in
/* 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 Miscellaneous
@@ -219,6 +226,16 @@ static void cleanup_service(VSTREAM *src, char *unused_service, char **argv)
break;
}
/*
* Can't do header checks if the MIME structure is nested too deeply.
*/
if ((state->mime_errs & MIME_ERR_NESTING)
&& (*var_header_checks || *var_mimehdr_checks || *var_nesthdr_checks)
&& state->reason == 0) {
state->errs |= CLEANUP_STAT_CONT;
state->reason = mystrdup("too much MIME nesting");
}
/*
* Keep reading in case of problems, until the sender is ready to receive
* our status report.

View File

@@ -24,6 +24,7 @@
#include <been_here.h>
#include <mail_stream.h>
#include <mail_conf.h>
#include <mime_state.h>
/*
* These state variables are accessed by many functions, and there is only
@@ -46,9 +47,7 @@ typedef struct CLEANUP_STATE {
int flags; /* processing options */
int errs; /* any badness experienced */
int err_mask; /* allowed badness */
VSTRING *header_buf; /* multi-record header */
int headers_seen; /* which headers were seen */
int prev_header_type; /* multi-record physical header line */
int hop_count; /* count of received: headers */
ARGV *recipients; /* recipients from regular headers */
ARGV *resent_recip; /* recipients from resent headers */
@@ -63,8 +62,12 @@ typedef struct CLEANUP_STATE {
int rcpt_count; /* recipient count */
char *reason; /* failure reason */
NVTABLE *attr; /* queue file attribute list */
MIME_STATE *mime_state; /* MIME state engine */
int mime_errs; /* MIME error flags */
} CLEANUP_STATE;
#define CLEANUP_CURR_HEADERS (1<<0) /* in main headers section */
/*
* Mappings.
*/
@@ -72,6 +75,8 @@ extern MAPS *cleanup_comm_canon_maps;
extern MAPS *cleanup_send_canon_maps;
extern MAPS *cleanup_rcpt_canon_maps;
extern MAPS *cleanup_header_checks;
extern MAPS *cleanup_mimehdr_checks;
extern MAPS *cleanup_nesthdr_checks;
extern MAPS *cleanup_body_checks;
extern MAPS *cleanup_virtual_maps;
extern ARGV *cleanup_masq_domains;
@@ -121,9 +126,9 @@ extern CONFIG_TIME_TABLE cleanup_time_table[];
/*
* cleanup_out.c
*/
extern void cleanup_out(CLEANUP_STATE *, int, char *, int);
extern void cleanup_out_string(CLEANUP_STATE *, int, char *);
extern void PRINTFLIKE(3, 4) cleanup_out_format(CLEANUP_STATE *, int, char *,...);
extern void cleanup_out(CLEANUP_STATE *, int, const char *, int);
extern void cleanup_out_string(CLEANUP_STATE *, int, const char *);
extern void PRINTFLIKE(3, 4) cleanup_out_format(CLEANUP_STATE *, int, const char *,...);
#define CLEANUP_OUT_BUF(s, t, b) \
cleanup_out((s), (t), vstring_str((b)), VSTRING_LEN((b)))

View File

@@ -91,14 +91,15 @@ char *cleanup_path; /* queue file name */
* Tunable parameters.
*/
int var_hopcount_limit; /* max mailer hop count */
int var_header_limit; /* max header length */
char *var_canonical_maps; /* common canonical maps */
char *var_send_canon_maps; /* sender canonical maps */
char *var_rcpt_canon_maps; /* recipient canonical maps */
char *var_virtual_maps; /* virtual maps */
char *var_masq_domains; /* masquerade domains */
char *var_masq_exceptions; /* users not masqueraded */
char *var_header_checks; /* any header checks */
char *var_header_checks; /* primary header checks */
char *var_mimehdr_checks; /* mime header checks */
char *var_nesthdr_checks; /* nested header checks */
char *var_body_checks; /* any body checks */
int var_dup_filter_limit; /* recipient dup filter */
char *var_empty_addr; /* destination of bounced bounces */
@@ -112,7 +113,6 @@ int var_qattr_count_limit; /* named attribute limit */
CONFIG_INT_TABLE cleanup_int_table[] = {
VAR_HOPCOUNT_LIMIT, DEF_HOPCOUNT_LIMIT, &var_hopcount_limit, 1, 0,
VAR_HEADER_LIMIT, DEF_HEADER_LIMIT, &var_header_limit, 1, 0,
VAR_DUP_FILTER_LIMIT, DEF_DUP_FILTER_LIMIT, &var_dup_filter_limit, 0, 0,
VAR_EXTRA_RCPT_LIMIT, DEF_EXTRA_RCPT_LIMIT, &var_extra_rcpt_limit, 0, 0,
VAR_QATTR_COUNT_LIMIT, DEF_QATTR_COUNT_LIMIT, &var_qattr_count_limit, 1, 0,
@@ -133,6 +133,8 @@ CONFIG_STR_TABLE cleanup_str_table[] = {
VAR_EMPTY_ADDR, DEF_EMPTY_ADDR, &var_empty_addr, 1, 0,
VAR_MASQ_EXCEPTIONS, DEF_MASQ_EXCEPTIONS, &var_masq_exceptions, 0, 0,
VAR_HEADER_CHECKS, DEF_HEADER_CHECKS, &var_header_checks, 0, 0,
VAR_MIMEHDR_CHECKS, DEF_MIMEHDR_CHECKS, &var_mimehdr_checks, 0, 0,
VAR_NESTHDR_CHECKS, DEF_NESTHDR_CHECKS, &var_nesthdr_checks, 0, 0,
VAR_BODY_CHECKS, DEF_BODY_CHECKS, &var_body_checks, 0, 0,
VAR_PROP_EXTENSION, DEF_PROP_EXTENSION, &var_prop_extension, 0, 0,
VAR_ALWAYS_BCC, DEF_ALWAYS_BCC, &var_always_bcc, 0, 0,
@@ -148,6 +150,8 @@ MAPS *cleanup_comm_canon_maps;
MAPS *cleanup_send_canon_maps;
MAPS *cleanup_rcpt_canon_maps;
MAPS *cleanup_header_checks;
MAPS *cleanup_mimehdr_checks;
MAPS *cleanup_nesthdr_checks;
MAPS *cleanup_body_checks;
MAPS *cleanup_virtual_maps;
ARGV *cleanup_masq_domains;
@@ -197,6 +201,12 @@ void cleanup_pre_jail(char *unused_name, char **unused_argv)
if (*var_header_checks)
cleanup_header_checks =
maps_create(VAR_HEADER_CHECKS, var_header_checks, DICT_FLAG_LOCK);
if (*var_mimehdr_checks)
cleanup_mimehdr_checks =
maps_create(VAR_MIMEHDR_CHECKS, var_mimehdr_checks, DICT_FLAG_LOCK);
if (*var_nesthdr_checks)
cleanup_nesthdr_checks =
maps_create(VAR_NESTHDR_CHECKS, var_nesthdr_checks, DICT_FLAG_LOCK);
if (*var_body_checks)
cleanup_body_checks =
maps_create(VAR_BODY_CHECKS, var_body_checks, DICT_FLAG_LOCK);

View File

@@ -78,19 +78,17 @@
#include <is_header.h>
#include <ext_prop.h>
#include <mail_proto.h>
#include <mime_state.h>
/* Application-specific. */
#include "cleanup.h"
static void cleanup_message_header(CLEANUP_STATE *, int, char *, int);
static void cleanup_message_body(CLEANUP_STATE *, int, char *, int);
/* cleanup_out_header - output one header as a bunch of records */
static void cleanup_out_header(CLEANUP_STATE *state)
static void cleanup_out_header(CLEANUP_STATE *state, VSTRING *header_buf)
{
char *start = vstring_str(state->header_buf);
char *start = vstring_str(header_buf);
char *line;
char *next_line;
@@ -113,9 +111,9 @@ static void cleanup_out_header(CLEANUP_STATE *state)
/* cleanup_fold_header - wrap address list header */
static void cleanup_fold_header(CLEANUP_STATE *state)
static void cleanup_fold_header(CLEANUP_STATE *state, VSTRING *header_buf)
{
char *start_line = vstring_str(state->header_buf);
char *start_line = vstring_str(header_buf);
char *end_line;
char *next_line;
char *line;
@@ -138,7 +136,7 @@ static void cleanup_fold_header(CLEANUP_STATE *state)
}
next_line = *end_line ? end_line + 1 : 0;
}
cleanup_out_header(state);
cleanup_out_header(state, header_buf);
}
/* cleanup_extract_internal - save unquoted copy of extracted address */
@@ -156,11 +154,13 @@ static char *cleanup_extract_internal(VSTRING *buffer, TOK822 *addr)
/* cleanup_rewrite_sender - sender address rewriting */
static void cleanup_rewrite_sender(CLEANUP_STATE *state, HEADER_OPTS *hdr_opts)
static void cleanup_rewrite_sender(CLEANUP_STATE *state, HEADER_OPTS *hdr_opts,
VSTRING *header_buf)
{
TOK822 *tree;
TOK822 **addr_list;
TOK822 **tpp;
char *addr;
if (msg_verbose)
msg_info("rewrite_sender: %s", hdr_opts->name);
@@ -170,8 +170,11 @@ static void cleanup_rewrite_sender(CLEANUP_STATE *state, HEADER_OPTS *hdr_opts)
* sender addresses, and regenerate the header line. Finally, pipe the
* result through the header line folding routine.
*/
tree = tok822_parse(vstring_str(state->header_buf)
+ strlen(hdr_opts->name) + 1);
#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);
addr_list = tok822_grep(tree, TOK822_ADDR);
for (tpp = addr_list; *tpp; tpp++) {
cleanup_rewrite_tree(*tpp);
@@ -185,33 +188,35 @@ static void cleanup_rewrite_sender(CLEANUP_STATE *state, HEADER_OPTS *hdr_opts)
&& (cleanup_masq_flags & CLEANUP_MASQ_FLAG_HDR_FROM))
cleanup_masquerade_tree(*tpp, cleanup_masq_domains);
if (hdr_opts->type == HDR_FROM && state->from == 0)
state->from = cleanup_extract_internal(state->header_buf, *tpp);
state->from = cleanup_extract_internal(header_buf, *tpp);
if (hdr_opts->type == HDR_RESENT_FROM && state->resent_from == 0)
state->resent_from =
cleanup_extract_internal(state->header_buf, *tpp);
cleanup_extract_internal(header_buf, *tpp);
if (hdr_opts->type == HDR_RETURN_RECEIPT_TO && !state->return_receipt)
state->return_receipt =
cleanup_extract_internal(state->header_buf, *tpp);
cleanup_extract_internal(header_buf, *tpp);
if (hdr_opts->type == HDR_ERRORS_TO && !state->errors_to)
state->errors_to =
cleanup_extract_internal(state->header_buf, *tpp);
cleanup_extract_internal(header_buf, *tpp);
}
vstring_sprintf(state->header_buf, "%s: ", hdr_opts->name);
tok822_externalize(state->header_buf, tree, TOK822_STR_HEAD);
vstring_sprintf(header_buf, "%s: ", hdr_opts->name);
tok822_externalize(header_buf, tree, TOK822_STR_HEAD);
myfree((char *) addr_list);
tok822_free_tree(tree);
if ((hdr_opts->flags & HDR_OPT_DROP) == 0)
cleanup_fold_header(state);
cleanup_fold_header(state, header_buf);
}
/* cleanup_rewrite_recip - recipient address rewriting */
static void cleanup_rewrite_recip(CLEANUP_STATE *state, HEADER_OPTS *hdr_opts)
static void cleanup_rewrite_recip(CLEANUP_STATE *state, HEADER_OPTS *hdr_opts,
VSTRING *header_buf)
{
TOK822 *tree;
TOK822 **addr_list;
TOK822 **tpp;
ARGV *rcpt;
char *addr;
if (msg_verbose)
msg_info("rewrite_recip: %s", hdr_opts->name);
@@ -221,8 +226,9 @@ static void cleanup_rewrite_recip(CLEANUP_STATE *state, HEADER_OPTS *hdr_opts)
* recipient addresses, and regenerate the header line. Finally, pipe the
* result through the header line folding routine.
*/
tree = tok822_parse(vstring_str(state->header_buf)
+ strlen(hdr_opts->name) + 1);
addr = vstring_str(header_buf) + strlen(hdr_opts->name);
SKIP_HEADER_THRASH(addr);
tree = tok822_parse(addr);
addr_list = tok822_grep(tree, TOK822_ADDR);
for (tpp = addr_list; *tpp; tpp++) {
cleanup_rewrite_tree(*tpp);
@@ -249,17 +255,17 @@ static void cleanup_rewrite_recip(CLEANUP_STATE *state, HEADER_OPTS *hdr_opts)
&& (cleanup_masq_flags & CLEANUP_MASQ_FLAG_HDR_RCPT))
cleanup_masquerade_tree(*tpp, cleanup_masq_domains);
}
vstring_sprintf(state->header_buf, "%s: ", hdr_opts->name);
tok822_externalize(state->header_buf, tree, TOK822_STR_HEAD);
vstring_sprintf(header_buf, "%s: ", hdr_opts->name);
tok822_externalize(header_buf, tree, TOK822_STR_HEAD);
myfree((char *) addr_list);
tok822_free_tree(tree);
if ((hdr_opts->flags & HDR_OPT_DROP) == 0)
cleanup_fold_header(state);
cleanup_fold_header(state, header_buf);
}
/* cleanup_act - act upon a header/body match */
static int cleanup_act(CLEANUP_STATE *state, char *context, char *buf,
static int cleanup_act(CLEANUP_STATE *state, char *context, const char *buf,
const char *value, const char *map_class)
{
const char *optional_text = value + strcspn(value, " \t");
@@ -308,12 +314,13 @@ static int cleanup_act(CLEANUP_STATE *state, char *context, char *buf,
return (CLEANUP_ACT_KEEP);
}
/* cleanup_header - process one complete header line */
/* cleanup_header_callback - process one complete header line */
static void cleanup_header(CLEANUP_STATE *state)
static void cleanup_header_callback(void *context, int header_class,
HEADER_OPTS *hdr_opts, VSTRING *header_buf)
{
char *myname = "cleanup_header";
HEADER_OPTS *hdr_opts;
CLEANUP_STATE *state = (CLEANUP_STATE *) context;
const char *myname = "cleanup_header_callback";
char *hdrval;
struct code_map {
const char *name;
@@ -328,16 +335,31 @@ static void cleanup_header(CLEANUP_STATE *state)
0,
};
struct code_map *cmp;
MAPS *checks;
const char *map_class;
if (msg_verbose)
msg_info("%s: '%s'", myname, vstring_str(state->header_buf));
msg_info("%s: '%s'", myname, vstring_str(header_buf));
if ((state->flags & CLEANUP_FLAG_FILTER) && cleanup_header_checks) {
char *header = vstring_str(state->header_buf);
/*
* Crude header filtering. This stops malware that isn't sophisticated
* enough to use fancy header encodings.
*/
#define CHECK(class, maps, var_name) \
(header_class == class && (map_class = var_name, checks = maps) != 0)
if (hdr_opts && (hdr_opts->flags & HDR_OPT_MIME))
header_class = MIME_HDR_MULTIPART;
if ((state->flags & CLEANUP_FLAG_FILTER)
&& (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);
const char *value;
if ((value = maps_find(cleanup_header_checks, header, 0)) != 0) {
if (cleanup_act(state, "header", header, value, VAR_HEADER_CHECKS)
if ((value = maps_find(checks, header, 0)) != 0) {
if (cleanup_act(state, "header", header, value, map_class)
== CLEANUP_ACT_DROP)
return;
}
@@ -346,10 +368,38 @@ static void cleanup_header(CLEANUP_STATE *state)
/*
* If this is an "unknown" header, just copy it to the output without
* even bothering to fold long lines. cleanup_out() will split long
* headers that do not fit in a REC_TYPE_NORM record.
* headers that do not fit a REC_TYPE_NORM record.
*/
if ((hdr_opts = header_opts_find(vstring_str(state->header_buf))) == 0) {
cleanup_out_header(state);
if (hdr_opts == 0) {
cleanup_out_header(state, header_buf);
return;
}
/*
* 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);
/* 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)
nvtable_update(state->attr, MAIL_ATTR_ENCODING,
cmp->encoding);
break;
}
}
}
/*
* Copy attachment etc. header blocks without further inspection.
*/
if (header_class != MIME_HDR_PRIMARY) {
cleanup_out_header(state, header_buf);
return;
}
/*
@@ -383,10 +433,6 @@ static void cleanup_header(CLEANUP_STATE *state)
*/
else {
state->headers_seen |= (1 << hdr_opts->type);
hdrval = vstring_str(state->header_buf) + strlen(hdr_opts->name) + 2;
while (ISSPACE(*hdrval))
hdrval++;
trimblanks(hdrval, 0);
if (hdr_opts->type == HDR_MESSAGE_ID)
msg_info("%s: message-id=%s", state->queue_id, hdrval);
if (hdr_opts->type == HDR_RESENT_MESSAGE_ID)
@@ -394,35 +440,25 @@ static void cleanup_header(CLEANUP_STATE *state)
if (hdr_opts->type == HDR_RECEIVED)
if (++state->hop_count >= var_hopcount_limit)
state->errs |= CLEANUP_STAT_HOPS;
if (hdr_opts->type == HDR_CONTENT_TRANSFER_ENCODING) {
if (nvtable_find(state->attr, MAIL_ATTR_ENCODING) == 0) {
for (cmp = code_map; cmp->name != 0; cmp++) {
if (strcasecmp(hdrval, cmp->name) == 0) {
nvtable_update(state->attr, MAIL_ATTR_ENCODING,
cmp->encoding);
break;
}
}
}
}
if (CLEANUP_OUT_OK(state)) {
if (hdr_opts->flags & HDR_OPT_RR)
state->resent = "Resent-";
if (hdr_opts->flags & HDR_OPT_SENDER) {
cleanup_rewrite_sender(state, hdr_opts);
cleanup_rewrite_sender(state, hdr_opts, header_buf);
} else if (hdr_opts->flags & HDR_OPT_RECIP) {
cleanup_rewrite_recip(state, hdr_opts);
cleanup_rewrite_recip(state, hdr_opts, header_buf);
} else if ((hdr_opts->flags & HDR_OPT_DROP) == 0) {
cleanup_out_header(state);
cleanup_out_header(state, header_buf);
}
}
}
}
/* cleanup_missing_headers - insert missing message headers */
/* cleanup_header_done_callback - insert missing message headers */
static void cleanup_missing_headers(CLEANUP_STATE *state)
static void cleanup_header_done_callback(void *context)
{
CLEANUP_STATE *state = (CLEANUP_STATE *) context;
char time_stamp[1024]; /* XXX locale dependent? */
struct tm *tp;
TOK822 *token;
@@ -507,6 +543,74 @@ static void cleanup_missing_headers(CLEANUP_STATE *state)
if ((state->headers_seen & VISIBLE_RCPT) == 0)
cleanup_out_format(state, REC_TYPE_NORM, "%s", var_rcpt_witheld);
/*
* Header buffer overflow is an unrecoverable error only if we extract
* recipients from the main message headers.
*/
if (state->mime_errs & MIME_ERR_TRUNC_HEADER)
state->errs |= CLEANUP_STAT_HOVFL;
}
/* cleanup_body_callback - output one body record */
static void cleanup_body_callback(void *context, int type, const char *buf, int len)
{
CLEANUP_STATE *state = (CLEANUP_STATE *) context;
/*
* Crude message body content filter for emergencies. This code has
* several problems: it sees one line at a time; it looks at long lines
* only in chunks of line_length_limit (2048) characters; it is easily
* bypassed with encodings and other tricks.
*/
if ((state->flags & CLEANUP_FLAG_FILTER) && cleanup_body_checks) {
const char *value;
if ((value = maps_find(cleanup_body_checks, buf, 0)) != 0) {
if (cleanup_act(state, "body", buf, value, VAR_BODY_CHECKS)
== CLEANUP_ACT_DROP)
return;
}
}
cleanup_out(state, type, buf, len);
}
/* cleanup_message_headerbody - process message content, header and body */
static void cleanup_message_headerbody(CLEANUP_STATE *state, int type,
char *buf, int len)
{
char *myname = "cleanup_message_headerbody";
/*
* Copy text record to the output.
*/
if (type == REC_TYPE_NORM || type == REC_TYPE_CONT) {
state->mime_errs = mime_state_update(state->mime_state, type, buf, len);
}
/*
* 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);
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);
state->action = cleanup_extracted;
}
/*
* This should never happen.
*/
else {
msg_warn("%s: unexpected record type: %d", myname, type);
state->errs |= CLEANUP_STAT_BAD;
}
}
/* cleanup_message - initialize message content segment */
@@ -529,136 +633,12 @@ void cleanup_message(CLEANUP_STATE *state, int type, char *buf, int len)
/*
* Pass control to the header processing routine.
*/
state->action = cleanup_message_header;
cleanup_message_header(state, type, buf, len);
}
/* cleanup_message_header - process message content, header */
static void cleanup_message_header(CLEANUP_STATE *state, int type, char *buf, int len)
{
char *myname = "cleanup_message_header";
/*
* Sanity check.
*/
if (strchr(REC_TYPE_CONTENT, type) == 0) {
msg_warn("%s: %s: unexpected record type %d",
state->queue_id, myname, type);
state->errs |= CLEANUP_STAT_BAD;
return;
}
/*
* First, deal with header information that we have accumulated from
* previous input records.
*
* If a physical header line exceeds the capacity of a Postfix queue file
* record, reconstruct the long line from multiple records (up to the
* header size limit), and break the long line up into multiple Postfix
* records upon output to the queue file. Discard text that does not fit
* in a header buffer, so as to avoid breaking MIME formatting.
*
* It is left up to delivery agents to glue long lines back together and to
* enforce an appropriate output line length limit.
*/
if (VSTRING_LEN(state->header_buf) > 0) {
if (type != REC_TYPE_XTRA) {
if (state->prev_header_type == REC_TYPE_CONT) {
if (VSTRING_LEN(state->header_buf) < var_header_limit)
vstring_strcat(state->header_buf, buf);
else
state->errs |= CLEANUP_STAT_HOVFL;
state->prev_header_type = type;
return;
}
if (ISSPACE(*buf)) {
if (VSTRING_LEN(state->header_buf) < var_header_limit) {
VSTRING_ADDCH(state->header_buf, '\n');
vstring_strcat(state->header_buf, buf);
} else
state->errs |= CLEANUP_STAT_HOVFL;
state->prev_header_type = type;
return;
}
}
/*
* No more input to append to this saved header. Do output processing
* and reset the saved header buffer.
*/
VSTRING_TERMINATE(state->header_buf);
cleanup_header(state);
VSTRING_RESET(state->header_buf);
}
/*
* Switch to body processing if this is not a header. Generate missing
* headers. Add one blank line when the message headers are immediately
* followed by a non-empty message body.
*/
if (type == REC_TYPE_XTRA || !is_header(buf)) {
cleanup_missing_headers(state);
if (type != REC_TYPE_XTRA && *buf) /* output blank line */
cleanup_out_string(state, REC_TYPE_NORM, "");
state->action = cleanup_message_body;
cleanup_message_body(state, type, buf, len);
}
/*
* Save this header record until we know that the header is complete.
*/
else {
vstring_strcpy(state->header_buf, buf);
state->prev_header_type = type;
}
}
/* cleanup_message_body - process message segment, body */
static void cleanup_message_body(CLEANUP_STATE *state, int type, char *buf, int len)
{
char *myname = "cleanup_message_body";
/*
* Copy body record to the output.
*/
if (type == REC_TYPE_NORM || type == REC_TYPE_CONT) {
/*
* Crude message body content filter for emergencies. This code has
* several problems: it sees one line at a time, and therefore does
* not recognize multi-line MIME headers in the body; it looks at
* long lines only in chunks of line_length_limit (2048) characters;
* it is easily bypassed with encodings and with multi-line tricks.
*/
if ((state->flags & CLEANUP_FLAG_FILTER) && cleanup_body_checks) {
const char *value;
if ((value = maps_find(cleanup_body_checks, buf, 0)) != 0) {
if (cleanup_act(state, "body", buf, value, VAR_BODY_CHECKS)
== CLEANUP_ACT_DROP)
return;
}
}
cleanup_out(state, type, buf, len);
}
/*
* 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) {
if ((state->xtra_offset = vstream_ftell(state->dst)) < 0)
msg_fatal("%s: vstream_ftell %s: %m", myname, cleanup_path);
state->action = cleanup_extracted;
}
/*
* This should never happen.
*/
else {
msg_warn("%s: unexpected record type: %d", myname, type);
state->errs |= CLEANUP_STAT_BAD;
}
state->mime_state = mime_state_alloc(MIME_OPT_REPORT_TRUNC_HEADER,
cleanup_header_callback,
cleanup_header_done_callback,
cleanup_body_callback,
(MIME_STATE_ANY_END) 0,
(void *) state);
state->action = cleanup_message_headerbody;
cleanup_message_headerbody(state, type, buf, len);
}

View File

@@ -12,13 +12,13 @@
/* void cleanup_out(state, type, data, len)
/* CLEANUP_STATE *state;
/* int type;
/* char *data;
/* const char *data;
/* int len;
/*
/* void cleanup_out_string(state, type, str)
/* CLEANUP_STATE *state;
/* int type;
/* char *str;
/* const char *str;
/*
/* void CLEANUP_OUT_BUF(state, type, buf)
/* CLEANUP_STATE *state;
@@ -28,7 +28,7 @@
/* void cleanup_out_format(state, type, format, ...)
/* CLEANUP_STATE *state;
/* int type;
/* char *format;
/* const char *format;
/* DESCRIPTION
/* This module writes records to the output stream.
/*
@@ -85,7 +85,7 @@
/* cleanup_out - output one single record */
void cleanup_out(CLEANUP_STATE *state, int type, char *string, int len)
void cleanup_out(CLEANUP_STATE *state, int type, const char *string, int len)
{
int err = 0;
@@ -129,14 +129,14 @@ void cleanup_out(CLEANUP_STATE *state, int type, char *string, int len)
/* cleanup_out_string - output string to one single record */
void cleanup_out_string(CLEANUP_STATE *state, int type, char *string)
void cleanup_out_string(CLEANUP_STATE *state, int type, const char *string)
{
cleanup_out(state, type, string, strlen(string));
}
/* cleanup_out_format - output one formatted record */
void cleanup_out_format(CLEANUP_STATE *state, int type, char *fmt,...)
void cleanup_out_format(CLEANUP_STATE *state, int type, const char *fmt,...)
{
static VSTRING *vp;
va_list ap;

View File

@@ -44,6 +44,7 @@
#include <been_here.h>
#include <mail_params.h>
#include <mime_state.h>
/* Application-specific. */
@@ -71,9 +72,7 @@ CLEANUP_STATE *cleanup_state_alloc(void)
state->flags = 0;
state->errs = 0;
state->err_mask = 0;
state->header_buf = vstring_alloc(100);
state->headers_seen = 0;
state->prev_header_type = 0;
state->hop_count = 0;
state->recipients = argv_alloc(2);
state->resent_recip = argv_alloc(2);
@@ -88,6 +87,8 @@ CLEANUP_STATE *cleanup_state_alloc(void)
state->rcpt_count = 0;
state->reason = 0;
state->attr = nvtable_create(10);
state->mime_state = 0;
state->mime_errs = 0;
return (state);
}
@@ -111,7 +112,6 @@ void cleanup_state_free(CLEANUP_STATE *state)
myfree(state->return_receipt);
if (state->errors_to)
myfree(state->errors_to);
vstring_free(state->header_buf);
argv_free(state->recipients);
argv_free(state->resent_recip);
if (state->queue_id)
@@ -120,5 +120,7 @@ void cleanup_state_free(CLEANUP_STATE *state)
if (state->reason)
myfree(state->reason);
nvtable_free(state->attr);
if (state->mime_state)
mime_state_free(state->mime_state);
myfree((char *) state);
}

View File

@@ -19,7 +19,7 @@ SRCS = been_here.c bounce.c canon_addr.c cleanup_strerror.c clnt_stream.c \
timed_ipc.c tok822_find.c tok822_node.c tok822_parse.c \
tok822_resolve.c tok822_rewrite.c tok822_tree.c xtext.c bounce_log.c \
flush_clnt.c mail_conf_time.c mbox_conf.c mbox_open.c abounce.c \
verp_sender.c match_parent_style.c
verp_sender.c match_parent_style.c mime_state.c header_token.c
OBJS = been_here.o bounce.o canon_addr.o cleanup_strerror.o clnt_stream.o \
debug_peer.o debug_process.o defer.o deliver_completed.o \
deliver_flock.o deliver_pass.o deliver_request.o domain_list.o \
@@ -40,7 +40,7 @@ OBJS = been_here.o bounce.o canon_addr.o cleanup_strerror.o clnt_stream.o \
timed_ipc.o tok822_find.o tok822_node.o tok822_parse.o \
tok822_resolve.o tok822_rewrite.o tok822_tree.o xtext.o bounce_log.o \
flush_clnt.o mail_conf_time.o mbox_conf.o mbox_open.o abounce.o \
verp_sender.o match_parent_style.o
verp_sender.o match_parent_style.o mime_state.o header_token.o
HDRS = been_here.h bounce.h canon_addr.h cleanup_user.h clnt_stream.h \
config.h debug_peer.h debug_process.h defer.h deliver_completed.h \
deliver_flock.h deliver_pass.h deliver_request.h domain_list.h \
@@ -57,7 +57,7 @@ HDRS = been_here.h bounce.h canon_addr.h cleanup_user.h clnt_stream.h \
rewrite_clnt.h sent.h smtp_stream.h split_addr.h string_list.h \
sys_exits.h timed_ipc.h tok822.h xtext.h bounce_log.h flush_clnt.h \
mbox_conf.h mbox_open.h abounce.h qmqp_proto.h verp_sender.h \
match_parent_style.h quote_flags.h
match_parent_style.h quote_flags.h mime_state.h header_token.h
TESTSRC = rec2stream.c stream2rec.c recdump.c
WARN = -W -Wformat -Wimplicit -Wmissing-prototypes \
-Wparentheses -Wstrict-prototypes -Wswitch -Wuninitialized \
@@ -70,7 +70,7 @@ TESTPROG= domain_list dot_lockfile mail_addr_crunch mail_addr_find \
mail_addr_map mail_date maps mynetworks mypwd namadr_list \
off_cvt quote_822_local rec2stream recdump resolve_clnt \
resolve_local rewrite_clnt stream2rec string_list tok822_parse \
quote_821_local mail_conf_time
quote_821_local mail_conf_time mime_state
LIBS = ../../lib/libutil.a
LIB_DIR = ../../lib
@@ -213,13 +213,23 @@ mail_conf_time: $(LIB) $(LIBS)
$(CC) -DTEST $(CFLAGS) -o $@ $@.c $(LIB) $(LIBS) $(SYSLIBS)
mv junk $@.o
tests: tok822_test
mime_state: $(LIB) $(LIBS)
mv $@.o junk
$(CC) -DTEST $(CFLAGS) -o $@ $@.c $(LIB) $(LIBS) $(SYSLIBS)
mv junk $@.o
tests: tok822_test mime_test
tok822_test: tok822_parse tok822_parse.in tok822_parse.ref
./tok822_parse <tok822_parse.in >tok822_parse.tmp
diff tok822_parse.ref tok822_parse.tmp
rm -f tok822_parse.tmp
mime_test: mime_state mime_test.in mime_test.ref
./mime_state <mime_test.in >mime_test.tmp
diff mime_test.ref mime_test.tmp
rm -f mime_test.tmp
printfck: $(OBJS) $(PROG)
rm -rf printfck
mkdir printfck
@@ -441,7 +451,14 @@ header_opts.o: ../../include/msg.h
header_opts.o: ../../include/htable.h
header_opts.o: ../../include/vstring.h
header_opts.o: ../../include/vbuf.h
header_opts.o: ../../include/stringops.h
header_opts.o: header_opts.h
header_token.o: header_token.c
header_token.o: ../../include/sys_defs.h
header_token.o: ../../include/msg.h
header_token.o: ../../include/vstring.h
header_token.o: ../../include/vbuf.h
header_token.o: header_token.h
is_header.o: is_header.c
is_header.o: ../../include/sys_defs.h
is_header.o: is_header.h
@@ -766,6 +783,18 @@ mbox_open.o: ../../include/myflock.h
mbox_open.o: mbox_conf.h
mbox_open.o: ../../include/argv.h
mbox_open.o: mbox_open.h
mime_state.o: mime_state.c
mime_state.o: ../../include/sys_defs.h
mime_state.o: ../../include/mymalloc.h
mime_state.o: ../../include/msg.h
mime_state.o: ../../include/vstring.h
mime_state.o: ../../include/vbuf.h
mime_state.o: rec_type.h
mime_state.o: is_header.h
mime_state.o: header_opts.h
mime_state.o: mail_params.h
mime_state.o: header_token.h
mime_state.o: mime_state.h
mkmap_db.o: mkmap_db.c
mkmap_db.o: ../../include/sys_defs.h
mkmap_db.o: ../../include/msg.h

32
postfix/src/global/foobar Normal file
View File

@@ -0,0 +1,32 @@
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

View File

@@ -38,6 +38,7 @@
#include <msg.h>
#include <htable.h>
#include <vstring.h>
#include <stringops.h>
/* Global library. */
@@ -51,14 +52,19 @@ static HEADER_OPTS header_opts[] = {
"Apparently-To", HDR_APPARENTLY_TO, HDR_OPT_RECIP,
"Bcc", HDR_BCC, HDR_OPT_DROP | HDR_OPT_XRECIP,
"Cc", HDR_CC, HDR_OPT_XRECIP,
"Content-Transfer-Encoding", HDR_CONTENT_TRANSFER_ENCODING, 0,
"Content-Description", HDR_CONTENT_DESCRIPTION, HDR_OPT_MIME,
"Content-Disposition", HDR_CONTENT_DISPOSITION, HDR_OPT_MIME,
"Content-ID", HDR_CONTENT_ID, HDR_OPT_MIME,
"Content-Length", HDR_CONTENT_LENGTH, HDR_OPT_DROP,
"Content-Transfer-Encoding", HDR_CONTENT_TRANSFER_ENCODING, HDR_OPT_MIME,
"Content-Type", HDR_CONTENT_TYPE, HDR_OPT_MIME,
"Delivered-To", HDR_DELIVERED_TO, 0,
"Date", HDR_DATE, 0,
"Errors-To", HDR_ERRORS_TO, HDR_OPT_SENDER,
"From", HDR_FROM, HDR_OPT_SENDER,
"Mail-Followup-To", HDR_MAIL_FOLLOWUP_TO, HDR_OPT_SENDER,
"Message-Id", HDR_MESSAGE_ID, 0,
"MIME-Version", HDR_MIME_VERSION, HDR_OPT_MIME,
"Received", HDR_RECEIVED, 0,
"Reply-To", HDR_REPLY_TO, HDR_OPT_SENDER,
"Resent-Bcc", HDR_RESENT_BCC, HDR_OPT_DROP | HDR_OPT_XRECIP | HDR_OPT_RR,
@@ -120,6 +126,9 @@ HEADER_OPTS *header_opts_find(const char *string)
msg_panic("header_opts_find: no colon in header: %.30s", string);
VSTRING_ADDCH(header_key, TOLOWER(*cp));
}
vstring_truncate(header_key,
trimblanks(vstring_str(header_key), cp - string)
- vstring_str(header_key));
VSTRING_TERMINATE(header_key);
return ((HEADER_OPTS *) htable_find(header_hash, vstring_str(header_key)));
}

View File

@@ -49,6 +49,10 @@ typedef struct {
#define HDR_SENDER 24
#define HDR_TO 25
#define HDR_MAIL_FOLLOWUP_TO 26
#define HDR_CONTENT_DESCRIPTION 27
#define HDR_CONTENT_DISPOSITION 28
#define HDR_CONTENT_ID 29
#define HDR_MIME_VERSION 30
/*
* Header flags.
@@ -58,6 +62,7 @@ typedef struct {
#define HDR_OPT_RECIP (1<<2) /* recipient address */
#define HDR_OPT_RR (1<<3) /* Resent- header */
#define HDR_OPT_EXTRACT (1<<4) /* extract flag */
#define HDR_OPT_MIME (1<<5) /* MIME header */
#define HDR_OPT_XRECIP (HDR_OPT_RECIP | HDR_OPT_EXTRACT)

View File

@@ -0,0 +1,263 @@
/*++
/* NAME
/* header_token 3
/* SUMMARY
/* mail header parser
/* SYNOPSIS
/* #include <header_token.h>
/*
/* typedef struct {
/* .in +4
/* int type;
/* const char *u.value;
/* /* ... */
/* .in
/* } HEADER_TOKEN;
/*
/* int header_token(token, token_len, token_buffer, ptr,
/* specials, terminator)
/* HEADER_TOKEN *token;
/* int token_len;
/* VSTRING *token_buffer;
/* const char **ptr;
/* const char *specials;
/* int terminator;
/* DESCRIPTION
/* This module parses a mail header value (text after field-name:)
/* into tokens. The parser understands RFC 822 linear white space,
/* quoted-string, comment, control characters, and a set of
/* user-specified special characters.
/*
/* A token type is one of the following:
/* .IP HEADER_TOK_QSTRING
/* Quoted string as per RFC 822.
/* .IP HEADER_TOK_TOKEN
/* Token as per RFC 822, and the special characters supplied by the
/* caller.
/* .IP other
/* The value of a control character or special character.
/* .PP
/* header_token() tokenizes the input and stops after a user-specified
/* terminator (ignoring all tokens that exceed the capacity of
/* the result storage), or when it runs out of space for the result.
/* The terminator is not stored. The result value is the number of
/* tokens stored, or -1 when the input was exhausted before any tokens
/* were found.
/*
/* Arguments:
/* .IP token
/* Result array of HEADER_TOKEN structures.
/* .IP token_len
/* Length of the array of HEADER_TOKEN structures.
/* .IP token_buffer
/* Storage for result token values.
/* .IP ptr
/* Input/output read position. The input is a null-terminated string.
/* .IP specials
/* Special characters according to the relevant RFC, or a
/* null pointer (default to the RFC 822 special characters).
/* This must include the optional terminator if one is specified.
/* .IP terminator
/* The special character to stop after, or zero.
/* BUGS
/* Eight-bit characters are not given special treatment.
/* SEE ALSO
/* RFC 822 (ARPA Internet Text Messages)
/* DIAGNOSTICS
/* Fatal errors: memory allocation problem.
/* 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 <string.h>
#include <ctype.h>
/* Utility library. */
#include <msg.h>
#include <vstring.h>
/* Global library. */
#include <header_token.h>
/* Application-specific. */
/*
* Special characters and linear white space, as per RFC 822.
*/
#define RFC822_SPECIALS "()<>@,;:\\\".[]"
#define RFC822_LWSP(ch) (ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r')
/*
* Silly little macros.
*/
#define STR(x) vstring_str(x)
#define LEN(x) VSTRING_LEN(x)
#define CU_CHAR_PTR(x) ((const unsigned char *) (x))
/* header_token - parse out the next item in a message header */
int header_token(HEADER_TOKEN *token, int token_len,
VSTRING *token_buffer, const char **ptr,
const char *user_specials, int user_terminator)
{
int comment_level;
const unsigned char *cp;
int len;
int ch;
int tok_count;
int n;
/*
* Initialize.
*/
VSTRING_RESET(token_buffer);
cp = CU_CHAR_PTR(*ptr);
tok_count = 0;
if (user_specials == 0)
user_specials = RFC822_SPECIALS;
/*
* Main parsing loop.
*/
while ((ch = *cp) != 0 && (user_terminator != 0 || tok_count < token_len)) {
cp++;
/*
* Skip RFC 822 linear white space.
*/
if (RFC822_LWSP(ch))
continue;
/*
* Terminator.
*/
if (ch == user_terminator)
break;
/*
* Skip RFC 822 comment.
*/
if (ch == '(') {
comment_level = 1;
while ((ch = *cp) != 0) {
cp++;
if (ch == '(') { /* comments can nest! */
comment_level++;
} else if (ch == ')') {
if (--comment_level == 0)
break;
} else if (ch == '\\') {
if ((ch = *cp) == 0)
break;
cp++;
}
}
continue;
}
/*
* Copy quoted text according to RFC 822.
*/
if (ch == '"') {
if (tok_count < token_len) {
token[tok_count].u.offset = LEN(token_buffer);
token[tok_count].type = HEADER_TOK_QSTRING;
}
while ((ch = *cp) != 0) {
cp++;
if (ch == '"')
break;
if (ch == '\n') { /* unfold */
len = LEN(token_buffer);
while (len > 0 && RFC822_LWSP(STR(token_buffer)[len - 1]))
len--;
if (len < LEN(token_buffer))
vstring_truncate(token_buffer, len);
continue;
}
if (ch == '\\') {
if ((ch = *cp) == 0)
break;
cp++;
}
if (tok_count < token_len)
VSTRING_ADDCH(token_buffer, ch);
}
if (tok_count < token_len) {
VSTRING_ADDCH(token_buffer, 0);
tok_count++;
}
continue;
}
/*
* Control, or special.
*/
if (strchr(user_specials, ch) || ISCNTRL(ch)) {
if (tok_count < token_len) {
token[tok_count].u.offset = LEN(token_buffer);
token[tok_count].type = ch;
VSTRING_ADDCH(token_buffer, ch);
VSTRING_ADDCH(token_buffer, 0);
tok_count++;
}
continue;
}
/*
* Token.
*/
else {
if (tok_count < token_len) {
token[tok_count].u.offset = LEN(token_buffer);
token[tok_count].type = HEADER_TOK_TOKEN;
VSTRING_ADDCH(token_buffer, ch);
}
while ((ch = *cp) != 0 && !RFC822_LWSP(ch)
&& !ISCNTRL(ch) && !strchr(user_specials, ch)) {
cp++;
if (tok_count < token_len)
VSTRING_ADDCH(token_buffer, ch);
}
if (tok_count < token_len) {
VSTRING_ADDCH(token_buffer, 0);
tok_count++;
}
continue;
}
}
/*
* Ignore a zero-length item after the last terminator.
*/
if (tok_count == 0 && ch == 0)
return (-1);
/*
* Finalize. Fill in the string pointer array, now that the token buffer
* is no longer dynamically reallocated as it grows.
*/
*ptr = (const char *) cp;
for (n = 0; n < tok_count; n++)
token[n].u.value = STR(token_buffer) + token[n].u.offset;
if (msg_verbose)
msg_info("header_token: %s %s %s",
tok_count > 0 ? token[0].u.value : "",
tok_count > 1 ? token[1].u.value : "",
tok_count > 2 ? token[2].u.value : "");
return (tok_count);
}

View File

@@ -0,0 +1,47 @@
#ifndef _HEADER_TOKEN_H_INCLUDED_
#define _HEADER_TOKEN_H_INCLUDED_
/*++
/* NAME
/* header_token 3h
/* SUMMARY
/* mail header parser
/* SYNOPSIS
/* #include "header_token.h"
DESCRIPTION
.nf
/*
* Utility library.
*/
#include <vstring.h>
/*
* HEADER header parser tokens. Specials and controls are represented by
* themselves. Character pointers point to substrings in a token buffer.
*/
typedef struct HEADER_TOKEN {
int type; /* see below */
union {
const char *value; /* just a pointer, not a copy */
int offset; /* index into token buffer */
} u; /* indent beats any alternative */
} HEADER_TOKEN;
#define HEADER_TOK_TOKEN 256
#define HEADER_TOK_QSTRING 257
extern int header_token(HEADER_TOKEN *, int, VSTRING *, const char **, const char *, int);
/* 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
/*--*/
#endif

View File

@@ -10,8 +10,8 @@
/* 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.
/* when it begins with a mail header name + optional space + colon.
/* The result is the length of the mail header name.
/* STANDARDS
/* RFC 822 (ARPA Internet Text Messages)
/* LICENSE
@@ -38,21 +38,42 @@
int is_header(const char *str)
{
const char *cp;
const unsigned char *cp;
int state;
int c;
int len;
#define INIT 0
#define IN_CHAR 1
#define IN_CHAR_SPACE 2
#define CU_CHAR_PTR(x) ((const unsigned char *) (x))
/*
* XXX RFC 2822 Section 4.5.2, Obsolete header fields: whitespace may
* 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.
*/
for (cp = str; (c = *(unsigned char *) cp) != 0; cp++) {
if (c == ':')
return (cp > str);
if ( /* !ISASCII(c) || */ ISSPACE(c) || ISCNTRL(c))
break;
for (len = 0, state = INIT, cp = CU_CHAR_PTR(str); (c = *cp) != 0; cp++) {
switch (c) {
default:
if (!ISASCII(c) || ISCNTRL(c))
return (0);
if (state == INIT)
state = IN_CHAR;
if (state == IN_CHAR) {
len++;
continue;
}
return (0);
case ' ':
case '\t':
if (state == IN_CHAR)
state = IN_CHAR_SPACE;
if (state == IN_CHAR_SPACE)
continue;
return (0);
case ':':
return ((state == IN_CHAR || state == IN_CHAR_SPACE) ? len : 0);
}
}
return (0);
}

View File

@@ -0,0 +1,73 @@
/*++
/* 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);
}

View File

@@ -87,6 +87,9 @@
/* char *var_flush_service;
/* int var_db_create_buf;
/* int var_db_read_buf;
/* int var_mime_maxdepth;
/* int var_mime_bound_len;
/* int var_header_limit;
/*
/* void mail_params_init()
/* DESCRIPTION
@@ -230,6 +233,9 @@ char *var_error_service;
char *var_flush_service;
int var_db_create_buf;
int var_db_read_buf;
int var_mime_maxdepth;
int var_mime_bound_len;
int var_header_limit;
#define MAIN_CONF_FILE "main.cf"
@@ -465,6 +471,9 @@ void mail_params_init()
VAR_FAULT_INJ_CODE, DEF_FAULT_INJ_CODE, &var_fault_inj_code, 0, 0,
VAR_DB_CREATE_BUF, DEF_DB_CREATE_BUF, &var_db_create_buf, 1, 0,
VAR_DB_READ_BUF, DEF_DB_READ_BUF, &var_db_read_buf, 1, 0,
VAR_HEADER_LIMIT, DEF_HEADER_LIMIT, &var_header_limit, 1, 0,
VAR_MIME_MAXDEPTH, DEF_MIME_MAXDEPTH, &var_mime_maxdepth, 1, 0,
VAR_MIME_BOUND_LEN, DEF_MIME_BOUND_LEN, &var_mime_bound_len, 1, 0,
0,
};
static CONFIG_TIME_TABLE time_defaults[] = {

View File

@@ -984,6 +984,14 @@ extern int var_queue_minfree;
#define DEF_HEADER_CHECKS ""
extern char *var_header_checks;
#define VAR_MIMEHDR_CHECKS "mime_header_checks"
#define DEF_MIMEHDR_CHECKS "$header_checks"
extern char *var_mimehdr_checks;
#define VAR_NESTHDR_CHECKS "nested_header_checks"
#define DEF_NESTHDR_CHECKS "$header_checks"
extern char *var_nesthdr_checks;
#define VAR_BODY_CHECKS "body_checks"
#define DEF_BODY_CHECKS ""
extern char *var_body_checks;
@@ -1504,6 +1512,17 @@ extern int var_db_read_buf;
#define DEF_QATTR_COUNT_LIMIT 100
extern int var_qattr_count_limit;
/*
* MIME support.
*/
#define VAR_MIME_MAXDEPTH "mime_nesting_limit"
#define DEF_MIME_MAXDEPTH 100
extern int var_mime_maxdepth;
#define VAR_MIME_BOUND_LEN "mime_boundary_length_limit"
#define DEF_MIME_BOUND_LEN 100
extern int var_mime_bound_len;
/* LICENSE
/* .ad
/* .fi

View File

@@ -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 "20020514"
#define MAIL_RELEASE_DATE "20020524"
#define VAR_MAIL_VERSION "mail_version"
#define DEF_MAIL_VERSION "1.1.10-" MAIL_RELEASE_DATE

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,84 @@
#ifndef _MIME_STATE_H_INCLUDED_
#define _MIME_STATE_H_INCLUDED_
/*++
/* NAME
/* mime_state 3h
/* SUMMARY
/* MIME parser state engine
/* SYNOPSIS
/* #include "mime_state.h"
DESCRIPTION
.nf
/*
* Utility library.
*/
#include <vstring.h>
/*
* Global library.
*/
#include <header_opts.h>
/*
* External interface. All MIME_STATE structure members are private.
*/
typedef struct MIME_STATE MIME_STATE;
typedef void (*MIME_STATE_HEAD_OUT) (void *, int, HEADER_OPTS *, VSTRING *);
typedef void (*MIME_STATE_BODY_OUT) (void *, int, const char *, int);
typedef void (*MIME_STATE_ANY_END) (void *);
extern MIME_STATE *mime_state_alloc(int, MIME_STATE_HEAD_OUT, MIME_STATE_ANY_END, MIME_STATE_BODY_OUT, MIME_STATE_ANY_END, void *);
extern int mime_state_update(MIME_STATE *, int, const char *, int);
extern MIME_STATE *mime_state_free(MIME_STATE *);
extern const char *mime_state_error(int);
/*
* Processing options.
*/
#define MIME_OPT_NONE (0)
#define MIME_OPT_DOWNGRADE (1<<0)
#define MIME_OPT_REPORT_8BIT_IN_7BIT_BODY (1<<1)
#define MIME_OPT_REPORT_8BIT_IN_HEADER (1<<2)
#define MIME_OPT_REPORT_ENCODING_DOMAIN (1<<3)
#define MIME_OPT_RECURSE_ALL_MESSAGE (1<<4)
#define MIME_OPT_REPORT_TRUNC_HEADER (1<<5)
#define MIME_OPT_DISABLE_MIME (1<<6)
/*
* Body encoding domains.
*/
#define MIME_ENC_7BIT (7)
#define MIME_ENC_8BIT (8)
#define MIME_ENC_BINARY (9)
/*
* Processing errors, not necessarily lethal.
*/
#define MIME_ERR_NESTING (1<<0)
#define MIME_ERR_TRUNC_HEADER (1<<1)
#define MIME_ERR_8BIT_IN_HEADER (1<<2)
#define MIME_ERR_8BIT_IN_7BIT_BODY (1<<3)
#define MIME_ERR_ENCODING_DOMAIN (1<<4)
/*
* Header classes. Look at the header_opts argument to find out if something
* is a MIME header in a primary or nested section.
*/
#define MIME_HDR_PRIMARY (1) /* initial headers */
#define MIME_HDR_MULTIPART (2) /* headers after multipart boundary */
#define MIME_HDR_NESTED (3) /* attached message initial headers */
/* 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
/*--*/
#endif

View File

@@ -0,0 +1,38 @@
subject: primary subject
content-type : multipart/(co\m\)ment)mumble mumble; boundary = "ab\cd
ef" mumble
abcdef prolog
--abcd ef
content-type: message/rfc822; mumble
subject: nested subject
content-type: multipart/mumble; boundary(comment)="pqrs"
content-transfer-encoding: base64
pqrs prolog
--pqrs
header: pqrs part 01
body pqrs part 01
--pqrs
header: pqrs part 02
body pqrs part 02
--bogus-boundary
header: wietse
body asdasads
--abcd ef
header: abcdef part 02
body abcdef part 02
--abcd ef--
epilog

View File

@@ -0,0 +1,51 @@
MAIN subject: primary subject
mime_state: header_token: multipart / mumble
mime_state: header_token: boundary = abcd ef
mime_state: PUSH boundary abcd ef
MAIN content-type: multipart/(co\m\)ment)mumble mumble; boundary = "ab\cd
ef" mumble
HEADER END
BODY
BODY abcdef prolog
BODY
BODY --abcd ef
mime_state: header_token: message / rfc822
MULT content-type: message/rfc822; mumble
BODY
NEST subject: nested subject
mime_state: header_token: multipart / mumble
mime_state: header_token: boundary = pqrs
mime_state: PUSH boundary pqrs
NEST content-type: multipart/mumble; boundary(comment)="pqrs"
mime_state: header_token: base64
NEST content-transfer-encoding: base64
BODY
BODY pqrs prolog
BODY
BODY --pqrs
MULT header: pqrs part 01
BODY
BODY body pqrs part 01
BODY
BODY --pqrs
MULT header: pqrs part 02
BODY
BODY body pqrs part 02
BODY
BODY --bogus-boundary
BODY header: wietse
BODY
BODY body asdasads
BODY
mime_state: POP boundary pqrs
BODY --abcd ef
MULT header: abcdef part 02
BODY
BODY body abcdef part 02
BODY
mime_state: POP boundary abcd ef
BODY --abcd ef--
BODY
BODY epilog
BODY END
mime_state: warning: improper message/* or multipart/* encoding domain

View File

@@ -25,7 +25,7 @@
/* This module implements record I/O on top of stream-lf files.
/*
/* rec_streamlf_get() reads one record from the specified stream.
/* The result is not null-terminated and may contain embedded null
/* The result is null-terminated and may contain embedded null
/* characters.
/* The \fImaxlen\fR argument specifies an upper bound to the amount
/* of data read. The result is REC_TYPE_NORM when the record was
@@ -87,10 +87,13 @@ int rec_streamlf_get(VSTREAM *stream, VSTRING *buf, int maxlen)
while (n-- > 0) {
if ((ch = VSTREAM_GETC(stream)) == VSTREAM_EOF)
return (VSTRING_LEN(buf) > 0 ? REC_TYPE_CONT : REC_TYPE_EOF);
if (ch == '\n')
if (ch == '\n') {
VSTRING_TERMINATE(buf);
return (REC_TYPE_NORM);
}
VSTRING_ADDCH(buf, ch);
}
VSTRING_TERMINATE(buf);
return (REC_TYPE_CONT);
}

View File

@@ -173,6 +173,15 @@ char *xfer_states[LMTP_STATE_LAST] = {
"sending QUIT",
};
char *xfer_request[LMTP_STATE_LAST] = {
"MAIL FROM command",
"RCPT TO command",
"DATA command",
"end of DATA command",
"final RSET command",
"QUIT command",
};
/* lmtp_lhlo - perform initial handshake with LMTP server */
int lmtp_lhlo(LMTP_STATE *state)
@@ -488,8 +497,10 @@ static int lmtp_loop(LMTP_STATE *state, int send_state, int recv_state)
case LMTP_STATE_MAIL:
if (resp->code / 100 != 2) {
lmtp_mesg_fail(state, resp->code,
"host %s said: %s", session->namaddr,
translit(resp->str, "\n", " "));
"host %s said: %s (in reply to %s)",
session->namaddr,
translit(resp->str, "\n", " "),
xfer_request[LMTP_STATE_MAIL]);
mail_from_rejected = 1;
}
recv_state = LMTP_STATE_RCPT;
@@ -522,8 +533,10 @@ static int lmtp_loop(LMTP_STATE *state, int send_state, int recv_state)
survivors[nrcpt++] = recv_rcpt;
} else {
lmtp_rcpt_fail(state, resp->code, rcpt,
"host %s said: %s", session->namaddr,
translit(resp->str, "\n", " "));
"host %s said: %s (in reply to %s)",
session->namaddr,
translit(resp->str, "\n", " "),
xfer_request[LMTP_STATE_RCPT]);
rcpt->offset = 0; /* in case deferred */
}
}
@@ -540,8 +553,10 @@ static int lmtp_loop(LMTP_STATE *state, int send_state, int recv_state)
if (resp->code / 100 != 3) {
if (nrcpt > 0)
lmtp_mesg_fail(state, resp->code,
"host %s said: %s", session->namaddr,
translit(resp->str, "\n", " "));
"host %s said: %s (in reply to %s)",
session->namaddr,
translit(resp->str, "\n", " "),
xfer_request[LMTP_STATE_DATA]);
nrcpt = -1;
}
recv_state = LMTP_STATE_DOT;
@@ -570,8 +585,10 @@ static int lmtp_loop(LMTP_STATE *state, int send_state, int recv_state)
}
} else {
lmtp_rcpt_fail(state, resp->code, rcpt,
"host %s said: %s", session->namaddr,
translit(resp->str, "\n", " "));
"host %s said: %s (in reply to %s)",
session->namaddr,
translit(resp->str, "\n", " "),
xfer_request[LMTP_STATE_DOT]);
rcpt->offset = 0; /* in case deferred */
}
}

View File

@@ -415,9 +415,12 @@ static int qmgr_message_read(QMGR_MESSAGE *message)
message->queue_id, error_text, start);
break;
}
if (strcmp(name, MAIL_ATTR_ENCODING) == 0)
if (message->encoding == 0)
message->encoding = mystrdup(value);
/* Allow extra segment to override envelope segment info. */
if (strcmp(name, MAIL_ATTR_ENCODING) == 0) {
if (message->encoding != 0)
myfree(message->encoding);
message->encoding = mystrdup(value);
}
} else if (rec_type == REC_TYPE_ERTO) {
if (message->errors_to == 0) {
message->errors_to = mystrdup(start);

View File

@@ -86,6 +86,9 @@
/* The output is a hashed file, named \fIfile_name\fB.db\fR.
/* This is available only on systems with support for \fBdb\fR databases.
/* .PP
/* Use the command \fBpostconf -m\fR to find out what types of database
/* your Postfix installation can support.
/*
/* When no \fIfile_type\fR is specified, the software uses the database
/* type specified via the \fBdatabase_type\fR configuration parameter.
/* The default value for this parameter depends on the host environment.

View File

@@ -48,6 +48,48 @@
/* .RE
/* .IP \fB-m\fR
/* List the names of all supported lookup table types.
/* .RS
/* .IP \fBbtree\fR
/* A sorted, balanced tree structure.
/* This is available only on systems with support for Berkeley DB
/* databases.
/* .IP \fBdbm\fR
/* An indexed file type based on hashing.
/* This is available only on systems with support for DBM databases.
/* .IP \fBenviron\fR
/* The UNIX process environment array. The lookup key is the variable
/* name. Originally implemented for testing, someone may find this
/* useful someday.
/* .IP \fBhash\fR
/* An indexed file type based on hashing.
/* This is available only on systems with support for Berkeley DB
/* databases.
/* .IP \fBldap\fR
/* Perform lookups using the LDAP protocol. This is described
/* in an LDAP_README file.
/* .IP \fBpcre\fR
/* A lookup table based on Perl Compatible Regular Expressions. The
/* file format is described in \fBpcre_table\fR(5).
/* .IP \fBregexp\fR
/* A lookup table based on regular expressions. The file format is
/* described in \fBregexp_table\fR(5).
/* .IP \fBstatic\fR
/* A table that always returns the same result. For example,
/* \fBstatic:foobar\fR always returns the string \fBfoobar\fR.
/* .IP \fBunix\fR
/* A limited way to query the UNIX authentication database. The
/* following tables are implemented:
/* .RS
/*. IP \fBunix:passwd.byname\fR
/* The table is the UNIX password database. The key is a login name.
/* The result is a password file entry in passwd(5) format.
/* .IP \fBunix:group.byname\fR
/* The table is the UNIX group database. The key is a group name.
/* The result is a group file entry in group(5) format.
/* .RE
/* .RE
/* .sp
/* Other table types may exist depending on how Postfix was built.
/* .IP \fB-n\fR
/* Print non-default parameter settings only.
/* .IP \fB-v\fR

View File

@@ -107,6 +107,9 @@
/* The output file is a hashed file, named \fIfile_name\fB.db\fR.
/* This is available only on systems with support for \fBdb\fR databases.
/* .PP
/* Use the command \fBpostconf -m\fR to find out what types of database
/* your Postfix installation can support.
/*
/* When no \fIfile_type\fR is specified, the software uses the database
/* type specified via the \fBdatabase_type\fR configuration parameter.
/* .RE

View File

@@ -305,9 +305,12 @@ static int qmgr_message_read(QMGR_MESSAGE *message)
message->queue_id, error_text, start);
break;
}
if (strcmp(name, MAIL_ATTR_ENCODING) == 0)
if (message->encoding == 0)
message->encoding = mystrdup(value);
/* Allow extra segment to override envelope segment info. */
if (strcmp(name, MAIL_ATTR_ENCODING) == 0) {
if (message->encoding != 0)
myfree(message->encoding);
message->encoding = mystrdup(value);
}
} else if (rec_type == REC_TYPE_ERTO) {
if (message->errors_to == 0)
message->errors_to = mystrdup(start);

View File

@@ -376,7 +376,7 @@ static void qmqpd_write_content(QMQPD_STATE *state)
if (first) {
if (strncmp(start + strspn(start, ">"), "From ", 5) == 0) {
rec_fprintf(state->cleanup, rec_type,
"Mailbox-Line: %*s", len, start);
"X-Mailbox-Line: %*s", len, start);
continue;
}
first = 0;

View File

@@ -152,6 +152,7 @@ smtp_proto.o: ../../include/vstring_vstream.h
smtp_proto.o: ../../include/stringops.h
smtp_proto.o: ../../include/mymalloc.h
smtp_proto.o: ../../include/iostuff.h
smtp_proto.o: ../../include/split_at.h
smtp_proto.o: ../../include/mail_params.h
smtp_proto.o: ../../include/smtp_stream.h
smtp_proto.o: ../../include/mail_queue.h
@@ -169,6 +170,8 @@ smtp_proto.o: ../../include/quote_821_local.h
smtp_proto.o: ../../include/quote_flags.h
smtp_proto.o: ../../include/mail_proto.h
smtp_proto.o: ../../include/attr.h
smtp_proto.o: ../../include/mime_state.h
smtp_proto.o: ../../include/header_opts.h
smtp_proto.o: smtp.h
smtp_proto.o: ../../include/argv.h
smtp_proto.o: smtp_sasl.h
@@ -224,6 +227,8 @@ smtp_state.o: ../../include/vstring.h
smtp_state.o: ../../include/vbuf.h
smtp_state.o: ../../include/vstream.h
smtp_state.o: ../../include/mail_conf.h
smtp_state.o: ../../include/mime_state.h
smtp_state.o: ../../include/header_opts.h
smtp_state.o: smtp.h
smtp_state.o: ../../include/argv.h
smtp_state.o: ../../include/deliver_request.h

View File

@@ -37,9 +37,12 @@
/* run chrooted at fixed low privilege.
/* STANDARDS
/* RFC 821 (SMTP protocol)
/* RFC 822 (ARPA Internet Text Messages)
/* RFC 1651 (SMTP service extensions)
/* RFC 1652 (8bit-MIME transport)
/* RFC 1870 (Message Size Declaration)
/* RFC 2045 (MIME: Format of Internet Message Bodies)
/* RFC 2046 (MIME: Media Types)
/* RFC 2197 (Pipelining)
/* RFC 2554 (AUTH command)
/* RFC 2821 (SMTP protocol)
@@ -328,6 +331,7 @@ static int deliver_message(DELIVER_REQUEST *request)
&& (state->error_mask & name_mask(VAR_NOTIFY_CLASSES,
mail_error_masks, var_notify_classes)))
smtp_chat_notify(state);
/* XXX smtp_xfer() may abort in the middle of DATA. */
smtp_session_free(state->session);
debug_peer_restore();
}

View File

@@ -53,6 +53,8 @@ typedef struct SMTP_STATE {
sasl_callback_t *sasl_callbacks; /* stateful callbacks */
#endif
off_t size_limit; /* server limit or unknown */
int space_left; /* output length control */
struct MIME_STATE *mime_state; /* mime state machine */
} SMTP_STATE;
#define SMTP_FEATURE_ESMTP (1<<0)

View File

@@ -149,6 +149,14 @@ void smtp_chat_cmd(SMTP_STATE *state, char *fmt,...)
* Send the command to the SMTP server.
*/
smtp_fputs(STR(state->buffer), LEN(state->buffer), session->stream);
/*
* Flush unsent output if no I/O happened for a while. This avoids
* timeouts with pipelined SMTP sessions that have lots of delays
* (typically, DNS lookups for sender/recipient unaliasing).
*/
if (time((time_t *) 0) - vstream_ftime(session->stream) > 10)
vstream_fflush(session->stream);
}
/* smtp_chat_resp - read and process SMTP server response */

View File

@@ -83,6 +83,7 @@
#include <stringops.h>
#include <mymalloc.h>
#include <iostuff.h>
#include <split_at.h>
/* Global library. */
@@ -101,6 +102,7 @@
#include <mark_corrupt.h>
#include <quote_821_local.h>
#include <mail_proto.h>
#include <mime_state.h>
/* Application-specific. */
@@ -147,6 +149,15 @@ char *xfer_states[SMTP_STATE_LAST] = {
"sending QUIT",
};
char *xfer_request[SMTP_STATE_LAST] = {
"MAIL FROM command",
"RCPT TO command",
"DATA command",
"end of DATA command",
"final RSET command",
"QUIT command",
};
/* smtp_helo - perform initial handshake with SMTP server */
int smtp_helo(SMTP_STATE *state)
@@ -273,6 +284,64 @@ int smtp_helo(SMTP_STATE *state)
return (0);
}
/* smtp_text_out - output one header/body record */
static void smtp_text_out(void *context, int rec_type,
const char *text, int len)
{
SMTP_STATE *state = (SMTP_STATE *) context;
SMTP_SESSION *session = state->session;
int data_left;
const char *data_start;
/*
* Deal with an impedance mismatch between Postfix queue files (record
* length <= $message_line_length_limit) and SMTP (DATA record length <=
* $smtp_line_length_limit). The code below does a little too much work
* when the SMTP line length limit is disabled, but it avoids code
* duplication, and thus, it avoids testing and maintenance problems.
*/
data_left = len;
data_start = text;
do {
if (var_smtp_line_limit > 0 && data_left >= state->space_left) {
smtp_fputs(data_start, state->space_left, session->stream);
data_start += state->space_left;
data_left -= state->space_left;
state->space_left = var_smtp_line_limit;
if (data_left > 0 || rec_type == REC_TYPE_CONT) {
smtp_fputc(' ', session->stream);
state->space_left -= 1;
}
} else {
if (rec_type == REC_TYPE_CONT) {
smtp_fwrite(data_start, data_left, session->stream);
state->space_left -= data_left;
} else {
smtp_fputs(data_start, data_left, session->stream);
state->space_left = var_smtp_line_limit;
}
break;
}
} while (data_left > 0);
}
/* smtp_header_out - output one message header */
static void smtp_header_out(void *context, int unused_header_class,
HEADER_OPTS *unused_info, VSTRING *buf)
{
char *start = vstring_str(buf);
char *line;
char *next_line;
for (line = start; line; line = next_line) {
next_line = split_at(line, '\n');
smtp_text_out(context, REC_TYPE_NORM, line, next_line ?
next_line - line - 1 : strlen(line));
}
}
/* smtp_xfer - send a batch of envelope information and the message data */
int smtp_xfer(SMTP_STATE *state)
@@ -297,9 +366,8 @@ int smtp_xfer(SMTP_STATE *state)
int sndbuffree;
SOCKOPT_SIZE optlen = sizeof(sndbufsize);
int mail_from_rejected;
int space_left = var_smtp_line_limit;
int data_left;
char *data_start;
int downgrading;
int mime_errs;
/*
* Macros for readability.
@@ -362,6 +430,8 @@ int smtp_xfer(SMTP_STATE *state)
if (getsockopt(vstream_fileno(state->session->stream), SOL_SOCKET,
SO_SNDBUF, (char *) &sndbufsize, &optlen) < 0)
msg_fatal("%s: getsockopt: %m", myname);
if (sndbufsize > VSTREAM_BUFSIZE)
sndbufsize = VSTREAM_BUFSIZE;
if (msg_verbose)
msg_info("Using ESMTP PIPELINING, TCP send buffer size is %d",
sndbufsize);
@@ -416,10 +486,10 @@ int smtp_xfer(SMTP_STATE *state)
}
vstring_sprintf(next_command, "MAIL FROM:<%s>",
vstring_str(state->scratch));
if (state->features & SMTP_FEATURE_SIZE) /* RFC 1652 */
if (state->features & SMTP_FEATURE_SIZE) /* RFC 1870 */
vstring_sprintf_append(next_command, " SIZE=%lu",
request->data_size);
if (state->features & SMTP_FEATURE_8BITMIME) {
if (state->features & SMTP_FEATURE_8BITMIME) { /* RFC 1652 */
if (strcmp(request->encoding, MAIL_ATTR_ENC_8BIT) == 0)
vstring_strcat(next_command, " BODY=8BITMIME");
else if (strcmp(request->encoding, MAIL_ATTR_ENC_7BIT) == 0)
@@ -537,8 +607,10 @@ int smtp_xfer(SMTP_STATE *state)
case SMTP_STATE_MAIL:
if (resp->code / 100 != 2) {
smtp_mesg_fail(state, resp->code,
"host %s said: %s", session->namaddr,
translit(resp->str, "\n", " "));
"host %s said: %s (in reply to %s)",
session->namaddr,
translit(resp->str, "\n", " "),
xfer_request[SMTP_STATE_MAIL]);
mail_from_rejected = 1;
}
recv_state = SMTP_STATE_RCPT;
@@ -567,8 +639,10 @@ int smtp_xfer(SMTP_STATE *state)
} else {
rcpt = request->rcpt_list.info + recv_rcpt;
smtp_rcpt_fail(state, resp->code, rcpt,
"host %s said: %s", session->namaddr,
translit(resp->str, "\n", " "));
"host %s said: %s (in reply to %s)",
session->namaddr,
translit(resp->str, "\n", " "),
xfer_request[SMTP_STATE_RCPT]);
rcpt->offset = 0; /* in case deferred */
}
}
@@ -585,8 +659,10 @@ int smtp_xfer(SMTP_STATE *state)
if (resp->code / 100 != 3) {
if (nrcpt > 0)
smtp_mesg_fail(state, resp->code,
"host %s said: %s", session->namaddr,
translit(resp->str, "\n", " "));
"host %s said: %s (in reply to %s)",
session->namaddr,
translit(resp->str, "\n", " "),
xfer_request[SMTP_STATE_DATA]);
nrcpt = -1;
}
recv_state = SMTP_STATE_DOT;
@@ -605,9 +681,10 @@ int smtp_xfer(SMTP_STATE *state)
if (nrcpt > 0) {
if (resp->code / 100 != 2) {
smtp_mesg_fail(state, resp->code,
"host %s said: %s",
"host %s said: %s (in reply to %s)",
session->namaddr,
translit(resp->str, "\n", " "));
translit(resp->str, "\n", " "),
xfer_request[SMTP_STATE_DOT]);
} else {
for (nrcpt = 0; nrcpt < recv_rcpt; nrcpt++) {
rcpt = request->rcpt_list.info + nrcpt;
@@ -678,8 +755,24 @@ int smtp_xfer(SMTP_STATE *state)
* Special case if the server accepted the DATA command. If the
* server accepted at least one recipient send the entire message.
* Otherwise, just send "." as per RFC 2197.
*
* XXX If there is a hard MIME error while downgrading to 7-bit mail,
* disconnect ungracefully, because there is no other way to cancel a
* 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);
if (downgrading)
state->mime_state = mime_state_alloc(MIME_OPT_DOWNGRADE
| MIME_OPT_REPORT_8BIT_IN_7BIT_BODY
| MIME_OPT_REPORT_8BIT_IN_HEADER,
smtp_header_out,
(MIME_STATE_ANY_END) 0,
smtp_text_out,
(MIME_STATE_ANY_END) 0,
(void *) state);
state->space_left = var_smtp_line_limit;
smtp_timeout_setup(state->session->stream,
var_smtp_data1_tmout);
if ((except = vstream_setjmp(state->session->stream)) != 0)
@@ -695,38 +788,21 @@ int smtp_xfer(SMTP_STATE *state)
if (prev_type != REC_TYPE_CONT)
if (vstring_str(state->scratch)[0] == '.')
smtp_fputc('.', session->stream);
/*
* Deal with an impedance mismatch between Postfix queue
* files (record length <= $message_line_length_limit) and
* SMTP (DATA record length <= $smtp_line_length_limit). The
* code below does a little too much work when the SMTP line
* length limit is disabled, but it avoids code duplication,
* and thus, it avoids testing and maintenance problems.
*/
data_left = VSTRING_LEN(state->scratch);
data_start = vstring_str(state->scratch);
do {
if (var_smtp_line_limit > 0 && data_left >= space_left) {
smtp_fputs(data_start, space_left, session->stream);
data_start += space_left;
data_left -= space_left;
space_left = var_smtp_line_limit;
if (data_left > 0 || rec_type == REC_TYPE_CONT) {
smtp_fputc(' ', session->stream);
space_left -= 1;
}
} else {
if (rec_type == REC_TYPE_CONT) {
smtp_fwrite(data_start, data_left, session->stream);
space_left -= data_left;
} else {
smtp_fputs(data_start, data_left, session->stream);
space_left = var_smtp_line_limit;
}
break;
if (downgrading == 0) {
smtp_text_out((void *) state, rec_type,
vstring_str(state->scratch),
VSTRING_LEN(state->scratch));
} else {
mime_errs =
mime_state_update(state->mime_state, rec_type,
vstring_str(state->scratch),
VSTRING_LEN(state->scratch));
if (mime_errs) {
smtp_mesg_fail(state, 554, "MIME 7-bit conversion failed: %s",
mime_state_error(mime_errs));
RETURN(0);
}
} while (data_left > 0);
}
prev_type = rec_type;
}

View File

@@ -43,6 +43,7 @@
/* Global library. */
#include <mail_conf.h>
#include <mime_state.h>
/* Application-specific. */
@@ -69,6 +70,8 @@ SMTP_STATE *smtp_state_alloc(void)
smtp_sasl_connect(state);
#endif
state->size_limit = 0;
state->space_left = 0;
state->mime_state = 0;
return (state);
}
@@ -82,5 +85,7 @@ void smtp_state_free(SMTP_STATE *state)
#ifdef USE_SASL_AUTH
smtp_sasl_cleanup(state);
#endif
if (state->mime_state)
mime_state_free(state->mime_state);
myfree((char *) state);
}

View File

@@ -617,6 +617,8 @@ static char *extract_addr(SMTPD_STATE *state, SMTPD_TOKEN *arg,
/*
* 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
@@ -776,15 +778,17 @@ static int mail_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *argv)
if (encoding != 0)
rec_fprintf(state->cleanup, REC_TYPE_ATTR, "%s=%s",
MAIL_ATTR_ENCODING, encoding);
rec_fprintf(state->cleanup, REC_TYPE_ATTR, "%s=%s",
MAIL_ATTR_CLIENT_NAME, state->name);
rec_fprintf(state->cleanup, REC_TYPE_ATTR, "%s=%s",
MAIL_ATTR_CLIENT_ADDR, state->addr);
rec_fprintf(state->cleanup, REC_TYPE_ATTR, "%s=%s",
MAIL_ATTR_ORIGIN, state->namaddr);
if (state->helo_name != 0)
if (SMTPD_STAND_ALONE(state) == 0) {
rec_fprintf(state->cleanup, REC_TYPE_ATTR, "%s=%s",
MAIL_ATTR_HELO_NAME, state->helo_name);
MAIL_ATTR_CLIENT_NAME, state->name);
rec_fprintf(state->cleanup, REC_TYPE_ATTR, "%s=%s",
MAIL_ATTR_CLIENT_ADDR, state->addr);
rec_fprintf(state->cleanup, REC_TYPE_ATTR, "%s=%s",
MAIL_ATTR_ORIGIN, state->namaddr);
if (state->helo_name != 0)
rec_fprintf(state->cleanup, REC_TYPE_ATTR, "%s=%s",
MAIL_ATTR_HELO_NAME, state->helo_name);
}
if (verp_delims)
rec_fputs(state->cleanup, REC_TYPE_VERP, verp_delims);
state->sender = mystrdup(argv[2].strval);
@@ -956,7 +960,7 @@ static int data_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *unused_argv)
state->protocol, state->queue_id);
quote_822_local(state->buffer, state->recipient);
rec_fprintf(state->cleanup, REC_TYPE_NORM,
"\tfor <%s>; %s", STR(state->buffer), mail_date(state->time));
"\tfor <%s>; %s", STR(state->buffer), mail_date(state->time));
} else {
rec_fprintf(state->cleanup, REC_TYPE_NORM,
"\tby %s (%s) with %s",
@@ -996,7 +1000,7 @@ static int data_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *unused_argv)
if (first) {
if (strncmp(start + strspn(start, ">"), "From ", 5) == 0) {
rec_fprintf(state->cleanup, curr_rec_type,
"Mailbox-Line: %s", start);
"X-Mailbox-Line: %s", start);
continue;
}
first = 0;

View File

@@ -49,7 +49,7 @@
/* argument. The result is null-terminated. This routine uses mymalloc().
/*
/* mymemdup() makes a copy of the memory pointed to by \fIptr\fR
/* with length \fIlen\fR. The result is null-terminated.
/* with length \fIlen\fR. The result is NOT null-terminated.
/* This routine uses mymalloc().
/* SEE ALSO
/* msg(3) diagnostics interface