diff options
| author | bwarsaw | 2006-12-29 22:20:25 +0000 |
|---|---|---|
| committer | bwarsaw | 2006-12-29 22:20:25 +0000 |
| commit | f4a456a83b630feb294724ab462c87ca1ce1c3ae (patch) | |
| tree | c5c88540dae8306d11671f603d8975b01803ea16 /Mailman/SecurityManager.py | |
| parent | ae185106a624bfa7888aa8722d35194d3c5150e8 (diff) | |
| download | mailman-f4a456a83b630feb294724ab462c87ca1ce1c3ae.tar.gz mailman-f4a456a83b630feb294724ab462c87ca1ce1c3ae.tar.zst mailman-f4a456a83b630feb294724ab462c87ca1ce1c3ae.zip | |
Diffstat (limited to 'Mailman/SecurityManager.py')
| -rw-r--r-- | Mailman/SecurityManager.py | 65 |
1 files changed, 13 insertions, 52 deletions
diff --git a/Mailman/SecurityManager.py b/Mailman/SecurityManager.py index 3865071b5..6740a958f 100644 --- a/Mailman/SecurityManager.py +++ b/Mailman/SecurityManager.py @@ -28,7 +28,7 @@ # # Each cookie has the following ingredients: the authorization context's # secret (i.e. the password, and a timestamp. We generate an SHA1 hex -# digest of these ingredients, which we call the `mac'. We then marshal +# digest of these ingredients, which we call the 'mac'. We then marshal # up a tuple of the timestamp and the mac, hexlify that and return that as # a cookie keyed off the authcontext. Note that authenticating the user # also requires the user's email address to be included in the cookie. @@ -48,7 +48,6 @@ import os import re -import md5 import sha import time import urllib @@ -64,19 +63,15 @@ from Mailman import Errors from Mailman import Utils from Mailman.configuration import config -try: - import crypt -except ImportError: - crypt = None - log = logging.getLogger('mailman.error') +dlog = logging.getLogger('mailman.debug') + +SLASH = '/' class SecurityManager: def InitVars(self): - # We used to set self.password here, from a crypted_password argument, - # but that's been removed when we generalized the mixin architecture. # self.password is really a SecurityManager attribute, but it's set in # MailList.InitVars(). self.mod_password = None @@ -144,50 +139,15 @@ class SecurityManager: if ok: return Defaults.AuthSiteAdmin elif ac == Defaults.AuthListAdmin: - def cryptmatchp(response, secret): - try: - salt = secret[:2] - if crypt and crypt.crypt(response, salt) == secret: - return True - return False - except TypeError: - # BAW: Hard to say why we can get a TypeError here. - # SF bug report #585776 says crypt.crypt() can raise - # this if salt contains null bytes, although I don't - # know how that can happen (perhaps if a MM2.0 list - # with USE_CRYPT = 0 has been updated? Doubtful. - return False # The password for the list admin and list moderator are not # kept as plain text, but instead as an sha hexdigest. The # response being passed in is plain text, so we need to - # digestify it first. Note however, that for backwards - # compatibility reasons, we'll also check the admin response - # against the crypted and md5'd passwords, and if they match, - # we'll auto-migrate the passwords to sha. + # digestify it first. key, secret = self.AuthContextInfo(ac) if secret is None: continue sharesponse = sha.new(response).hexdigest() - upgrade = ok = False if sharesponse == secret: - ok = True - elif md5.new(response).digest() == secret: - ok = upgrade = True - elif cryptmatchp(response, secret): - ok = upgrade = True - if upgrade: - save_and_unlock = False - if not self.Locked(): - self.Lock() - save_and_unlock = True - try: - self.password = sharesponse - if save_and_unlock: - self.Save() - finally: - if save_and_unlock: - self.Unlock() - if ok: return ac elif ac == Defaults.AuthListModerator: # The list moderator password must be sha'd @@ -227,21 +187,22 @@ class SecurityManager: return False def _cookie_path(self): - return '/'.join(os.environ['SCRIPT_NAME'].split('/')[:-1]) + '/' + script_name = os.environ.get('SCRIPT_NAME', '') + return SLASH.join(script_name.split(SLASH)[:-1]) + SLASH def MakeCookie(self, authcontext, user=None): key, secret = self.AuthContextInfo(authcontext, user) - if key is None or secret is None or not isinstance(secret, str): + if key is None or secret is None or not isinstance(secret, basestring): raise ValueError # Timestamp issued = int(time.time()) # Get a digest of the secret, plus other information. - mac = sha.new(secret + `issued`).hexdigest() + mac = sha.new(secret + repr(issued)).hexdigest() # Create the cookie object. c = Cookie.SimpleCookie() c[key] = binascii.hexlify(marshal.dumps((issued, mac))) c[key]['path'] = self._cookie_path() - # We use session cookies, so don't set `expires' or `max-age' keys. + # We use session cookies, so don't set 'expires' or 'max-age' keys. # Set the RFC 2109 required header. c[key]['version'] = 1 return c @@ -290,7 +251,7 @@ class SecurityManager: for k in c.keys(): if k.startswith(prefix): usernames.append(k[len(prefix):]) - # If any check out, we're golden. Note: `@'s are no longer legal + # If any check out, we're golden. Note: '@'s are no longer legal # values in cookie keys. for user in [Utils.UnobscureEmail(u) for u in usernames]: ok = self.__checkone(c, authcontext, user) @@ -307,7 +268,7 @@ class SecurityManager: key, secret = self.AuthContextInfo(authcontext, user) except Errors.NotAMemberError: return False - if not c.has_key(key) or not isinstance(secret, str): + if key not in c or not isinstance(secret, basestring): return False # Undo the encoding we performed in MakeCookie() above. BAW: I # believe this is safe from exploit because marshal can't be forced to @@ -329,7 +290,7 @@ class SecurityManager: return False # Calculate what the mac ought to be based on the cookie's timestamp # and the shared secret. - mac = sha.new(secret + `issued`).hexdigest() + mac = sha.new(secret + repr(issued)).hexdigest() if mac <> received_mac: return False # Authenticated! |
