From: Stephan Bosch Date: Wed, 14 Dec 2016 01:51:54 +0000 (+0100) Subject: lib-imap: imap-bodystructure: Prevent writing erroneous whitespace between items... X-Git-Tag: 2.3.0.rc1~2440 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=f549b400d50935754cbeb6ceabd922ab777b4d77;p=thirdparty%2Fdovecot%2Fcore.git lib-imap: imap-bodystructure: Prevent writing erroneous whitespace between items in an envelope address list. Both imap_bodystructure_write() and imap_body_parse_from_bodystructure() produced such invalid output. This caused an RFC 3501 violation in IMAP FETCH BODY and BODYSTRUCTURE responses. Test suite is amended to test this situation. --- diff --git a/src/lib-imap/imap-bodystructure.c b/src/lib-imap/imap-bodystructure.c index d5445d15ec..857209f5e2 100644 --- a/src/lib-imap/imap-bodystructure.c +++ b/src/lib-imap/imap-bodystructure.c @@ -547,12 +547,16 @@ get_nstring(const struct imap_arg *arg, pool_t pool, string_t *tmpstr, return TRUE; } -static void imap_write_list(const struct imap_arg *args, string_t *str) +static void +imap_write_envelope_list(const struct imap_arg *args, string_t *str, + bool toplevel) { const struct imap_arg *children; /* don't do any typechecking, just write it out */ while (!IMAP_ARG_IS_EOL(args)) { + bool list = FALSE; + if (!str_append_nstring(str, args)) { if (!imap_arg_get_list(args, &children)) { /* everything is either nstring or list */ @@ -560,16 +564,24 @@ static void imap_write_list(const struct imap_arg *args, string_t *str) } str_append_c(str, '('); - imap_write_list(children, str); + imap_write_envelope_list(children, str, FALSE); str_append_c(str, ')'); + + list = TRUE; } args++; - if (!IMAP_ARG_IS_EOL(args)) + if ((toplevel || !list) && !IMAP_ARG_IS_EOL(args)) str_append_c(str, ' '); } } +static void +imap_write_envelope(const struct imap_arg *args, string_t *str) +{ + imap_write_envelope_list(args, str, TRUE); +} + static int imap_write_nstring_list(const struct imap_arg *args, string_t *str) { str_truncate(str, 0); @@ -814,7 +826,7 @@ imap_bodystructure_parse_args(const struct imap_arg *args, pool_t pool, return -1; } str_truncate(tmpstr, 0); - imap_write_list(list_args, tmpstr); + imap_write_envelope(list_args, tmpstr); child_data = part->children->context; child_data->envelope_str = p_strdup(pool, str_c(tmpstr)); @@ -974,7 +986,7 @@ static int imap_parse_bodystructure_args(const struct imap_arg *args, return -1; } str_append_c(str, '('); - imap_write_list(list_args, str); + imap_write_envelope(list_args, str); str_append(str, ") ("); if (!imap_arg_get_list(&args[1], &list_args)) { diff --git a/src/lib-imap/test-imap-bodystructure.c b/src/lib-imap/test-imap-bodystructure.c index 0df8998b12..83dec59c5f 100644 --- a/src/lib-imap/test-imap-bodystructure.c +++ b/src/lib-imap/test-imap-bodystructure.c @@ -31,6 +31,7 @@ static const char testmsg[] = "Content-Type: message/rfc822\n" "\n" "From: sub@domain.org\n" +"To: sub-to1@domain.org, sub-to2@domain.org\n" "Date: Sun, 12 Aug 2012 12:34:56 +0300\n" "Subject: submsg\n" "Content-Type: multipart/alternative; boundary=\"sub1\"\n" @@ -55,10 +56,10 @@ static const char testmsg[] = "Root MIME epilogue\n"; static const char testmsg_bodystructure[] = -"(\"text\" \"x-myown\" (\"charset\" \"us-ascii\" \"foo\" \"quoted\\\"string\") \"\" \"hellodescription\" \"7bit\" 7 1 \"Q2hlY2sgSW50ZWdyaXR5IQ==\" (\"inline\" (\"foo\" \"bar\")) (\"en\" \"fi\" \"se\") \"http://example.com/test.txt\")(\"message\" \"rfc822\" NIL NIL NIL \"7bit\" 368 (\"Sun, 12 Aug 2012 12:34:56 +0300\" \"submsg\" ((NIL NIL \"sub\" \"domain.org\")) ((NIL NIL \"sub\" \"domain.org\")) ((NIL NIL \"sub\" \"domain.org\")) NIL NIL NIL NIL NIL) ((\"text\" \"html\" (\"charset\" \"us-ascii\") NIL NIL \"8bit\" 20 1 NIL NIL NIL NIL)(\"text\" \"plain\" (\"charset\" \"us-ascii\") NIL NIL \"7bit\" 21 1 NIL NIL NIL NIL) \"alternative\" (\"boundary\" \"sub1\") NIL NIL NIL) 20 NIL NIL NIL NIL) \"mixed\" (\"boundary\" \"foo bar\") NIL NIL NIL"; +"(\"text\" \"x-myown\" (\"charset\" \"us-ascii\" \"foo\" \"quoted\\\"string\") \"\" \"hellodescription\" \"7bit\" 7 1 \"Q2hlY2sgSW50ZWdyaXR5IQ==\" (\"inline\" (\"foo\" \"bar\")) (\"en\" \"fi\" \"se\") \"http://example.com/test.txt\")(\"message\" \"rfc822\" NIL NIL NIL \"7bit\" 412 (\"Sun, 12 Aug 2012 12:34:56 +0300\" \"submsg\" ((NIL NIL \"sub\" \"domain.org\")) ((NIL NIL \"sub\" \"domain.org\")) ((NIL NIL \"sub\" \"domain.org\")) ((NIL NIL \"sub-to1\" \"domain.org\")(NIL NIL \"sub-to2\" \"domain.org\")) NIL NIL NIL NIL) ((\"text\" \"html\" (\"charset\" \"us-ascii\") NIL NIL \"8bit\" 20 1 NIL NIL NIL NIL)(\"text\" \"plain\" (\"charset\" \"us-ascii\") NIL NIL \"7bit\" 21 1 NIL NIL NIL NIL) \"alternative\" (\"boundary\" \"sub1\") NIL NIL NIL) 21 NIL NIL NIL NIL) \"mixed\" (\"boundary\" \"foo bar\") NIL NIL NIL"; static const char testmsg_body[] = -"(\"text\" \"x-myown\" (\"charset\" \"us-ascii\" \"foo\" \"quoted\\\"string\") \"\" \"hellodescription\" \"7bit\" 7 1)(\"message\" \"rfc822\" NIL NIL NIL \"7bit\" 368 (\"Sun, 12 Aug 2012 12:34:56 +0300\" \"submsg\" ((NIL NIL \"sub\" \"domain.org\")) ((NIL NIL \"sub\" \"domain.org\")) ((NIL NIL \"sub\" \"domain.org\")) NIL NIL NIL NIL NIL) ((\"text\" \"html\" (\"charset\" \"us-ascii\") NIL NIL \"8bit\" 20 1)(\"text\" \"plain\" (\"charset\" \"us-ascii\") NIL NIL \"7bit\" 21 1) \"alternative\") 20) \"mixed\""; +"(\"text\" \"x-myown\" (\"charset\" \"us-ascii\" \"foo\" \"quoted\\\"string\") \"\" \"hellodescription\" \"7bit\" 7 1)(\"message\" \"rfc822\" NIL NIL NIL \"7bit\" 412 (\"Sun, 12 Aug 2012 12:34:56 +0300\" \"submsg\" ((NIL NIL \"sub\" \"domain.org\")) ((NIL NIL \"sub\" \"domain.org\")) ((NIL NIL \"sub\" \"domain.org\")) ((NIL NIL \"sub-to1\" \"domain.org\")(NIL NIL \"sub-to2\" \"domain.org\")) NIL NIL NIL NIL) ((\"text\" \"html\" (\"charset\" \"us-ascii\") NIL NIL \"8bit\" 20 1)(\"text\" \"plain\" (\"charset\" \"us-ascii\") NIL NIL \"7bit\" 21 1) \"alternative\") 21) \"mixed\""; static struct message_part *msg_parse(pool_t pool, bool parse_bodystructure) {