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:
committed by
Viktor Dukhovni
parent
f0d9a4857f
commit
5eb74275bf
6
postfix/.indent.pro
vendored
6
postfix/.indent.pro
vendored
@@ -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
|
||||
|
@@ -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.
|
||||
|
@@ -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 | :
|
||||
.......................|...........
|
||||
^ |
|
||||
|
@@ -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
|
||||
==========================================================
|
||||
|
||||
|
@@ -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 <>.
|
||||
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>
|
||||
@@ -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>
|
||||
|
@@ -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
|
||||
|
@@ -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>
|
||||
|
@@ -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.
|
||||
|
@@ -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)
|
||||
|
@@ -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.
|
||||
|
@@ -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
|
||||
|
@@ -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
|
||||
|
@@ -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
|
||||
|
@@ -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)
|
||||
|
@@ -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
|
||||
|
@@ -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.
|
||||
|
@@ -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)))
|
||||
|
@@ -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);
|
||||
|
@@ -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);
|
||||
}
|
||||
|
@@ -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;
|
||||
|
@@ -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);
|
||||
}
|
||||
|
@@ -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
32
postfix/src/global/foobar
Normal 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
|
@@ -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)));
|
||||
}
|
||||
|
@@ -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)
|
||||
|
||||
|
263
postfix/src/global/header_token.c
Normal file
263
postfix/src/global/header_token.c
Normal 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);
|
||||
}
|
47
postfix/src/global/header_token.h
Normal file
47
postfix/src/global/header_token.h
Normal 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
|
@@ -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);
|
||||
}
|
||||
|
73
postfix/src/global/is_header.c+
Normal file
73
postfix/src/global/is_header.c+
Normal 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);
|
||||
}
|
@@ -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[] = {
|
||||
|
@@ -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
|
||||
|
@@ -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
|
||||
|
1061
postfix/src/global/mime_state.c
Normal file
1061
postfix/src/global/mime_state.c
Normal file
File diff suppressed because it is too large
Load Diff
84
postfix/src/global/mime_state.h
Normal file
84
postfix/src/global/mime_state.h
Normal 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
|
38
postfix/src/global/mime_test.in
Normal file
38
postfix/src/global/mime_test.in
Normal 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
|
51
postfix/src/global/mime_test.ref
Normal file
51
postfix/src/global/mime_test.ref
Normal 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
|
@@ -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);
|
||||
}
|
||||
|
||||
|
@@ -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 */
|
||||
}
|
||||
}
|
||||
|
@@ -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);
|
||||
|
@@ -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.
|
||||
|
@@ -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
|
||||
|
@@ -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
|
||||
|
@@ -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);
|
||||
|
@@ -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;
|
||||
|
@@ -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
|
||||
|
@@ -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();
|
||||
}
|
||||
|
@@ -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)
|
||||
|
@@ -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 */
|
||||
|
@@ -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;
|
||||
}
|
||||
|
||||
|
@@ -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);
|
||||
}
|
||||
|
@@ -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;
|
||||
|
@@ -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
|
||||
|
Reference in New Issue
Block a user