error or table lookup error. Victor Duchovni. Files:
smtpd/smtpd_check.c.
- Horrible workaround: don't insert blank line before message/*
- starting with a mailbox From_ or =46rom_ line, and output
- this garbage as body content, without actually switching
- to message body state. File: global/mime_state.c.
+ Horrible workaround: don't insert header/body blank line
+ separator in malformed attachments. This breaks digital
+ signatures. People concerned about MIME evasion can use a
+ MIME normalizer to corrupt their user's legitimate email.
+ File: global/mime_state.c.
Wish list:
own_inet_addr: own_inet_addr.c $(LIB) $(LIBS)
$(CC) $(CFLAGS) -DTEST -o $@ $@.c $(LIB) $(LIBS) $(SYSLIBS)
-tests: tok822_test mime_test mime_nest mime_8bit mime_dom mime_trunc \
- mime_cvt mime_cvt2 mime_cvt3 strip_addr_test tok822_limit_test \
+tests: tok822_test mime_tests strip_addr_test tok822_limit_test \
xtext_test scache_multi_test ehlo_mask_test \
- namadr_list_test mail_conf_time_test mime_garb1 mime_garb2
+ namadr_list_test mail_conf_time_test
+
+mime_tests: mime_test mime_nest mime_8bit mime_dom mime_trunc mime_cvt \
+ mime_cvt2 mime_cvt3 mime_garb1 mime_garb2 mime_garb3
root_tests: rewrite_clnt_test resolve_clnt_test
diff mime_garb2.ref mime_cvt.tmp
rm -f mime_cvt.tmp
+mime_garb3: mime_state mime_garb3.in mime_garb3.ref
+ ./mime_state <mime_garb3.in >mime_cvt.tmp
+ diff mime_garb3.ref mime_cvt.tmp
+ rm -f mime_cvt.tmp
+
tok822_limit_test: tok822_parse tok822_limit.in tok822_limit.ref
./tok822_parse <tok822_limit.in >tok822_limit.tmp
diff tok822_limit.ref tok822_limit.tmp
* Patches change both the patchlevel and the release date. Snapshots have no
* patchlevel; they change the release date only.
*/
-#define MAIL_RELEASE_DATE "20070112"
+#define MAIL_RELEASE_DATE "20070113"
#define MAIL_VERSION_NUMBER "2.4"
#ifdef SNAPSHOT
MULT 72 |Content-Disposition: inline
mime_state: warning: invalid message/* or multipart/* encoding domain: quoted-printable
BODY N 0 |
-BODY N 1 |=46rom user@example.com Thu Jan 11 13:08:21 CET 2007
-NEST 0 |To: user@example.com
-NEST 36 |=46rom: Some One <user@example.com>
-NEST 60 |Subject: Forwarded Test
-BODY N 0 |
-BODY N 1 |Blah
-BODY N 6 |
+mime_state: garbage in nested header
+BODY N 0 |=46rom user@example.com Thu Jan 11 13:08:21 CET 2007
+BODY N 53 |To: user@example.com
+BODY N 74 |=46rom: Some One <user@example.com>
+BODY N 110 |Subject: Forwarded Test
+BODY N 134 |
+BODY N 135 |Blah
+BODY N 140 |
BODY END
mime_state: warning: improper message/* or multipart/* encoding domain
mime_state: POP boundary Boundary-00=_mvhpFky0yqNhsa4
--Boundary-00=_mvhpFky0yqNhsa4
Content-Type: message/rfc822;
name="forwarded message"
-Content-Transfer-Encoding: quoted-printable
+Content-Transfer-Encoding: 7bit
Content-Disposition: inline
From user@example.com Thu Jan 11 13:08:21 CET 2007
mime_state: header_token: message / rfc822
MULT 0 |Content-Type: message/rfc822;
name="forwarded message"
-mime_state: header_token: quoted-printable
-MULT 44 |Content-Transfer-Encoding: quoted-printable
-MULT 72 |Content-Disposition: inline
-mime_state: warning: invalid message/* or multipart/* encoding domain: quoted-printable
-BODY N 0 |
-BODY N 1 |From user@example.com Thu Jan 11 13:08:21 CET 2007
-NEST 0 |To: user@example.com
-NEST 34 |From: Some One <user@example.com>
-NEST 58 |Subject: Forwarded Test
+mime_state: header_token: 7bit
+MULT 32 |Content-Transfer-Encoding: 7bit
+MULT 60 |Content-Disposition: inline
BODY N 0 |
-BODY N 1 |Blah
-BODY N 6 |
+mime_state: garbage in nested header
+BODY N 0 |From user@example.com Thu Jan 11 13:08:21 CET 2007
+BODY N 51 |To: user@example.com
+BODY N 72 |From: Some One <user@example.com>
+BODY N 106 |Subject: Forwarded Test
+BODY N 130 |
+BODY N 131 |Blah
+BODY N 136 |
BODY END
-mime_state: warning: improper message/* or multipart/* encoding domain
mime_state: POP boundary Boundary-00=_mvhpFky0yqNhsa4
--- /dev/null
+From: Some One <user@example.com>
+To: Some One <user@example.com>
+Subject: Test
+MIME-Version: 1.0
+Content-Type: Multipart/Mixed;
+ boundary="Boundary-00=_mvhpFky0yqNhsa4"
+junk in primary header
+
+--Boundary-00=_mvhpFky0yqNhsa4
+Content-Type: text/plain;
+ charset="utf-8"
+Content-Transfer-Encoding: quoted-printable
+Content-Disposition: inline
+junk in multipart header
+
+This is a test
+--Boundary-00=_mvhpFky0yqNhsa4
+Content-Type: message/rfc822;
+ name="forwarded message"
+Content-Transfer-Encoding: quoted-printable
+Content-Disposition: inline
+
+=46rom user@example.com Thu Jan 11 13:08:21 CET 2007
+To: user@example.com
+=46rom: Some One <user@example.com>
+Subject: Forwarded Test
+
+Blah
+
--- /dev/null
+MAIN 0 |From: Some One <user@example.com>
+MAIN 32 |To: Some One <user@example.com>
+MAIN 46 |Subject: Test
+MAIN 64 |MIME-Version: 1.0
+mime_state: header_token: Multipart / Mixed
+mime_state: header_token: boundary = Boundary-00=_mvhpFky0yqNhsa4
+mime_state: PUSH boundary Boundary-00=_mvhpFky0yqNhsa4
+MAIN 95 |Content-Type: Multipart/Mixed;
+ boundary="Boundary-00=_mvhpFky0yqNhsa4"
+HEADER END
+mime_state: garbage in primary header
+BODY N -1 |
+BODY N 0 |junk in primary header
+BODY N 23 |
+BODY N 24 |--Boundary-00=_mvhpFky0yqNhsa4
+mime_state: header_token: text / plain
+MULT 0 |Content-Type: text/plain;
+ charset="utf-8"
+mime_state: header_token: quoted-printable
+MULT 44 |Content-Transfer-Encoding: quoted-printable
+MULT 72 |Content-Disposition: inline
+mime_state: garbage in multipart header
+BODY N 0 |junk in multipart header
+BODY N 25 |
+BODY N 26 |This is a test
+BODY N 41 |--Boundary-00=_mvhpFky0yqNhsa4
+mime_state: header_token: message / rfc822
+MULT 0 |Content-Type: message/rfc822;
+ name="forwarded message"
+mime_state: header_token: quoted-printable
+MULT 44 |Content-Transfer-Encoding: quoted-printable
+MULT 72 |Content-Disposition: inline
+mime_state: warning: invalid message/* or multipart/* encoding domain: quoted-printable
+BODY N 0 |
+mime_state: garbage in nested header
+BODY N 0 |=46rom user@example.com Thu Jan 11 13:08:21 CET 2007
+BODY N 53 |To: user@example.com
+BODY N 74 |=46rom: Some One <user@example.com>
+BODY N 110 |Subject: Forwarded Test
+BODY N 134 |
+BODY N 135 |Blah
+BODY N 140 |
+BODY END
+mime_state: warning: improper message/* or multipart/* encoding domain
+mime_state: POP boundary Boundary-00=_mvhpFky0yqNhsa4
* Invalid input. Force output of one blank line and jump to the
* body state, leaving all other state alone.
*
- * XXX Some broken software sends a From_ line at the start of
- * Message/rfc822 content, and some doubly brain-damaged software
- * even encodes Message/rfc822 content as quoted-printable. If we
- * force output of a blank line after such garbage then we are
- * safe: all headers that follow are permanently neutralized, but
- * of course the message is modified.
+ * We don't break legitimate mail by inserting a blank line
+ * separator between primary headers and a non-empty body. Many
+ * MTA's don't even record the presence or absence of this
+ * separator, nor does the Milter protocol pass it on to Milter
+ * applications.
*
- * XXX If we don't force output of a blank line before garbage, we
- * must still inspect the text that follows garbage as message
- * headers. Otherwise we would introduce a trivial security hole
- * to slip forbidden content past Postfix header_checks.
+ * XXX We don't insert a blank line separator with attachments, as
+ * this breaks digital signatures. Postfix shall not do a worse
+ * mail delivery job than crappy MTAs that can't even parse MIME.
+ * But we switch to the body state anyway.
*
- * XXX Because the garbage is not a valid header, we must not feed
- * it into call-back routines that expect valid header lines.
- * This code therefore falls through into the code that emits
- * body lines, which we already use anyway to emit the empty line
- * between a header and body block, and between MIME headers and
- * message/* headers. Using body output code for garbage output
- * is safe provided that rec_type is REC_TYPE_NORM and that
- * state->curr_domain is MIME_ENC_7BIT, so that we don't have to
- * worry about MIME downgrading. If any of this changes then we
- * have a problem.
+ * People who worry about MIME evasion can use a MIME normalizer,
+ * and knowlingly corrupt legitimate email for their users.
+ * Postfix has a different mission.
*/
else {
- if (state->curr_state == MIME_STATE_NESTED
- && rec_type == REC_TYPE_NORM
- && len > 7
- && (strncmp(text + (*text == '>'), "From ", 5) == 0
- || strncmp(text, "=46rom ", 7) == 0)) {
- /* Output as body, but don't change state just yet. */ ;
- } else {
- SET_CURR_STATE(state, MIME_STATE_BODY);
+ if (msg_verbose)
+ msg_info("garbage in %s header",
+ state->curr_state == MIME_STATE_MULTIPART ? "multipart" :
+ state->curr_state == MIME_STATE_PRIMARY ? "primary" :
+ state->curr_state == MIME_STATE_NESTED ? "nested" :
+ "other");
+ if (state->curr_state == MIME_STATE_PRIMARY)
BODY_OUT(state, REC_TYPE_NORM, "", 0);
- }
+ SET_CURR_STATE(state, MIME_STATE_BODY);
}
}