Package: mailman Severity: wishlist Tags: patch Please apply the attached patch which prevents extra subscription spam. By this I mean that on lists where admin approval is required for subscription, an annoying user could attempt to subscribe the same email address over and over again, spamming the list admin or the person they attempt to subscribe (depending on the list config).
I've posted this patch to the upstream tracker too: http://sf.net/tracker/?func=detail&aid=1527537&group_id=103&atid=300103 -- bye, pabs http://wiki.debian.org/PaulWise
Paul Wise <[EMAIL PROTECTED]> http://pabs.zip.to Prevent (and log) subscription spam diff -urNad mailman-2.1.8~/Mailman/ListAdmin.py mailman-2.1.8/Mailman/ListAdmin.py --- mailman-2.1.8~/Mailman/ListAdmin.py 2006-07-24 03:24:02.000000000 +0800 +++ mailman-2.1.8/Mailman/ListAdmin.py 2006-07-24 03:24:03.000000000 +0800 @@ -376,6 +376,10 @@ def HoldSubscription(self, addr, fullname, password, digest, lang): # Assure that the database is open for writing self.__opendb() + # Check for attempts at spamming the admin + for k, (type, data) in self.__db.items(): + if type == SUBSCRIPTION and data[1] == addr: + return 1 # Get the next unique id id = self.__nextid() # Save the information to the request database. for held subscription @@ -412,6 +416,7 @@ msg = Message.UserNotification(owneraddr, owneraddr, subject, text, self.preferred_language) msg.send(self, **{'tomoderators': 1}) + return 0 def __handlesubscription(self, record, value, comment): stime, addr, fullname, password, digest, lang = record @@ -440,6 +445,10 @@ def HoldUnsubscription(self, addr): # Assure the database is open for writing self.__opendb() + # Check for attempts at spamming the admin + for k, (type, data) in self.__db.items(): + if type == UNSUBSCRIPTION and data[1] == addr: + return 1 # Get the next unique id id = self.__nextid() # All we need to do is save the unsubscribing address @@ -464,6 +473,7 @@ msg = Message.UserNotification(owneraddr, owneraddr, subject, text, self.preferred_language) msg.send(self, **{'tomoderators': 1}) + return 0 def __handleunsubscription(self, record, value, comment): addr = record diff -urNad mailman-2.1.8~/Mailman/MailList.py mailman-2.1.8/Mailman/MailList.py --- mailman-2.1.8~/Mailman/MailList.py 2006-07-24 03:24:02.000000000 +0800 +++ mailman-2.1.8/Mailman/MailList.py 2006-07-24 03:24:03.000000000 +0800 @@ -966,6 +966,10 @@ # User confirmation required. BAW: this should probably just # accept a userdesc instance. cookie = self.pend_new(Pending.SUBSCRIPTION, userdesc) + if cookie == '': + # Someone tried to spam some random email address + syslog('mischief', 'Duplicate subscription attempt on list %s for %s by %s', self.internal_name(), email, remote) + raise Errors.MMSubscribeNeedsConfirmation # Send the user the confirmation mailback if remote is None: by = remote = '' @@ -1003,7 +1007,9 @@ # Subscription approval is required. Add this entry to the admin # requests database. BAW: this should probably take a userdesc # just like above. - self.HoldSubscription(email, name, password, digest, lang) + if self.HoldSubscription(email, name, password, digest, lang): + # Someone tried to spam the poor list admin + syslog('mischief', 'Duplicate subscription attempt on list %s for %s by %s', self.internal_name(), email, remote) raise Errors.MMNeedApproval, _( 'subscriptions to %(realname)s require moderator approval') @@ -1091,7 +1097,9 @@ if self.unsubscribe_policy == 0: self.ApprovedDeleteMember(name, whence, admin_notif, userack) else: - self.HoldUnsubscription(email) + if self.HoldUnsubscription(email): + # Someone tried to spam the poor list admin + syslog('mischief', 'Duplicate subscription attempt on list %s for %s by %s', self.internal_name(), email, whence) raise Errors.MMNeedApproval, _( 'unsubscriptions require moderator approval') diff -urNad mailman-2.1.8~/Mailman/Pending.py mailman-2.1.8/Mailman/Pending.py --- mailman-2.1.8~/Mailman/Pending.py 2005-08-27 09:40:15.000000000 +0800 +++ mailman-2.1.8/Mailman/Pending.py 2006-07-24 03:24:26.000000000 +0800 @@ -63,6 +63,16 @@ assert self.Locked() # Load the database db = self.__load() + evictions = db['evictions'] + now = time.time() + for cookie, data in db.items(): + if cookie in ('evictions', 'version'): + continue + timestamp = evictions[cookie] + if now > timestamp: + continue + if data[0] in (SUBSCRIPTION, UNSUBSCRIPTION) and data[1].address == content[0].address: + return '' # Calculate a unique cookie. Algorithm vetted by the Timbot. time() # has high resolution on Linux, clock() on Windows. random gives us # about 45 bits in Python 2.2, 53 bits on Python 2.3. The time and
signature.asc
Description: This is a digitally signed message part