Mercurial > public > mercurial-scm > hg
comparison mercurial/hgweb.py @ 1825:a9343f9d7365
Make hgweb.staticfile() more secure and portable.
Without this, files in directories next to the static directory starting
with 'static' could be retrieved, e.g. with '../static.private/foo'.
Additionally staticfile now generates platform specific pathnames from
the /-separated paths given in the URL.
Illegal file names (e.g. containing %00) now yield a sane error message.
author | Thomas Arendsen Hein <thomas@intevation.de> |
---|---|
date | Thu, 02 Mar 2006 09:17:04 +0100 |
parents | a373881fdf2a |
children | 4ced57680ce7 |
comparison
equal
deleted
inserted
replaced
1824:dca000ef7d52 | 1825:a9343f9d7365 |
---|---|
71 return os.stat(cl_path).st_mtime | 71 return os.stat(cl_path).st_mtime |
72 else: | 72 else: |
73 return os.stat(hg_path).st_mtime | 73 return os.stat(hg_path).st_mtime |
74 | 74 |
75 def staticfile(directory, fname): | 75 def staticfile(directory, fname): |
76 fname = os.path.realpath(os.path.join(directory, fname)) | 76 """return a file inside directory with guessed content-type header |
77 | 77 |
78 fname always uses '/' as directory separator and isn't allowed to | |
79 contain unusual path components. | |
80 Content-type is guessed using the mimetypes module. | |
81 Return an empty string if fname is illegal or file not found. | |
82 | |
83 """ | |
84 parts = fname.split('/') | |
85 path = directory | |
86 for part in parts: | |
87 if (part in ('', os.curdir, os.pardir) or | |
88 os.sep in part or os.altsep is not None and os.altsep in part): | |
89 return "" | |
90 path = os.path.join(path, part) | |
78 try: | 91 try: |
79 # the static dir should be a substring in the real | 92 os.stat(path) |
80 # file path, if it is not, we have something strange | 93 ct = mimetypes.guess_type(path)[0] or "text/plain" |
81 # going on => security breach attempt? | 94 return "Content-type: %s\n\n%s" % (ct, file(path).read()) |
82 # | 95 except (TypeError, OSError): |
83 # This will either: | 96 # illegal fname or unreadable file |
84 # 1) find the `static' path at index 0 = success | |
85 # 2) find the `static' path at other index = error | |
86 # 3) not find the `static' path = ValueError generated | |
87 if fname.index(directory) != 0: | |
88 # generate ValueError manually | |
89 raise ValueError() | |
90 | |
91 os.stat(fname) | |
92 | |
93 ct = mimetypes.guess_type(fname)[0] or "text/plain" | |
94 return "Content-type: %s\n\n%s" % (ct, file(fname).read()) | |
95 except ValueError: | |
96 # security breach attempt | |
97 return "" | 97 return "" |
98 except OSError, e: | |
99 if e.errno == errno.ENOENT: | |
100 return "" | |
101 | 98 |
102 class hgrequest(object): | 99 class hgrequest(object): |
103 def __init__(self, inp=None, out=None, env=None): | 100 def __init__(self, inp=None, out=None, env=None): |
104 self.inp = inp or sys.stdin | 101 self.inp = inp or sys.stdin |
105 self.out = out or sys.stdout | 102 self.out = out or sys.stdout |