|
20 | 20 | #include "msc_util.h" |
21 | 21 | #include "msc_parsers.h" |
22 | 22 |
|
| 23 | +static const char* mime_charset_special = "!#$&+-^_`~%{}"; |
| 24 | +static const char* attr_char_special = "!#$&+-^_`~."; |
| 25 | + |
23 | 26 | void validate_quotes(modsec_rec *msr, char *data, char quote) { |
24 | 27 | assert(msr != NULL); |
25 | 28 | int i, len; |
@@ -85,7 +88,8 @@ static int multipart_parse_content_disposition(modsec_rec *msr, char *c_d_value) |
85 | 88 | assert(msr != NULL); |
86 | 89 | assert(c_d_value != NULL); |
87 | 90 | char *p = NULL, *t = NULL; |
88 | | - |
| 91 | + char* filenameStar = NULL; |
| 92 | + |
89 | 93 | /* accept only what we understand */ |
90 | 94 | if (strncmp(c_d_value, "form-data", 9) != 0) { |
91 | 95 | return -1; |
@@ -223,6 +227,64 @@ static int multipart_parse_content_disposition(modsec_rec *msr, char *c_d_value) |
223 | 227 | msr_log(msr, 9, "Multipart: Content-Disposition filename: %s", |
224 | 228 | log_escape_nq(msr->mp, value)); |
225 | 229 | } |
| 230 | + else if (strcmp(name, "filename*") == 0) { |
| 231 | + /* old restrictive code |
| 232 | + if (strncasecmp(value, "UTF-8''", 7) && strncasecmp(value, "ISO-8859-1''", 12)) { |
| 233 | + msr_log(msr, 4, "Multipart: filename* must contain encoding: %s", log_escape_nq(msr->mp, value)); |
| 234 | + msr->mpd->flag_error = 1; |
| 235 | + return -16; |
| 236 | + } |
| 237 | + //msr_log(msr, 4, "Multipart: Warning: Content-Disposition filename* is obsolete (ignore it)"); |
| 238 | + */ |
| 239 | + |
| 240 | + /* filename*=charset'[optional-language]'filename */ |
| 241 | + /* Read beyond the charset and the optional language*/ |
| 242 | + const char* start_of_charset = p; |
| 243 | + /* |
| 244 | + if (strncasecmp(value, "UTF-8''", 7) == 0) p += 7; |
| 245 | + else if (strncasecmp(value, "ISO-8859-1''", 12) == 0) p += 12; |
| 246 | + */ |
| 247 | + while ((*p != '\0') && (isalnum(*p) || strchr(mime_charset_special, *p) )) { |
| 248 | + p++; |
| 249 | + } |
| 250 | + if ((*p != '\'') || (p == start_of_charset)) { |
| 251 | + return -16; // Must be at least one legit char before ' for start of language |
| 252 | + } |
| 253 | + p++; |
| 254 | + while (isalnum(*p) || *p == '-') p++; |
| 255 | + if (*p != '\'') { |
| 256 | + return -17; // Single quote for end-of-language not found |
| 257 | + } |
| 258 | + p++; |
| 259 | + |
| 260 | + /* Now read what should be the actual filename */ |
| 261 | + const char* start_of_filename = p; |
| 262 | + while ((*p != '\0') && (*p != ';')) { |
| 263 | + if (*p == '%') { |
| 264 | + if ((!isxdigit(*(p + 1))) || (!isxdigit(*(p + 2)))) { |
| 265 | + return -18; |
| 266 | + } |
| 267 | + p += 3; |
| 268 | + } |
| 269 | + else if ((*p != '\0') && (isalnum(*p) || strchr(mime_charset_special, *p))) { |
| 270 | + p++; |
| 271 | + } |
| 272 | + else { |
| 273 | + return -19; |
| 274 | + } |
| 275 | + } |
| 276 | + value = apr_pmemdup(msr->mp, start_of_filename, p - start_of_filename); |
| 277 | + if (filenameStar != NULL) { |
| 278 | + msr_log(msr, 4, |
| 279 | + "Multipart: Warning: Duplicate Content-Disposition filename*: %s.", log_escape_nq(msr->mp, value)); |
| 280 | + return -20; |
| 281 | + } |
| 282 | + filenameStar = apr_pstrdup(msr->mp, value); |
| 283 | + if (msr->txcfg->debuglog_level >= 9) { |
| 284 | + msr_log(msr, 9, "Multipart: Content-Disposition filename*: %s.", |
| 285 | + log_escape_nq(msr->mp, value)); |
| 286 | + } |
| 287 | + } |
226 | 288 | } |
227 | 289 | else return -11; |
228 | 290 |
|
|
0 commit comments