Mercurial > hg-stable
diff 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 |
line wrap: on
line diff
--- a/mercurial/hgweb.py Wed Mar 01 21:44:00 2006 -0800 +++ b/mercurial/hgweb.py Thu Mar 02 09:17:04 2006 +0100 @@ -73,31 +73,28 @@ return os.stat(hg_path).st_mtime def staticfile(directory, fname): - fname = os.path.realpath(os.path.join(directory, fname)) + """return a file inside directory with guessed content-type header + + fname always uses '/' as directory separator and isn't allowed to + contain unusual path components. + Content-type is guessed using the mimetypes module. + Return an empty string if fname is illegal or file not found. + """ + parts = fname.split('/') + path = directory + for part in parts: + if (part in ('', os.curdir, os.pardir) or + os.sep in part or os.altsep is not None and os.altsep in part): + return "" + path = os.path.join(path, part) try: - # the static dir should be a substring in the real - # file path, if it is not, we have something strange - # going on => security breach attempt? - # - # This will either: - # 1) find the `static' path at index 0 = success - # 2) find the `static' path at other index = error - # 3) not find the `static' path = ValueError generated - if fname.index(directory) != 0: - # generate ValueError manually - raise ValueError() - - os.stat(fname) - - ct = mimetypes.guess_type(fname)[0] or "text/plain" - return "Content-type: %s\n\n%s" % (ct, file(fname).read()) - except ValueError: - # security breach attempt + os.stat(path) + ct = mimetypes.guess_type(path)[0] or "text/plain" + return "Content-type: %s\n\n%s" % (ct, file(path).read()) + except (TypeError, OSError): + # illegal fname or unreadable file return "" - except OSError, e: - if e.errno == errno.ENOENT: - return "" class hgrequest(object): def __init__(self, inp=None, out=None, env=None):