Commit | Line | Data |
---|---|---|
de45f55a AM |
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 | |
6 | ||
7 | --- | |
8 | src/mime.c | 103 ++++++++++++++++++++++------------------ | |
9 | test/log/4000 | 3 ++ | |
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(-) | |
14 | ||
15 | diff --git a/src/mime.c b/src/mime.c | |
16 | index ab701f2..a61e9f2 100644 | |
17 | --- a/src/mime.c | |
18 | +++ b/src/mime.c | |
19 | @@ -528,26 +528,24 @@ while(1) | |
20 | */ | |
21 | if (context != NULL) | |
22 | { | |
23 | - while(fgets(CS header, MIME_MAX_HEADER_SIZE, f) != NULL) | |
24 | + while(fgets(CS header, MIME_MAX_HEADER_SIZE, f)) | |
25 | { | |
26 | /* boundary line must start with 2 dashes */ | |
27 | - if (Ustrncmp(header,"--",2) == 0) | |
28 | - { | |
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) | |
32 | + { | |
33 | + /* found boundary */ | |
34 | + if (Ustrncmp((header+2+Ustrlen(context->boundary)), "--", 2) == 0) | |
35 | { | |
36 | - /* found boundary */ | |
37 | - if (Ustrncmp((header+2+Ustrlen(context->boundary)),"--",2) == 0) | |
38 | - { | |
39 | - /* END boundary found */ | |
40 | - debug_printf("End boundary found %s\n", context->boundary); | |
41 | - return rc; | |
42 | - } | |
43 | - else | |
44 | - debug_printf("Next part with boundary %s\n", context->boundary); | |
45 | - | |
46 | - /* can't use break here */ | |
47 | - goto DECODE_HEADERS; | |
48 | + /* END boundary found */ | |
49 | + debug_printf("End boundary found %s\n", context->boundary); | |
50 | + return rc; | |
51 | } | |
52 | + else | |
53 | + debug_printf("Next part with boundary %s\n", context->boundary); | |
54 | + | |
55 | + /* can't use break here */ | |
56 | + goto DECODE_HEADERS; | |
57 | } | |
58 | } | |
59 | /* Hit EOF or read error. Ugh. */ | |
60 | @@ -557,92 +555,103 @@ while(1) | |
61 | ||
62 | DECODE_HEADERS: | |
63 | /* parse headers, set up expansion variables */ | |
64 | - while (mime_get_header(f,header)) | |
65 | + while (mime_get_header(f, header)) | |
66 | { | |
67 | int i; | |
68 | /* loop through header list */ | |
69 | for (i = 0; i < mime_header_list_size; i++) | |
70 | - { | |
71 | - uschar *header_value = NULL; | |
72 | - int header_value_len = 0; | |
73 | - | |
74 | - /* found an interesting header? */ | |
75 | - if (strncmpic(mime_header_list[i].name,header,mime_header_list[i].namelen) == 0) | |
76 | - { | |
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; | |
86 | + | |
87 | + /* grab the value (normalize to lower case) | |
88 | + and copy to its corresponding expansion variable */ | |
89 | while(*p != ';') | |
90 | { | |
91 | *p = tolower(*p); | |
92 | p++; | |
93 | } | |
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; | |
105 | ||
106 | /* make p point to the next character after the closing ';' */ | |
107 | - p += (header_value_len+1); | |
108 | + p += header_value_len+1; | |
109 | ||
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 */ | |
113 | NEXT_PARAM_SEARCH: | |
114 | - while (*p != 0) | |
115 | + while (*p) | |
116 | { | |
117 | mime_parameter * mp; | |
118 | for (mp = mime_parameter_list; | |
119 | mp < &mime_parameter_list[mime_parameter_list_size]; | |
120 | mp++) | |
121 | { | |
122 | - uschar *param_value = NULL; | |
123 | - int param_value_len = 0; | |
124 | + uschar * param_value = NULL; | |
125 | ||
126 | /* found an interesting parameter? */ | |
127 | if (strncmpic(mp->name, p, mp->namelen) == 0) | |
128 | { | |
129 | - uschar *q = p + mp->namelen; | |
130 | + uschar * q = p + mp->namelen; | |
131 | + int plen = 0; | |
132 | int size = 0; | |
133 | int ptr = 0; | |
134 | ||
135 | /* yes, grab the value and copy to its corresponding expansion variable */ | |
136 | while(*q && *q != ';') /* ; terminates */ | |
137 | - { | |
138 | if (*q == '"') | |
139 | { | |
140 | q++; /* skip leading " */ | |
141 | - while(*q && *q != '"') /* which protects ; */ | |
142 | + plen++; /* and account for the skip */ | |
143 | + while(*q && *q != '"') /* " protects ; */ | |
144 | + { | |
145 | param_value = string_cat(param_value, &size, &ptr, q++, 1); | |
146 | - if (*q) q++; /* skip trailing " */ | |
147 | + plen++; | |
148 | + } | |
149 | + if (*q) | |
150 | + { | |
151 | + q++; /* skip trailing " */ | |
152 | + plen++; | |
153 | + } | |
154 | } | |
155 | else | |
156 | + { | |
157 | param_value = string_cat(param_value, &size, &ptr, q++, 1); | |
158 | - } | |
159 | + plen++; | |
160 | + } | |
161 | + | |
162 | if (param_value) | |
163 | { | |
164 | param_value[ptr++] = '\0'; | |
165 | - param_value_len = ptr; | |
166 | ||
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, | |
172 | param_value); | |
173 | } | |
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; | |
178 | } | |
179 | } | |
180 | /* There is something, but not one of our interesting parameters. | |
181 | Advance to the next semicolon */ | |
182 | - while(*p != ';') p++; | |
183 | + while(*p != ';') | |
184 | + { | |
185 | + if (*p == '"') while(*++p && *p != '"') ; | |
186 | + p++; | |
187 | + } | |
188 | p++; | |
189 | } | |
190 | } | |
191 | - } | |
192 | } | |
193 | ||
194 | /* set additional flag variables (easier access) */ |