From: Timo Sirainen Date: Sun, 26 Jul 2009 22:13:41 +0000 (-0400) Subject: message-decoder: Fixed assert-crashes caused by the previous quoted-printable change. X-Git-Tag: 2.0.alpha1~388 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=db24d60c306c9d477392ff5b61cb3fc95fef3bb7;p=thirdparty%2Fdovecot%2Fcore.git message-decoder: Fixed assert-crashes caused by the previous quoted-printable change. --HG-- branch : HEAD --- diff --git a/src/lib-mail/Makefile.am b/src/lib-mail/Makefile.am index 486c62ff84..5868bf2dbf 100644 --- a/src/lib-mail/Makefile.am +++ b/src/lib-mail/Makefile.am @@ -57,6 +57,7 @@ test_programs = \ test-mbox-from \ test-message-address \ test-message-date \ + test-message-decoder \ test-message-header-parser \ test-message-id \ test-message-parser \ @@ -89,6 +90,10 @@ test_message_date_SOURCES = test-message-date.c test_message_date_LDADD = message-date.lo rfc822-parser.lo $(test_libs) test_message_date_DEPENDENCIES = message-date.lo rfc822-parser.lo $(test_libs) +test_message_decoder_SOURCES = test-message-decoder.c +test_message_decoder_LDADD = message-decoder.lo rfc822-parser.lo rfc2231-parser.lo $(test_libs) +test_message_decoder_DEPENDENCIES = message-decoder.lo rfc822-parser.lo rfc2231-parser.lo $(test_libs) + test_message_header_parser_SOURCES = test-message-header-parser.c test_message_header_parser_LDADD = message-header-parser.lo $(test_libs) test_message_header_parser_DEPENDENCIES = message-header-parser.lo $(test_libs) diff --git a/src/lib-mail/message-decoder.c b/src/lib-mail/message-decoder.c index 2f21ea2eb5..cae1cbea73 100644 --- a/src/lib-mail/message-decoder.c +++ b/src/lib-mail/message-decoder.c @@ -39,8 +39,7 @@ struct message_decoder_context { char translation_buf[MAX_TRANSLATION_BUF_SIZE]; unsigned int translation_size; - char encoding_buf[MAX_ENCODING_BUF_SIZE]; - unsigned int encoding_size; + buffer_t *encoding_buf; char *content_charset; enum content_type content_type; @@ -58,6 +57,7 @@ message_decoder_init(enum message_decoder_flags flags) ctx->flags = flags; ctx->buf = buffer_create_dynamic(default_pool, 8192); ctx->buf2 = buffer_create_dynamic(default_pool, 8192); + ctx->encoding_buf = buffer_create_dynamic(default_pool, 128); return ctx; } @@ -70,6 +70,7 @@ void message_decoder_deinit(struct message_decoder_context **_ctx) if (ctx->charset_trans != NULL) charset_to_utf8_end(&ctx->charset_trans); + buffer_free(&ctx->encoding_buf); buffer_free(&ctx->buf); buffer_free(&ctx->buf2); i_free(ctx->charset_trans_charset); @@ -250,18 +251,13 @@ static bool message_decode_body(struct message_decoder_context *ctx, struct message_block *input, struct message_block *output) { - unsigned char new_buf[MAX_ENCODING_BUF_SIZE+1]; const unsigned char *data = NULL; - size_t pos, size = 0, skip = 0; + size_t pos, size = 0; int ret; - if (ctx->encoding_size != 0) { + if (ctx->encoding_buf->used != 0) { /* @UNSAFE */ - memcpy(new_buf, ctx->encoding_buf, ctx->encoding_size); - skip = sizeof(new_buf) - ctx->encoding_size; - if (skip > input->size) - skip = input->size; - memcpy(new_buf + ctx->encoding_size, input->data, skip); + buffer_append(ctx->encoding_buf, input->data, input->size); } switch (ctx->content_type) { @@ -275,34 +271,27 @@ static bool message_decode_body(struct message_decoder_context *ctx, break; case CONTENT_TYPE_QP: buffer_set_used_size(ctx->buf, 0); - if (ctx->encoding_size != 0) { - quoted_printable_decode(new_buf, - ctx->encoding_size + skip, + if (ctx->encoding_buf->used != 0) { + quoted_printable_decode(ctx->encoding_buf->data, + ctx->encoding_buf->used, + &pos, ctx->buf); + } else { + quoted_printable_decode(input->data, input->size, &pos, ctx->buf); - i_assert(pos >= ctx->encoding_size); - skip = pos - ctx->encoding_size; } - - quoted_printable_decode(input->data + skip, input->size - skip, - &pos, ctx->buf); - pos += skip; data = ctx->buf->data; size = ctx->buf->used; break; case CONTENT_TYPE_BASE64: buffer_set_used_size(ctx->buf, 0); - if (ctx->encoding_size != 0) { - if (base64_decode(new_buf, ctx->encoding_size + skip, - &pos, ctx->buf) < 0) { - /* corrupted base64 data, don't bother with - the rest of it */ - return FALSE; - } - i_assert(pos >= ctx->encoding_size); - skip = pos - ctx->encoding_size; + if (ctx->encoding_buf->used != 0) { + ret = base64_decode(ctx->encoding_buf->data, + ctx->encoding_buf->used, + &pos, ctx->buf); + } else { + ret = base64_decode(input->data, input->size, + &pos, ctx->buf); } - ret = base64_decode(input->data + skip, input->size - skip, - &pos, ctx->buf); if (ret < 0) { /* corrupted base64 data, don't bother with the rest of it */ @@ -310,23 +299,19 @@ static bool message_decode_body(struct message_decoder_context *ctx, } if (ret == 0) { /* end of base64 input */ - pos = input->size - skip; + pos = input->size; + buffer_set_used_size(ctx->encoding_buf, 0); } - pos += skip; data = ctx->buf->data; size = ctx->buf->used; break; } - if (pos != input->size) { - /* @UNSAFE */ - i_assert(pos < input->size); - ctx->encoding_size = input->size - pos; - i_assert(ctx->encoding_size <= sizeof(ctx->encoding_buf)); - memcpy(ctx->encoding_buf, input->data + pos, - ctx->encoding_size); - } else { - ctx->encoding_size = 0; + if (ctx->encoding_buf->used != 0) + buffer_delete(ctx->encoding_buf, 0, pos); + else if (pos != input->size) { + buffer_append(ctx->encoding_buf, + input->data + pos, input->size - pos); } if (ctx->binary_input) { @@ -408,5 +393,5 @@ void message_decoder_decode_reset(struct message_decoder_context *ctx) i_free_and_null(ctx->content_charset); ctx->content_type = CONTENT_TYPE_BINARY; ctx->charset_utf8 = TRUE; - ctx->encoding_size = 0; + buffer_set_used_size(ctx->encoding_buf, 0); } diff --git a/src/lib-mail/test-message-decoder.c b/src/lib-mail/test-message-decoder.c new file mode 100644 index 0000000000..a3dc30e390 --- /dev/null +++ b/src/lib-mail/test-message-decoder.c @@ -0,0 +1,99 @@ +/* Copyright (c) 2007-2009 Dovecot authors, see the included COPYING file */ + +#include "lib.h" +#include "buffer.h" +#include "charset-utf8.h" +#include "quoted-printable.h" +#include "message-parser.h" +#include "message-header-decode.h" +#include "message-decoder.h" +#include "test-common.h" + +bool message_header_decode_utf8(const unsigned char *data, size_t size, + buffer_t *dest, bool dtcase ATTR_UNUSED) +{ + buffer_append(dest, data, size); + return FALSE; +} + +void quoted_printable_decode(const unsigned char *src, size_t src_size, + size_t *src_pos_r, buffer_t *dest) +{ + while (src_size > 0 && src[src_size-1] == ' ') + src_size--; + buffer_append(dest, src, src_size); + *src_pos_r = src_size; +} + +int charset_to_utf8_begin(const char *charset ATTR_UNUSED, + enum charset_flags flags ATTR_UNUSED, + struct charset_translation **t_r) +{ + *t_r = NULL; + return 0; +} +void charset_to_utf8_end(struct charset_translation **t ATTR_UNUSED) { } +bool charset_is_utf8(const char *charset ATTR_UNUSED) { return TRUE; } + +enum charset_result +charset_to_utf8(struct charset_translation *t ATTR_UNUSED, + const unsigned char *src, size_t *src_size, buffer_t *dest) +{ + buffer_append(dest, src, *src_size); + return CHARSET_RET_OK; +} + +static void test_message_decoder(void) +{ + struct message_decoder_context *ctx; + struct message_part part; + struct message_header_line hdr; + struct message_block input, output; + + test_begin("message decoder"); + + memset(&part, 0, sizeof(part)); + memset(&input, 0, sizeof(input)); + memset(&output, 0, sizeof(output)); + input.part = ∂ + + ctx = message_decoder_init(0); + + hdr.name = "Content-Transfer-Encoding"; + hdr.name_len = strlen(hdr.name); + hdr.full_value = (const void *)"quoted-printable"; + hdr.full_value_len = strlen((const char *)hdr.full_value); + input.hdr = &hdr; + test_assert(message_decoder_decode_next_block(ctx, &input, &output)); + + input.hdr = NULL; + test_assert(message_decoder_decode_next_block(ctx, &input, &output)); + + input.hdr = NULL; + test_assert(message_decoder_decode_next_block(ctx, &input, &output)); + + input.data = (const void *)"foo "; + input.size = strlen((const char *)input.data); + test_assert(message_decoder_decode_next_block(ctx, &input, &output)); + test_assert(output.size == 3); + test_assert(memcmp(output.data, "foo", 3) == 0); + + input.data = (const void *)"bar"; + input.size = strlen((const char *)input.data); + test_assert(message_decoder_decode_next_block(ctx, &input, &output)); + test_assert(output.size == 14); + test_assert(memcmp(output.data, " bar", 14) == 0); + + message_decoder_deinit(&ctx); + + test_end(); +} + +int main(void) +{ + static void (*test_functions[])(void) = { + test_message_decoder, + NULL + }; + return test_run(test_functions); +}