1 From 5c6cf6a0d5cb7da39e7fde01dca1ff862c1fa1c8 Mon Sep 17 00:00:00 2001
2 From: Jeremy Harris <jgh146exb@wizmail.org>
3 Date: Sun, 14 Dec 2014 15:15:34 +0000
4 Subject: [PATCH] Account properly for quoted or 2047-encoded MIME parameters
5 while walking headers. Bug 1558
8 src/mime.c | 103 ++++++++++++++++++++++------------------
10 test/mail/4000.userx | 38 +++++++++++++++
11 test/scripts/4000-scanning/4000 | 29 +++++++++++
12 test/stdout/4000 | 11 +++++
13 5 files changed, 137 insertions(+), 47 deletions(-)
15 diff --git a/src/mime.c b/src/mime.c
16 index ab701f2..a61e9f2 100644
19 @@ -528,26 +528,24 @@ while(1)
23 - while(fgets(CS header, MIME_MAX_HEADER_SIZE, f) != NULL)
24 + while(fgets(CS header, MIME_MAX_HEADER_SIZE, f))
26 /* boundary line must start with 2 dashes */
27 - if (Ustrncmp(header,"--",2) == 0)
29 - if (Ustrncmp((header+2),context->boundary,Ustrlen(context->boundary)) == 0)
30 + if ( Ustrncmp(header, "--", 2) == 0
31 + && Ustrncmp(header+2, context->boundary, Ustrlen(context->boundary)) == 0)
33 + /* found boundary */
34 + if (Ustrncmp((header+2+Ustrlen(context->boundary)), "--", 2) == 0)
36 - /* found boundary */
37 - if (Ustrncmp((header+2+Ustrlen(context->boundary)),"--",2) == 0)
39 - /* END boundary found */
40 - debug_printf("End boundary found %s\n", context->boundary);
44 - debug_printf("Next part with boundary %s\n", context->boundary);
46 - /* can't use break here */
47 - goto DECODE_HEADERS;
48 + /* END boundary found */
49 + debug_printf("End boundary found %s\n", context->boundary);
53 + debug_printf("Next part with boundary %s\n", context->boundary);
55 + /* can't use break here */
56 + goto DECODE_HEADERS;
59 /* Hit EOF or read error. Ugh. */
60 @@ -557,92 +555,103 @@ while(1)
63 /* parse headers, set up expansion variables */
64 - while (mime_get_header(f,header))
65 + while (mime_get_header(f, header))
68 /* loop through header list */
69 for (i = 0; i < mime_header_list_size; i++)
71 - uschar *header_value = NULL;
72 - int header_value_len = 0;
74 - /* found an interesting header? */
75 - if (strncmpic(mime_header_list[i].name,header,mime_header_list[i].namelen) == 0)
77 - uschar *p = header + mime_header_list[i].namelen;
78 - /* yes, grab the value (normalize to lower case)
79 - and copy to its corresponding expansion variable */
80 + if (strncmpic(mime_header_list[i].name,
81 + header, mime_header_list[i].namelen) == 0)
82 + { /* found an interesting header */
83 + uschar * header_value;
84 + int header_value_len;
85 + uschar * p = header + mime_header_list[i].namelen;
87 + /* grab the value (normalize to lower case)
88 + and copy to its corresponding expansion variable */
94 - header_value_len = (p - (header + mime_header_list[i].namelen));
95 - header_value = (uschar *)malloc(header_value_len+1);
96 - memset(header_value,0,header_value_len+1);
97 + header_value_len = p - (header + mime_header_list[i].namelen);
98 p = header + mime_header_list[i].namelen;
99 - Ustrncpy(header_value, p, header_value_len);
100 - debug_printf("Found %s MIME header, value is '%s'\n", mime_header_list[i].name, header_value);
101 + header_value = string_copyn(p, header_value_len);
102 + debug_printf("Found %s MIME header, value is '%s'\n",
103 + mime_header_list[i].name, header_value);
104 *((uschar **)(mime_header_list[i].value)) = header_value;
106 /* make p point to the next character after the closing ';' */
107 - p += (header_value_len+1);
108 + p += header_value_len+1;
110 - /* grab all param=value tags on the remaining line, check if they are interesting */
111 + /* grab all param=value tags on the remaining line,
112 + check if they are interesting */
118 for (mp = mime_parameter_list;
119 mp < &mime_parameter_list[mime_parameter_list_size];
122 - uschar *param_value = NULL;
123 - int param_value_len = 0;
124 + uschar * param_value = NULL;
126 /* found an interesting parameter? */
127 if (strncmpic(mp->name, p, mp->namelen) == 0)
129 - uschar *q = p + mp->namelen;
130 + uschar * q = p + mp->namelen;
135 /* yes, grab the value and copy to its corresponding expansion variable */
136 while(*q && *q != ';') /* ; terminates */
140 q++; /* skip leading " */
141 - while(*q && *q != '"') /* which protects ; */
142 + plen++; /* and account for the skip */
143 + while(*q && *q != '"') /* " protects ; */
145 param_value = string_cat(param_value, &size, &ptr, q++, 1);
146 - if (*q) q++; /* skip trailing " */
151 + q++; /* skip trailing " */
157 param_value = string_cat(param_value, &size, &ptr, q++, 1);
164 param_value[ptr++] = '\0';
165 - param_value_len = ptr;
167 param_value = rfc2047_decode(param_value,
168 - check_rfc2047_length, NULL, 32, ¶m_value_len, &q);
169 + check_rfc2047_length, NULL, 32, NULL, &q);
170 debug_printf("Found %s MIME parameter in %s header, "
171 "value is '%s'\n", mp->name, mime_header_list[i].name,
174 *mp->value = param_value;
175 - p += (mp->namelen + param_value_len + 1);
176 + p += mp->namelen + plen + 1; /* name=, content, ; */
177 goto NEXT_PARAM_SEARCH;
180 /* There is something, but not one of our interesting parameters.
181 Advance to the next semicolon */
182 - while(*p != ';') p++;
185 + if (*p == '"') while(*++p && *p != '"') ;
194 /* set additional flag variables (easier access) */