# -*- coding: iso8859-15 -*- ############################################################################### # ldap_passwd.py : manipulation des mots de passes LDAP # $Id: ldap_passwd.py,v 1.6 2006-04-28 00:25:35 chove Exp $ ############################################################################### # The authors of this code are # Bjorn Ove Grotan # Etienne Chové # # Copyright (C) 2005 Bjorn Ove Grotan # Copyright (C) 2006 Etienne Chové # All rights reserved. # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # 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 ############################################################################### # For extra strength passwords, we wanted SSHA in our LDAP-environment # as the standard python-module 'sha' does not support ssha, but this can # easily be implemented with a few extra functions. # # SSHA can be described as: # the SHA1-digest of a password with a sequence of "salt" bytes, where # the bytes are randomly chosen - followed by the same salt bytes # For LDAP-use, the SHA1 and SSHA-digest has to be base64-encoded. # # Example-LDIF: # {SSHA}oaEG3PJ10sHxGcSxsDRRooTifL55/2NOdN3nU1VEV+NFzc9Q # # This package should now support passwords compatible with [1] Samba using the [2] # smbpasswd module for [3] Python. The samba compability is added for use with Samba # as PDC with storing user and host-information in LDAP. # # [1] http://www.samba.org # [2] http://barryp.org/software/py-smbpasswd/ # [3] http://www.python.org import string,base64 import random,sys import exceptions import md5,sha,crypt try: import smbpasswd smb = True except: smb = False algos={} algos = { 'ssha':'Seeded SHA', 'sha':'Secure Hash Algorithm', 'md5':'MD5', 'smd5':'Seeded MD5', 'crypt':'standard unix crypt', 'cleartext':'clear text' } if smb: algos['lmpassword'] = 'lan man hash' algos['ntpassword'] = 'nt hash' def getsalt(chars=string.letters+string.digits, length=16): ''' Generate a random salt. Default length is 16 ''' salt = '' for i in range(int(length)): salt += random.choice(chars) return salt def mkpasswd(pwd, sambaver=3, algo='SSHA', salt=None): ''' Make a given password cryptated, possibly with different crypt-algorihtms. This module was written for use with LDAP - so default is seeded sha ''' if salt == None: salt = getsalt() algo = algo.lower() if algo not in algos.keys(): raise TypeError, 'Algorithm <%s> not supported in this version.' % algo if algo == 'ssha': pwdhash = "{SSHA}" + base64.encodestring(sha.new(str(pwd) + salt).digest() + salt) elif algo =='sha': pwdhash = "{SHA}" + base64.encodestring(sha.new(str(pwd)).digest()) elif algo =='md5': pwdhash = "{MD5}" + base64.encodestring(md5.new(str(pwd)).digest()) elif algo == 'smd5': pwdhash = "{SMD5}" + base64.encodestring(md5.new(str(pwd) + salt).digest() + salt) elif algo =='crypt': pwdhash = "{CRYPT}" + crypt.crypt(str(pwd),getsalt(length=2)) # crypt only uses a salt of length 2 elif algo == 'lmpassword': if sambaver==3: pwdhash = "{sambaLMPassword}" + smbpasswd.lmhash(pwd) elif sambaver==2: pwdhash = "{lmPassword}" + smbpasswd.lmhash(pwd) elif algo == 'ntpassword': if sambaver == 3: pwdhash = "{sambaNTPassword}" + smbpasswd.lmhash(pwd) elif sambaver == 2: pwdhash = "{NTPassword}" + smbpasswd.lmhash(pwd) elif algo == 'cleartext': pwdhash = "{CLEARTEXT}" + pwd return pwdhash.strip() def checkpwd(pwd, pwdhash): ''' Check if the password matches the hash ''' algo = pwdhash[1:].split('}')[0] algo = algo.lower() if algo.startswith('samba'): sambaver = 3 algo = algo[5:] else: sambaver = 2 if not algo in algos.keys(): raise TypeError, 'Algorithm <%s> not supported in this version.' % algo if algos[algo].startswith('Seeded '): salt = base64.decodestring(pwdhash.split('}')[1])[-16:] else: salt = None return mkpasswd(pwd, sambaver=sambaver, algo=algo, salt=salt) == pwdhash