[exim-cvs] Fix MIME parsing of filenames specified using mul…

Startseite
Nachricht löschen
Nachricht beantworten
Autor: Exim Git Commits Mailing List
Datum:  
To: exim-cvs
Betreff: [exim-cvs] Fix MIME parsing of filenames specified using multiple parameters. Bug 3099
Gitweb: https://git.exim.org/exim.git/commitdiff/6ce5c70cff8989418e05d01fd2a57703007a6357
Commit:     6ce5c70cff8989418e05d01fd2a57703007a6357
Parent:     86e280ca236af22136ad21cc8da30ed82afb0a02
Author:     Jeremy Harris <jgh146exb@???>
AuthorDate: Mon Jul 1 19:35:12 2024 +0100
Committer:  Jeremy Harris <jgh146exb@???>
CommitDate: Mon Jul 1 19:35:12 2024 +0100


    Fix MIME parsing of filenames specified using multiple parameters.  Bug 3099
---
 doc/doc-docbook/spec.xfpt       | 14 ++++-----
 doc/doc-txt/ChangeLog           |  3 ++
 src/src/mime.c                  | 51 +++++++++++++++++-------------
 src/src/string.c                |  1 +
 test/log/4000                   |  3 ++
 test/mail/4000.userx            | 70 +++++++++++++++++++++++++++++++++++++++++
 test/scripts/4000-scanning/4000 | 31 ++++++++++++++++++
 test/stdout/4000                | 12 +++++++
 8 files changed, 156 insertions(+), 29 deletions(-)


diff --git a/doc/doc-docbook/spec.xfpt b/doc/doc-docbook/spec.xfpt
index cfdf0ca1a..514ec24d0 100644
--- a/doc/doc-docbook/spec.xfpt
+++ b/doc/doc-docbook/spec.xfpt
@@ -35231,13 +35231,13 @@ If the string does not start with a slash, it is used as the
filename, and the default path is then used.
.endlist
The &%decode%& condition normally succeeds. It is only false for syntax
-errors or unusual circumstances such as memory shortages. You can easily decode
-a file with its original, proposed filename using
-.code
-decode = $mime_filename
-.endd
-However, you should keep in mind that &$mime_filename$& might contain
-anything. If you place files outside of the default path, they are not
+errors or unusual circumstances such as memory shortages.
+.new
+The variable &$mime_filename$& will have the suggested name for the file.
+Note however that this might contain anything, and is very difficult
+to safely use as all or even part of the filename.
+.wen
+If you place files outside of the default path, they are not
automatically unlinked.

 For RFC822 attachments (these are messages attached to messages, with a
diff --git a/doc/doc-txt/ChangeLog b/doc/doc-txt/ChangeLog
index daa62ad0e..acb779605 100644
--- a/doc/doc-txt/ChangeLog
+++ b/doc/doc-txt/ChangeLog
@@ -164,6 +164,9 @@ JH/33 Bug 2994: A subdir dsearch lookup should permit a directory name that star
 JH/34 Fix delivery ordering for 2-phase queue run combined with
       queue_run_in_order.


+JH/35 Bug 3099: fix parsing of MIME filenames split over multiple paramemters.
+      Previously the $mime_filename variable would have an incorrect value.
+


Exim version 4.97
-----------------
diff --git a/src/src/mime.c b/src/src/mime.c
index 975ddca85..5f9e1ade7 100644
--- a/src/src/mime.c
+++ b/src/src/mime.c
@@ -587,10 +587,10 @@ while(1)

     while (*p)
       {
-      DEBUG(D_acl) debug_printf_indent("MIME:   considering paramlist '%s'\n", p);
+      DEBUG(D_acl)
+        debug_printf_indent("MIME:   considering paramlist '%s'\n", p);


-      if (  !mime_filename
-         && strncmpic(CUS"content-disposition:", header, 20) == 0
+      if (  strncmpic(CUS"content-disposition:", header, 20) == 0
          && strncmpic(CUS"filename*", p, 9) == 0
          )
         {                    /* RFC 2231 filename */
@@ -604,11 +604,12 @@ while(1)


         if (q && *q)
           {
-          uschar * temp_string, * err_msg;
+          uschar * temp_string, * err_msg, * fname = q;
           int slen;


           /* build up an un-decoded filename over successive
           filename*= parameters (for use when 2047 decode fails) */
+/*XXX could grow a gstring here */


           mime_fname_rfc2231 = string_sprintf("%#s%s",
         mime_fname_rfc2231, q);
@@ -623,26 +624,32 @@ while(1)
           /* 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 (*s)            /* there was a ' */
+            {
+            if ((size = s-q) > 0)
+              mime_filename_charset = string_copyn(q, size);


-          if (*(p = s)) p++;
-          while(*p == '\'') p++;    /* p is after 2nd ' */
+            if (*(fname = s)) fname++;
+            while(*fname == '\'') fname++;    /* fname 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"<NULL>", p);
+        DEBUG(D_acl)
+          debug_printf_indent("MIME:    charset %s fname '%s'\n",
+            mime_filename_charset ? mime_filename_charset : US"<NULL>",
+            fname);


-        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 = rfc2231_to_2047(fname, 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);
+                          NULL, &err_msg);
+        DEBUG(D_acl)
+          debug_printf_indent("MIME:    plain-name %s\n", temp_string);


-        if (!temp_string || (size = Ustrlen(temp_string))  == slen)
+        if (!temp_string || (size = Ustrlen(temp_string)) == slen)
           decoding_failed = TRUE;
         else
           /* build up a decoded filename over successive
@@ -651,9 +658,9 @@ while(1)
           mime_filename = mime_fname = mime_fname
             ? string_sprintf("%s%s", mime_fname, temp_string)
             : temp_string;
-        }
-          }
-        }
+        }    /*!decoding_failed*/
+          }        /*q*/
+        }        /*2231 filename*/


       else
         /* look for interesting parameters */
@@ -682,7 +689,7 @@ while(1)



       /* There is something, but not one of our interesting parameters.
-         Advance past the next semicolon */
+      Advance past the next semicolon */
       p = mime_next_semicolon(p);
       if (*p) p++;
       }                /* param scan on line */
@@ -800,5 +807,5 @@ return rc;


 #endif    /*WITH_CONTENT_SCAN*/


-/* vi: sw ai sw=2
+/* vi: aw ai sw=2
 */
diff --git a/src/src/string.c b/src/src/string.c
index 113c05754..aa768d03c 100644
--- a/src/src/string.c
+++ b/src/src/string.c
@@ -1342,6 +1342,7 @@ Field width:        decimal digits, or *
 Precision:        dot, followed by decimal digits or *
 Length modifiers:    h  L  l  ll  z
 Conversion specifiers:    n d o u x X p f e E g G % c s S T W V Y D M
+Alternate-form:        %#s is silent about a null string


Returns the possibly-new (if copy for growth or taint-handling was needed)
string, not nul-terminated.
diff --git a/test/log/4000 b/test/log/4000
index 4aed68039..912a32a1a 100644
--- a/test/log/4000
+++ b/test/log/4000
@@ -20,3 +20,6 @@
1999-03-02 09:44:33 10HmbE-000000005vi-0000 => userx <userx@???> R=r1 T=t1
1999-03-02 09:44:33 10HmbE-000000005vi-0000 Completed
1999-03-02 09:44:33 10HmaX-000000005vi-0000 U=CALLER F=<CALLER@???> rejected during MIME ACL checks: this is a deny from the mime acl
+1999-03-02 09:44:33 10HmbF-000000005vi-0000 <= CALLER@??? U=CALLER P=local-esmtp S=sss T="Bug 3099 (2)"
+1999-03-02 09:44:33 10HmbF-000000005vi-0000 => userx <userx@???> R=r1 T=t1
+1999-03-02 09:44:33 10HmbF-000000005vi-0000 Completed
diff --git a/test/mail/4000.userx b/test/mail/4000.userx
index 569813066..242be6627 100644
--- a/test/mail/4000.userx
+++ b/test/mail/4000.userx
@@ -406,3 +406,73 @@ foobar

--T4sUOijqQbZv57TR--

+From CALLER@??? Tue Mar 02 09:44:33 1999
+Received: from CALLER (helo=test.ex)
+    by myhost.test.ex with local-esmtp (Exim x.yz)
+    (envelope-from <CALLER@???>)
+    id 10HmbF-000000005vi-0000
+    for userx@???;
+    Tue, 2 Mar 1999 09:44:33 +0000
+From: localpart@???
+To: localpart@???
+Subject: Bug 3099 (2)
+MIME-Version: 1.0
+Content-Type: multipart/mixed; boundary="----=_MIME_BOUNDARY_000_695039"
+Message-Id: <E10HmbF-000000005vi-0000@???>
+Sender: CALLER_NAME <CALLER@???>
+Date: Tue, 2 Mar 1999 09:44:33 +0000
+X-0-content-type: multipart/mixed
+X-0-filename: 
+X-0-charset: 
+X-0-boundary: ----=_MIME_BOUNDARY_000_695039
+X-0-content-disposition: 
+X-0-content-transfer-encoding: 
+X-0-content-id: 
+X-0-content-description: 
+X-0-is-multipart: 1
+X-0-is-coverletter: 1
+X-0-is-rfc822: 0
+X-0-decode-filename: TESTSUITE/spool/scan/10HmbF-000000005vi-0000/10HmbF-000000005vi-0000-00000
+X-0-content-size: 1
+X-1-content-type: text/plain
+X-1-filename: 
+X-1-charset: 
+X-1-boundary: 
+X-1-content-disposition: 
+X-1-content-transfer-encoding: 
+X-1-content-id: 
+X-1-content-description: 
+X-1-is-multipart: 0
+X-1-is-coverletter: 1
+X-1-is-rfc822: 0
+X-1-decode-filename: TESTSUITE/spool/scan/10HmbF-000000005vi-0000/10HmbF-000000005vi-0000-00001
+X-1-content-size: 1
+X-2-content-type: application/octet-stream
+X-2-filename: example3.exe
+X-2-charset: 
+X-2-boundary: 
+X-2-content-disposition: attachment
+X-2-content-transfer-encoding: base64
+X-2-content-id: 
+X-2-content-description: 
+X-2-is-multipart: 0
+X-2-is-coverletter: 0
+X-2-is-rfc822: 0
+X-2-decode-filename: TESTSUITE/spool/scan/10HmbF-000000005vi-0000/10HmbF-000000005vi-0000-00002
+X-2-content-size: 1
+
+------=_MIME_BOUNDARY_000_695039
+Content-Type: text/plain
+
+This is a test mailing
+------=_MIME_BOUNDARY_000_695039
+Content-Type: application/octet-stream
+Content-Disposition: attachment;
+    filename*0*="example3";
+    filename*1*=".exe"
+Content-Transfer-Encoding: BASE64
+
+QmVpc3BpZWwK
+
+------=_MIME_BOUNDARY_000_695039--
+
diff --git a/test/scripts/4000-scanning/4000 b/test/scripts/4000-scanning/4000
index 623c5420f..bb2835ed3 100644
--- a/test/scripts/4000-scanning/4000
+++ b/test/scripts/4000-scanning/4000
@@ -272,3 +272,34 @@ foobar
 .
 quit
 ****
+#
+#
+# Filename using parameter value continuation (RFC 2231 sec. 3)
+exim -odi -bs
+ehlo test.ex
+mail from:<>
+rcpt to:<userx@???>
+data
+From: localpart@???
+To: localpart@???
+Subject: Bug 3099 (2)
+MIME-Version: 1.0
+Content-Type: multipart/mixed; boundary="----=_MIME_BOUNDARY_000_695039"
+
+------=_MIME_BOUNDARY_000_695039
+Content-Type: text/plain
+
+This is a test mailing
+------=_MIME_BOUNDARY_000_695039
+Content-Type: application/octet-stream
+Content-Disposition: attachment;
+    filename*0*="example3";
+    filename*1*=".exe"
+Content-Transfer-Encoding: BASE64
+
+QmVpc3BpZWwK
+
+------=_MIME_BOUNDARY_000_695039--
+.
+quit
+****
diff --git a/test/stdout/4000 b/test/stdout/4000
index b9098d554..ec6593646 100644
--- a/test/stdout/4000
+++ b/test/stdout/4000
@@ -94,3 +94,15 @@
 354 Enter message, ending with "." on a line by itself
 550 this is a deny from the mime acl
 221 myhost.test.ex closing connection
+220 myhost.test.ex ESMTP Exim x.yz Tue, 2 Mar 1999 09:44:33 +0000
+250-myhost.test.ex Hello CALLER at test.ex
+250-SIZE 52428800
+250-LIMITS MAILMAX=1000 RCPTMAX=50000
+250-8BITMIME
+250-PIPELINING
+250 HELP
+250 OK
+250 Accepted
+354 Enter message, ending with "." on a line by itself
+250 OK id=10HmbF-000000005vi-0000
+221 myhost.test.ex closing connection


--
## subscription configuration (requires account):
## https://lists.exim.org/mailman3/postorius/lists/exim-cvs.lists.exim.org/
## unsubscribe (doesn't require an account):
## exim-cvs-unsubscribe@???
## Exim details at http://www.exim.org/
## Please use the Wiki with this list - http://wiki.exim.org/