From: Timo Sirainen Date: Mon, 30 Nov 2015 11:14:29 +0000 (+0200) Subject: lib-mail: rfc822_parse_content_param() was unescaping already unescaped parameters X-Git-Tag: 2.2.20.rc1~17 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=efb00f1b47d7219f77d89a963c9f3584583b207e;p=thirdparty%2Fdovecot%2Fcore.git lib-mail: rfc822_parse_content_param() was unescaping already unescaped parameters This caused all Content-* parameter parsing to be unescaped once too many times, resulting in somewhat broken BODY and BODYSTRUCTURE replies if any <\> characters were used. Also MIME boundaries were parsed in case <\> was used in them, but this probably didn't practically happen. --- diff --git a/src/lib-mail/Makefile.am b/src/lib-mail/Makefile.am index 6a3510afc6..7ae5a9d3ea 100644 --- a/src/lib-mail/Makefile.am +++ b/src/lib-mail/Makefile.am @@ -95,7 +95,8 @@ test_programs = \ test-ostream-dot \ test-qp-decoder \ test-quoted-printable \ - test-rfc2231-parser + test-rfc2231-parser \ + test-rfc822-parser noinst_PROGRAMS = $(test_programs) @@ -196,6 +197,10 @@ test_rfc2231_parser_SOURCES = test-rfc2231-parser.c test_rfc2231_parser_LDADD = rfc2231-parser.lo rfc822-parser.lo $(test_libs) test_rfc2231_parser_DEPENDENCIES = $(test_deps) +test_rfc822_parser_SOURCES = test-rfc822-parser.c +test_rfc822_parser_LDADD = rfc822-parser.lo $(test_libs) +test_rfc822_parser_DEPENDENCIES = $(test_deps) + check: check-am check-test check-test: all-am for bin in $(test_programs); do \ diff --git a/src/lib-mail/rfc822-parser.c b/src/lib-mail/rfc822-parser.c index 21e95fa3cc..7bc3876310 100644 --- a/src/lib-mail/rfc822-parser.c +++ b/src/lib-mail/rfc822-parser.c @@ -409,7 +409,6 @@ int rfc822_parse_content_param(struct rfc822_parser_context *ctx, /* broken / no value */ } else if (*ctx->data == '"') { ret = rfc822_parse_quoted_string(ctx, tmp); - (void)str_unescape(str_c_modifiable(tmp) + value_pos); } else if (ctx->data != ctx->end && *ctx->data == '=') { /* workaround for broken input: name==?utf-8?b?...?= */ diff --git a/src/lib-mail/test-rfc822-parser.c b/src/lib-mail/test-rfc822-parser.c new file mode 100644 index 0000000000..70a871b62f --- /dev/null +++ b/src/lib-mail/test-rfc822-parser.c @@ -0,0 +1,74 @@ +/* Copyright (c) 2015 Dovecot authors, see the included COPYING file */ + +#include "lib.h" +#include "str.h" +#include "rfc822-parser.h" +#include "test-common.h" + +static void test_rfc822_parse_quoted_string(void) +{ + const struct { + const char *input, *output; + int ret; + } tests[] = { + { "\"", "", -1 }, + { "\"\"", "", 0 }, + { "\"foo\"", "foo", 0 }, + { "\"\"foo", "", 1 }, + { "\"\"\"", "", 1 }, + { "\"\\\"\"", "\"", 0 }, + { "\"\\\\\"", "\\", 0 }, + { "\"\\\\foo\\\\foo\\\\\"", "\\foo\\foo\\", 0 } + }; + struct rfc822_parser_context parser; + string_t *str = t_str_new(64); + unsigned int i = 0; + + test_begin("rfc822 parse quoted string"); + for (i = 0; i < N_ELEMENTS(tests); i++) { + rfc822_parser_init(&parser, (const void *)tests[i].input, + strlen(tests[i].input), NULL); + test_assert_idx(rfc822_parse_quoted_string(&parser, str) == tests[i].ret, i); + test_assert_idx(tests[i].ret < 0 || + strcmp(tests[i].output, str_c(str)) == 0, i); + str_truncate(str, 0); + } + test_end(); +} + +static void test_rfc822_parse_content_param(void) +{ + const char *input = + "; key1=value1#$!%&'*+-.^_`{|}~" + "; key2=\" \\\"(),/:;<=>?@[\\\\]\""; + const struct { + const char *key, *value; + } output[] = { + { "key1", "value1#$!%&'*+-.^_`{|}~" }, + { "key2", " \"(),/:;<=>?@[\\]" } + }; + struct rfc822_parser_context parser; + const char *key, *value; + unsigned int i = 0; + int ret; + + test_begin("rfc822 parse content param"); + rfc822_parser_init(&parser, (const void *)input, strlen(input), NULL); + while ((ret = rfc822_parse_content_param(&parser, &key, &value)) > 0) { + test_assert_idx(strcmp(output[i].key, key) == 0, i); + test_assert_idx(strcmp(output[i].value, value) == 0, i); + i++; + } + test_assert(ret == 0); + test_end(); +} + +int main(void) +{ + static void (*test_functions[])(void) = { + test_rfc822_parse_quoted_string, + test_rfc822_parse_content_param, + NULL + }; + return test_run(test_functions); +}