From 5c6cf6a0d5cb7da39e7fde01dca1ff862c1fa1c8 Mon Sep 17 00:00:00 2001 From: Jeremy Harris Date: Sun, 14 Dec 2014 15:15:34 +0000 Subject: [PATCH] Account properly for quoted or 2047-encoded MIME parameters while walking headers. Bug 1558 --- src/src/mime.c | 103 +++++++++++++++++--------------- test/log/4000 | 3 + test/mail/4000.userx | 38 ++++++++++++ test/scripts/4000-scanning/4000 | 29 +++++++++ test/stdout/4000 | 11 ++++ 5 files changed, 137 insertions(+), 47 deletions(-) diff --git a/src/src/mime.c b/src/src/mime.c index ab701f2a6..a61e9f22f 100644 --- a/src/src/mime.c +++ b/src/src/mime.c @@ -528,26 +528,24 @@ while(1) */ if (context != NULL) { - while(fgets(CS header, MIME_MAX_HEADER_SIZE, f) != NULL) + while(fgets(CS header, MIME_MAX_HEADER_SIZE, f)) { /* boundary line must start with 2 dashes */ - if (Ustrncmp(header,"--",2) == 0) - { - if (Ustrncmp((header+2),context->boundary,Ustrlen(context->boundary)) == 0) + if ( Ustrncmp(header, "--", 2) == 0 + && Ustrncmp(header+2, context->boundary, Ustrlen(context->boundary)) == 0) + { + /* found boundary */ + if (Ustrncmp((header+2+Ustrlen(context->boundary)), "--", 2) == 0) { - /* found boundary */ - if (Ustrncmp((header+2+Ustrlen(context->boundary)),"--",2) == 0) - { - /* END boundary found */ - debug_printf("End boundary found %s\n", context->boundary); - return rc; - } - else - debug_printf("Next part with boundary %s\n", context->boundary); - - /* can't use break here */ - goto DECODE_HEADERS; + /* END boundary found */ + debug_printf("End boundary found %s\n", context->boundary); + return rc; } + else + debug_printf("Next part with boundary %s\n", context->boundary); + + /* can't use break here */ + goto DECODE_HEADERS; } } /* Hit EOF or read error. Ugh. */ @@ -557,92 +555,103 @@ while(1) DECODE_HEADERS: /* parse headers, set up expansion variables */ - while (mime_get_header(f,header)) + while (mime_get_header(f, header)) { int i; /* loop through header list */ for (i = 0; i < mime_header_list_size; i++) - { - uschar *header_value = NULL; - int header_value_len = 0; - - /* found an interesting header? */ - if (strncmpic(mime_header_list[i].name,header,mime_header_list[i].namelen) == 0) - { - uschar *p = header + mime_header_list[i].namelen; - /* yes, grab the value (normalize to lower case) - and copy to its corresponding expansion variable */ + if (strncmpic(mime_header_list[i].name, + header, mime_header_list[i].namelen) == 0) + { /* found an interesting header */ + uschar * header_value; + int header_value_len; + uschar * p = header + mime_header_list[i].namelen; + + /* grab the value (normalize to lower case) + and copy to its corresponding expansion variable */ while(*p != ';') { *p = tolower(*p); p++; } - header_value_len = (p - (header + mime_header_list[i].namelen)); - header_value = (uschar *)malloc(header_value_len+1); - memset(header_value,0,header_value_len+1); + header_value_len = p - (header + mime_header_list[i].namelen); p = header + mime_header_list[i].namelen; - Ustrncpy(header_value, p, header_value_len); - debug_printf("Found %s MIME header, value is '%s'\n", mime_header_list[i].name, header_value); + header_value = string_copyn(p, header_value_len); + debug_printf("Found %s MIME header, value is '%s'\n", + mime_header_list[i].name, header_value); *((uschar **)(mime_header_list[i].value)) = header_value; /* make p point to the next character after the closing ';' */ - p += (header_value_len+1); + p += header_value_len+1; - /* grab all param=value tags on the remaining line, check if they are interesting */ + /* grab all param=value tags on the remaining line, + check if they are interesting */ NEXT_PARAM_SEARCH: - while (*p != 0) + while (*p) { mime_parameter * mp; for (mp = mime_parameter_list; mp < &mime_parameter_list[mime_parameter_list_size]; mp++) { - uschar *param_value = NULL; - int param_value_len = 0; + uschar * param_value = NULL; /* found an interesting parameter? */ if (strncmpic(mp->name, p, mp->namelen) == 0) { - uschar *q = p + mp->namelen; + uschar * q = p + mp->namelen; + int plen = 0; int size = 0; int ptr = 0; /* yes, grab the value and copy to its corresponding expansion variable */ while(*q && *q != ';') /* ; terminates */ - { if (*q == '"') { q++; /* skip leading " */ - while(*q && *q != '"') /* which protects ; */ + plen++; /* and account for the skip */ + while(*q && *q != '"') /* " protects ; */ + { param_value = string_cat(param_value, &size, &ptr, q++, 1); - if (*q) q++; /* skip trailing " */ + plen++; + } + if (*q) + { + q++; /* skip trailing " */ + plen++; + } } else + { param_value = string_cat(param_value, &size, &ptr, q++, 1); - } + plen++; + } + if (param_value) { param_value[ptr++] = '\0'; - param_value_len = ptr; param_value = rfc2047_decode(param_value, - check_rfc2047_length, NULL, 32, ¶m_value_len, &q); + check_rfc2047_length, NULL, 32, NULL, &q); debug_printf("Found %s MIME parameter in %s header, " "value is '%s'\n", mp->name, mime_header_list[i].name, param_value); } *mp->value = param_value; - p += (mp->namelen + param_value_len + 1); + p += mp->namelen + plen + 1; /* name=, content, ; */ goto NEXT_PARAM_SEARCH; } } /* There is something, but not one of our interesting parameters. Advance to the next semicolon */ - while(*p != ';') p++; + while(*p != ';') + { + if (*p == '"') while(*++p && *p != '"') ; + p++; + } p++; } } - } } /* set additional flag variables (easier access) */ diff --git a/test/log/4000 b/test/log/4000 index c5d503a03..a6f5d2f70 100644 --- a/test/log/4000 +++ b/test/log/4000 @@ -4,3 +4,6 @@ 1999-03-02 09:44:33 10HmaY-0005vi-00 <= CALLER@myhost.test.ex U=CALLER P=local-esmtp S=sss id=20041217133501.GA3058@test.ex 1999-03-02 09:44:33 10HmaY-0005vi-00 => userx R=r1 T=t1 1999-03-02 09:44:33 10HmaY-0005vi-00 Completed +1999-03-02 09:44:33 10HmaZ-0005vi-00 <= CALLER@myhost.test.ex U=CALLER P=local-esmtp S=sss id=20041217133501.GA3059@test.ex +1999-03-02 09:44:33 10HmaZ-0005vi-00 => userx R=r1 T=t1 +1999-03-02 09:44:33 10HmaZ-0005vi-00 Completed diff --git a/test/mail/4000.userx b/test/mail/4000.userx index ec9b2cba5..725770d63 100644 --- a/test/mail/4000.userx +++ b/test/mail/4000.userx @@ -180,3 +180,41 @@ foobar --T4sUOijqQbZv57TR-- +From CALLER@myhost.test.ex Tue Mar 02 09:44:33 1999 +Received: from CALLER (helo=test.ex) + by myhost.test.ex with local-esmtp (Exim x.yz) + (envelope-from ) + id 10HmaZ-0005vi-00 + for userx@test.ex; Tue, 2 Mar 1999 09:44:33 +0000 +Date: Tue, 2 Mar 1999 09:44:33 +0000 +From: J Caesar +To: a-list00@exim.org +Message-ID: <20041217133501.GA3059@test.ex> +Mime-Version: 1.0 +Content-Type: text/html; + charset=UTF-8; + name="" +Content-Disposition: inline +Subject: Nasty +Sender: CALLER_NAME +X-0-content-type: text/html +X-0-filename: +X-0-charset: UTF-8 +X-0-boundary: +X-0-content-disposition: inline +X-0-content-transfer-encoding: +X-0-content-id: +X-0-content-description: +X-0-is-multipart: 0 +X-0-is-coverletter: 1 +X-0-is-rfc822: 0 +X-0-decode-filename: TESTSUITE/spool/scan/10HmaZ-0005vi-00/10HmaZ-0005vi-00-00000 +X-0-content-size: 1 + +--T4sUOijqQbZv57TR +Content-Type: text/plain; + +foobar + +--T4sUOijqQbZv57TR-- + diff --git a/test/scripts/4000-scanning/4000 b/test/scripts/4000-scanning/4000 index 649f9825a..2f760bca0 100644 --- a/test/scripts/4000-scanning/4000 +++ b/test/scripts/4000-scanning/4000 @@ -97,3 +97,32 @@ foobar . quit **** +# +# +# This one has a different rotten parameter, but should not induce a crash +# +exim -odi -bs +ehlo test.ex +mail from:<> +rcpt to: +data +Date: Fri, 17 Dec 2004 14:35:01 +0100 +From: J Caesar +To: a-list00@exim.org +Message-ID: <20041217133501.GA3059@test.ex> +Mime-Version: 1.0 +Content-Type: text/html; + charset=UTF-8; + name="" +Content-Disposition: inline +Subject: Nasty + +--T4sUOijqQbZv57TR +Content-Type: text/plain; + +foobar + +--T4sUOijqQbZv57TR-- +. +quit +**** diff --git a/test/stdout/4000 b/test/stdout/4000 index 789a8fe1a..42d2eefc7 100644 --- a/test/stdout/4000 +++ b/test/stdout/4000 @@ -20,3 +20,14 @@ 354 Enter message, ending with "." on a line by itself 250 OK id=10HmaY-0005vi-00 221 myhost.test.ex closing connection +220 myhost.test.ex ESMTP Exim x.yz Tue, 2 Mar 1999 09:44:33 +0000 +250-myhost.test.ex Hello CALLER at test.ex +250-SIZE 52428800 +250-8BITMIME +250-PIPELINING +250 HELP +250 OK +250 Accepted +354 Enter message, ending with "." on a line by itself +250 OK id=10HmaZ-0005vi-00 +221 myhost.test.ex closing connection -- 2.30.2