Index: ACKNOWLEDGMENTS =================================================================== RCS file: /cvsroot/mailman/mailman/ACKNOWLEDGMENTS,v retrieving revision 1.35 retrieving revision 1.35.2.1 diff -u -r1.35 -r1.35.2.1 --- ACKNOWLEDGMENTS 16 Nov 2000 21:57:06 -0000 1.35 +++ ACKNOWLEDGMENTS 3 Apr 2002 05:07:52 -0000 1.35.2.1 @@ -39,6 +39,7 @@ Stan Bubrouski Ted Cabeen David Champion + Rob Ellis Fil Erik Forsberg Darrell Fuhriman @@ -50,6 +51,7 @@ Andrew Kuchling Ricardo Kustner J C Lawrence + Greg Lindahl Christopher P. Lindsey Tanner Lovelace Gergely Madarasz Index: NEWS =================================================================== RCS file: /cvsroot/mailman/mailman/NEWS,v retrieving revision 1.25.2.11 retrieving revision 1.25.2.13 diff -u -r1.25.2.11 -r1.25.2.13 --- NEWS 27 Nov 2001 22:52:39 -0000 1.25.2.11 +++ NEWS 3 Apr 2002 22:50:10 -0000 1.25.2.13 @@ -4,6 +4,26 @@ Here is a history of user visible changes to Mailman. +2.0.9 (02-Apr-2002) + + - Closed a race condition which could, under rare circumstances, + cause the occasional message to get lost. + + - HTML escape message excerpts and headers on the admindb page so + JavaScript and other evil tags can't mess up the display. + + - Some additional Python 2.2 compatibility fixes. + + - Unlink the footer logos so as not to bug the python.org and + gnu.org maintainers as much. :( + + - Fix a crash in the DSN bounce detection module, which could + cause some bounce messages to remain in the queue. + + - Add the RFC-2822 mandated Date: header on internally generated + outgoing messages. Not all MTAs add this field if missing + (read: Qmail). + 2.0.8 (27-Nov-2001) Security fix release to prevent cross-site scripting exploits. Index: Mailman/Message.py =================================================================== RCS file: /cvsroot/mailman/mailman/Mailman/Message.py,v retrieving revision 1.40 retrieving revision 1.40.2.2 diff -u -r1.40 -r1.40.2.2 --- Mailman/Message.py 2 Aug 2000 02:00:13 -0000 1.40 +++ Mailman/Message.py 3 Apr 2002 22:40:41 -0000 1.40.2.2 @@ -177,11 +177,14 @@ marshal.dump(msgdata, dbfp) dbfp.close() # If it doesn't already exist, or if the text of the message has - # changed, write the message file to disk. + # changed, write the message file to disk, but do it atomically so as + # not to hit a race condition with the qrunner. if not existsp or dirty: - msgfp = Utils.open_ex(msgfile, 'w') + tmpfile = msgfile + '.tmp' + msgfp = Utils.open_ex(tmpfile, 'w') msgfp.write(text) msgfp.close() + os.rename(tmpfile, msgfile) @@ -192,6 +195,10 @@ # also begin with the body of the message but in that case you better # make sure that the first line does NOT contain a colon! Message.__init__(self, StringIO(text)) + # RFC 2822 requires a Date: header, and while most MTAs add one if + # it's missing, Qmail does not. + if not self.get('date'): + self['Date'] = Utils.formatdate(localtime=1) Index: Mailman/Utils.py =================================================================== RCS file: /cvsroot/mailman/mailman/Mailman/Utils.py,v retrieving revision 1.104.2.4 retrieving revision 1.104.2.5 diff -u -r1.104.2.4 -r1.104.2.5 --- Mailman/Utils.py 25 Jul 2001 18:06:46 -0000 1.104.2.4 +++ Mailman/Utils.py 3 Apr 2002 22:47:12 -0000 1.104.2.5 @@ -27,6 +27,7 @@ import os import string import re +import time from UserDict import UserDict from types import StringType import random @@ -690,3 +691,49 @@ if kws: raise TypeError('unexpected keywords') file.write(string.join(map(str, args), sep) + end) + + + +def formatdate(timeval=None, localtime=0): + """Returns a date string as specified by RFC 2822, e.g.: + + Fri, 09 Nov 2001 01:08:47 -0000 + + Optional timeval if given is a floating point time value as accepted by + gmtime() and localtime(), otherwise the current time is used. + + Optional localtime is a flag that when true, interprets timeval, and + returns a date relative to the local timezone instead of UTC, properly + taking daylight savings time into account. + """ + # Note: we cannot use strftime() because that honors the locale and RFC + # 2822 requires that day and month names be the English abbreviations. + if timeval is None: + timeval = time.time() + if localtime: + now = time.localtime(timeval) + # Calculate timezone offset, based on whether the local zone has + # daylight savings time, and whether DST is in effect. + if time.daylight and now[-1]: + offset = time.altzone + else: + offset = time.timezone + hours, minutes = divmod(abs(offset), 3600) + # Remember offset is in seconds west of UTC, but the timezone is in + # minutes east of UTC, so the signs differ. + if offset > 0: + sign = '-' + else: + sign = '+' + zone = '%s%02d%02d' % (sign, hours, minutes / 60) + else: + now = time.gmtime(timeval) + # Timezone offset is always -0000 + zone = '-0000' + return '%s, %02d %s %04d %02d:%02d:%02d %s' % ( + ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'][now[6]], + now[2], + ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', + 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'][now[1] - 1], + now[0], now[3], now[4], now[5], + zone) Index: Mailman/Version.py =================================================================== RCS file: /cvsroot/mailman/mailman/Mailman/Version.py,v retrieving revision 1.20.2.8 retrieving revision 1.20.2.9 diff -u -r1.20.2.8 -r1.20.2.9 --- Mailman/Version.py 27 Nov 2001 22:47:00 -0000 1.20.2.8 +++ Mailman/Version.py 2 Apr 2002 23:36:35 -0000 1.20.2.9 @@ -15,7 +15,7 @@ # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. # Mailman version -VERSION = "2.0.8" +VERSION = "2.0.9" # 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 = 8 +MICRO_REV = 9 REL_LEVEL = FINAL # at most 15 beta releases! REL_SERIAL = 0 Index: Mailman/htmlformat.py =================================================================== RCS file: /cvsroot/mailman/mailman/Mailman/htmlformat.py,v retrieving revision 1.31 retrieving revision 1.31.2.1 diff -u -r1.31 -r1.31.2.1 --- Mailman/htmlformat.py 12 Sep 2000 04:02:36 -0000 1.31 +++ Mailman/htmlformat.py 2 Apr 2002 22:28:59 -0000 1.31.2.1 @@ -519,23 +519,13 @@ if mm_cfg.IMAGE_LOGOS: def logo(file): return mm_cfg.IMAGE_LOGOS + file - mmlink = Link(MAILMAN_URL, - '<img src="%s" alt="Delivered by Mailman" border=0>' - '<br>version %s' - % (logo(DELIVERED_BY), mm_cfg.VERSION)) - pylink = Link(PYTHON_URL, - '<img src="%s" alt="Python Powered" border=0>' % - logo(PYTHON_POWERED)) - gnulink = Link(GNU_URL, - '<img src="%s" alt="GNU\'s Not Unix" border=0>' % - logo(GNU_HEAD)) - text = Container(Link(MAILMAN_URL, 'Mailman home page'), - '<br>', - Link(PYTHON_URL, 'Python home page'), - '<br>', - Link(GNU_URL, 'GNU home page'), - ) - t.AddRow([mmlink, pylink, gnulink, text]) + mmlink = '<img src="%s" alt="Delivered by Mailman" border=0>' \ + '<br>version %s' % (logo(DELIVERED_BY), mm_cfg.VERSION) + pylink = '<img src="%s" alt="Python Powered" border=0>' % \ + logo(PYTHON_POWERED) + gnulink = '<img src="%s" alt="GNU\'s Not Unix" border=0>' % \ + logo(GNU_HEAD) + t.AddRow([mmlink, pylink, gnulink]) else: # use only textual links mmlink = Link(MAILMAN_URL, Index: Mailman/Archiver/HyperArch.py =================================================================== RCS file: /cvsroot/mailman/mailman/Mailman/Archiver/HyperArch.py,v retrieving revision 1.46 retrieving revision 1.46.2.1 diff -u -r1.46 -r1.46.2.1 --- Mailman/Archiver/HyperArch.py 13 Nov 2000 21:50:05 -0000 1.46 +++ Mailman/Archiver/HyperArch.py 2 Apr 2002 23:39:35 -0000 1.46.2.1 @@ -39,11 +39,12 @@ import time import pickle import os -import posixfile import HyperDatabase import pipermail -from Mailman import mm_cfg, EncWord +from Mailman import mm_cfg +from Mailman import LockFile +from Mailman import EncWord from Mailman.Logging.Syslog import syslog from Mailman.Utils import mkdir, open_ex @@ -699,27 +700,18 @@ def GetArchLock(self): if self._lock_file: return 1 - # TBD: This needs to be rewritten to use the generalized locking - # mechanism (when that exists). -baw - ou = os.umask(0) + self._lock_file = LockFile.LockFile( + os.path.join(mm_cfg.LOCK_DIR, + self.maillist.internal_name() + '-arch.lock')) try: - self._lock_file = posixfile.open( - os.path.join(mm_cfg.LOCK_DIR, '%s@arch.lock' - % self.maillist.internal_name()), 'a+') - finally: - os.umask(ou) - # minor race condition here, there is no way to atomicly - # check & get a lock. That shouldn't matter here tho' -ddm - if not self._lock_file.lock('w?', 1): - self._lock_file.lock('w|', 1) - else: + self._lock_file.lock(timeout=0.5) + except LockFile.TimeOutError: return 0 return 1 def DropArchLock(self): if self._lock_file: - self._lock_file.lock('u') - self._lock_file.close() + self._lock_file.unlock(unconditionally=1) self._lock_file = None def processListArch(self): Index: Mailman/Bouncers/DSN.py =================================================================== RCS file: /cvsroot/mailman/mailman/Mailman/Bouncers/DSN.py,v retrieving revision 1.7.2.2 retrieving revision 1.7.2.4 diff -u -r1.7.2.2 -r1.7.2.4 --- Mailman/Bouncers/DSN.py 6 Nov 2001 04:27:30 -0000 1.7.2.2 +++ Mailman/Bouncers/DSN.py 29 Mar 2002 18:44:05 -0000 1.7.2.4 @@ -43,7 +43,7 @@ def process(msg): - ctype = msg.gettype() + ctype = msg.gettype() or '' param = msg.getparam('report-type') or '' if string.lower(ctype) <> 'multipart/report' or \ string.lower(param) <> 'delivery-status': @@ -59,6 +59,11 @@ more = mfile.next() except multifile.Error: # the message *looked* like a DSN, but it really wasn't :( + return None + except TypeError: + # This message has serious problems, pass it on. Seen in the + # wild: it is a MIME document with no boundary parameter in its + # Content-Type: header. return None if not more: # we didn't find it Index: Mailman/Cgi/admindb.py =================================================================== RCS file: /cvsroot/mailman/mailman/Mailman/Cgi/admindb.py,v retrieving revision 1.36.2.5 retrieving revision 1.36.2.7 diff -u -r1.36.2.5 -r1.36.2.7 --- Mailman/Cgi/admindb.py 27 Nov 2001 20:23:53 -0000 1.36.2.5 +++ Mailman/Cgi/admindb.py 1 Apr 2002 18:47:46 -0000 1.36.2.7 @@ -207,7 +207,7 @@ return raise t = Table(cellspacing=0, cellpadding=0, width='100%') - t.AddRow([Bold('From:'), sender]) + t.AddRow([Bold('From:'), cgi.escape(sender)]) row, col = t.GetCurrentRowIndex(), t.GetCurrentCellIndex() t.AddCellInfo(row, col-1, align='right') t.AddRow([Bold('Subject:'), cgi.escape(subject)]) @@ -247,12 +247,14 @@ row, col = t.GetCurrentRowIndex(), t.GetCurrentCellIndex() t.AddCellInfo(row, col-1, align='right') t.AddRow([Bold('Message Headers:'), - TextArea('headers-%d' % id, string.join(msg.headers, ''), + TextArea('headers-%d' % id, + cgi.escape(string.join(msg.headers, '')), rows=10, cols=80)]) row, col = t.GetCurrentRowIndex(), t.GetCurrentCellIndex() t.AddCellInfo(row, col-1, align='right') t.AddRow([Bold('Message Excerpt:'), - TextArea('fulltext-%d' % id, text, rows=10, cols=80)]) + TextArea('fulltext-%d' % id, cgi.escape(text), + rows=10, cols=80)]) t.AddCellInfo(row+1, col-1, align='right') form.AddItem(t) form.AddItem('<p>') Index: admin/www/download.ht =================================================================== RCS file: /cvsroot/mailman/mailman/admin/www/download.ht,v retrieving revision 1.5.2.9 retrieving revision 1.5.2.10 diff -u -r1.5.2.9 -r1.5.2.10 --- admin/www/download.ht 27 Nov 2001 22:27:42 -0000 1.5.2.9 +++ admin/www/download.ht 3 Apr 2002 05:11:22 -0000 1.5.2.10 @@ -65,9 +65,9 @@ <h3>Downloading</h3> <p>Version -(<!-VERSION--->2.0.8<!-VERSION--->, +(<!-VERSION--->2.0.9<!-VERSION--->, released on -<!-DATE--->Nov 27 2001<!-DATE--->) +<!-DATE--->Apr 3 2002<!-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.11 retrieving revision 1.6.2.12 diff -u -r1.6.2.11 -r1.6.2.12 --- admin/www/download.html 27 Nov 2001 22:27:42 -0000 1.6.2.11 +++ admin/www/download.html 3 Apr 2002 05:11:22 -0000 1.6.2.12 @@ -1,8 +1,9 @@ +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <HTML> <!-- THIS PAGE IS AUTOMATICALLY GENERATED. DO NOT EDIT. --> -<!-- Tue Nov 27 17:26:44 2001 --> -<!-- USING HT2HTML 1.2 --> -<!-- SEE http://barry.wooz.org/software/ht2html --> +<!-- Wed Apr 3 00:10:44 2002 --> +<!-- USING HT2HTML 2.0 --> +<!-- SEE http://ht2html.sf.net --> <!-- User-specified headers: Title: Downloading Mailman @@ -10,30 +11,36 @@ <HEAD> <TITLE>Downloading Mailman</TITLE> +<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=us-ascii"> +<STYLE TYPE="text/css"> +<!-- +body { margin: 0px; } +--> +</STYLE> </HEAD> <BODY BGCOLOR="#ffffff" TEXT="#000000" - TOPMARGIN="0" LEFTMARGIN="0" MARGINWIDTH="0" MARGINHEIGHT="0" + MARGINWIDTH="0" MARGINHEIGHT="0" LINK="#0000bb" VLINK="#551a8b" ALINK="#ff0000"> <!-- start of page table --> -<TABLE WIDTH="100%" BORDER=0 CELLSPACING=0 CELLPADDING=0> +<TABLE WIDTH="100%" BORDER="0" CELLSPACING="0" CELLPADDING="0"> <!-- start of banner row --> <TR> <!-- start of corner cells --> -<TD WIDTH=150 VALIGN=CENTER BGCOLOR="black"> +<TD WIDTH="150" VALIGN="MIDDLE" BGCOLOR="black"> <center> <a href="./index.html"> <img border=0 src="./images/logo-70.jpg"></a></center> </TD> -<TD WIDTH=15 BGCOLOR="#99997c"> </TD><!--spacer--> +<TD WIDTH="15" BGCOLOR="#99997c"> </TD><!--spacer--> <!-- end of corner cells --> <!-- start of banner --> <TD WIDTH="90%" BGCOLOR="#99997c"> <!-- start of site links table --> -<TABLE WIDTH="100%" BORDER=0 +<TABLE WIDTH="100%" BORDER="0" CELLSPACING=0 CELLPADDING=0 - COLS=3 ROWS=4 BGCOLOR="#ffffff"> + BGCOLOR="#ffffff"> <TR> <TD BGCOLOR="#99997c"> <a href="./index.html">Home</a> @@ -81,9 +88,9 @@ </TR><!-- end of banner row --> <TR><!-- start of sidebar/body row --> <!-- start of sidebar cells --> -<TD WIDTH=150 VALIGN=TOP BGCOLOR="#99997c"> +<TD WIDTH="150" VALIGN="TOP" BGCOLOR="#99997c"> <!-- start of sidebar table --> -<TABLE WIDTH="100%" BORDER=0 CELLSPACING=0 CELLPADDING=3 +<TABLE WIDTH="100%" BORDER="0" CELLSPACING="0" CELLPADDING="3" BGCOLOR="#ffffff"> <TR><TD BGCOLOR="#663300"><B><FONT COLOR="#ffffff"> Overview @@ -184,10 +191,10 @@ </TABLE><!-- end of sidebar table --> </TD> -<TD WIDTH=15> </TD><!--spacer--> +<TD WIDTH="15"> </TD><!--spacer--> <!-- end of sidebar cell --> <!-- start of body cell --> -<TD VALIGN=TOP WIDTH="90%"><BR> +<TD VALIGN="TOP" WIDTH="90%"><BR> <h3>Requirements</h3> <p>Mailman currently runs only on Unix-y systems, such as Linux, @@ -240,9 +247,9 @@ <h3>Downloading</h3> <p>Version -(<!-VERSION--->2.0.8<!-VERSION--->, +(<!-VERSION--->2.0.9<!-VERSION--->, released on -<!-DATE--->Nov 27 2001<!-DATE--->) +<!-DATE--->Apr 3 2002<!-DATE--->) is the current GNU release. It is available from the following mirror sites: <ul> Index: cron/qrunner =================================================================== RCS file: /cvsroot/mailman/mailman/cron/Attic/qrunner,v retrieving revision 1.18.2.3 retrieving revision 1.18.2.4 diff -u -r1.18.2.3 -r1.18.2.4 --- cron/qrunner 18 Apr 2001 03:58:35 -0000 1.18.2.3 +++ cron/qrunner 2 Apr 2002 22:38:50 -0000 1.18.2.4 @@ -195,13 +195,13 @@ lock.refresh() root, ext = os.path.splitext(os.path.join(mm_cfg.QUEUE_DIR, file)) if ext == '.db': - # If the .db file has no corresponding .msg file, we might as well - # remove the .db file, since there's little we can do about it. - if not os.path.exists(root+'.msg'): - syslog('qrunner', 'Unlinking orphaned .db file: %s.db' % root) - os.unlink(root+'.db') - # just trigger off the .msg files + # Just trigger off the .msg files. This may leave stale .db files + # in qfiles, but these can't be cleaned up without storing a + # timestamp and watching out for race conditions. continue + if not os.path.exists(root+'.db'): + syslog('qrunner', 'Unlinking orphaned .msg file: %s.msg' % root) + os.unlink(root+'.msg') # Have we exceeded either resource limit? if mm_cfg.QRUNNER_PROCESS_LIFETIME is not None and \ (time.time() - t0) > mm_cfg.QRUNNER_PROCESS_LIFETIME: