summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorbwarsaw2000-09-29 00:05:05 +0000
committerbwarsaw2000-09-29 00:05:05 +0000
commitceddf83bf0000704b4c2c3428db124e88d4a1ee4 (patch)
treeafb489a2eb004c39366553fb4cb12d9da5c8b7e7
parent8fab2b4ea200b7fbdac7e5f99881f07047ef467c (diff)
downloadmailman-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.py15
-rw-r--r--Mailman/Cgi/admindb.py6
-rw-r--r--Mailman/Cgi/edithtml.py44
-rw-r--r--Mailman/Cgi/handle_opts.py18
-rw-r--r--Mailman/Cgi/listinfo.py10
-rw-r--r--Mailman/Cgi/options.py10
-rw-r--r--Mailman/Cgi/private.py16
-rw-r--r--Mailman/Cgi/roster.py56
-rw-r--r--Mailman/Cgi/subscribe.py14
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