diff -urN ../exim-4.93.orig/src/mime.c ./src/mime.c --- ../exim-4.93.orig/src/mime.c 2019-12-08 14:53:48.000000000 +0200 +++ ./src/mime.c 2022-10-18 22:49:41.803500000 +0300 @@ -574,10 +574,7 @@ if (*(p = q)) p++; /* jump past the ; */ { - uschar * mime_fname = NULL; - uschar * mime_fname_rfc2231 = NULL; - uschar * mime_filename_charset = NULL; - BOOL decoding_failed = FALSE; + BOOL header_is_content_disposition = (strncmpic(US"content-disposition:",header,20) == 0); /* grab all param=value tags on the remaining line, check if they are interesting */ @@ -586,73 +583,6 @@ { DEBUG(D_acl) debug_printf_indent("MIME: considering paramlist '%s'\n", p); - if ( !mime_filename - && strncmpic(CUS"content-disposition:", header, 20) == 0 - && strncmpic(CUS"filename*", p, 9) == 0 - ) - { /* RFC 2231 filename */ - uschar * q; - - /* find value of the filename */ - p += 9; - while(*p != '=' && *p) p++; - if (*p) p++; /* p is filename or NUL */ - q = mime_param_val(&p); /* p now trailing ; or NUL */ - - if (q && *q) - { - uschar * temp_string, * err_msg; - int slen; - - /* build up an un-decoded filename over successive - filename*= parameters (for use when 2047 decode fails) */ - - mime_fname_rfc2231 = string_sprintf("%#s%s", - mime_fname_rfc2231, q); - - if (!decoding_failed) - { - int size; - if (!mime_filename_charset) - { - uschar * s = q; - - /* look for a ' in the "filename" */ - while(*s != '\'' && *s) s++; /* s is 1st ' or NUL */ - - if ((size = s-q) > 0) - mime_filename_charset = string_copyn(q, size); - - if (*(p = s)) p++; - while(*p == '\'') p++; /* p is after 2nd ' */ - } - else - p = q; - - DEBUG(D_acl) debug_printf_indent("MIME: charset %s fname '%s'\n", - mime_filename_charset ? mime_filename_charset : US"", p); - - temp_string = rfc2231_to_2047(p, mime_filename_charset, &slen); - DEBUG(D_acl) debug_printf_indent("MIME: 2047-name %s\n", temp_string); - - temp_string = rfc2047_decode(temp_string, FALSE, NULL, ' ', - NULL, &err_msg); - DEBUG(D_acl) debug_printf_indent("MIME: plain-name %s\n", temp_string); - - if (!temp_string || (size = Ustrlen(temp_string)) == slen) - decoding_failed = TRUE; - else - /* build up a decoded filename over successive - filename*= parameters */ - - mime_filename = mime_fname = mime_fname - ? string_sprintf("%s%s", mime_fname, temp_string) - : temp_string; - } - } - } - - else /* look for interesting parameters */ for (mime_parameter * mp = mime_parameter_list; mp < mime_parameter_list + nelem(mime_parameter_list); @@ -675,6 +605,90 @@ mp->name, mh->name, *mp->value); break; /* done matching param names */ + } else { + if (header_is_content_disposition && (strncmpic(US"filename=",mp->name,9) == 0)) { +#define MIME_FILENAME_RFC2231_MAX_SIZE 1024 + uschar * mime_filename_rfc2231; + int size; + BOOL rfc2231_decoded = FALSE; + + mime_filename_rfc2231 = store_get(MIME_FILENAME_RFC2231_MAX_SIZE, is_tainted(p)); + memset(mime_filename_rfc2231, 0, MIME_FILENAME_RFC2231_MAX_SIZE); + + // found an RFC 2231 filename? + while (strncmpic(US"filename*",p,9) == 0) { + // find value of the filename + p += 9; + while((*p != '=') && ((p - header) < Ustrlen(header))) p++; + p++; + uschar *q = p; + while((*q != ';') && ((q - header) < Ustrlen(header))) q++; + size = q - p; + uschar *q_prev = q; + q_prev--; + if ((size > 1) && (*p == '"') && (*q_prev == '"')) { + p++; + size -= 2; + } + if (size > 0) { + if (size > MIME_FILENAME_RFC2231_MAX_SIZE - Ustrlen(mime_filename_rfc2231) - 1) size = MIME_FILENAME_RFC2231_MAX_SIZE - Ustrlen(mime_filename_rfc2231) - 1; + Ustrncpy(mime_filename_rfc2231 + Ustrlen(mime_filename_rfc2231), p, size); + } + p = q; p++; + } + DEBUG(D_acl) debug_printf_indent("MIME: fname '%s'\n", mime_filename_rfc2231); + + if (Ustrlen(mime_filename_rfc2231) > 0) { + uschar * mime_filename_rfc2231_decoded; + int mime_filename_rfc2231_decoded_len = 0; +#define MIME_FILENAME_CHARSET_MAX_SIZE 24 + uschar * mime_filename_charset; + uschar *i1 = mime_filename_rfc2231; + uschar *i2 = mime_filename_rfc2231; + uschar *temp_string, *err_msg; + int temp_string_len = 0; + + mime_filename_charset = store_get(MIME_FILENAME_CHARSET_MAX_SIZE, is_tainted(mime_filename_rfc2231)); + memset(mime_filename_charset, 0, MIME_FILENAME_CHARSET_MAX_SIZE); + + while ((*i1 != '\'') && ((i1 - i2) < Ustrlen(mime_filename_rfc2231)-2)) i1++; + i2 = i1; i2++; + + if ((*i1 == '\'') && (*i2 == '\'')) { + size = i1 - mime_filename_rfc2231; + if (size > MIME_FILENAME_CHARSET_MAX_SIZE - 1) size = MIME_FILENAME_CHARSET_MAX_SIZE - 1; + Ustrncpy(mime_filename_charset, mime_filename_rfc2231, size); + i1 += 2; + + DEBUG(D_acl) debug_printf_indent("MIME: charset %s fname '%s'\n", + Ustrlen(mime_filename_charset) > 0 ? mime_filename_charset : US"", i1); + + temp_string = rfc2231_to_2047(i1, mime_filename_charset, &temp_string_len); + DEBUG(D_acl) debug_printf_indent("MIME: 2047-name %s\n", temp_string); + mime_filename_rfc2231_decoded = rfc2047_decode(temp_string, FALSE, NULL, 32, &mime_filename_rfc2231_decoded_len, &err_msg); + + if ((mime_filename_rfc2231_decoded_len > 0) && (mime_filename_rfc2231_decoded_len != temp_string_len)) { + rfc2231_decoded = TRUE; + + DEBUG(D_acl) debug_printf_indent("MIME: plain-name %s\n", mime_filename_rfc2231_decoded); + *((uschar **)(mp->value)) = mime_filename_rfc2231_decoded; + + DEBUG(D_acl) debug_printf_indent( + "MIME: found %s parameter in %s header, value '%s'\n", + mp->name, mh->name, *mp->value); + } + } + if (!rfc2231_decoded) { + mime_filename_rfc2231_decoded = rfc2047_decode(mime_filename_rfc2231, check_rfc2047_length, NULL, 32, &mime_filename_rfc2231_decoded_len, &err_msg); + + *((uschar **)(mp->value)) = mime_filename_rfc2231_decoded; + + DEBUG(D_acl) debug_printf_indent( + "MIME: found %s parameter in %s header, value '%s'\n", + mp->name, mh->name, *mp->value); + } + } + } } @@ -684,14 +698,6 @@ if (*p) p++; } /* param scan on line */ - if (strncmpic(CUS"content-disposition:", header, 20) == 0) - { - if (decoding_failed) mime_filename = mime_fname_rfc2231; - - DEBUG(D_acl) debug_printf_indent( - "MIME: found %s parameter in %s header, value is '%s'\n", - "filename", mh->name, mime_filename); - } } }