aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Mailman/Cgi/admin.py27
-rw-r--r--Mailman/Defaults.py.in8
-rw-r--r--Mailman/Handlers/Approve.py5
-rw-r--r--Mailman/SecurityManager.py9
-rw-r--r--Mailman/Version.py4
-rw-r--r--Mailman/versions.py3
-rw-r--r--NEWS5
7 files changed, 55 insertions, 6 deletions
diff --git a/Mailman/Cgi/admin.py b/Mailman/Cgi/admin.py
index 22ebe16a..569aa61c 100644
--- a/Mailman/Cgi/admin.py
+++ b/Mailman/Cgi/admin.py
@@ -1258,6 +1258,22 @@ and also provide the email addresses of the list moderators in the
PasswordBox('confirmmodpw', size=20)])
# Add these tables to the overall password table
table.AddRow([atable, mtable])
+ table.AddRow([_("""\
+In addition to the above passwords you may specify a password for
+pre-approving posts to the list. Either of the above two passwords can
+be used in an Approved: header or first body line pseudo-header to
+pre-approve a post that would otherwise be held for moderation. In
+addition, the password below, if set, can be used for that purpose and
+no other.""")])
+ table.AddCellInfo(table.GetCurrentRowIndex(), 0, colspan=2)
+ # Set up the post password table
+ ptable = Table(border=0, cellspacing=3, cellpadding=4,
+ bgcolor=mm_cfg.WEB_ADMINPW_COLOR)
+ ptable.AddRow([Label(_('Enter new poster password:')),
+ PasswordBox('newpostpw', size=20)])
+ ptable.AddRow([Label(_('Confirm poster password:')),
+ PasswordBox('confirmpostpw', size=20)])
+ table.AddRow([ptable])
return table
@@ -1288,6 +1304,17 @@ def change_options(mlist, category, subcat, cgidata, doc):
# password doesn't get you into these pages.
else:
doc.addError(_('Moderator passwords did not match'))
+ # Handle changes to the list poster password. Do this before checking
+ # the new admin password, since the latter will force a reauthentication.
+ new = cgidata.getvalue('newpostpw', '').strip()
+ confirm = cgidata.getvalue('confirmpostpw', '').strip()
+ if new or confirm:
+ if new == confirm:
+ mlist.post_password = sha_new(new).hexdigest()
+ # No re-authentication necessary because the poster's
+ # password doesn't get you into these pages.
+ else:
+ doc.addError(_('Poster passwords did not match'))
# Handle changes to the list administrator password
new = cgidata.getvalue('newpw', '').strip()
confirm = cgidata.getvalue('confirmpw', '').strip()
diff --git a/Mailman/Defaults.py.in b/Mailman/Defaults.py.in
index e6a0e400..9ffa16e3 100644
--- a/Mailman/Defaults.py.in
+++ b/Mailman/Defaults.py.in
@@ -1375,6 +1375,11 @@ OPTINFO = {'hide' : ConcealSubscription,
# option settings
# - List creator, someone who can create and delete lists, but cannot
# (necessarily) configure the list.
+# - List poster, someone who can pre-approve her/his own posts to the list by
+# including an Approved: or X-Approved: header or first body line pseudo-
+# header containing the poster password. The list admin and moderator
+# passwords can also be used for this purpose, but the poster password can
+# only be used for this and nothing else.
# - List moderator, someone who can tend to pending requests such as
# subscription requests, or held messages
# - List administrator, someone who has total control over a list, can
@@ -1389,7 +1394,8 @@ AuthUser = 1 # Joe Shmoe User
AuthCreator = 2 # List Creator / Destroyer
AuthListAdmin = 3 # List Administrator (total control over list)
AuthListModerator = 4 # List Moderator (can only handle held requests)
-AuthSiteAdmin = 5 # Site Administrator (total control over everything)
+AuthListPoster = 5 # List poster (Approved: <pw> header in posts only)
+AuthSiteAdmin = 6 # Site Administrator (total control over everything)
# Useful directories
LIST_DATA_DIR = os.path.join(VAR_PREFIX, 'lists')
diff --git a/Mailman/Handlers/Approve.py b/Mailman/Handlers/Approve.py
index 68f23cf1..9567325a 100644
--- a/Mailman/Handlers/Approve.py
+++ b/Mailman/Handlers/Approve.py
@@ -1,4 +1,4 @@
-# Copyright (C) 1998-2010 by the Free Software Foundation, Inc.
+# Copyright (C) 1998-2011 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
@@ -117,7 +117,8 @@ def process(mlist, msg, msgdata):
lines = part.get_payload(decode=True)
if re.search(pattern, lines):
reset_payload(part, re.sub(pattern, '', lines))
- if passwd is not missing and mlist.Authenticate((mm_cfg.AuthListModerator,
+ if passwd is not missing and mlist.Authenticate((mm_cfg.AuthListPoster,
+ mm_cfg.AuthListModerator,
mm_cfg.AuthListAdmin),
passwd):
# BAW: should we definitely deny if the password exists but does not
diff --git a/Mailman/SecurityManager.py b/Mailman/SecurityManager.py
index c2f57cc4..5d5acd5b 100644
--- a/Mailman/SecurityManager.py
+++ b/Mailman/SecurityManager.py
@@ -83,6 +83,7 @@ class SecurityManager:
# self.password is really a SecurityManager attribute, but it's set in
# MailList.InitVars().
self.mod_password = None
+ self.post_password = None
# Non configurable
self.passwords = {}
@@ -106,6 +107,9 @@ class SecurityManager:
secret = self.getMemberPassword(user)
userdata = urllib.quote(Utils.ObscureEmail(user), safe='')
key += 'user+%s' % userdata
+ elif authcontext == mm_cfg.AuthListPoster:
+ secret = self.post_password
+ key += 'poster'
elif authcontext == mm_cfg.AuthListModerator:
secret = self.mod_password
key += 'moderator'
@@ -200,6 +204,11 @@ class SecurityManager:
key, secret = self.AuthContextInfo(ac)
if secret and sha_new(response).hexdigest() == secret:
return ac
+ elif ac == mm_cfg.AuthListPoster:
+ # The list poster password must be sha'd
+ key, secret = self.AuthContextInfo(ac)
+ if secret and sha_new(response).hexdigest() == secret:
+ return ac
elif ac == mm_cfg.AuthUser:
if user is not None:
try:
diff --git a/Mailman/Version.py b/Mailman/Version.py
index 74c7a6f5..54d11484 100644
--- a/Mailman/Version.py
+++ b/Mailman/Version.py
@@ -1,4 +1,4 @@
-# Copyright (C) 1998-2010 by the Free Software Foundation, Inc.
+# Copyright (C) 1998-2011 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
@@ -37,7 +37,7 @@ HEX_VERSION = ((MAJOR_REV << 24) | (MINOR_REV << 16) | (MICRO_REV << 8) |
(REL_LEVEL << 4) | (REL_SERIAL << 0))
# config.pck schema version number
-DATA_FILE_VERSION = 98
+DATA_FILE_VERSION = 99
# qfile/*.db schema version number
QFILE_SCHEMA_VERSION = 3
diff --git a/Mailman/versions.py b/Mailman/versions.py
index ade72ae2..8de192cd 100644
--- a/Mailman/versions.py
+++ b/Mailman/versions.py
@@ -1,4 +1,4 @@
-# Copyright (C) 1998-2010 by the Free Software Foundation, Inc.
+# Copyright (C) 1998-2011 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
@@ -339,6 +339,7 @@ def NewVars(l):
mm_cfg.DEFAULT_DIGEST_VOLUME_FREQUENCY)
add_only_if_missing('digest_last_sent_at', 0)
add_only_if_missing('mod_password', None)
+ add_only_if_missing('post_password', None)
add_only_if_missing('moderator', [])
add_only_if_missing('topics', [])
add_only_if_missing('topics_enabled', 0)
diff --git a/NEWS b/NEWS
index 8ee35b09..38549b4a 100644
--- a/NEWS
+++ b/NEWS
@@ -12,6 +12,11 @@ Here is a history of user visible changes to Mailman.
New Features
+ - A new list poster password has been implemented. This password may only
+ be used in Approved: or X-Approved: headers for pre-approving posts.
+ Using this password for that purpose precludes compromise of a more
+ valuable password sent in plain text email. Bug #770581.
+
- A new mm_cfg.py setting AUTHENTICATION_COOKIE_LIFETIME has been added.
If this is set to a non-zero value, web authentication cookies will
expire that many seconds following their last use. Its default value is