2
0
mirror of https://github.com/vdukhovni/postfix synced 2025-08-30 21:55:20 +00:00

postfix-1.1.11-20020529

This commit is contained in:
Wietse Venema
2002-05-29 00:00:00 -05:00
committed by Viktor Dukhovni
parent 2f5c5bf795
commit 15df7b4fbf
18 changed files with 1859 additions and 61 deletions

View File

@@ -6572,6 +6572,12 @@ Apologies for any names omitted.
pcre_table(5) manual page. Files: util/dict_pcre.c, pcre_table(5) manual page. Files: util/dict_pcre.c,
proto/pcre_table. proto/pcre_table.
20020529
Bugfix: mail rejected due to MIME errors was rejected
without proper logging. Files: global/mime_state.c,
cleanup/cleanup_message.c.
Open problems: Open problems:
Medium: old maildrop files are no longer readable by the Medium: old maildrop files are no longer readable by the

View File

@@ -56,6 +56,7 @@ tidy: clean
.nfs* */.nfs* */*/.nfs* \ .nfs* */.nfs* */*/.nfs* \
.pure */.pure */*/.pure \ .pure */.pure */*/.pure \
*.out */*.out */*/*.out \ *.out */*.out */*/*.out \
*.tmp */*.tmp */*/*.tmp \
*.a */*.a */*/*.a \ *.a */*.a */*/*.a \
*~ */*~ */*/*~ \ *~ */*~ */*/*~ \
*- */*- */*/*- \ *- */*- */*/*- \

View File

@@ -258,16 +258,6 @@ static void cleanup_service(VSTREAM *src, char *unused_service, char **argv)
break; 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 * Keep reading in case of problems, until the sender is ready to receive
* our status report. * our status report.

View File

@@ -603,10 +603,6 @@ static void cleanup_message_headerbody(CLEANUP_STATE *state, int type,
state->mime_errs = mime_state_update(state->mime_state, type, buf, len); state->mime_errs = mime_state_update(state->mime_state, type, buf, len);
/* Ignore header truncation after primary message headers. */ /* Ignore header truncation after primary message headers. */
state->mime_errs &= ~MIME_ERR_TRUNC_HEADER; state->mime_errs &= ~MIME_ERR_TRUNC_HEADER;
/* Ignore MIME nesting error if bouncing or forwarding mail. */
/* XXX Also: ignore if not header checking. */
if ((state->flags & CLEANUP_FLAG_FILTER) == 0)
state->mime_errs &= ~MIME_ERR_NESTING;
if (state->mime_errs && state->reason == 0) { if (state->mime_errs && state->reason == 0) {
state->errs |= CLEANUP_STAT_CONT; state->errs |= CLEANUP_STAT_CONT;
state->reason = mystrdup(mime_state_error(state->mime_errs)); state->reason = mystrdup(mime_state_error(state->mime_errs));
@@ -626,6 +622,27 @@ static void cleanup_message_headerbody(CLEANUP_STATE *state, int type,
} }
} }
/* cleanup_mime_error_callback - error report call-back routine */
static void cleanup_mime_error_callback(void *context, int err_code,
const char *text)
{
CLEANUP_STATE *state = (CLEANUP_STATE *) context;
const char *origin;
/*
* Message header too large errors are handled after the end of the
* primary message headers.
*/
if ((err_code & ~MIME_ERR_TRUNC_HEADER) != 0) {
if ((origin = nvtable_find(state->attr, MAIL_ATTR_ORIGIN)) == 0)
origin = MAIL_ATTR_ORG_NONE;
msg_info("%s: reject: mime-error %s: %.100s from %s; from=<%s> to=<%s>",
state->queue_id, mime_state_error(err_code), text, origin,
state->sender, state->recip ? state->recip : "unknown");
}
}
/* cleanup_message - initialize message content segment */ /* cleanup_message - initialize message content segment */
void cleanup_message(CLEANUP_STATE *state, int type, char *buf, int len) void cleanup_message(CLEANUP_STATE *state, int type, char *buf, int len)
@@ -653,7 +670,7 @@ void cleanup_message(CLEANUP_STATE *state, int type, char *buf, int len)
if (var_disable_mime_input) { if (var_disable_mime_input) {
mime_options |= MIME_OPT_DISABLE_MIME; mime_options |= MIME_OPT_DISABLE_MIME;
} else { } else {
/* Turn off strict MIME checks if bouncing or forwarding mail. */ /* Turn off content checks if bouncing or forwarding mail. */
if (state->flags & CLEANUP_FLAG_FILTER) { if (state->flags & CLEANUP_FLAG_FILTER) {
if (var_strict_8bitmime || var_strict_7bit_hdrs) if (var_strict_8bitmime || var_strict_7bit_hdrs)
mime_options |= MIME_OPT_REPORT_8BIT_IN_HEADER; mime_options |= MIME_OPT_REPORT_8BIT_IN_HEADER;
@@ -661,6 +678,11 @@ void cleanup_message(CLEANUP_STATE *state, int type, char *buf, int len)
mime_options |= MIME_OPT_REPORT_8BIT_IN_7BIT_BODY; mime_options |= MIME_OPT_REPORT_8BIT_IN_7BIT_BODY;
if (var_strict_encoding) if (var_strict_encoding)
mime_options |= MIME_OPT_REPORT_ENCODING_DOMAIN; mime_options |= MIME_OPT_REPORT_ENCODING_DOMAIN;
if (var_strict_8bitmime || var_strict_7bit_hdrs
|| var_strict_8bit_body || var_strict_encoding
|| *var_header_checks || *var_mimehdr_checks
|| *var_nesthdr_checks)
mime_options |= MIME_OPT_REPORT_NESTING;
} }
} }
state->mime_state = mime_state_alloc(mime_options, state->mime_state = mime_state_alloc(mime_options,
@@ -668,6 +690,7 @@ void cleanup_message(CLEANUP_STATE *state, int type, char *buf, int len)
cleanup_header_done_callback, cleanup_header_done_callback,
cleanup_body_callback, cleanup_body_callback,
(MIME_STATE_ANY_END) 0, (MIME_STATE_ANY_END) 0,
cleanup_mime_error_callback,
(void *) state); (void *) state);
/* /*

View File

@@ -219,7 +219,7 @@ mime_state: $(LIB) $(LIBS)
$(CC) -DTEST $(CFLAGS) -o $@ $@.c $(LIB) $(LIBS) $(SYSLIBS) $(CC) -DTEST $(CFLAGS) -o $@ $@.c $(LIB) $(LIBS) $(SYSLIBS)
mv junk $@.o mv junk $@.o
tests: tok822_test mime_test tests: tok822_test mime_test mime_nest mime_8bit mime_dom mime_trunc
tok822_test: tok822_parse tok822_parse.in tok822_parse.ref tok822_test: tok822_parse tok822_parse.in tok822_parse.ref
./tok822_parse <tok822_parse.in >tok822_parse.tmp ./tok822_parse <tok822_parse.in >tok822_parse.tmp
@@ -231,6 +231,26 @@ mime_test: mime_state mime_test.in mime_test.ref
diff mime_test.ref mime_test.tmp diff mime_test.ref mime_test.tmp
rm -f mime_test.tmp rm -f mime_test.tmp
mime_nest: mime_state mime_nest.in mime_nest.ref
./mime_state <mime_nest.in >mime_nest.tmp
diff mime_nest.ref mime_nest.tmp
rm -f mime_nest.tmp
mime_8bit: mime_state mime_8bit.in mime_8bit.ref
./mime_state <mime_8bit.in >mime_8bit.tmp
diff mime_8bit.ref mime_8bit.tmp
rm -f mime_8bit.tmp
mime_dom: mime_state mime_dom.in mime_dom.ref
./mime_state <mime_dom.in >mime_dom.tmp
diff mime_dom.ref mime_dom.tmp
rm -f mime_dom.tmp
mime_trunc: mime_state mime_trunc.in mime_trunc.ref
./mime_state <mime_trunc.in >mime_trunc.tmp
diff mime_trunc.ref mime_trunc.tmp
rm -f mime_trunc.tmp
printfck: $(OBJS) $(PROG) printfck: $(OBJS) $(PROG)
rm -rf printfck rm -rf printfck
mkdir printfck mkdir printfck

View File

@@ -20,7 +20,7 @@
* Patches change the patchlevel and the release date. Snapshots change the * Patches change the patchlevel and the release date. Snapshots change the
* release date only, unless they include the same bugfix as a patch release. * release date only, unless they include the same bugfix as a patch release.
*/ */
#define MAIL_RELEASE_DATE "20020528" #define MAIL_RELEASE_DATE "20020529"
#define VAR_MAIL_VERSION "mail_version" #define VAR_MAIL_VERSION "mail_version"
#define DEF_MAIL_VERSION "1.1.11-" MAIL_RELEASE_DATE #define DEF_MAIL_VERSION "1.1.11-" MAIL_RELEASE_DATE

View File

@@ -0,0 +1,3 @@
Header: f<><66>bar
b<EFBFBD>dy

View File

@@ -0,0 +1,9 @@
mime_state: warning: improper use of 8-bit data in message header: Header: f??bar
MAIN Header: f<><66>bar
HEADER END
BODY
mime_state: warning: improper use of 8-bit data in message body: b?dy
BODY b<>dy
BODY END
mime_state: warning: improper use of 8-bit data in message header
mime_state: warning: improper use of 8-bit data in message body

View File

@@ -0,0 +1,2 @@
content-type: message/rfc822
content-transfer-encoding: base64

View File

@@ -0,0 +1,8 @@
mime_state: header_token: message / rfc822
MAIN content-type: message/rfc822
mime_state: header_token: base64
MAIN content-transfer-encoding: base64
HEADER END
mime_state: warning: invalid message/* or multipart/* encoding domain: base64
BODY END
mime_state: warning: improper message/* or multipart/* encoding domain

View File

@@ -0,0 +1,69 @@
content-type: multipart/mixed; boundary=foobar
--foobar
content-type: multipart/mixed; boundary=foobar
--foobar
content-type: multipart/mixed; boundary=foobar
--foobar
content-type: multipart/mixed; boundary=foobar
--foobar
content-type: multipart/mixed; boundary=foobar
--foobar
content-type: multipart/mixed; boundary=foobar
--foobar
content-type: multipart/mixed; boundary=foobar
--foobar
content-type: multipart/mixed; boundary=foobar
--foobar
content-type: multipart/mixed; boundary=foobar
--foobar
content-type: multipart/mixed; boundary=foobar
--foobar
content-type: multipart/mixed; boundary=foobar
--foobar
content-type: multipart/mixed; boundary=foobar
--foobar
content-type: multipart/mixed; boundary=foobar
--foobar
content-type: multipart/mixed; boundary=foobar
--foobar
content-type: multipart/mixed; boundary=foobar
--foobar
content-type: multipart/mixed; boundary=foobar
--foobar
content-type: multipart/mixed; boundary=foobar
--foobar
content-type: multipart/mixed; boundary=foobar
--foobar
content-type: multipart/mixed; boundary=foobar
--foobar
content-type: multipart/mixed; boundary=foobar
--foobar
content-type: multipart/mixed; boundary=foobar
--foobar
content-type: multipart/mixed; boundary=foobar
--foobar
content-type: multipart/mixed; boundary=foobar
--foobar

View File

@@ -0,0 +1,163 @@
mime_state: header_token: multipart / mixed
mime_state: header_token: boundary = foobar
mime_state: PUSH boundary foobar
MAIN content-type: multipart/mixed; boundary=foobar
HEADER END
BODY
BODY --foobar
mime_state: header_token: multipart / mixed
mime_state: header_token: boundary = foobar
mime_state: PUSH boundary foobar
MULT content-type: multipart/mixed; boundary=foobar
BODY
BODY --foobar
mime_state: header_token: multipart / mixed
mime_state: header_token: boundary = foobar
mime_state: PUSH boundary foobar
MULT content-type: multipart/mixed; boundary=foobar
BODY
BODY --foobar
mime_state: header_token: multipart / mixed
mime_state: header_token: boundary = foobar
mime_state: PUSH boundary foobar
MULT content-type: multipart/mixed; boundary=foobar
BODY
BODY --foobar
mime_state: header_token: multipart / mixed
mime_state: header_token: boundary = foobar
mime_state: PUSH boundary foobar
MULT content-type: multipart/mixed; boundary=foobar
BODY
BODY --foobar
mime_state: header_token: multipart / mixed
mime_state: header_token: boundary = foobar
mime_state: PUSH boundary foobar
MULT content-type: multipart/mixed; boundary=foobar
BODY
BODY --foobar
mime_state: header_token: multipart / mixed
mime_state: header_token: boundary = foobar
mime_state: PUSH boundary foobar
MULT content-type: multipart/mixed; boundary=foobar
BODY
BODY --foobar
mime_state: header_token: multipart / mixed
mime_state: header_token: boundary = foobar
mime_state: PUSH boundary foobar
MULT content-type: multipart/mixed; boundary=foobar
BODY
BODY --foobar
mime_state: header_token: multipart / mixed
mime_state: header_token: boundary = foobar
mime_state: PUSH boundary foobar
MULT content-type: multipart/mixed; boundary=foobar
BODY
BODY --foobar
mime_state: header_token: multipart / mixed
mime_state: header_token: boundary = foobar
mime_state: PUSH boundary foobar
MULT content-type: multipart/mixed; boundary=foobar
BODY
BODY --foobar
mime_state: header_token: multipart / mixed
mime_state: header_token: boundary = foobar
mime_state: PUSH boundary foobar
MULT content-type: multipart/mixed; boundary=foobar
BODY
BODY --foobar
mime_state: header_token: multipart / mixed
mime_state: header_token: boundary = foobar
mime_state: PUSH boundary foobar
MULT content-type: multipart/mixed; boundary=foobar
BODY
BODY --foobar
mime_state: header_token: multipart / mixed
mime_state: header_token: boundary = foobar
mime_state: PUSH boundary foobar
MULT content-type: multipart/mixed; boundary=foobar
BODY
BODY --foobar
mime_state: header_token: multipart / mixed
mime_state: header_token: boundary = foobar
mime_state: PUSH boundary foobar
MULT content-type: multipart/mixed; boundary=foobar
BODY
BODY --foobar
mime_state: header_token: multipart / mixed
mime_state: header_token: boundary = foobar
mime_state: PUSH boundary foobar
MULT content-type: multipart/mixed; boundary=foobar
BODY
BODY --foobar
mime_state: header_token: multipart / mixed
mime_state: header_token: boundary = foobar
mime_state: PUSH boundary foobar
MULT content-type: multipart/mixed; boundary=foobar
BODY
BODY --foobar
mime_state: header_token: multipart / mixed
mime_state: header_token: boundary = foobar
mime_state: PUSH boundary foobar
MULT content-type: multipart/mixed; boundary=foobar
BODY
BODY --foobar
mime_state: header_token: multipart / mixed
mime_state: header_token: boundary = foobar
mime_state: PUSH boundary foobar
MULT content-type: multipart/mixed; boundary=foobar
BODY
BODY --foobar
mime_state: header_token: multipart / mixed
mime_state: header_token: boundary = foobar
mime_state: PUSH boundary foobar
MULT content-type: multipart/mixed; boundary=foobar
BODY
BODY --foobar
mime_state: header_token: multipart / mixed
mime_state: header_token: boundary = foobar
mime_state: PUSH boundary foobar
MULT content-type: multipart/mixed; boundary=foobar
BODY
BODY --foobar
mime_state: header_token: multipart / mixed
mime_state: header_token: boundary = foobar
mime_state: PUSH boundary foobar
MULT content-type: multipart/mixed; boundary=foobar
BODY
BODY --foobar
mime_state: header_token: multipart / mixed
mime_state: header_token: boundary = foobar
mime_state: PUSH boundary foobar
MULT content-type: multipart/mixed; boundary=foobar
BODY
BODY --foobar
mime_state: header_token: multipart / mixed
mime_state: header_token: boundary = foobar
mime_state: warning: MIME nesting exceeds safety limit: content-type: multipart/mixed; boundary=foobar
MULT content-type: multipart/mixed; boundary=foobar
BODY
BODY --foobar
BODY END
mime_state: warning: MIME nesting exceeds safety limit
mime_state: POP boundary foobar
mime_state: POP boundary foobar
mime_state: POP boundary foobar
mime_state: POP boundary foobar
mime_state: POP boundary foobar
mime_state: POP boundary foobar
mime_state: POP boundary foobar
mime_state: POP boundary foobar
mime_state: POP boundary foobar
mime_state: POP boundary foobar
mime_state: POP boundary foobar
mime_state: POP boundary foobar
mime_state: POP boundary foobar
mime_state: POP boundary foobar
mime_state: POP boundary foobar
mime_state: POP boundary foobar
mime_state: POP boundary foobar
mime_state: POP boundary foobar
mime_state: POP boundary foobar
mime_state: POP boundary foobar
mime_state: POP boundary foobar
mime_state: POP boundary foobar

View File

@@ -7,7 +7,8 @@
/* #include <mime_state.h> /* #include <mime_state.h>
/* /*
/* MIME_STATE *mime_state_alloc(flags, head_out, head_end, /* MIME_STATE *mime_state_alloc(flags, head_out, head_end,
/* body_out, body_end, context) /* body_out, body_end,
/* err_print, context)
/* int flags; /* int flags;
/* void (*head_out)(void *ptr, int header_class, /* void (*head_out)(void *ptr, int header_class,
/* HEADER_OPTS *header_info, VSTRING *buf); /* HEADER_OPTS *header_info, VSTRING *buf);
@@ -15,6 +16,7 @@
/* void (*body_out)(void *ptr, int rec_type, /* void (*body_out)(void *ptr, int rec_type,
/* const char *buf, int len); /* const char *buf, int len);
/* void (*body_end)(void *ptr); /* void (*body_end)(void *ptr);
/* void (*err_print(void *ptr, int err_flag, const char *text)
/* void *context; /* void *context;
/* /*
/* int mime_state_update(state, rec_type, buf, len) /* int mime_state_update(state, rec_type, buf, len)
@@ -80,6 +82,10 @@
/* routines. /* routines.
/* .IP enc_type /* .IP enc_type
/* The content encoding: MIME_ENC_7BIT or MIME_ENC_8BIT. /* The content encoding: MIME_ENC_7BIT or MIME_ENC_8BIT.
/* .IP err_print
/* Null pointer, or pointer to a function that is called with
/* arguments: the application context, the error type, and the
/* offending input. Only one instance per error type is reported.
/* .IP flags /* .IP flags
/* Special processing options. Specify the bit-wise OR of zero or /* Special processing options. Specify the bit-wise OR of zero or
/* more of the following: /* more of the following:
@@ -102,6 +108,9 @@
/* .IP MIME_OPT_REPORT_ENCODING_DOMAIN /* .IP MIME_OPT_REPORT_ENCODING_DOMAIN
/* Report errors that set the MIME_ERR_ENCODING_DOMAIN error /* Report errors that set the MIME_ERR_ENCODING_DOMAIN error
/* flag (see above). /* flag (see above).
/* .IP MIME_OPT_REPORT_NESTING
/* Report errors that set the MIME_ERR_NESTING error flag
/* (see above).
/* .IP MIME_OPT_RECURSE_ALL_MESSAGE /* .IP MIME_OPT_RECURSE_ALL_MESSAGE
/* Recurse into message/anything types other than message/rfc822. /* Recurse into message/anything types other than message/rfc822.
/* This feature can detect "bad" information in headers of /* This feature can detect "bad" information in headers of
@@ -274,6 +283,7 @@ struct MIME_STATE {
MIME_STATE_ANY_END head_end; /* end of primary header routine */ MIME_STATE_ANY_END head_end; /* end of primary header routine */
MIME_STATE_BODY_OUT body_out; /* body output routine */ MIME_STATE_BODY_OUT body_out; /* body output routine */
MIME_STATE_ANY_END body_end; /* end of body output routine */ MIME_STATE_ANY_END body_end; /* end of body output routine */
MIME_STATE_ERR_PRINT err_print; /* error report */
void *app_context; /* application context */ void *app_context; /* application context */
}; };
@@ -329,6 +339,15 @@ typedef struct MIME_ENCODING {
#define MIME_ENC_BINARY 9 /* domain only */ #define MIME_ENC_BINARY 9 /* domain only */
#endif #endif
static MIME_ENCODING mime_encoding_map[] = { /* RFC 2045 */
"7bit", MIME_ENC_7BIT, MIME_ENC_7BIT, /* domain */
"8bit", MIME_ENC_8BIT, MIME_ENC_8BIT, /* domain */
"binary", MIME_ENC_BINARY, MIME_ENC_BINARY, /* domain */
"base64", MIME_ENC_BASE64, MIME_ENC_7BIT, /* encoding */
"quoted-printable", MIME_ENC_QP, MIME_ENC_7BIT, /* encoding */
0,
};
/* /*
* Silly Little Macros. * Silly Little Macros.
*/ */
@@ -337,6 +356,14 @@ typedef struct MIME_ENCODING {
#define END(x) vstring_end(x) #define END(x) vstring_end(x)
#define CU_CHAR_PTR(x) ((const unsigned char *) (x)) #define CU_CHAR_PTR(x) ((const unsigned char *) (x))
#define REPORT_ERROR(state, err_type, text) do { \
if ((state->err_flags & err_type) == 0) { \
if (state->err_print != 0) \
state->err_print(state->app_context, err_type, text); \
state->err_flags |= err_type; \
} \
} while (0)
/* mime_state_push - push boundary onto stack */ /* mime_state_push - push boundary onto stack */
static void mime_state_push(MIME_STATE *state, int def_ctype, int def_stype, static void mime_state_push(MIME_STATE *state, int def_ctype, int def_stype,
@@ -355,21 +382,17 @@ static void mime_state_push(MIME_STATE *state, int def_ctype, int def_stype,
* will still correctly detect all intermediate boundaries and all the * will still correctly detect all intermediate boundaries and all the
* message headers that follow those boundaries. * message headers that follow those boundaries.
*/ */
if (state->nesting_level > var_mime_maxdepth) { state->nesting_level += 1;
state->err_flags |= MIME_ERR_NESTING; stack = (MIME_STACK *) mymalloc(sizeof(*stack));
} else { stack->def_ctype = def_ctype;
state->nesting_level += 1; stack->def_stype = def_stype;
stack = (MIME_STACK *) mymalloc(sizeof(*stack)); if ((stack->bound_len = strlen(boundary)) > var_mime_bound_len)
stack->def_ctype = def_ctype; stack->bound_len = var_mime_bound_len;
stack->def_stype = def_stype; stack->boundary = mystrndup(boundary, stack->bound_len);
if ((stack->bound_len = strlen(boundary)) > var_mime_bound_len) stack->next = state->stack;
stack->bound_len = var_mime_bound_len; state->stack = stack;
stack->boundary = mystrndup(boundary, stack->bound_len); if (msg_verbose)
stack->next = state->stack; msg_info("PUSH boundary %s", stack->boundary);
state->stack = stack;
if (msg_verbose)
msg_info("PUSH boundary %s", stack->boundary);
}
} }
/* mime_state_pop - pop boundary from stack */ /* mime_state_pop - pop boundary from stack */
@@ -395,6 +418,7 @@ MIME_STATE *mime_state_alloc(int flags,
MIME_STATE_ANY_END head_end, MIME_STATE_ANY_END head_end,
MIME_STATE_BODY_OUT body_out, MIME_STATE_BODY_OUT body_out,
MIME_STATE_ANY_END body_end, MIME_STATE_ANY_END body_end,
MIME_STATE_ERR_PRINT err_print,
void *context) void *context)
{ {
MIME_STATE *state; MIME_STATE *state;
@@ -417,6 +441,7 @@ MIME_STATE *mime_state_alloc(int flags,
state->head_end = head_end; state->head_end = head_end;
state->body_out = body_out; state->body_out = body_out;
state->body_end = body_end; state->body_end = body_end;
state->err_print = err_print;
state->app_context = context; state->app_context = context;
return (state); return (state);
} }
@@ -521,9 +546,16 @@ static void mime_state_content_type(MIME_STATE *state,
while ((tok_count = PARSE_CONTENT_TYPE_HEADER(state, &cp)) >= 0) { while ((tok_count = PARSE_CONTENT_TYPE_HEADER(state, &cp)) >= 0) {
if (tok_count >= 3 if (tok_count >= 3
&& TOKEN_MATCH(state->token[0], "boundary") && TOKEN_MATCH(state->token[0], "boundary")
&& state->token[1].type == '=') && state->token[1].type == '=') {
mime_state_push(state, def_ctype, def_stype, if (state->nesting_level > var_mime_maxdepth) {
state->token[2].u.value); if (state->static_flags & MIME_OPT_REPORT_NESTING)
REPORT_ERROR(state, MIME_ERR_NESTING,
STR(state->output_buffer));
} else {
mime_state_push(state, def_ctype, def_stype,
state->token[2].u.value);
}
}
} }
} }
return; return;
@@ -544,14 +576,6 @@ static void mime_state_content_encoding(MIME_STATE *state,
HEADER_OPTS *header_info) HEADER_OPTS *header_info)
{ {
const char *cp; const char *cp;
static MIME_ENCODING code_map[] = { /* RFC 2045 */
"7bit", MIME_ENC_7BIT, MIME_ENC_7BIT, /* domain */
"8bit", MIME_ENC_8BIT, MIME_ENC_8BIT, /* domain */
"binary", MIME_ENC_BINARY, MIME_ENC_BINARY, /* domain */
"base64", MIME_ENC_BASE64, MIME_ENC_7BIT, /* encoding */
"quoted-printable", MIME_ENC_QP, MIME_ENC_7BIT, /* encoding */
0,
};
MIME_ENCODING *cmp; MIME_ENCODING *cmp;
#define PARSE_CONTENT_ENCODING_HEADER(state, ptr) \ #define PARSE_CONTENT_ENCODING_HEADER(state, ptr) \
@@ -565,7 +589,7 @@ static void mime_state_content_encoding(MIME_STATE *state,
cp = STR(state->output_buffer) + strlen(header_info->name) + 1; cp = STR(state->output_buffer) + strlen(header_info->name) + 1;
if (PARSE_CONTENT_ENCODING_HEADER(state, &cp) > 0 if (PARSE_CONTENT_ENCODING_HEADER(state, &cp) > 0
&& state->token[0].type == HEADER_TOK_TOKEN) { && state->token[0].type == HEADER_TOK_TOKEN) {
for (cmp = code_map; cmp->name != 0; cmp++) { for (cmp = mime_encoding_map; cmp->name != 0; cmp++) {
if (strcasecmp(state->token[0].u.value, cmp->name) == 0) { if (strcasecmp(state->token[0].u.value, cmp->name) == 0) {
state->curr_encoding = cmp->encoding; state->curr_encoding = cmp->encoding;
state->curr_domain = cmp->domain; state->curr_domain = cmp->domain;
@@ -575,6 +599,18 @@ static void mime_state_content_encoding(MIME_STATE *state,
} }
} }
/* mime_state_enc_name - encoding to printable form */
static const char *mime_state_enc_name(int encoding)
{
MIME_ENCODING *cmp;
for (cmp = mime_encoding_map; cmp->name != 0; cmp++)
if (encoding == cmp->encoding)
return (cmp->name);
return ("unknown");
}
/* mime_state_downgrade - convert 8-bit data to quoted-printable */ /* mime_state_downgrade - convert 8-bit data to quoted-printable */
static void mime_state_downgrade(MIME_STATE *state, int rec_type, static void mime_state_downgrade(MIME_STATE *state, int rec_type,
@@ -643,10 +679,10 @@ int mime_state_update(MIME_STATE *state, int rec_type,
HEADER_OPTS *header_info; HEADER_OPTS *header_info;
const unsigned char *cp; const unsigned char *cp;
#define SAVE_PREV_REC_TYPE_AND_RETURN_ERR_FLAGS(state, rec_type) { \ #define SAVE_PREV_REC_TYPE_AND_RETURN_ERR_FLAGS(state, rec_type) do { \
state->prev_rec_type = rec_type; \ state->prev_rec_type = rec_type; \
return (state->err_flags); \ return (state->err_flags); \
} } while (0)
/* /*
* Be sure to flush any partial output line that might still be buffered * Be sure to flush any partial output line that might still be buffered
@@ -681,7 +717,8 @@ int mime_state_update(MIME_STATE *state, int rec_type,
vstring_strcat(state->output_buffer, text); vstring_strcat(state->output_buffer, text);
} else { } else {
if (state->static_flags & MIME_OPT_REPORT_TRUNC_HEADER) if (state->static_flags & MIME_OPT_REPORT_TRUNC_HEADER)
state->err_flags |= MIME_ERR_TRUNC_HEADER; REPORT_ERROR(state, MIME_ERR_TRUNC_HEADER,
STR(state->output_buffer));
} }
SAVE_PREV_REC_TYPE_AND_RETURN_ERR_FLAGS(state, rec_type); SAVE_PREV_REC_TYPE_AND_RETURN_ERR_FLAGS(state, rec_type);
} }
@@ -691,7 +728,8 @@ int mime_state_update(MIME_STATE *state, int rec_type,
vstring_strcat(state->output_buffer, text); vstring_strcat(state->output_buffer, text);
} else { } else {
if (state->static_flags & MIME_OPT_REPORT_TRUNC_HEADER) if (state->static_flags & MIME_OPT_REPORT_TRUNC_HEADER)
state->err_flags |= MIME_ERR_TRUNC_HEADER; REPORT_ERROR(state, MIME_ERR_TRUNC_HEADER,
STR(state->output_buffer));
} }
SAVE_PREV_REC_TYPE_AND_RETURN_ERR_FLAGS(state, rec_type); SAVE_PREV_REC_TYPE_AND_RETURN_ERR_FLAGS(state, rec_type);
} }
@@ -721,7 +759,8 @@ int mime_state_update(MIME_STATE *state, int rec_type,
for (cp = CU_CHAR_PTR(STR(state->output_buffer)); for (cp = CU_CHAR_PTR(STR(state->output_buffer));
cp < CU_CHAR_PTR(END(state->output_buffer)); cp++) cp < CU_CHAR_PTR(END(state->output_buffer)); cp++)
if (*cp & 0200) { if (*cp & 0200) {
state->err_flags |= MIME_ERR_8BIT_IN_HEADER; REPORT_ERROR(state, MIME_ERR_8BIT_IN_HEADER,
STR(state->output_buffer));
break; break;
} }
} }
@@ -803,14 +842,17 @@ int mime_state_update(MIME_STATE *state, int rec_type,
if (state->curr_stype == MIME_STYPE_PARTIAL if (state->curr_stype == MIME_STYPE_PARTIAL
|| state->curr_stype == MIME_STYPE_EXTERN_BODY) { || state->curr_stype == MIME_STYPE_EXTERN_BODY) {
if (state->curr_domain != MIME_ENC_7BIT) if (state->curr_domain != MIME_ENC_7BIT)
state->err_flags |= MIME_ERR_ENCODING_DOMAIN; REPORT_ERROR(state, MIME_ERR_ENCODING_DOMAIN,
mime_state_enc_name(state->curr_encoding));
} else { } else {
if (state->curr_encoding != state->curr_domain) if (state->curr_encoding != state->curr_domain)
state->err_flags |= MIME_ERR_ENCODING_DOMAIN; REPORT_ERROR(state, MIME_ERR_ENCODING_DOMAIN,
mime_state_enc_name(state->curr_encoding));
} }
} else if (state->curr_ctype == MIME_CTYPE_MULTIPART) { } else if (state->curr_ctype == MIME_CTYPE_MULTIPART) {
if (state->curr_encoding != state->curr_domain) if (state->curr_encoding != state->curr_domain)
state->err_flags |= MIME_ERR_ENCODING_DOMAIN; REPORT_ERROR(state, MIME_ERR_ENCODING_DOMAIN,
mime_state_enc_name(state->curr_encoding));
} }
} }
@@ -885,7 +927,7 @@ int mime_state_update(MIME_STATE *state, int rec_type,
&& (state->err_flags & MIME_ERR_8BIT_IN_7BIT_BODY) == 0) { && (state->err_flags & MIME_ERR_8BIT_IN_7BIT_BODY) == 0) {
for (cp = CU_CHAR_PTR(text); cp < CU_CHAR_PTR(text + len); cp++) for (cp = CU_CHAR_PTR(text); cp < CU_CHAR_PTR(text + len); cp++)
if (*cp & 0200) { if (*cp & 0200) {
state->err_flags |= MIME_ERR_8BIT_IN_7BIT_BODY; REPORT_ERROR(state, MIME_ERR_8BIT_IN_7BIT_BODY, text);
break; break;
} }
} }
@@ -944,7 +986,7 @@ const char *mime_state_error(int error_code)
if (error_code & MIME_ERR_NESTING) if (error_code & MIME_ERR_NESTING)
return ("MIME nesting exceeds safety limit"); return ("MIME nesting exceeds safety limit");
if (error_code & MIME_ERR_TRUNC_HEADER) if (error_code & MIME_ERR_TRUNC_HEADER)
return ("message header was truncated"); return ("message header length exceeds safety limit");
if (error_code & MIME_ERR_8BIT_IN_HEADER) if (error_code & MIME_ERR_8BIT_IN_HEADER)
return ("improper use of 8-bit data in message header"); return ("improper use of 8-bit data in message header");
if (error_code & MIME_ERR_8BIT_IN_7BIT_BODY) if (error_code & MIME_ERR_8BIT_IN_7BIT_BODY)
@@ -1005,9 +1047,14 @@ static void body_end(void *context)
vstream_fprintf(stream, "BODY END\n"); vstream_fprintf(stream, "BODY END\n");
} }
int var_header_limit = DEF_HEADER_LIMIT; static void err_print(void *context, int err_flag, const char *text)
int var_mime_maxdepth = DEF_MIME_MAXDEPTH; {
int var_mime_bound_len = DEF_MIME_BOUND_LEN; msg_warn("%s: %.100s", mime_state_error(err_flag), text);
}
int var_header_limit = 200;
int var_mime_maxdepth = 20;
int var_mime_bound_len = 200;
int main(int unused_argc, char **argv) int main(int unused_argc, char **argv)
{ {
@@ -1024,6 +1071,8 @@ int main(int unused_argc, char **argv)
(MIME_OPT_REPORT_8BIT_IN_7BIT_BODY \ (MIME_OPT_REPORT_8BIT_IN_7BIT_BODY \
| MIME_OPT_REPORT_8BIT_IN_HEADER \ | MIME_OPT_REPORT_8BIT_IN_HEADER \
| MIME_OPT_REPORT_ENCODING_DOMAIN \ | MIME_OPT_REPORT_ENCODING_DOMAIN \
| MIME_OPT_REPORT_TRUNC_HEADER \
| MIME_OPT_REPORT_NESTING \
| MIME_OPT_DOWNGRADE) | MIME_OPT_DOWNGRADE)
msg_vstream_init(basename(argv[0]), VSTREAM_OUT); msg_vstream_init(basename(argv[0]), VSTREAM_OUT);
@@ -1032,6 +1081,7 @@ int main(int unused_argc, char **argv)
state = mime_state_alloc(MIME_OPTIONS, state = mime_state_alloc(MIME_OPTIONS,
head_out, head_end, head_out, head_end,
body_out, body_end, body_out, body_end,
err_print,
(void *) VSTREAM_OUT); (void *) VSTREAM_OUT);
/* /*
@@ -1048,7 +1098,7 @@ int main(int unused_argc, char **argv)
* Error reporting. * Error reporting.
*/ */
if (err & MIME_ERR_TRUNC_HEADER) if (err & MIME_ERR_TRUNC_HEADER)
msg_warn("message header was truncated"); msg_warn("message header length exceeds safety limit");
if (err & MIME_ERR_NESTING) if (err & MIME_ERR_NESTING)
msg_warn("MIME nesting exceeds safety limit"); msg_warn("MIME nesting exceeds safety limit");
if (err & MIME_ERR_8BIT_IN_HEADER) if (err & MIME_ERR_8BIT_IN_HEADER)

View File

@@ -28,8 +28,9 @@ typedef struct MIME_STATE MIME_STATE;
typedef void (*MIME_STATE_HEAD_OUT) (void *, int, HEADER_OPTS *, VSTRING *); 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_BODY_OUT) (void *, int, const char *, int);
typedef void (*MIME_STATE_ANY_END) (void *); typedef void (*MIME_STATE_ANY_END) (void *);
typedef void (*MIME_STATE_ERR_PRINT) (void *, int, const char *);
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 MIME_STATE *mime_state_alloc(int, MIME_STATE_HEAD_OUT, MIME_STATE_ANY_END, MIME_STATE_BODY_OUT, MIME_STATE_ANY_END, MIME_STATE_ERR_PRINT, void *);
extern int mime_state_update(MIME_STATE *, int, const char *, int); extern int mime_state_update(MIME_STATE *, int, const char *, int);
extern MIME_STATE *mime_state_free(MIME_STATE *); extern MIME_STATE *mime_state_free(MIME_STATE *);
extern const char *mime_state_error(int); extern const char *mime_state_error(int);
@@ -45,6 +46,7 @@ extern const char *mime_state_error(int);
#define MIME_OPT_RECURSE_ALL_MESSAGE (1<<4) #define MIME_OPT_RECURSE_ALL_MESSAGE (1<<4)
#define MIME_OPT_REPORT_TRUNC_HEADER (1<<5) #define MIME_OPT_REPORT_TRUNC_HEADER (1<<5)
#define MIME_OPT_DISABLE_MIME (1<<6) #define MIME_OPT_DISABLE_MIME (1<<6)
#define MIME_OPT_REPORT_NESTING (1<<7)
/* /*
* Body encoding domains. * Body encoding domains.

View File

@@ -19,6 +19,7 @@ mime_state: PUSH boundary pqrs
NEST content-type: multipart/mumble; boundary(comment)="pqrs" NEST content-type: multipart/mumble; boundary(comment)="pqrs"
mime_state: header_token: base64 mime_state: header_token: base64
NEST content-transfer-encoding: base64 NEST content-transfer-encoding: base64
mime_state: warning: invalid message/* or multipart/* encoding domain: base64
BODY BODY
BODY pqrs prolog BODY pqrs prolog
BODY BODY

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,8 @@
mime_state: warning: message header length exceeds safety limit: Header: ??garbage garbage garbage garbage garbage garbage garbage garbage garbage ??garbage garbage
MAIN Header:
garbage garbage garbage garbage garbage garbage garbage garbage garbage
garbage garbage garbage garbage garbage garbage garbage garbage garbage
garbage garbage garbage garbage garbage garbage garbage garbage garbage
HEADER END
BODY END
mime_state: warning: message header length exceeds safety limit

View File

@@ -771,11 +771,13 @@ int smtp_xfer(SMTP_STATE *state)
&& (state->features & SMTP_FEATURE_8BITMIME) == 0 && (state->features & SMTP_FEATURE_8BITMIME) == 0
&& strcmp(request->encoding, MAIL_ATTR_ENC_7BIT) != 0); && strcmp(request->encoding, MAIL_ATTR_ENC_7BIT) != 0);
if (downgrading) if (downgrading)
state->mime_state = mime_state_alloc(MIME_OPT_DOWNGRADE, state->mime_state = mime_state_alloc(MIME_OPT_DOWNGRADE
| MIME_OPT_REPORT_NESTING,
smtp_header_out, smtp_header_out,
(MIME_STATE_ANY_END) 0, (MIME_STATE_ANY_END) 0,
smtp_text_out, smtp_text_out,
(MIME_STATE_ANY_END) 0, (MIME_STATE_ANY_END) 0,
(MIME_STATE_ERR_PRINT) 0,
(void *) state); (void *) state);
state->space_left = var_smtp_line_limit; state->space_left = var_smtp_line_limit;
smtp_timeout_setup(state->session->stream, smtp_timeout_setup(state->session->stream,