Browse Source

2010-03-08 Tatsuhiro Tsujikawa <t-tujikawa@users.sourceforge.net>

	Ignore filename parameter if it contains directory traversal
	directives.
	* src/util.cc
	* test/UtilTest.cc
Tatsuhiro Tsujikawa 15 years ago
parent
commit
3ecf6e4b6f
3 changed files with 36 additions and 26 deletions
  1. 7 0
      ChangeLog
  2. 16 18
      src/util.cc
  3. 13 8
      test/UtilTest.cc

+ 7 - 0
ChangeLog

@@ -1,3 +1,10 @@
+2010-03-08  Tatsuhiro Tsujikawa  <t-tujikawa@users.sourceforge.net>
+
+	Ignore filename parameter if it contains directory traversal
+	directives.
+	* src/util.cc
+	* test/UtilTest.cc
+
 2010-03-07  Tatsuhiro Tsujikawa  <t-tujikawa@users.sourceforge.net>
 
 	urldecode -> percentDecode

+ 16 - 18
src/util.cc

@@ -656,18 +656,6 @@ void parsePrioritizePieceRange
   result.insert(result.end(), indexes.begin(), indexes.end());
 }
 
-static std::string trimBasename(const std::string& src)
-{
-  static const std::string TRIMMED("\r\n\t '\"");
-  std::string fn = File(trim(src, TRIMMED)).getBasename();
-  std::string::iterator enditer = std::remove(fn.begin(), fn.end(), '\\');
-  fn = std::string(fn.begin(), enditer);
-  if(fn == ".." || fn == A2STR::DOT_C) {
-    fn = A2STR::NIL;
-  }
-  return fn;
-}
-
 // Converts ISO/IEC 8859-1 string to UTF-8 string.  If there is a
 // character not in ISO/IEC 8859-1, returns empty string.
 std::string iso8859ToUtf8(const std::string& src)
@@ -759,12 +747,17 @@ std::string getContentDispositionFilename(const std::string& header)
       if(bad) {
         continue;
       }
-      value = trimBasename(percentDecode(value));
+      value = percentDecode(value);
       if(toLower(extValues[0]) == "iso-8859-1") {
         value = iso8859ToUtf8(value);
       }
-      filename = value;
-      break;
+      if(!detectDirTraversal(value) &&
+         value.find(A2STR::SLASH_C) == std::string::npos) {
+        filename = value;
+      }
+      if(!filename.empty()) {
+        break;
+      }
     } else {
       for(; markeritr != param.end() && *markeritr == ' '; ++markeritr);
       if(markeritr == param.end() || *markeritr != '=') {
@@ -785,9 +778,14 @@ std::string getContentDispositionFilename(const std::string& header)
       } else {
         filenameLast = value.end();
       }
-      value =
-        trimBasename(percentDecode(std::string(value.begin(), filenameLast)));
-      filename = value;
+      static const std::string TRIMMED("\r\n\t '\"");
+      value = percentDecode(std::string(value.begin(), filenameLast));
+      trimSelf(value, TRIMMED);
+      value.erase(std::remove(value.begin(), value.end(), '\\'), value.end());
+      if(!detectDirTraversal(value) &&
+         value.find(A2STR::SLASH_C) == std::string::npos) {
+        filename = value;
+      }
       // continue because there is a chance we can find filename*=...
     }
   }

+ 13 - 8
test/UtilTest.cc

@@ -307,16 +307,12 @@ void UtilTest::testGetContentDispositionFilename() {
   CPPUNIT_ASSERT_EQUAL(std::string(""), util::getContentDispositionFilename(h11));
 
   std::string filenameWithDir = "attachment; filename=dir/file";
-  CPPUNIT_ASSERT_EQUAL(std::string("file"),
+  CPPUNIT_ASSERT_EQUAL(std::string(""),
                        util::getContentDispositionFilename(filenameWithDir));
+  CPPUNIT_ASSERT_EQUAL
+    (std::string(""),
+     util::getContentDispositionFilename("filename=\"%2E%2E%2Ffoo.html\""));
 
-  std::string parentDir = "attachment; filename=..";
-  CPPUNIT_ASSERT_EQUAL(std::string(),
-                       util::getContentDispositionFilename(parentDir));
-
-  std::string currentDir = "attachment; filename=.";
-  CPPUNIT_ASSERT_EQUAL(std::string(),
-                       util::getContentDispositionFilename(currentDir));
   // RFC2231 Section4
   std::string extparam2 = "filename*=''aria2";
   CPPUNIT_ASSERT_EQUAL(std::string("aria2"),
@@ -345,6 +341,15 @@ void UtilTest::testGetContentDispositionFilename() {
   extparam9ans += 0xa3;
   CPPUNIT_ASSERT_EQUAL(extparam9ans,
                        util::getContentDispositionFilename(extparam9));
+  CPPUNIT_ASSERT_EQUAL
+    (std::string(""),
+     util::getContentDispositionFilename("filename*=UTF-8''foo%2F.html"));
+  CPPUNIT_ASSERT_EQUAL
+    (std::string("foo.html"),
+     util::getContentDispositionFilename("filename*=UTF-8'';filename=\"foo.html\""));
+  CPPUNIT_ASSERT_EQUAL
+    (std::string(""),
+     util::getContentDispositionFilename("filename*=UTF-8''%2E%2E%2Ffoo.html"));
 
   // Tests from http://greenbytes.de/tech/tc2231/
   // attwithasciifnescapedchar