tags 393843 +patch
thanks

This adds unescaping and validation of the path for file and FTP
fetchers.

The file fetcher is broken, but this doesn't seem to break it any
further.

Ben.

diff -Nru /tmp/oETpXsOSpU/apt-proxy-1.9.35/apt_proxy/fetchers.py 
/tmp/YC8tWgUWxx/apt-proxy-1.9.35.1/apt_proxy/fetchers.py
--- /tmp/oETpXsOSpU/apt-proxy-1.9.35/apt_proxy/fetchers.py      2006-08-14 
12:44:57.000000000 +0000
+++ /tmp/YC8tWgUWxx/apt-proxy-1.9.35.1/apt_proxy/fetchers.py    2006-10-24 
01:05:43.000000000 +0000
@@ -21,7 +21,7 @@
 network backends
 """
 
-import re, os, string, time, glob, signal, stat, base64
+import re, os, string, time, glob, signal, stat, base64, urllib
 from twisted.web import static, http
 from twisted.internet import protocol, reactor, defer, error, abstract
 from twisted.python import failure
@@ -244,6 +244,23 @@
             self.connection_closed(self.fetcher)
         self.deferred.callback((True, ""))
 
+def uri_path_to_path(path, check_part):
+    # Split into parts and unescape them.
+    parts = [urllib.unquote(part) for part in path.split('/')]
+    for part in parts:
+        if not check_part(part):
+            return None
+    # Join up the parts.
+    return os.sep.join(parts)
+
+def is_valid_local_path_part(part):
+    # Deny use of parent directory or characters that are invalid in a
+    # path part.
+    return not (part == os.pardir
+                or '\0' in part
+                or os.sep in part
+                or (os.altsep and os.altsep in part))
+
 class FileFetcher:
     """
     A Fetcher that simply copies files from disk
@@ -268,7 +285,11 @@
         self.cache_mtime = mtime
         self.request_uri = uri
 
-        self.local_file = self.backendServer.uri[len("file://"):] + '/' + uri
+        path = uri_path_to_path(uri, is_valid_local_path_part)
+        if path is None:
+            self.parent.file_not_found()
+            return
+        self.local_file = self.backendServer.uri[len("file://"):] + '/' + path
         if not os.path.exists(self.local_file):
             self.parent.file_not_found()
             return
@@ -508,6 +529,13 @@
             self.connection.transport.loseConnection()
             self.isConnected = False
 
+# RFC 959 says pathnames must be ASCII and not include CR or LF.
+ftp_path_part_re = re.compile(r'[^\r\n\x80-\xFF]+$')
+def is_valid_ftp_path_part(part):
+    # Also deny use of parent directory, assuming Unix path conventions
+    # on the server.
+    return part != '..' and ftp_path_part_re.match(part)
+
 class FtpFetcher(protocol.Protocol):
     """
     This is the secuence here:
@@ -575,8 +603,12 @@
         self.parent = fetcher
         self.cache_mtime = mtime
         self.request_uri = uri
+        path = uri_path_to_path(uri, is_valid_ftp_path_part)
+        if path is None:
+            self.parent.file_not_found()
+            return
         self.remote_file = (self.parent.backendServer.path + '/' 
-                            + uri)
+                            + path)
         self.ftpFetchMtime()
 
     def ftpFetchMtime(self):
-- END --

-- 
Ben Hutchings -- [EMAIL PROTECTED] shortened to [EMAIL PROTECTED]
If you've signed my GPG key, please send a signature on and to the new uid.
It is easier to change the specification to fit the program than vice versa.

Attachment: signature.asc
Description: This is a digitally signed message part

Reply via email to