Skip to content

Commit cd4905b

Browse files
committed
Handle "filename*" field in MP header
1 parent fd0e042 commit cd4905b

File tree

1 file changed

+51
-3
lines changed

1 file changed

+51
-3
lines changed

apache2/msc_multipart.c

Lines changed: 51 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,9 @@
2020
#include "msc_util.h"
2121
#include "msc_parsers.h"
2222

23+
static const char* mime_charset_special = "!#$%&+-^_`{}~";
24+
static const char* attr_char_special = "!#$&+-.^_`~";
25+
2326
void validate_quotes(modsec_rec *msr, char *data, char quote) {
2427
assert(msr != NULL);
2528
int i, len;
@@ -85,6 +88,7 @@ static int multipart_parse_content_disposition(modsec_rec *msr, char *c_d_value)
8588
assert(msr != NULL);
8689
assert(c_d_value != NULL);
8790
char *p = NULL, *t = NULL;
91+
char *filenameStar = NULL;
8892

8993
/* accept only what we understand */
9094
if (strncmp(c_d_value, "form-data", 9) != 0) {
@@ -130,7 +134,41 @@ static int multipart_parse_content_disposition(modsec_rec *msr, char *c_d_value)
130134
*/
131135

132136
char quote = '\0';
133-
if ((*p == '"') || (*p == '\'')) {
137+
if (name == "filename*") {
138+
/* filename*=charset'[optional-language]'filename */
139+
/* Read beyond the charset and the optional language*/
140+
const char* start_of_charset = p;
141+
while ((*p != '\0') && (isalnum(*p) || (strchr(mime_charset_special, *p)))) {
142+
p++;
143+
}
144+
if ((*p != '\'') || (p == start_of_charset)) {
145+
return -16; // Must be at least one legit char before ' for start of language
146+
}
147+
p++;
148+
while ((*p != '\0') && (*p != '\'')) {
149+
p++;
150+
}
151+
if (*p != '\'') {
152+
return -17; // Single quote for end-of-language not found
153+
}
154+
p++;
155+
156+
/* Now read what should be the actual filename */
157+
const char* start_of_filename = p;
158+
while ((*p != '\0') && (*p != ';')) {
159+
if (*p == '%') {
160+
if ((*(p+1) == '\0') || (!isxdigit(*(p+1))) || (!isxdigit(*(p+2)))) {
161+
return -18;
162+
}
163+
p += 3;
164+
} else if (isalnum(*p) || strchr(attr_char_special, *p)) {
165+
p++;
166+
} else {
167+
return -19;
168+
}
169+
}
170+
value = apr_pmemdup(msr->mp, start_of_filename, p - start_of_filename);
171+
} else if ((*p == '"') || (*p == '\'')) {
134172
/* quoted */
135173
quote = *p; // remember which quote character was used for the value
136174

@@ -205,8 +243,7 @@ static int multipart_parse_content_disposition(modsec_rec *msr, char *c_d_value)
205243
log_escape_nq(msr->mp, value));
206244
}
207245
}
208-
else
209-
if (strcmp(name, "filename") == 0) {
246+
else if (strcmp(name, "filename") == 0) {
210247

211248
validate_quotes(msr, value, quote);
212249

@@ -223,6 +260,17 @@ static int multipart_parse_content_disposition(modsec_rec *msr, char *c_d_value)
223260
msr_log(msr, 9, "Multipart: Content-Disposition filename: %s",
224261
log_escape_nq(msr->mp, value));
225262
}
263+
} else if (strcmp(name, "filename*") == 0) {
264+
if (filenameStar != NULL && strlen(filenameStar) != 0) {
265+
msr_log(msr, 4,
266+
"Multipart: Warning: Duplicate Content-Disposition filename*: %s.", log_escape_nq(msr->mp, value));
267+
return -20;
268+
}
269+
filenameStar = apr_pstrdup(msr->mp, value);
270+
if (msr->txcfg->debuglog_level >= 9) {
271+
msr_log(msr, 9, "Multipart: Content-Disposition filename*: %s.",
272+
log_escape_nq(msr->mp, value));
273+
}
226274
}
227275
else return -11;
228276

0 commit comments

Comments
 (0)