Index: NEWS
===================================================================
RCS file: /cvsroot/mailman/mailman/NEWS,v
retrieving revision 1.25.2.6
retrieving revision 1.25.2.9
diff -u -r1.25.2.6 -r1.25.2.9
--- NEWS	2001/05/03 21:06:56	1.25.2.6
+++ NEWS	2001/07/25 18:52:27	1.25.2.9
@@ -4,6 +4,34 @@
 
 Here is a history of user visible changes to Mailman.
 
+2.0.6 (25-Jul-2001)
+
+    Security fix:
+
+    - Fixed a potential security hole which could allow access to list
+      administrative features by unauthorized users.  If there is an
+      empty data/adm.pw file (the site password file), then any
+      password will be accepted as the list administrative password.
+      This exploit is caused by a common "bug" in the crypt() function
+      suffered by several Unix distributions, including at least
+      GNU/Linux and Solaris.  Given a salt string of length zero,
+      crypt() always returns the empty string.
+
+      In lieu of applying this patch, sites can run bin/mmsitepass and
+      ensure that data/adm.pw is of length 2 or greater.
+
+    Bug fixes:
+
+    - Ensure that even if DEFAULT_URL is misconfigured in mm_cfg.py
+      (i.e. is missing a trailing slash), it is always fixed upon list
+      creation.
+
+    - Check for administrivia holds before any other tests.
+
+    - SF bugs fixed: 407666, 227694
+
+    - Other miscellaneous buglets fixed.
+
 2.0.5 (04-May-2001)
 
     Fix a lock stagnation problem that can result when the user hits
Index: Mailman/MailList.py
===================================================================
RCS file: /cvsroot/mailman/mailman/Mailman/MailList.py,v
retrieving revision 1.189
retrieving revision 1.189.2.2
diff -u -r1.189 -r1.189.2.2
--- Mailman/MailList.py	2000/11/16 04:33:27	1.189
+++ Mailman/MailList.py	2001/05/29 14:45:27	1.189.2.2
@@ -1,4 +1,4 @@
-# Copyright (C) 1998,1999,2000 by the Free Software Foundation, Inc.
+# Copyright (C) 1998,1999,2000,2001 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
@@ -712,7 +712,7 @@
              " fails, or if the pattern does contain an `@', then the pattern"
              " is matched against the entire recipient address. "
              " <p>Matching against the local part is deprecated; in a future"
-             " release, the patterm will always be matched against the "
+             " release, the pattern will always be matched against the "
              " entire recipient address."),
 
 	    ('max_num_recipients', mm_cfg.Number, 5, 0, 
@@ -787,6 +787,7 @@
         self.InitVars(name, admin, crypted_password)
         self._ready = 1
         self.InitTemplates()
+        self.CheckValues()
         self.Save()
 	# Touch these files so they have the right dir perms no matter what.
 	# A "just-in-case" thing.  This shouldn't have to be here.
Index: Mailman/SecurityManager.py
===================================================================
RCS file: /cvsroot/mailman/mailman/Mailman/SecurityManager.py,v
retrieving revision 1.31
retrieving revision 1.31.2.1
diff -u -r1.31 -r1.31.2.1
--- Mailman/SecurityManager.py	2000/10/02 20:40:41	1.31
+++ Mailman/SecurityManager.py	2001/07/25 18:07:51	1.31.2.1
@@ -1,4 +1,4 @@
-# Copyright (C) 1998,1999,2000 by the Free Software Foundation, Inc.
+# Copyright (C) 1998,1999,2000,2001 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
@@ -44,8 +44,12 @@
     def ValidAdminPassword(self, pw):
 	if Utils.CheckSiteAdminPassword(pw):
             return 1
-	return type(pw) == StringType and \
-               Crypt.crypt(pw, self.password) == self.password
+        salt = self.password[:2]
+        # crypt() has a bug in that if the salt is the empty string, it will
+        # always return the empty string, regardless of the key. :(
+        if len(salt) < 2:
+            return 0
+	return Crypt.crypt(pw, salt) == self.password
 
     def ConfirmAdminPassword(self, pw):
         if not self.ValidAdminPassword(pw):
Index: Mailman/Utils.py
===================================================================
RCS file: /cvsroot/mailman/mailman/Mailman/Utils.py,v
retrieving revision 1.104.2.2
retrieving revision 1.104.2.4
diff -u -r1.104.2.2 -r1.104.2.4
--- Mailman/Utils.py	2001/04/18 04:23:07	1.104.2.2
+++ Mailman/Utils.py	2001/07/25 18:06:46	1.104.2.4
@@ -262,7 +262,7 @@
 	    finally:
 		os.umask(ou)
 	    if verbose:
-		print 'made directory: ', madepart
+		print 'made directory: ', made_part
   
 
 
@@ -405,7 +405,12 @@
         f = open(mm_cfg.SITE_PW_FILE)
         pw2 = f.read()
         f.close()
-        return Crypt.crypt(pw1, pw2[:2]) == pw2
+        salt = pw2[:2]
+        # crypt() has a bug in that if the salt is the empty string, it will
+        # always return the empty string, regardless of the key. :(
+        if len(salt) < 2:
+            return 0
+        return Crypt.crypt(pw1, salt) == pw2
     # There probably is no site admin password if there was an exception
     except IOError:
         return 0
Index: Mailman/Version.py
===================================================================
RCS file: /cvsroot/mailman/mailman/Mailman/Version.py,v
retrieving revision 1.20.2.5
retrieving revision 1.20.2.6
diff -u -r1.20.2.5 -r1.20.2.6
--- Mailman/Version.py	2001/05/03 20:58:19	1.20.2.5
+++ Mailman/Version.py	2001/07/25 18:05:30	1.20.2.6
@@ -15,7 +15,7 @@
 # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 
 # Mailman version
-VERSION = "2.0.5"
+VERSION = "2.0.6"
 
 # And as a hex number in the manner of PY_VERSION_HEX
 ALPHA = 0xa
@@ -27,7 +27,7 @@
 
 MAJOR_REV = 2
 MINOR_REV = 0
-MICRO_REV = 5
+MICRO_REV = 6
 REL_LEVEL = FINAL
 # at most 15 beta releases!
 REL_SERIAL = 0
Index: Mailman/versions.py
===================================================================
RCS file: /cvsroot/mailman/mailman/Mailman/versions.py,v
retrieving revision 1.27
retrieving revision 1.27.2.1
diff -u -r1.27 -r1.27.2.1
--- Mailman/versions.py	2000/06/14 05:09:58	1.27
+++ Mailman/versions.py	2001/07/10 14:58:56	1.27.2.1
@@ -142,7 +142,7 @@
     # set admin_notify_mchanges
     #
     if not hasattr(l, "admin_notify_mchanges"):
-        setatrr(l, "admin_notify_mchanges",
+        setattr(l, "admin_notify_mchanges",
                 mm_cfg.DEFAULT_ADMIN_NOTIFY_MCHANGES)
     #
     # Convert the members and digest_members addresses so that the keys of
Index: Mailman/Archiver/pipermail.py
===================================================================
RCS file: /cvsroot/mailman/mailman/Mailman/Archiver/pipermail.py,v
retrieving revision 1.15
retrieving revision 1.15.2.2
diff -u -r1.15 -r1.15.2.2
--- Mailman/Archiver/pipermail.py	2000/10/20 06:18:11	1.15
+++ Mailman/Archiver/pipermail.py	2001/06/01 22:30:16	1.15.2.2
@@ -62,7 +62,7 @@
 
 # Abstract class for databases
 
-class DatabaseInterface:    
+class DatabaseInterface:
     def __init__(self): pass
     def close(self): pass
     def getArticle(self, archive, msgid): pass
@@ -162,13 +162,15 @@
 	id = strip_separators(message.getheader('Message-Id'))
 	if id == "":
             self.msgid = str(self.sequence)
-	else: self.msgid = id
+	else:
+            self.msgid = id
 
 	if message.has_key('Subject'):
             self.subject = str(message['Subject'])
 	else:
+            self.subject = 'No subject'
+	if self.subject == "":
             self.subject = 'No subject'
-	if self.subject == "": self.subject = 'No subject'
 
         self._set_date(message)
 
@@ -180,7 +182,8 @@
 	self.email = strip_separators(self.email)
 	self.author = strip_separators(self.author)
 
-	if self.author == "": self.author = self.email
+	if self.author == "":
+            self.author = self.email
 
 	# Save the In-Reply-To:, References:, and Message-ID: lines
         #
@@ -197,8 +200,10 @@
             self.in_reply_to = ''
 	else:
 	    match = msgid_pat.search(i_r_t)
-	    if match is None: self.in_reply_to = ''
-	    else: self.in_reply_to = strip_separators(match.group(1))
+	    if match is None:
+                self.in_reply_to = ''
+	    else:
+                self.in_reply_to = strip_separators(match.group(1))
 		
 	references = message.getheader('References')
 	if references is None:
@@ -352,7 +357,7 @@
                                                    refs[0])
                 for ref in refs[1:]:
                     a = self.database.getArticle(self.archive, ref)
-                    if a.date > maxdate.data:
+                    if a.date > maxdate.date:
                         maxdate = a
                 parentID = maxdate.msgid
 	    else:
Index: Mailman/Bouncers/BouncerAPI.py
===================================================================
RCS file: /cvsroot/mailman/mailman/Mailman/Bouncers/BouncerAPI.py,v
retrieving revision 1.11
retrieving revision 1.11.2.1
diff -u -r1.11 -r1.11.2.1
--- Mailman/Bouncers/BouncerAPI.py	2000/09/21 04:50:10	1.11
+++ Mailman/Bouncers/BouncerAPI.py	2001/07/10 15:00:09	1.11.2.1
@@ -82,6 +82,7 @@
 
 # for testing
 if __name__ == '__main__':
+    import sys
     import mimetools
     from Mailman import MailList
 
Index: Mailman/Bouncers/DSN.py
===================================================================
RCS file: /cvsroot/mailman/mailman/Mailman/Bouncers/DSN.py,v
retrieving revision 1.7
retrieving revision 1.7.2.1
diff -u -r1.7 -r1.7.2.1
--- Mailman/Bouncers/DSN.py	2000/07/21 05:25:53	1.7
+++ Mailman/Bouncers/DSN.py	2001/07/25 18:04:42	1.7.2.1
@@ -1,4 +1,4 @@
-# Copyright (C) 1998,1999,2000 by the Free Software Foundation, Inc.
+# Copyright (C) 1998,1999,2000,2001 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
@@ -43,8 +43,8 @@
 
 
 def process(msg):
-    if msg.gettype() <> 'multipart/report' or \
-       msg.getparam('report-type') <> 'delivery-status':
+    if string.lower(msg.gettype()) <> 'multipart/report' or \
+       string.lower(msg.getparam('report-type')) <> 'delivery-status':
         # then
         return None
     boundary = msg.getparam('boundary')
Index: Mailman/Cgi/handle_opts.py
===================================================================
RCS file: /cvsroot/mailman/mailman/Mailman/Cgi/Attic/handle_opts.py,v
retrieving revision 1.30.2.2
retrieving revision 1.30.2.3
diff -u -r1.30.2.2 -r1.30.2.3
--- Mailman/Cgi/handle_opts.py	2001/05/03 21:05:06	1.30.2.2
+++ Mailman/Cgi/handle_opts.py	2001/07/10 14:52:32	1.30.2.3
@@ -266,14 +266,14 @@
         except Errors.MMNotAMemberError:
             PrintResults(mlist, operation, doc,
                          "%s isn't subscribed to this list."
-                         % mail.GetSender(), user)
+                         % user, user)
         except Errors.MMListNotReadyError:
             PrintResults(mlist, operation, doc, "List is not functional.",
                          user)
         except Errors.MMNoSuchUserError:
             PrintResults(mlist, operation, doc,
                          "%s is not subscribed to this list."
-                         % mail.GetSender(), user)
+                         % user, user)
         except Errors.MMBadPasswordError:
             PrintResults(mlist, operation, doc,
                          "You gave the wrong password.", user)
Index: Mailman/Handlers/Hold.py
===================================================================
RCS file: /cvsroot/mailman/mailman/Mailman/Handlers/Hold.py,v
retrieving revision 1.16
retrieving revision 1.16.2.2
diff -u -r1.16 -r1.16.2.2
--- Mailman/Handlers/Hold.py	2000/08/01 23:02:28	1.16
+++ Mailman/Handlers/Hold.py	2001/05/31 21:05:44	1.16.2.2
@@ -1,4 +1,4 @@
-# Copyright (C) 1998,1999,2000 by the Free Software Foundation, Inc.
+# Copyright (C) 1998,1999,2000,2001 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
@@ -118,6 +118,11 @@
     if not sender or sender[:len(listname)+6] == adminaddr:
         sender = msg.GetSender(use_envelope=0)
     #
+    # possible administrivia?
+    if mlist.administrivia and Utils.IsAdministrivia(msg):
+        hold_for_approval(mlist, msg, msgdata, Administrivia)
+        # no return
+    #
     # is the poster in the list of explicitly forbidden posters?
     if len(mlist.forbidden_posters):
         forbiddens = Utils.List2Dict(mlist.forbidden_posters)
@@ -175,11 +180,6 @@
        not msgdata.get('fromusenet'):
         # then
         hold_for_approval(mlist, msg, msgdata, ImplicitDestination)
-        # no return
-    #
-    # possible administrivia?
-    if mlist.administrivia and Utils.IsAdministrivia(msg):
-        hold_for_approval(mlist, msg, msgdata, Administrivia)
         # no return
     #
     # suspicious headers?
Index: admin/www/download.ht
===================================================================
RCS file: /cvsroot/mailman/mailman/admin/www/download.ht,v
retrieving revision 1.5.2.6
retrieving revision 1.5.2.7
diff -u -r1.5.2.6 -r1.5.2.7
--- admin/www/download.ht	2001/05/03 21:09:36	1.5.2.6
+++ admin/www/download.ht	2001/07/25 18:08:31	1.5.2.7
@@ -65,9 +65,9 @@
 <h3>Downloading</h3>
 
 <p>Version
-(<!-VERSION--->2.0.5<!-VERSION--->,
+(<!-VERSION--->2.0.6<!-VERSION--->,
 released on
-<!-DATE--->May  4 2001<!-DATE--->)
+<!-DATE--->Jul 25 2001<!-DATE--->)
 is the current GNU release.  It is available from the following mirror sites:
 
 <ul>
Index: admin/www/download.html
===================================================================
RCS file: /cvsroot/mailman/mailman/admin/www/download.html,v
retrieving revision 1.6.2.8
retrieving revision 1.6.2.9
diff -u -r1.6.2.8 -r1.6.2.9
--- admin/www/download.html	2001/05/03 21:09:36	1.6.2.8
+++ admin/www/download.html	2001/07/25 18:08:31	1.6.2.9
@@ -1,6 +1,6 @@
 <HTML>
 <!-- THIS PAGE IS AUTOMATICALLY GENERATED.  DO NOT EDIT. -->
-<!-- Thu May  3 17:09:03 2001 -->
+<!-- Wed Jul 25 14:08:14 2001 -->
 <!-- USING HT2HTML 1.1 -->
 <!-- SEE http://www.wooz.org/barry/software/pyware.html -->
 <!-- User-specified headers:
@@ -237,9 +237,9 @@
 <h3>Downloading</h3>
 
 <p>Version
-(<!-VERSION--->2.0.5<!-VERSION--->,
+(<!-VERSION--->2.0.6<!-VERSION--->,
 released on
-<!-DATE--->May  4 2001<!-DATE--->)
+<!-DATE--->Jul 25 2001<!-DATE--->)
 is the current GNU release.  It is available from the following mirror sites:
 
 <ul>
Index: bin/find_member
===================================================================
RCS file: /cvsroot/mailman/mailman/bin/find_member,v
retrieving revision 1.5
retrieving revision 1.5.2.1
diff -u -r1.5 -r1.5.2.1
--- bin/find_member	2000/09/11 03:58:57	1.5
+++ bin/find_member	2001/07/25 17:38:43	1.5.2.1
@@ -90,7 +90,7 @@
         try:
             mlist = MailList.MailList(listname, lock=0)
         except Errors.MMListError:
-            print 'No such list "%s"' % name
+            print 'No such list "%s"' % listname
             continue
         if options.owners:
             owners = mlist.owner
Index: src/cgi-wrapper.c
===================================================================
RCS file: /cvsroot/mailman/mailman/src/cgi-wrapper.c,v
retrieving revision 1.13
retrieving revision 1.13.2.1
diff -u -r1.13 -r1.13.2.1
--- src/cgi-wrapper.c	2000/03/21 06:26:41	1.13
+++ src/cgi-wrapper.c	2001/05/29 13:20:27	1.13.2.1
@@ -23,7 +23,7 @@
 
 /* passed in by configure */
 #define SCRIPTNAME  SCRIPT
-#define LOG_IDENT   "Mailman cgi-wrapper (" ## SCRIPT ## ")"
+#define LOG_IDENT   "Mailman cgi-wrapper (" SCRIPT ")"
 
 /* GID that CGI scripts run as.  See your Web server's documentation. */
 #define LEGAL_PARENT_GID CGI_GID
Index: src/common.c
===================================================================
RCS file: /cvsroot/mailman/mailman/src/common.c,v
retrieving revision 1.26
retrieving revision 1.26.2.1
diff -u -r1.26 -r1.26.2.1
--- src/common.c	2000/11/09 06:18:02	1.26
+++ src/common.c	2001/05/29 13:20:27	1.26.2.1
@@ -20,7 +20,7 @@
 #include "common.h"
 
 /* passed in by configure */
-#define SCRIPTDIR PREFIX ## "/scripts/"	     /* trailing slash */
+#define SCRIPTDIR PREFIX "/scripts/"	     /* trailing slash */
 #define MODULEDIR PREFIX		     /* no trailing slash */
 
 const char* scriptdir = SCRIPTDIR;