[packages/mailman] Rel 3. Backport options-page membership-info-leak fixes

arekm arekm at pld-linux.org
Tue Oct 20 23:58:46 CEST 2026


commit 5347eb89ed6640829a5e30e98e3e7b59eaa1e98b
Author: Arkadiusz Miśkiewicz <arekm at maven.pl>
Date:   Tue Oct 20 23:58:12 2026 +0200

    Rel 3. Backport options-page membership-info-leak fixes

 mailman-options-membership-leak.patch | 140 ++++++++++++++++++++++++++++++++++
 mailman.spec                          |   4 +-
 2 files changed, 143 insertions(+), 1 deletion(-)
---
diff --git a/mailman.spec b/mailman.spec
index cdc915e..91683e4 100644
--- a/mailman.spec
+++ b/mailman.spec
@@ -3,7 +3,7 @@
 # Conditional build:
 %bcond_with	umbrella_hack	# break anonimization (for use with moderated umbrella list of moderated lists)
 
-%define		rel	2
+%define		rel	3
 Summary:	The GNU Mailing List Management System
 Summary(es.UTF-8):	El Sistema de Mantenimiento de listas de GNU
 Summary(pl.UTF-8):	System Zarządzania Listami Pocztowymi GNU
@@ -54,6 +54,7 @@ Patch10:	%{name}-daemonize-fds.patch
 Patch11:	%{name}-httpauth.patch
 Patch12:	%{name}-MM_FIND_USER_NAME.patch
 Patch13:	keep-original-mime-headers.patch
+Patch14:	%{name}-options-membership-leak.patch
 URL:		http://www.list.org/
 BuildRequires:	autoconf
 BuildRequires:	automake
@@ -205,6 +206,7 @@ uruchamiać mailmana.
 %patch -P11 -p1
 %patch -P12 -p1
 %patch -P13 -p1
+%patch -P14 -p1
 
 # Conflicts with python built-in email package
 sed -i -e 's,EMAILPKG=,#EMAILPKG=,g' misc/Makefile.in
diff --git a/mailman-options-membership-leak.patch b/mailman-options-membership-leak.patch
new file mode 100644
index 0000000..ce12e24
--- /dev/null
+++ b/mailman-options-membership-leak.patch
@@ -0,0 +1,140 @@
+Fix membership information leak through the options page on lists with
+private rosters (LP: #1968443, LP: #2015416, LP: #2017813) and the 500
+Internal Server Error the earlier LP: #1951769 fix could cause for a
+non-existent user (LP: #1961762).  Backport of Mark Sapiro's
+consolidated GNU Mailman 2.1.40 fix against the 2.1.39 base.
+
+--- mailman-2.1.39/Mailman/Cgi/options.py
++++ mailman-2.1.39/Mailman/Cgi/options.py
+@@ -1,4 +1,4 @@
+-# Copyright (C) 1998-2018 by the Free Software Foundation, Inc.
++# Copyright (C) 1998-2023 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
+@@ -164,13 +164,40 @@
+         loginpage(mlist, doc, None, language)
+         print doc.Format()
+         return
+-    # Sanity check the user, but only give the "no such member" error when
+-    # using public rosters, otherwise, we'll leak membership information.
++    # Sanity check the user, but we have to give the appropriate error msg
++    # to not potentially leak membership info. This is a kludge here. We
++    # have to check membership here to avoid LP: #1951769, but then we have
++    # to give the appropriate error to avoid LP: #1968443
++    msgc = _('If you are a list member, a confirmation email has been sent.')
++    msgb = _('You already have a subscription pending confirmation')
++    msga = _("""If you are a list member, your unsubscription request has been
++             forwarded to the list administrator for approval.""")
++    msgd = _("""If you are a list member,
++            your password has been emailed to you.""")
+     if not mlist.isMember(user):
+         if mlist.private_roster == 0:
+             doc.addError(_('No such member: %(safeuser)s.'))
+-            loginpage(mlist, doc, None, language)
+-            print doc.Format()
++            user = None
++        elif cgidata.has_key('login-unsub'):
++            syslog('mischief',
++                   'Unsub attempt of non-member w/ private rosters: %s',
++                   user)
++            if mlist.unsubscribe_policy:
++                doc.addError(msga, tag='')
++            else:
++                doc.addError(msgc, tag='')
++            user = None
++        elif cgidata.has_key('login-remind'):
++            syslog('mischief',
++                   'Reminder attempt of non-member w/ private rosters: %s',
++                   user)
++            doc.addError(msgd, tag='')
++            user = None
++        # We get here with a non-None user in the case of a non-member with
++        # private rosters.  This creates a possible membership leak, but we
++        # fix that a different way. See LP: #2017813.
++        loginpage(mlist, doc, user, language)
++        print doc.Format()
+         return
+ 
+     # Avoid cross-site scripting attacks
+@@ -204,10 +231,6 @@
+     i18n.set_language(userlang)
+ 
+     # Are we processing an unsubscription request from the login screen?
+-    msgc = _('If you are a list member, a confirmation email has been sent.')
+-    msgb = _('You already have a subscription pending confirmation')
+-    msga = _("""If you are a list member, your unsubscription request has been
+-             forwarded to the list administrator for approval.""")
+     if cgidata.has_key('login-unsub'):
+         # Because they can't supply a password for unsubscribing, we'll need
+         # to do the confirmation dance.
+@@ -233,39 +256,20 @@
+             finally:
+                 mlist.Unlock()
+         else:
+-            # Not a member
+-            if mlist.private_roster == 0:
+-                # Public rosters
+-                doc.addError(_('No such member: %(safeuser)s.'))
+-            else:
+-                syslog('mischief',
+-                       'Unsub attempt of non-member w/ private rosters: %s',
+-                       user)
+-                if mlist.unsubscribe_policy:
+-                    doc.addError(msga, tag='')
+-                else:
+-                    doc.addError(msgc, tag='')
++            # Not a member handled above.
++            pass
+         loginpage(mlist, doc, user, language)
+         print doc.Format()
+         return
+ 
+     # Are we processing a password reminder from the login screen?
+-    msg = _("""If you are a list member,
+-            your password has been emailed to you.""")
+     if cgidata.has_key('login-remind'):
+         if mlist.isMember(user):
+             mlist.MailUserPassword(user)
+-            doc.addError(msg, tag='')
++            doc.addError(msgd, tag='')
+         else:
+-            # Not a member
+-            if mlist.private_roster == 0:
+-                # Public rosters
+-                doc.addError(_('No such member: %(safeuser)s.'))
+-            else:
+-                syslog('mischief',
+-                       'Reminder attempt of non-member w/ private rosters: %s',
+-                       user)
+-                doc.addError(msg, tag='')
++            # Not a member handled above.
++            pass
+         loginpage(mlist, doc, user, language)
+         print doc.Format()
+         return
+@@ -293,7 +297,9 @@
+         # to authenticate via cgi (instead of cookie), then print an error
+         # message.
+         if cgidata.has_key('password'):
+-            doc.addError(_('Authentication failed.'))
++            if mlist.private_roster == 0:
++                # Only add error with public rosters lp: #2015416
++                doc.addError(_('Authentication failed.'))
+             remote = os.environ.get('HTTP_FORWARDED_FOR',
+                      os.environ.get('HTTP_X_FORWARDED_FOR',
+                      os.environ.get('REMOTE_ADDR',
+@@ -307,9 +313,11 @@
+                 syslog('mischief',
+                        'Login failure with private rosters: %s from %s',
+                        user, remote)
+-                user = None
++                # Don't clear user here. See LP: #2017813.
+             # give an HTTP 401 for authentication failure
+-            print 'Status: 401 Unauthorized'
++            if mlist.private_roster == 0:
++                # Only add error with public rosters lp: #2015416
++                print 'Status: 401 Unauthorized'
+         loginpage(mlist, doc, user, language)
+         print doc.Format()
+         return
================================================================

---- gitweb:

http://git.pld-linux.org/gitweb.cgi/packages/mailman.git/commitdiff/5347eb89ed6640829a5e30e98e3e7b59eaa1e98b



More information about the pld-cvs-commit mailing list