diff options
Diffstat (limited to 'Mailman/Cgi/private.py')
| -rw-r--r-- | Mailman/Cgi/private.py | 190 |
1 files changed, 0 insertions, 190 deletions
diff --git a/Mailman/Cgi/private.py b/Mailman/Cgi/private.py deleted file mode 100644 index 5bd1a0458..000000000 --- a/Mailman/Cgi/private.py +++ /dev/null @@ -1,190 +0,0 @@ -# Copyright (C) 1998-2008 by the Free Software Foundation, Inc. -# -# This program is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License -# as published by the Free Software Foundation; either version 2 -# of the License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, -# USA. - -"""Provide a password-interface wrapper around private archives.""" - -import os -import sys -import cgi -import logging -import mimetypes - -from Mailman import Errors -from Mailman import MailList -from Mailman import Utils -from Mailman import i18n -from Mailman.configuration import config -from Mailman.htmlformat import * - -# Set up i18n. Until we know which list is being requested, we use the -# server's default. -_ = i18n._ -i18n.set_language(config.DEFAULT_SERVER_LANGUAGE) - -SLASH = '/' - -log = logging.getLogger('mailman.error') -mlog = logging.getLogger('mailman.mischief') - - - -def true_path(path): - "Ensure that the path is safe by removing .." - # Workaround for path traverse vulnerability. Unsuccessful attempts will - # be logged in logs/error. - parts = [x for x in path.split(SLASH) if x not in ('.', '..')] - return SLASH.join(parts)[1:] - - - -def guess_type(url, strict): - if hasattr(mimetypes, 'common_types'): - return mimetypes.guess_type(url, strict) - return mimetypes.guess_type(url) - - - -def main(): - doc = Document() - doc.set_language(config.DEFAULT_SERVER_LANGUAGE) - - parts = Utils.GetPathPieces() - if not parts: - doc.SetTitle(_("Private Archive Error")) - doc.AddItem(Header(3, _("You must specify a list."))) - print doc.Format() - return - - path = os.environ.get('PATH_INFO') - tpath = true_path(path) - if tpath <> path[1:]: - msg = _('Private archive - "./" and "../" not allowed in URL.') - doc.SetTitle(msg) - doc.AddItem(Header(2, msg)) - print doc.Format() - mlog.error('Private archive hostile path: %s', path) - return - # BAW: This needs to be converted to the Site module abstraction - true_filename = os.path.join( - config.PRIVATE_ARCHIVE_FILE_DIR, tpath) - - listname = parts[0].lower() - mboxfile = '' - if len(parts) > 1: - mboxfile = parts[1] - - # See if it's the list's mbox file is being requested - if listname.endswith('.mbox') and mboxfile.endswith('.mbox') and \ - listname[:-5] == mboxfile[:-5]: - listname = listname[:-5] - else: - mboxfile = '' - - # If it's a directory, we have to append index.html in this script. We - # must also check for a gzipped file, because the text archives are - # usually stored in compressed form. - if os.path.isdir(true_filename): - true_filename = true_filename + '/index.html' - if not os.path.exists(true_filename) and \ - os.path.exists(true_filename + '.gz'): - true_filename = true_filename + '.gz' - - try: - mlist = MailList.MailList(listname, lock=0) - except Errors.MMListError, e: - # Avoid cross-site scripting attacks - safelistname = Utils.websafe(listname) - msg = _('No such list <em>%(safelistname)s</em>') - doc.SetTitle(_("Private Archive Error - %(msg)s")) - doc.AddItem(Header(2, msg)) - print doc.Format() - log.error('No such list "%s": %s\n', listname, e) - return - - i18n.set_language(mlist.preferred_language) - doc.set_language(mlist.preferred_language) - - cgidata = cgi.FieldStorage() - username = cgidata.getvalue('username', '') - password = cgidata.getvalue('password', '') - - is_auth = 0 - realname = mlist.real_name - message = '' - - if not mlist.WebAuthenticate((config.AuthUser, - config.AuthListModerator, - config.AuthListAdmin, - config.AuthSiteAdmin), - password, username): - if cgidata.has_key('submit'): - # This is a re-authorization attempt - message = Bold(FontSize('+1', _('Authorization failed.'))).Format() - # Output the password form - charset = Utils.GetCharSet(mlist.preferred_language) - print 'Content-type: text/html; charset=' + charset + '\n\n' - # Put the original full path in the authorization form, but avoid - # trailing slash if we're not adding parts. We add it below. - action = mlist.GetScriptURL('private') - if parts[1:]: - action = os.path.join(action, SLASH.join(parts[1:])) - # If we added '/index.html' to true_filename, add a slash to the URL. - # We need this because we no longer add the trailing slash in the - # private.html template. It's always OK to test parts[-1] since we've - # already verified parts[0] is listname. The basic rule is if the - # post URL (action) is a directory, it must be slash terminated, but - # not if it's a file. Otherwise, relative links in the target archive - # page don't work. - if true_filename.endswith('/index.html') and parts[-1] <> 'index.html': - action += SLASH - # Escape web input parameter to avoid cross-site scripting. - print Utils.maketext( - 'private.html', - {'action' : Utils.websafe(action), - 'realname': mlist.real_name, - 'message' : message, - }, mlist=mlist) - return - - lang = mlist.getMemberLanguage(username) - i18n.set_language(lang) - doc.set_language(lang) - - # Authorization confirmed... output the desired file - try: - ctype, enc = guess_type(path, strict=0) - if ctype is None: - ctype = 'text/html' - if mboxfile: - f = open(os.path.join(mlist.archive_dir() + '.mbox', - mlist.internal_name() + '.mbox')) - ctype = 'text/plain' - elif true_filename.endswith('.gz'): - import gzip - f = gzip.open(true_filename, 'r') - else: - f = open(true_filename, 'r') - except IOError: - msg = _('Private archive file not found') - doc.SetTitle(msg) - doc.AddItem(Header(2, msg)) - print doc.Format() - log.error('Private archive file not found: %s', true_filename) - else: - print 'Content-type: %s\n' % ctype - sys.stdout.write(f.read()) - f.close() |
