147 lines
4.9 KiB
Python
147 lines
4.9 KiB
Python
# -*- coding: utf-8 -*-
|
|
###############################################################################
|
|
# ldap_passwd.py : manipulation des mots de passes LDAP
|
|
# $Id: ldap_passwd.py,v 1.7 2006-05-04 17:46:58 chove Exp $
|
|
###############################################################################
|
|
# The authors of this code are
|
|
# Bjorn Ove Grotan <bgrotan@grotan.com>
|
|
# Etienne Chové <etienne.chove@crans.org>
|
|
#
|
|
# 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 crypt
|
|
import hashlib
|
|
|
|
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':
|
|
h = hashlib.sha1()
|
|
h.update(str(pwd) + salt)
|
|
pwdhash = "{SSHA}" + base64.encodestring(h.digest() + salt)
|
|
elif algo =='sha':
|
|
h = hashlib.sha1()
|
|
h.update(str(pwd))
|
|
pwdhash = "{SHA}" + base64.encodestring(h.digest())
|
|
elif algo =='md5':
|
|
h = hashlib.md5()
|
|
h.update(str(pwd))
|
|
pwdhash = "{MD5}" + base64.encodestring(h.digest())
|
|
elif algo == 'smd5':
|
|
h = hashlib.md5()
|
|
h.update(str(pwd) + salt)
|
|
pwdhash = "{SMD5}" + base64.encodestring(h.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])[20:]
|
|
else:
|
|
salt = None
|
|
|
|
return mkpasswd(pwd, sambaver=sambaver, algo=algo, salt=salt) == pwdhash
|