diff options
| author | bwarsaw | 2000-09-29 00:05:05 +0000 |
|---|---|---|
| committer | bwarsaw | 2000-09-29 00:05:05 +0000 |
| commit | ceddf83bf0000704b4c2c3428db124e88d4a1ee4 (patch) | |
| tree | afb489a2eb004c39366553fb4cb12d9da5c8b7e7 | |
| parent | 8fab2b4ea200b7fbdac7e5f99881f07047ef467c (diff) | |
| download | mailman-ceddf83bf0000704b4c2c3428db124e88d4a1ee4.tar.gz mailman-ceddf83bf0000704b4c2c3428db124e88d4a1ee4.tar.zst mailman-ceddf83bf0000704b4c2c3428db124e88d4a1ee4.zip | |
Fixes for a minor local security hole. Some of the CGI scripts could
bomb with tracebacks if PATH_INFO environment variable wasn't defined.
Fixed this by making them all use Utils.GetPathPieces() and "doing
something sensible" when that returned a false value.
Also, edithtml is now hidden behind a login screen, so there's no need
to enter the list password to edit the html. You can't even get to
the list of files to edit unless you've admin authenticated. Closes
SF bug #114091, Jitterbug PR# 24.
| -rw-r--r-- | Mailman/Cgi/admin.py | 15 | ||||
| -rw-r--r-- | Mailman/Cgi/admindb.py | 6 | ||||
| -rw-r--r-- | Mailman/Cgi/edithtml.py | 44 | ||||
| -rw-r--r-- | Mailman/Cgi/handle_opts.py | 18 | ||||
| -rw-r--r-- | Mailman/Cgi/listinfo.py | 10 | ||||
| -rw-r--r-- | Mailman/Cgi/options.py | 10 | ||||
| -rw-r--r-- | Mailman/Cgi/private.py | 16 | ||||
| -rw-r--r-- | Mailman/Cgi/roster.py | 56 | ||||
| -rw-r--r-- | Mailman/Cgi/subscribe.py | 14 |
9 files changed, 62 insertions, 127 deletions
diff --git a/Mailman/Cgi/admin.py b/Mailman/Cgi/admin.py index 120e305f4..fd856bc61 100644 --- a/Mailman/Cgi/admin.py +++ b/Mailman/Cgi/admin.py @@ -55,15 +55,10 @@ def main(): """ doc = Document() - try: - path = os.environ['PATH_INFO'] - except KeyError: - path = '' - parts = Utils.GetPathPieces(path) - # How many ../'s we need to get back to http://host/mailman - if len(parts) == 0: + parts = Utils.GetPathPieces() + if not parts: FormatAdminOverview() - return + return # get the list object listname = string.lower(parts[0]) try: @@ -378,8 +373,8 @@ def FormatOptionHelp(doc, varref, mlist): item = i break if not item: - bad = ("Option %s/%s not found. %s" - % (category, varname, os.environ['PATH_INFO'])) + bad = 'Option %s/%s not found: %s' % ( + category, varname, os.environ.get('PATH_INFO')) AddErrorMessage(doc, bad) return got = GetItemCharacteristics(item) diff --git a/Mailman/Cgi/admindb.py b/Mailman/Cgi/admindb.py index 99ef7740f..fa07655db 100644 --- a/Mailman/Cgi/admindb.py +++ b/Mailman/Cgi/admindb.py @@ -50,13 +50,11 @@ def handle_no_list(doc, extra=''): def main(): doc = Document() # figure out which list we're going to process - try: - path = os.environ['PATH_INFO'] - except KeyError: + parts = Utils.GetPathPieces() + if not parts: handle_no_list(doc) return # get URL components. the list name should be the zeroth part - parts = Utils.GetPathPieces(path) try: listname = string.lower(parts[0]) except IndexError: diff --git a/Mailman/Cgi/edithtml.py b/Mailman/Cgi/edithtml.py index 45a326e26..76c3338e9 100644 --- a/Mailman/Cgi/edithtml.py +++ b/Mailman/Cgi/edithtml.py @@ -25,6 +25,7 @@ from Mailman import MailList from Mailman.htmlformat import * from Mailman.HTMLFormatter import HTMLFormatter from Mailman import Errors +from Mailman.Cgi import Auth from Mailman.Logging.Syslog import syslog @@ -38,11 +39,8 @@ def main(): ) doc = Document() - - path = os.environ['PATH_INFO'] - parts = Utils.GetPathPieces(path) - - if len(parts) < 1: + parts = Utils.GetPathPieces() + if not parts: doc.AddItem(Header(2, "List name is required.")) print doc.Format(bgcolor='#ffffff') return @@ -56,6 +54,14 @@ def main(): syslog('error', 'No such list "%s": %s\n' % (listname, e)) return + # Must be authenticated to get any farther + cgidata = cgi.FieldStorage() + try: + Auth.authenticate(mlist, cgidata) + except Auth.NotLoggedInError, e: + Auth.loginpage(mlist, 'edithtml', e.message) + return + # get the list._template_dir attribute HTMLFormatter.InitVars(mlist) @@ -87,20 +93,8 @@ def main(): return try: - cgi_data = cgi.FieldStorage() - if len(cgi_data.keys()): - if not cgi_data.has_key('adminpw'): - m = 'Error: You must supply the admin password to edit html.' - doc.AddItem(Header(3, Italic(FontAttr(m, color="ff5060")))) - doc.AddItem('<hr>') - else: - try: - mlist.ConfirmAdminPassword(cgi_data['adminpw'].value) - ChangeHTML(mlist, cgi_data, template_name, doc) - except Errors.MMBadPasswordError: - m = 'Error: Incorrect admin password.' - doc.AddItem(Header(3, Italic(FontAttr(m, color="ff5060")))) - doc.AddItem('<hr>') + if cgidata.keys(): + ChangeHTML(mlist, cgidata, template_name, doc) FormatHTML(mlist, doc, template_name, template_info) finally: doc.AddItem(mlist.GetMailmanFooter()) @@ -120,17 +114,11 @@ def FormatHTML(mlist, doc, template_name, template_info): doc.AddItem('<p>') doc.AddItem('<hr>') form = Form(mlist.GetScriptURL('edithtml') + '/' + template_name) - doc.AddItem(form) - - password_table = Table() - password_table.AddRow(['Enter the admin password to edit html:', - PasswordBox('adminpw')]) - password_table.AddRow(['When you are done making changes...', - SubmitButton('submit', 'Submit Changes')]) - - form.AddItem(password_table) text = Utils.QuoteHyperChars(mlist.SnarfHTMLTemplate(template_name)) form.AddItem(TextArea('html_code', text, rows=40, cols=75)) + form.AddItem('<p>When you are done making changes...') + form.AddItem(SubmitButton('submit', 'Submit Changes')) + doc.AddItem(form) diff --git a/Mailman/Cgi/handle_opts.py b/Mailman/Cgi/handle_opts.py index 4620e0425..66e9e2c41 100644 --- a/Mailman/Cgi/handle_opts.py +++ b/Mailman/Cgi/handle_opts.py @@ -50,14 +50,8 @@ def PrintResults(mlist, operation, doc, results, user=None): def main(): doc = Document() - - path = os.environ.get('PATH_INFO') - if path: - parts = Utils.GetPathPieces(path) - else: - parts = [] - - if len(parts) < 2: + parts = Utils.GetPathPieces() + if not parts or len(parts) < 2: doc.AddItem(Header(2, "Error")) doc.AddItem(Bold("Invalid options to CGI script.")) print doc.Format(bgcolor="#ffffff") @@ -66,12 +60,6 @@ def main(): listname = string.lower(parts[0]) user = parts[1] - if len(parts) < 2: - doc.AddItem(Header(2, "Error")) - doc.AddItem(Bold("Invalid options to CGI script.")) - print doc.Format(bgcolor="#ffffff") - return - try: mlist = MailList.MailList(listname) except Errors.MMListError, e: @@ -97,7 +85,7 @@ def process_form(mlist, user, doc): if not Utils.FindMatchingAddresses(user, mlist.members, mlist.digest_members): - PrintResults(mlist, operation, doc, "%s not a member!<p>" % user, user) + PrintResults(mlist, operation, doc, "%s not a member!<p>" % user) if form.has_key("unsub"): operation = "Unsubscribe" diff --git a/Mailman/Cgi/listinfo.py b/Mailman/Cgi/listinfo.py index 92fa038a8..8c9e78229 100644 --- a/Mailman/Cgi/listinfo.py +++ b/Mailman/Cgi/listinfo.py @@ -32,14 +32,8 @@ from Mailman.Logging.Syslog import syslog def main(): - try: - path = os.environ['PATH_INFO'] - except KeyError: - FormatListinfoOverview() - return - - parts = Utils.GetPathPieces(path) - if len(parts) == 0: + parts = Utils.GetPathPieces() + if not parts: FormatListinfoOverview() return diff --git a/Mailman/Cgi/options.py b/Mailman/Cgi/options.py index 4d66f671a..c79e90459 100644 --- a/Mailman/Cgi/options.py +++ b/Mailman/Cgi/options.py @@ -39,14 +39,8 @@ from Mailman.Logging.Syslog import syslog def main(): doc = HeadlessDocument() - try: - path = os.environ['PATH_INFO'] - except KeyError: - path = '' - - parts = Utils.GetPathPieces(path) - # sanity check options - if len(parts) < 2: + parts = Utils.GetPathPieces() + if not parts or len(parts) < 2: doc.AddItem(Header(2, "Error")) doc.AddItem(Bold("Invalid options to CGI script.")) print doc.Format() diff --git a/Mailman/Cgi/private.py b/Mailman/Cgi/private.py index 000f46d59..240cc35d0 100644 --- a/Mailman/Cgi/private.py +++ b/Mailman/Cgi/private.py @@ -92,27 +92,19 @@ def content_type(path): def main(): doc = Document() - - try: - path = os.environ['PATH_INFO'] - except KeyError: + parts = Utils.GetPathPieces() + if not parts: doc.SetTitle("Private Archive Error") doc.AddItem(Header(3, "You must specify a list.")) print doc.Format(bgcolor="#FFFFFF") sys.exit(0) + path = os.environ.get('PATH_INFO') true_filename = os.path.join( mm_cfg.PRIVATE_ARCHIVE_FILE_DIR, true_path(path)) - list_info = Utils.GetPathPieces(path) - - if len(list_info) < 1: - doc.SetTitle("Private Archive Error") - doc.AddItem(Header(3, "You must specify a list.")) - print doc.Format(bgcolor="#FFFFFF") - sys.exit(0) - listname = string.lower(list_info[0]) + listname = string.lower(parts[0]) # 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 diff --git a/Mailman/Cgi/roster.py b/Mailman/Cgi/roster.py index 603667e84..22cb305a3 100644 --- a/Mailman/Cgi/roster.py +++ b/Mailman/Cgi/roster.py @@ -37,74 +37,68 @@ from Mailman.Logging.Syslog import syslog def main(): doc = htmlformat.HeadlessDocument() + + parts = Utils.GetPathPieces() + if not parts: + error_page('Invalid options to CGI script') + return + + listname = string.lower(parts[0]) + try: + mlist = MailList.MailList(listname, lock=0) + except Errors.MMListError, e: + error_page('No such list <em>%s</em>' % listname) + syslog('error', 'roster: no such list "%s": %s' % (listname, e)) + return + form = cgi.FieldStorage() - list = get_list() bad = "" # These nested conditionals constituted a cascading authentication # check, yielding a - if not list.private_roster: + if not mlist.private_roster: # No privacy. bad = "" else: auth_req = ("%s subscriber list requires authentication." - % list.real_name) + % mlist.real_name) if not form.has_key("roster-pw"): bad = auth_req else: pw = form['roster-pw'].value # Just the admin password is sufficient - check it early. - if not list.ValidAdminPassword(pw): + if not mlist.ValidAdminPassword(pw): if not form.has_key('roster-email'): # No admin password and no user id, nogo. bad = auth_req else: id = form['roster-email'].value - if list.private_roster == 1: + if mlist.private_roster == 1: # Private list - members visible. try: - list.ConfirmUserPassword(id, pw) + mlist.ConfirmUserPassword(id, pw) except (Errors.MMBadUserError, Errors.MMBadPasswordError, Errors.MMNotAMemberError): bad = ("%s subscriber authentication failed." - % list.real_name) + % mlist.real_name) else: # Anonymous list - admin-only visible # - and we already tried admin password, above. bad = ("%s admin authentication failed." - % list.real_name) + % mlist.real_name) if bad: doc = error_page_doc(bad) - doc.AddItem(list.GetMailmanFooter()) + doc.AddItem(mlist.GetMailmanFooter()) print doc.Format() sys.exit(0) - replacements = list.GetAllReplacements() - doc.AddItem(list.ParseTags('roster.html', replacements)) + replacements = mlist.GetAllReplacements() + doc.AddItem(mlist.ParseTags('roster.html', replacements)) print doc.Format() -def get_list(): - "Return list or bail out with error page." - list_info = [] - try: - list_info = Utils.GetPathPieces(os.environ['PATH_INFO']) - except KeyError: - pass - if len(list_info) != 1: - error_page("Invalid options to CGI script.") - sys.exit(0) - listname = string.lower(list_info[0]) - try: - mlist = MailList.MailList(listname, lock=0) - mlist.IsListInitialized() - except Errors.MMListError, e: - error_page('No such list <em>%s</em>' % listname) - syslog('error', 'No such list "%s": %s\n' % (listname, e)) - sys.exit(0) - return mlist - + def error_page(errmsg, *args): print apply(error_page_doc, (errmsg,) + args).Format() diff --git a/Mailman/Cgi/subscribe.py b/Mailman/Cgi/subscribe.py index fc62d56d5..a84f2c0ef 100644 --- a/Mailman/Cgi/subscribe.py +++ b/Mailman/Cgi/subscribe.py @@ -32,18 +32,10 @@ from Mailman.Logging.Syslog import syslog def main(): doc = Document() - try: - path = os.environ['PATH_INFO'] - except KeyError: - doc.AddItem(Header(2, "Error")) - doc.AddItem(Bold("You must include a listname in the url.")) - print doc.Format(bgcolor="#ffffff") - return - - parts = Utils.GetPathPieces(path) - if len(parts) < 1: + parts = Utils.GetPathPieces() + if not parts: doc.AddItem(Header(2, "Error")) - doc.AddItem(Bold("Invalid options to CGI script.")) + doc.AddItem(Bold('Invalid options to CGI script')) print doc.Format(bgcolor="#ffffff") return |
