Merge authors:
  Jim Popovitch (jimpop)
Related merge proposals:
  https://code.launchpad.net/~jimpop/mailman/security-logging/+merge/347728
  proposed by: Jim Popovitch (jimpop)
  review: Approve - Mark Sapiro (msapiro)
  review: Resubmit - Jim Popovitch (jimpop)
------------------------------------------------------------
revno: 1768 [merge]
committer: Mark Sapiro <m...@msapiro.net>
branch nick: 2.1
timestamp: Mon 2018-06-11 09:59:26 -0700
message:
  Implement security log.
modified:
  Mailman/Cgi/admin.py
  Mailman/Cgi/admindb.py
  Mailman/Cgi/edithtml.py
  Mailman/Cgi/options.py
  Mailman/Cgi/private.py
  Mailman/Cgi/roster.py
  Mailman/Utils.py
  NEWS


--
lp:mailman/2.1
https://code.launchpad.net/~mailman-coders/mailman/2.1

Your team Mailman Checkins is subscribed to branch lp:mailman/2.1.
To unsubscribe from this branch go to 
https://code.launchpad.net/~mailman-coders/mailman/2.1/+edit-subscription
=== modified file 'Mailman/Cgi/admin.py'
--- Mailman/Cgi/admin.py	2017-06-21 16:59:41 +0000
+++ Mailman/Cgi/admin.py	2018-06-11 16:59:26 +0000
@@ -119,6 +119,13 @@
         if cgidata.has_key('adminpw'):
             # This is a re-authorization attempt
             msg = Bold(FontSize('+1', _('Authorization failed.'))).Format()
+            remote = os.environ.get('HTTP_FORWARDED_FOR',
+                     os.environ.get('HTTP_X_FORWARDED_FOR',
+                     os.environ.get('REMOTE_ADDR',
+                                    'unidentified origin')))
+            syslog('security',
+                   'Authorization failed (admin): list=%s: remote=%s',
+                   listname, remote)
         else:
             msg = ''
         Auth.loginpage(mlist, 'admin', msg=msg)

=== modified file 'Mailman/Cgi/admindb.py'
--- Mailman/Cgi/admindb.py	2017-06-24 21:34:48 +0000
+++ Mailman/Cgi/admindb.py	2018-06-11 16:59:26 +0000
@@ -159,6 +159,13 @@
         if cgidata.has_key('adminpw'):
             # This is a re-authorization attempt
             msg = Bold(FontSize('+1', _('Authorization failed.'))).Format()
+            remote = os.environ.get('HTTP_FORWARDED_FOR',
+                     os.environ.get('HTTP_X_FORWARDED_FOR',
+                     os.environ.get('REMOTE_ADDR',
+                                    'unidentified origin')))
+            syslog('security',
+                   'Authorization failed (admindb): list=%s: remote=%s',
+                   listname, remote)
         else:
             msg = ''
         Auth.loginpage(mlist, 'admindb', msg=msg)

=== modified file 'Mailman/Cgi/edithtml.py'
--- Mailman/Cgi/edithtml.py	2017-06-06 05:47:05 +0000
+++ Mailman/Cgi/edithtml.py	2018-06-11 16:59:26 +0000
@@ -126,6 +126,13 @@
         if cgidata.has_key('admlogin'):
             # This is a re-authorization attempt
             msg = Bold(FontSize('+1', _('Authorization failed.'))).Format()
+            remote = os.environ.get('HTTP_FORWARDED_FOR',
+                     os.environ.get('HTTP_X_FORWARDED_FOR',
+                     os.environ.get('REMOTE_ADDR',
+                                    'unidentified origin')))
+            syslog('security',
+                   'Authorization failed (edithtml): list=%s: remote=%s',
+                   listname, remote)
         else:
             msg = ''
         Auth.loginpage(mlist, 'admin', msg=msg)

=== modified file 'Mailman/Cgi/options.py'
--- Mailman/Cgi/options.py	2018-02-04 16:41:19 +0000
+++ Mailman/Cgi/options.py	2018-06-11 16:59:26 +0000
@@ -288,13 +288,16 @@
         # message.
         if cgidata.has_key('password'):
             doc.addError(_('Authentication failed.'))
+            remote = os.environ.get('HTTP_FORWARDED_FOR',
+                     os.environ.get('HTTP_X_FORWARDED_FOR',
+                     os.environ.get('REMOTE_ADDR',
+                                    'unidentified origin')))
+            syslog('security',
+                 'Authorization failed (private): user=%s: list=%s: remote=%s',
+                   user, listname, remote)
             # So as not to allow membership leakage, prompt for the email
             # address and the password here.
             if mlist.private_roster <> 0:
-                remote = os.environ.get('HTTP_FORWARDED_FOR',
-                         os.environ.get('HTTP_X_FORWARDED_FOR',
-                         os.environ.get('REMOTE_ADDR',
-                                        'unidentified origin')))
                 syslog('mischief',
                        'Login failure with private rosters: %s from %s',
                        user, remote)

=== modified file 'Mailman/Cgi/private.py'
--- Mailman/Cgi/private.py	2017-06-06 05:47:05 +0000
+++ Mailman/Cgi/private.py	2018-06-11 16:59:26 +0000
@@ -142,6 +142,13 @@
         if cgidata.has_key('submit'):
             # This is a re-authorization attempt
             message = Bold(FontSize('+1', _('Authorization failed.'))).Format()
+            remote = os.environ.get('HTTP_FORWARDED_FOR',
+                     os.environ.get('HTTP_X_FORWARDED_FOR',
+                     os.environ.get('REMOTE_ADDR',
+                                    'unidentified origin')))
+            syslog('security',
+                 'Authorization failed (private): user=%s: list=%s: remote=%s',
+                   username, listname, remote)
             # give an HTTP 401 for authentication failure
             print 'Status: 401 Unauthorized'
         # Are we processing a password reminder from the login screen?

=== modified file 'Mailman/Cgi/roster.py'
--- Mailman/Cgi/roster.py	2017-06-06 03:48:34 +0000
+++ Mailman/Cgi/roster.py	2018-06-11 16:59:26 +0000
@@ -118,6 +118,13 @@
         error_page_doc(doc, _('%(realname)s roster authentication failed.'))
         doc.AddItem(mlist.GetMailmanFooter())
         print doc.Format()
+        remote = os.environ.get('HTTP_FORWARDED_FOR',
+                 os.environ.get('HTTP_X_FORWARDED_FOR',
+                 os.environ.get('REMOTE_ADDR',
+                                'unidentified origin')))
+        syslog('security',
+               'Authorization failed (roster): list=%s: remote=%s',
+               listname, remote)
         return
 
     # The document and its language

=== modified file 'Mailman/Utils.py'
--- Mailman/Utils.py	2018-06-05 19:14:08 +0000
+++ Mailman/Utils.py	2018-06-11 16:59:26 +0000
@@ -111,7 +111,12 @@
     # But first ensure the list name doesn't contain a path traversal
     # attack.
     if len(re.sub(mm_cfg.ACCEPTABLE_LISTNAME_CHARACTERS, '', listname)) > 0:
-        syslog('mischief', 'Hostile listname: %s', listname)
+        remote = os.environ.get('HTTP_FORWARDED_FOR',
+                 os.environ.get('HTTP_X_FORWARDED_FOR',
+                 os.environ.get('REMOTE_ADDR',
+                                'unidentified origin')))
+        syslog('mischief',
+               'Hostile listname: listname=%s: remote=%s', listname, remote)
         return False
     basepath = Site.get_listpath(listname)
     for ext in ('.pck', '.pck.last', '.db', '.db.last'):

=== modified file 'NEWS'
--- NEWS	2018-06-05 19:14:08 +0000
+++ NEWS	2018-06-11 16:59:26 +0000
@@ -30,6 +30,15 @@
       py2-ipaddress module is installed.  The module can be installed via pip
       if not included in your Python.
 
+    - Thanks to Jim Popovitch, Mailman has a new 'security' log and logs
+      authentication failures to the various web CGI functions.  The logged
+      data include the remote IP and can be used to automate blocking of IPs
+      with something like fail2ban.  Since Mailman 2.1.14, these have returned
+      an http 401 status and the information should be logged by the web
+      server, but this new log makes that more convenient.  Also, the
+      'mischief' log entries for 'hostile listname' noe include the remote IP
+      if available.
+
   i18n
 
     - The Japanese translation has been updated by Yasuhito FUTATSUKI.

_______________________________________________
Mailman-checkins mailing list
Mailman-checkins@python.org
Unsubscribe: 
https://mail.python.org/mailman/options/mailman-checkins/archive%40jab.org

Reply via email to