summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHanno Böck <hanno@gentoo.org>2008-02-05 11:24:01 +0000
committerHanno Böck <hanno@gentoo.org>2008-02-05 11:24:01 +0000
commita0e5e09a344dec3b38ecff9cabf405b4e9545fc4 (patch)
tree4f35a7918f93cd79146ee05afef44f8195c881c3 /net-mail
parentStable on ppc64 (diff)
downloadgentoo-2-a0e5e09a344dec3b38ecff9cabf405b4e9545fc4.tar.gz
gentoo-2-a0e5e09a344dec3b38ecff9cabf405b4e9545fc4.tar.bz2
gentoo-2-a0e5e09a344dec3b38ecff9cabf405b4e9545fc4.zip
mailman security bump
(Portage version: 2.1.4.1)
Diffstat (limited to 'net-mail')
-rw-r--r--net-mail/mailman/ChangeLog8
-rw-r--r--net-mail/mailman/files/mailman-2.1.9-fix-XSS.patch275
-rw-r--r--net-mail/mailman/mailman-2.1.9-r3.ebuild147
3 files changed, 429 insertions, 1 deletions
diff --git a/net-mail/mailman/ChangeLog b/net-mail/mailman/ChangeLog
index 8d66c1a1a953..dda00d042dcd 100644
--- a/net-mail/mailman/ChangeLog
+++ b/net-mail/mailman/ChangeLog
@@ -1,6 +1,12 @@
# ChangeLog for net-mail/mailman
# Copyright 2002-2008 Gentoo Foundation; Distributed under the GPL v2
-# $Header: /var/cvsroot/gentoo-x86/net-mail/mailman/ChangeLog,v 1.105 2008/01/31 20:29:02 hollow Exp $
+# $Header: /var/cvsroot/gentoo-x86/net-mail/mailman/ChangeLog,v 1.106 2008/02/05 11:24:00 hanno Exp $
+
+*mailman-2.1.9-r3 (05 Feb 2008)
+
+ 05 Feb 2008; Hanno Boeck <hanno@gentoo.org>
+ +files/mailman-2.1.9-fix-XSS.patch, +mailman-2.1.9-r3.ebuild:
+ Patch XSS issues, CVE-2008-0564.
31 Jan 2008; Benedikt Böhm <hollow@gentoo.org> mailman-2.1.9.ebuild,
mailman-2.1.9-r1.ebuild, mailman-2.1.9-r2.ebuild:
diff --git a/net-mail/mailman/files/mailman-2.1.9-fix-XSS.patch b/net-mail/mailman/files/mailman-2.1.9-fix-XSS.patch
new file mode 100644
index 000000000000..b80c50dca6fd
--- /dev/null
+++ b/net-mail/mailman/files/mailman-2.1.9-fix-XSS.patch
@@ -0,0 +1,275 @@
+=== modified file 'Mailman/Cgi/edithtml.py'
+--- Mailman/Cgi/edithtml.py 2006-08-30 14:54:22 +0000
++++ Mailman/Cgi/edithtml.py 2007-12-04 19:52:18 +0000
+@@ -1,4 +1,4 @@
+-# Copyright (C) 1998-2006 by the Free Software Foundation, Inc.
++# Copyright (C) 1998-2007 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
+@@ -159,7 +159,20 @@
+ doc.AddItem('<hr>')
+ return
+ code = cgi_info['html_code'].value
+- code = re.sub(r'<([/]?script.*?)>', r'&lt;\1&gt;', code)
++ if Utils.suspiciousHTML(code):
++ doc.AddItem(Header(3,
++ _("""The page you saved contains suspicious HTML that could
++potentially expose your users to cross-site scripting attacks. This change
++has therefore been rejected. If you still want to make these changes, you
++must have shell access to your Mailman server.
++ """)))
++ doc.AddItem(_('See '))
++ doc.AddItem(Link(
++'http://www.python.org/cgi-bin/faqw-mm.py?req=show&file=faq04.048.htp',
++ _('FAQ 4.48.')))
++ doc.AddItem(Header(3,_("Page Unchanged.")))
++ doc.AddItem('<hr>')
++ return
+ langdir = os.path.join(mlist.fullpath(), mlist.preferred_language)
+ # Make sure the directory exists
+ omask = os.umask(0)
+
+=== modified file 'Mailman/Gui/General.py'
+--- Mailman/Gui/General.py 2006-08-30 14:54:22 +0000
++++ Mailman/Gui/General.py 2007-12-04 19:52:18 +0000
+@@ -1,4 +1,4 @@
+-# Copyright (C) 2001-2006 by the Free Software Foundation, Inc.
++# Copyright (C) 2001-2007 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
+@@ -436,17 +442,21 @@
+ # Convert any html entities to Unicode
+ mlist.subject_prefix = Utils.canonstr(
+ val, mlist.preferred_language)
++ elif property == 'info':
++ if val <> mlist.info:
++ if Utils.suspiciousHTML(val):
++ doc.addError(_("""The <b>info</b> attribute you saved
++contains suspicious HTML that could potentially expose your users to cross-site
++scripting attacks. This change has therefore been rejected. If you still want
++to make these changes, you must have shell access to your Mailman server.
++This change can be made with bin/withlist or with bin/config_list by setting
++mlist.info.
++ """))
++ else:
++ mlist.info = val
+ else:
+ GUIBase._setValue(self, mlist, property, val, doc)
+
+- def _escape(self, property, value):
+- # The 'info' property allows HTML, but let's sanitize it to avoid XSS
+- # exploits. Everything else should be fully escaped.
+- if property <> 'info':
+- return GUIBase._escape(self, property, value)
+- # Sanitize <script> and </script> tags but nothing else. Not the best
+- # solution, but expedient.
+- return re.sub(r'(?i)<([/]?script.*?)>', r'&lt;\1&gt;', value)
+
+ def _postValidate(self, mlist, doc):
+ if not mlist.reply_to_address.strip() and \
+
+=== modified file 'Mailman/Gui/GUIBase.py'
+--- Mailman/Gui/GUIBase.py 2005-08-27 01:40:17 +0000
++++ Mailman/Gui/GUIBase.py 2007-11-18 20:01:26 +0000
+@@ -1,4 +1,4 @@
+-# Copyright (C) 2002-2004 by the Free Software Foundation, Inc.
++# Copyright (C) 2002-2007 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
+@@ -12,7 +12,8 @@
+ #
+ # You should have received a copy of the GNU General Public License
+ # along with this program; if not, write to the Free Software
+-# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
++# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
++# USA.
+
+ """Base class for all web GUI components."""
+
+@@ -122,10 +127,6 @@
+ # Validate all the attributes for this category
+ pass
+
+- def _escape(self, property, value):
+- value = value.replace('<', '&lt;')
+- return value
+-
+ def handleForm(self, mlist, category, subcat, cgidata, doc):
+ for item in self.GetConfigInfo(mlist, category, subcat):
+ # Skip descriptions and legacy non-attributes
+@@ -144,10 +145,9 @@
+ elif not cgidata.has_key(property):
+ continue
+ elif isinstance(cgidata[property], ListType):
+- val = [self._escape(property, x.value)
+- for x in cgidata[property]]
++ val = [x.value for x in cgidata[property]]
+ else:
+- val = self._escape(property, cgidata[property].value)
++ val = cgidata[property].value
+ # Coerce the value to the expected type, raising exceptions if the
+ # value is invalid.
+ try:
+
+=== modified file 'Mailman/Utils.py'
+--- Mailman/Utils.py 2007-11-25 08:04:30 +0000
++++ Mailman/Utils.py 2007-12-04 19:52:18 +0000
+@@ -876,3 +876,154 @@
+ except (LookupError, UnicodeError, ValueError, HeaderParseError):
+ # possibly charset problem. return with undecoded string in one line.
+ return EMPTYSTRING.join(s.splitlines())
++
++
++# Patterns and functions to flag possible XSS attacks in HTML.
++# This list is compiled from information at http://ha.ckers.org/xss.html,
++# http://www.quirksmode.org/js/events_compinfo.html,
++# http://www.htmlref.com/reference/appa/events1.htm,
++# http://lxr.mozilla.org/mozilla/source/content/events/src/nsDOMEvent.cpp#59,
++# http://www.w3.org/TR/DOM-Level-2-Events/events.html and
++# http://www.xulplanet.com/references/elemref/ref_EventHandlers.html
++# Many thanks are due to Moritz Naumann for his assistance with this.
++_badwords = [
++ '<i?frame',
++ '<link',
++ '<meta',
++ '<script',
++ r'(?:^|\W)j(?:ava)?script(?:\W|$)',
++ r'(?:^|\W)vbs(?:cript)?(?:\W|$)',
++ r'(?:^|\W)domactivate(?:\W|$)',
++ r'(?:^|\W)domattrmodified(?:\W|$)',
++ r'(?:^|\W)domcharacterdatamodified(?:\W|$)',
++ r'(?:^|\W)domfocus(?:in|out)(?:\W|$)',
++ r'(?:^|\W)dommenuitem(?:in)?active(?:\W|$)',
++ r'(?:^|\W)dommousescroll(?:\W|$)',
++ r'(?:^|\W)domnodeinserted(?:intodocument)?(?:\W|$)',
++ r'(?:^|\W)domnoderemoved(?:fromdocument)?(?:\W|$)',
++ r'(?:^|\W)domsubtreemodified(?:\W|$)',
++ r'(?:^|\W)fscommand(?:\W|$)',
++ r'(?:^|\W)onabort(?:\W|$)',
++ r'(?:^|\W)on(?:de)?activate(?:\W|$)',
++ r'(?:^|\W)on(?:after|before)print(?:\W|$)',
++ r'(?:^|\W)on(?:after|before)update(?:\W|$)',
++ r'(?:^|\W)onbefore(?:(?:de)?activate|copy|cut|editfocus|paste)(?:\W|$)',
++ r'(?:^|\W)onbeforeunload(?:\W|$)',
++ r'(?:^|\W)onbegin(?:\W|$)',
++ r'(?:^|\W)onblur(?:\W|$)',
++ r'(?:^|\W)onbounce(?:\W|$)',
++ r'(?:^|\W)onbroadcast(?:\W|$)',
++ r'(?:^|\W)on(?:cell)?change(?:\W|$)',
++ r'(?:^|\W)oncheckboxstatechange(?:\W|$)',
++ r'(?:^|\W)on(?:dbl)?click(?:\W|$)',
++ r'(?:^|\W)onclose(?:\W|$)',
++ r'(?:^|\W)oncommand(?:update)?(?:\W|$)',
++ r'(?:^|\W)oncomposition(?:end|start)(?:\W|$)',
++ r'(?:^|\W)oncontextmenu(?:\W|$)',
++ r'(?:^|\W)oncontrolselect(?:\W|$)',
++ r'(?:^|\W)oncopy(?:\W|$)',
++ r'(?:^|\W)oncut(?:\W|$)',
++ r'(?:^|\W)ondataavailable(?:\W|$)',
++ r'(?:^|\W)ondataset(?:changed|complete)(?:\W|$)',
++ r'(?:^|\W)ondrag(?:drop|end|enter|exit|gesture|leave|over)?(?:\W|$)',
++ r'(?:^|\W)ondragstart(?:\W|$)',
++ r'(?:^|\W)ondrop(?:\W|$)',
++ r'(?:^|\W)onend(?:\W|$)',
++ r'(?:^|\W)onerror(?:update)?(?:\W|$)',
++ r'(?:^|\W)onfilterchange(?:\W|$)',
++ r'(?:^|\W)onfinish(?:\W|$)',
++ r'(?:^|\W)onfocus(?:in|out)?(?:\W|$)',
++ r'(?:^|\W)onhelp(?:\W|$)',
++ r'(?:^|\W)oninput(?:\W|$)',
++ r'(?:^|\W)onkey(?:up|down|press)(?:\W|$)',
++ r'(?:^|\W)onlayoutcomplete(?:\W|$)',
++ r'(?:^|\W)on(?:un)?load(?:\W|$)',
++ r'(?:^|\W)onlosecapture(?:\W|$)',
++ r'(?:^|\W)onmedia(?:complete|error)(?:\W|$)',
++ r'(?:^|\W)onmouse(?:down|enter|leave|move|out|over|up|wheel)(?:\W|$)',
++ r'(?:^|\W)onmove(?:end|start)?(?:\W|$)',
++ r'(?:^|\W)on(?:off|on)line(?:\W|$)',
++ r'(?:^|\W)onoutofsync(?:\W|$)',
++ r'(?:^|\W)onoverflow(?:changed)?(?:\W|$)',
++ r'(?:^|\W)onpage(?:hide|show)(?:\W|$)',
++ r'(?:^|\W)onpaint(?:\W|$)',
++ r'(?:^|\W)onpaste(?:\W|$)',
++ r'(?:^|\W)onpause(?:\W|$)',
++ r'(?:^|\W)onpopup(?:hidden|hiding|showing|shown)(?:\W|$)',
++ r'(?:^|\W)onprogress(?:\W|$)',
++ r'(?:^|\W)onpropertychange(?:\W|$)',
++ r'(?:^|\W)onradiostatechange(?:\W|$)',
++ r'(?:^|\W)onreadystatechange(?:\W|$)',
++ r'(?:^|\W)onrepeat(?:\W|$)',
++ r'(?:^|\W)onreset(?:\W|$)',
++ r'(?:^|\W)onresize(?:end|start)?(?:\W|$)',
++ r'(?:^|\W)onresume(?:\W|$)',
++ r'(?:^|\W)onreverse(?:\W|$)',
++ r'(?:^|\W)onrow(?:delete|enter|exit|inserted)(?:\W|$)',
++ r'(?:^|\W)onrows(?:delete|enter|inserted)(?:\W|$)',
++ r'(?:^|\W)onscroll(?:\W|$)',
++ r'(?:^|\W)onseek(?:\W|$)',
++ r'(?:^|\W)onselect(?:start)?(?:\W|$)',
++ r'(?:^|\W)onselectionchange(?:\W|$)',
++ r'(?:^|\W)onstart(?:\W|$)',
++ r'(?:^|\W)onstop(?:\W|$)',
++ r'(?:^|\W)onsubmit(?:\W|$)',
++ r'(?:^|\W)onsync(?:from|to)preference(?:\W|$)',
++ r'(?:^|\W)onsyncrestored(?:\W|$)',
++ r'(?:^|\W)ontext(?:\W|$)',
++ r'(?:^|\W)ontimeerror(?:\W|$)',
++ r'(?:^|\W)ontrackchange(?:\W|$)',
++ r'(?:^|\W)onunderflow(?:\W|$)',
++ r'(?:^|\W)onurlflip(?:\W|$)',
++ r'(?:^|\W)seeksegmenttime(?:\W|$)',
++ r'(?:^|\W)svgabort(?:\W|$)',
++ r'(?:^|\W)svgerror(?:\W|$)',
++ r'(?:^|\W)svgload(?:\W|$)',
++ r'(?:^|\W)svgresize(?:\W|$)',
++ r'(?:^|\W)svgscroll(?:\W|$)',
++ r'(?:^|\W)svgunload(?:\W|$)',
++ r'(?:^|\W)svgzoom(?:\W|$)',
++ ]
++
++
++# This is the actual re to look for the above patterns
++_badhtml = re.compile('|'.join(_badwords), re.IGNORECASE)
++# This is used to filter non-printable us-ascii characters, some of which
++# can be used to break words to avoid recognition.
++_filterchars = re.compile('[\000-\011\013\014\016-\037\177-\237]')
++# This is used to recognize '&#' and '%xx' strings for _translate which
++# translates them to characters
++_encodedchars = re.compile('(&#[0-9]+;?)|(&#x[0-9a-f]+;?)|(%[0-9a-f]{2})',
++ re.IGNORECASE)
++
++
++def _translate(mo):
++ """Translate &#... and %xx encodings into the encoded character."""
++ match = mo.group().lower().strip('&#;')
++ try:
++ if match.startswith('x') or match.startswith('%'):
++ val = int(match[1:], 16)
++ else:
++ val = int(match, 10)
++ except ValueError:
++ return ''
++ if val < 256:
++ return chr(val)
++ else:
++ return ''
++
++
++def suspiciousHTML(html):
++ """Check HTML string for various tags, script language names and
++ 'onxxx' actions that can be used in XSS attacks.
++ Currently, this a very simple minded test. It just looks for
++ patterns without analyzing context. Thus, it potentially flags lots
++ of benign stuff.
++ Returns True if anything suspicious found, False otherwise.
++ """
++
++ if _badhtml.search(_filterchars.sub(
++ '', _encodedchars.sub(_translate, html))):
++ return True
++ else:
++ return False
+
diff --git a/net-mail/mailman/mailman-2.1.9-r3.ebuild b/net-mail/mailman/mailman-2.1.9-r3.ebuild
new file mode 100644
index 000000000000..78941571db85
--- /dev/null
+++ b/net-mail/mailman/mailman-2.1.9-r3.ebuild
@@ -0,0 +1,147 @@
+# Copyright 1999-2008 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+# $Header: /var/cvsroot/gentoo-x86/net-mail/mailman/mailman-2.1.9-r3.ebuild,v 1.1 2008/02/05 11:24:00 hanno Exp $
+
+inherit eutils python multilib
+
+DESCRIPTION="A python-based mailing list server with an extensive web interface"
+SRC_URI="mirror://sourceforge/${PN}/${P}.tgz"
+HOMEPAGE="http://www.list.org/"
+
+SLOT="0"
+LICENSE="GPL-2"
+KEYWORDS="~amd64 ~ppc ~sparc ~x86"
+IUSE=""
+
+DEPEND=">=dev-lang/python-2.3
+ virtual/mta
+ virtual/cron
+ virtual/httpd-cgi"
+
+pkg_setup() {
+ INSTALLDIR=${MAILMAN_PREFIX:-"/usr/$(get_libdir)/mailman"}
+ VAR_PREFIX=${MAILMAN_VAR_PREFIX:-"/var/lib/mailman"}
+ CGIGID=${MAILMAN_CGIGID:-81}
+ MAILUSR=${MAILMAN_MAILUSR:-mailman}
+ MAILUID=${MAILMAN_MAILUID:-280}
+ MAILGRP=${MAILMAN_MAILGRP:-mailman}
+ MAILGID=${MAILMAN_MAILGID:-280}
+
+ # Bug #58526: switch to enew{group,user}.
+ # need to add mailman here for compile process.
+ # Duplicated at pkg_postinst() for binary install.
+ enewgroup ${MAILGRP} ${MAILGID}
+ enewuser ${MAILUSR} ${MAILUID} /bin/bash ${INSTALLDIR} mailman -G cron -c "mailman"
+}
+
+src_unpack() {
+ unpack ${A}
+ cd "${S}"
+ epatch "${FILESDIR}/${PN}-2.1.8_rc1-directory-check.patch" || die "patch failed."
+ epatch "${FILESDIR}/mailman-2.1.9-fix-XSS.patch" || die "patch failed."
+}
+
+src_compile() {
+ econf --without-permcheck \
+ --prefix="${INSTALLDIR}" \
+ --with-mail-gid=${MAILGID} \
+ --with-cgi-gid=${CGIGID} \
+ --with-cgi-ext="${MAILMAN_CGIEXT}" \
+ --with-var-prefix="${VAR_PREFIX}" \
+ --with-username=${MAILUSR} \
+ --with-groupname=${MAILGRP} \
+ || die "configure failed"
+
+ emake || die "make failed"
+}
+
+src_install () {
+ emake "DESTDIR=${D}" doinstall || die
+
+ insinto /etc/apache2/modules.d
+ doins "${FILESDIR}/50_mailman.conf"
+ dosed "s:/usr/local/mailman/cgi-bin:${INSTALLDIR}/cgi-bin:g" /etc/apache2/modules.d/50_mailman.conf
+ dosed "s:/usr/local/mailman/archives:${VAR_PREFIX}/archives:g" /etc/apache2/modules.d/50_mailman.conf
+
+ newdoc "${FILESDIR}/README.gentoo-r2" README.gentoo || die "newdoc failed"
+
+ dodoc ACK* BUGS FAQ NEWS README* TODO UPGRADING INSTALL contrib/mailman.mc \
+ contrib/README.check_perms_grsecurity contrib/virtusertable || die "dodoc failed"
+
+ exeinto ${INSTALLDIR}/bin
+ doexe build/contrib/*.py contrib/majordomo2mailman.pl contrib/auto \
+ contrib/mm-handler* || die
+
+ dodir /etc/mailman
+ mv "${D}/${INSTALLDIR}/Mailman/mm_cfg.py" "${D}/etc/mailman"
+ dosym /etc/mailman/mm_cfg.py ${INSTALLDIR}/Mailman/mm_cfg.py
+
+ # Save the old config for updates from pre-2.1.9-r2
+ # To be removed some distant day
+ for i in /var/mailman /home/mailman /usr/local/mailman ${INSTALLDIR}
+ do
+ if [ -f ${i}/Mailman/mm_cfg.py ] && ! [ -L ${i}/Mailman/mm_cfg.py ]; then
+ cp ${i}/Mailman/mm_cfg.py "${D}/etc/mailman/mm_cfg.py"
+ fi
+ done
+
+ newinitd "${FILESDIR}/mailman.rc" mailman
+
+ keepdir ${VAR_PREFIX}/logs
+ keepdir ${VAR_PREFIX}/locks
+ keepdir ${VAR_PREFIX}/spam
+ keepdir ${VAR_PREFIX}/archives/public
+ keepdir ${VAR_PREFIX}/archives/private
+ keepdir ${VAR_PREFIX}/lists
+ keepdir ${VAR_PREFIX}/qfiles
+
+ chown -R ${MAILUSR}:${MAILGRP} "${D}/${VAR_PREFIX}" "${D}/${INSTALLDIR}" "${D}"/etc/mailman/*
+ chmod 2775 "${D}/${INSTALLDIR}" "${D}/${INSTALLDIR}"/templates/* \
+ "${D}/${INSTALLDIR}"/messages/* "${D}/${VAR_PREFIX}" "${D}/${VAR_PREFIX}"/{logs,lists,spam,locks,archives/public}
+ chmod 2750 "${D}/${VAR_PREFIX}/archives/private"
+ chmod 2770 "${D}/${VAR_PREFIX}/qfiles"
+ chmod 2755 "${D}/${INSTALLDIR}"/cgi-bin/* "${D}/${INSTALLDIR}/mail/mailman"
+
+}
+
+pkg_postinst() {
+ python_mod_optimize ${INSTALLDIR}/bin/ ${INSTALLDIR}/Mailman
+
+ enewgroup ${MAILGRP} ${MAILGID}
+ enewuser ${MAILUSR} ${MAILUID} -1 ${INSTALLDIR} mailman -G cron -c "mailman"
+ elog
+ elog "Please read /usr/share/doc/${PF}/README.gentoo.bz2 for additional"
+ elog "Setup information, mailman will NOT run unless you follow"
+ elog "those instructions!"
+ elog
+
+ elog "An example Mailman configuration file for Apache has been installed into:"
+ elog " ${APACHE_MODULES_CONFDIR}/50_mailman.conf"
+ elog
+ elog "To enable, you will need to add \"-D MAILMAN\" to"
+ elog "/etc/conf.d/apache2."
+ elog
+
+ ewarn "Default-Configuration has changed deeply in 2.1.9-r2. You can configure"
+ ewarn "mailman with the following variables:"
+ ewarn "MAILMAN_PREFIX (default: /usr/$(get_libdir)/mailman)"
+ ewarn "MAILMAN_VAR_PREFIX (default: /var/lib/mailman)"
+ ewarn "MAILMAN_CGIGID (default: 81)"
+ ewarn "MAILMAN_CGIEXT (default: empty)"
+ ewarn "MAILMAN_MAILUSR (default: mailman)"
+ ewarn "MAILMAN_MAILUID (default: 280)"
+ ewarn "MAILMAN_MAILGRP (default: mailman)"
+ ewarn "MAILMAN_MAILGID (default: 280)"
+ ewarn
+ ewarn "Config file is now symlinked in /etc/mailman, so etc-update works."
+ ewarn
+ ewarn "If you're upgrading from below 2.1.9-r2 or changed MAILMAN_PREFIX, you"
+ ewarn "MUST change the homedir of the mailman-user manually:"
+ ewarn "usermod -d ${INSTALLDIR} mailman"
+ ebeep
+}
+
+pkg_postrm() {
+ INSTALLDIR=${MAILMAN_PREFIX:-"/usr/$(get_libdir)/mailman"}
+ python_mod_cleanup ${INSTALLDIR}/bin ${INSTALLDIR}/Mailman
+}