Package easyLDAP :: Module easyLDAP_utils
[frames] | no frames]

Source Code for Module easyLDAP.easyLDAP_utils

  1  # -*- coding: utf-8 -*- 
  2   
  3  #    easyLDAP - a python library that makes LDAP management easier than before... 
  4  #    Copyright (C) 2004-2010,2020 Mike Gabriel <m.gabriel@das-netzwerkteam.de> 
  5  # 
  6  #    This program is free software: you can redistribute it and/or modify 
  7  #    it under the terms of the GNU General Public License as published by 
  8  #    the Free Software Foundation, either version 3 of the License, or 
  9  #    (at your option) any later version. 
 10  # 
 11  #    This program is distributed in the hope that it will be useful, 
 12  #    but WITHOUT ANY WARRANTY; without even the implied warranty of 
 13  #    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
 14  #    GNU General Public License for more details. 
 15  # 
 16  #    You should have received a copy of the GNU General Public License 
 17  #    along with this program.  If not, see <http://www.gnu.org/licenses/>. 
 18  # 
 19   
 20  import string, types, re 
 21  import datetime, time 
 22  import crypt 
 23   
 24  # for debugging 
 25  import pprint 
 26   
 27  # these modules appear in python-crypto 
 28  from Crypto.Hash import MD4 
 29  from Crypto.Cipher import DES 
 30   
 31  import random 
 32  import locale 
 33  import copy  
 34   
 35  # these modules appear in python-ldap 
 36  import ldap, ldap.schema 
 37   
 38  from easyLDAP_defaults import * 
 39  from easyLDAP_defaults import _invalidIA5map 
 40  from easyLDAP_class_base import easyLDAP 
 41   
 42  from easyLDAP_exceptions import * 
 43   
44 -def _unique(duplicates_list):
45 """ 46 Remove duplicate elements from a Python list. 47 48 @param duplicates_list: list that may contain duplicate items 49 @type duplicates_list: list 50 """ 51 if type(duplicates_list) is types.ListType: 52 uniqueList = [] 53 for element in duplicates_list: 54 if element not in uniqueList: 55 uniqueList.append(element) 56 return uniqueList 57 return []
58
59 -def is_uppercase(test_str):
60 """ 61 Checks, whether all alphabetical characters in a given string 62 are upper case characters. 63 64 @param test_str: string that shall be tested for uppercase characters 65 @type test_str: str 66 """ 67 return test_str.uppercase() == test_str
68 69
70 -def is_lowercase(test_str):
71 """ 72 Checks, whether all alphabetical characters in a given string 73 are lower case characters. 74 75 @param test_str: string that shall be tested for lowercase characters 76 @type test_str: str 77 """ 78 return test_str.lowercase() == test_str
79 80
81 -def is_mingledcase(test_str):
82 """ 83 Checks, whether lower as well as upper case characters appear 84 in a given string. 85 86 @param test_str: string that shall be tested for mixed lowercase 87 and uppercase characters 88 @type test_str: str 89 """ 90 return (test_str.lowercase() != test_str) and (test_str.uppercase() != test_str)
91 92
93 -def ia5string(non_ia5_str):
94 """ 95 Tries to map special characters in a human readable string 96 to IA5 string characters. 97 98 @param non_ia5_str: string that shall be mapped to an IA5 string 99 @type non_ia5_str: str 100 """ 101 convertedStringAsList = [] 102 if type(non_ia5_string) is types.StringType: 103 for char in non_ia5_string: 104 105 # printable characters will always be accepted 106 if char in string.printable: 107 convertedStringAsList.append(char) 108 109 # some other characters may be mapped to printables 110 elif char in [ key.encode(locale.getdefaultlocale()[1]) for key in _invalidIA5map.keys() ]: 111 convertedStringAsList.append(_invalidIA5map[char.decode(locale.getdefaultlocale()[1])]) 112 113 # any other character will be ignored 114 else: 115 # leave out the char if we can't map one way or the other... 116 pass 117 118 return string.join(convertedStringAsList,'')
119 120
121 -def days_since_1970():
122 """ 123 Calculate number of days since 1970. 124 """ 125 return int(time.time() / 24 / 3600)
126 shadowAgeToday = days_since_1970 127 128
129 -def crypthash(password):
130 """ 131 Generate a crypt password hash for a given plain text password. 132 133 @param password: plain text password that is to be hashed with the Crypt algorithm 134 @type password: str 135 """ 136 salt = random.choice (string.letters+string.digits) + random.choice (string.letters+string.digits) 137 return '{crypt}'+crypt.crypt(password,salt)
138 139
140 -def nthash(password):
141 """ 142 Generate a smbpasswd-style NT hash. 143 144 @param password: plain text password that is to be hashed with the NT hash 145 algorithm (MD4) 146 @type password: str 147 """ 148 # building the nt-hash is pretty easy in python 149 hash = MD4.new() 150 hash.update(password.encode("utf-16-le")) 151 return hash.hexdigest().upper()
152 153
154 -def lmhash(password):
155 """ 156 Generate a smbpasswd-style LanManager (Win9x) hash. 157 158 @param password: plain text password that is to be hashed 159 with the LanManager hash algorithm 160 @type password: str 161 """ 162 bin = ['0000','0001','0010','0011', 163 '0100','0101','0110','0111', 164 '1000','1001','1010','1011', 165 '1100','1101','1110','1111'] 166 hx = '0123456789ABCDEF' 167 168 # generating the lm-password is rather complicated 169 lmPasswordStr = password.upper() 170 lmPasswordLen = len(lmPasswordStr) 171 if lmPasswordLen < 14: 172 for i in range(lmPasswordLen,14): 173 lmPasswordStr = lmPasswordStr + "\x00" 174 lmPasswordStr = lmPasswordStr[:14] 175 lmPasswordBin = '' 176 for s in lmPasswordStr: 177 hexstr = string.zfill(str(hex(ord(s)))[2:],2) 178 for h in hexstr: 179 lmPasswordBin += bin[int(h,base=16)] 180 181 # make a parity check (7bit+1par) 182 j = 0 183 parBit = 0 184 lmPwBinList = list(lmPasswordBin) 185 for i in range(0,len(lmPwBinList)+1): 186 if i % 7 == 0: 187 lmPwBinList.insert (i + j, str(parBit)+'|') 188 j += 1 189 parBit = 0 190 if i+j <= len(lmPasswordBin): 191 parBit = (parBit + int(lmPwBinList[i+j])) % 2 192 del lmPwBinList[0] 193 194 # concatenate list components back into "binary" string format 195 lmDESKey1BinStr = string.replace(string.replace(string.replace(string.join(lmPwBinList),'0 ','0'),'1 ','1'),'| ','|')[:71] 196 lmDESKey2BinStr = string.replace(string.replace(string.replace(string.join(lmPwBinList),'0 ','0'),'1 ','1'),'| ','|')[72:] 197 198 lmDESKey1BinList = string.split(string.rstrip(lmDESKey1BinStr,'|'), '|') 199 lmDESKey2BinList = string.split(string.rstrip(lmDESKey2BinStr,'|'), '|') 200 201 # transform "binary" strings into real ascii strings 202 lmDESKey1 = '' 203 lmDESKey2 = '' 204 for i in range(len(lmDESKey1BinList)): 205 lmDESKey1 += chr(bin.index(lmDESKey1BinList[i][:4])*16 + bin.index(lmDESKey1BinList[i][4:])) 206 for i in range(len(lmDESKey2BinList)): 207 lmDESKey2 += chr(bin.index(lmDESKey2BinList[i][:4])*16 + bin.index(lmDESKey2BinList[i][4:])) 208 209 # encrypt the "magic" word 'KGS!@#$%' with DES.MODE_ECB 210 des1 = DES.new(lmDESKey1,DES.MODE_ECB) 211 des2 = DES.new(lmDESKey2,DES.MODE_ECB) 212 lmhash1Str=des1.encrypt('KGS!@#$%') 213 lmhash2Str=des2.encrypt('KGS!@#$%') 214 215 # turn encrypted stuff into hexdecimal hashes (smbpasswd style) 216 lmhash1 = '' 217 lmhash2 = '' 218 for ch in lmhash1Str: 219 lmhash1 += hx[ord(ch)/16]+hx[ord(ch)%16] 220 for ch in lmhash2Str: 221 lmhash2 += hx[ord(ch)/16]+hx[ord(ch)%16] 222 223 return lmhash1+lmhash2
224 225 226
227 -def _attrtype(this_attrdesc):
228 return string.split(this_attrdesc,';')[0]
229 230
231 -def _attropt(this_attrdesc):
232 try: 233 return string.split(this_attrdesc,';')[1] 234 except IndexError: 235 return ''
236 237
238 -def _attrdesc(this_attrtype, this_attropt):
239 if this_attropt: 240 return '%s;%s' % (this_attrtype, this_attropt) 241 else: 242 return this_attrtype
243 244
245 -def changeAttrTypeInAttrDescDict(attrdesc_dict, attrtype_alias):
246 """ 247 This function is used to replace aliases of attribute types in 248 the easyLDAP internal data structure. 249 250 The function expects a dictionary of attribute descriptions and their 251 values (i.e. dictionary keys of the form <attrType>;<attrOption>). 252 253 The function will fail if the attribute descriptions (i.e. the dictionary 254 keys) are not all of the same attribute type. It furtheron expects 255 an alias of the attribute type name that shall replace the commonly 256 used attribute type in the formerly named dictionary. 257 258 The attribute options, however, must be supported by the LDAPv3 protocol. 259 Attribute description values must be given as multi-valued or single-valued 260 lists (depending on the attribute's properties in the server's LDAP schema). 261 262 Example:: 263 264 attrdesc_dict = { 'ou': ['network administration team',], 265 'ou;lang-de': ['NETZWERKTEAM',],} 266 267 attrtype_alias = 'organizationalUnit' 268 269 result = { 'organizationalUnit': ['network administration team',], 270 'organizationalUnit;lang-de': ['NETZWERKTEAM',],} 271 272 If the function fails, the value C{None} is returned. 273 274 @param attrdesc_dict: attribute description dictionary (pre-requisites, see above) 275 @type attrdesc_dict: dict 276 @param attrtype_alias: alias attribute type name that will replace attribute type 277 names in the dictionary keys of attrdesc_dict 278 """ 279 try: 280 # presume that the first attrDesc in this_attrtype_dict must have the same attribute type as 281 # the following attribute description. if this is not the case the method will abort with an error 282 attrType = attrtype(attrdesc_dict.keys()[0]) 283 284 # check the other attribute descriptions in this_attrtype_dict 285 for attrDesc in attrdesc_dict.keys(): 286 if attrtype(attrDesc) != attrType: 287 # found invalid attribute description 288 return None 289 290 # we need a list of all given attribute options 291 attrOptions = [ attropt(option) for option in attrdesc_dict.keys() ] 292 293 resultDict = {} 294 295 # set up the resulting dictionary 296 for option in attrOptions: 297 resultDict[_attrdesc(attrtype_alias,option)] = attrdesc_dict[_attrdesc(attrType,option)] 298 299 return resultDict 300 301 except: 302 pass 303 304 return None
305 306 307
308 -def is_pyldapobject(pyldapobject, strict=True):
309 """ 310 Return C{True}, if the given data structure (a single Python 311 dictionary in a Python list) conforms to the Python LDAP data format 312 and only contains data of a single DN. 313 314 @param pyldapobject: the LDAP data structure to be tested for Python LDAP 315 compliancy 316 @type pyldapobject: list 317 @param strict: test if the LDAP object also contains objectClass values 318 @type strict: bool 319 """ 320 if type(pyldapobject) != types.ListType: 321 return False 322 323 if len (pyldapobject) != 1: 324 return False 325 326 if (type(pyldapobject[0]) != types.ListType) and (type(pyldapobject[0]) != types.TupleType): 327 return False 328 329 if len(pyldapobject[0]) != 2: 330 return False 331 332 if (type(pyldapobject[0][0]) != types.StringType) or (type(pyldapobject[0][1]) != types.DictType): 333 return False 334 335 if strict: 336 if ('objectclass' not in [ key.lower() for key in pyldapobject[0][1].keys() ]): 337 return False 338 339 return True
340
341 -def is_pyldaptree(pyldaptree):
342 """ 343 Return C{True}, if the given data structure (several Python dictionaries 344 in a Python list) conforms to the Python LDAP data format and all the 345 contained LDAP DNs form a coherent LDAP (sub)tree. 346 347 @param pyldaptree: the LDAP data structure to be tested for Python LDAP 348 compliancy 349 @type pyldaptree: list 350 """ 351 # 352 # TODO: really check, if the DNs form something like a tree hierarchy 353 # 354 if len(pyldaptree) > 1: 355 for dn_object in pyldaptree: 356 if not is_pyldapobject([dn_object], strict=False): 357 return False 358 else: 359 return False 360 361 return True
362 363
364 -def to_list_of_strings(values):
365 """ 366 Convert any object of a standard Pythonian variable type to a list of strings. 367 368 @param values: value(s) to be converted 369 @type values; tuple, list 370 """ 371 # neither list nor tuple 372 if type(values) not in (types.BooleanType, types.FloatType, types.IntType, types.ListType, types.LongType, types.NoneType, types.StringType, types.TupleType, types.UnicodeType): 373 raise TypeError 374 375 # convert non-list like objects to a list... 376 if type(values) not in (types.ListType, types.TupleType): 377 values = [str(values)] 378 379 # not a tuple, we want a list!!! 380 if type(values) == types.TupleType: 381 values = list(values) 382 383 # convert list elements to string 384 if type(values) == types.ListType: 385 for i in range(len(values)): 386 if type(i) in (types.TupleType, types.ListType): 387 raise TypeError 388 values[i] = str(values[i]) 389 390 return values
391 392
393 -def generate_ldif(from_single_pyldapobject, to_single_pyldapobject):
394 """ 395 Generate an ldif formatted text, that can be used with official 396 OpenLDAP Utils (ldapadd, ldapmodify) or any other LDIF capable 397 LDAP tool. 398 399 The method expects two Python LDAP objects that only contain a single 400 DN each. To create an LDIF output it is also a pre-requisite that 401 both LDAP objects share the same DN. 402 403 The method returns a list, each item represents a line of the LDIF output 404 format. 405 406 If this function returns an empty list it means that both Python LDAP 407 objects are identical. 408 409 If this function returns C{None} it means that we met an error on our 410 way. 411 412 @param from_single_pyldapobject: current LDAP object in database 413 @type from_single_pyldapobject: list 414 @param to_single_pyldapobject: LDAP object containing the database changes that shall 415 be represented in the expected LDIF output text 416 @type to_single_pyldapobject: list 417 """ 418 easyldap = easyLDAP() 419 ldif_output = [] 420 if (len(from_single_pyldapobject) <= 1) and (len(to_single_pyldapobject) <= 1): 421 if (is_pyldapobject(from_single_pyldapobject)) and (is_pyldapobject(to_single_pyldapobject)): 422 423 # adding the complete DN 424 if (not from_single_pyldapobject[0][1]) and to_single_pyldapobject[0][1]: 425 # the object is new to the LDAP server's directory 426 # first line has to be the DN 427 ldif_output.append('dn: %s' % to_single_pyldapobject[0][0]) 428 # then all objectClasses 429 for objectClass in to_single_pyldapobject[0][1]['objectClass']: 430 ldif_output.append('objectClass: %s' % objectClass) 431 # then all attribute descriptions 432 for attrDesc in [ key for key in to_single_pyldapobject[0][1].keys() if key != 'objectClass' ]: 433 for value in to_single_pyldapobject[0][1][attrDesc]: 434 ldif_output.append('%s: %s' % (attrDesc, value)) 435 436 # deleting the complete DN 437 elif from_single_pyldapobject[0][1] and (not to_single_pyldapobject[0][1]): 438 # first line has to be the DN 439 ldif_output.append('dn: %s' % to_single_pyldapobject[0][0]) 440 ldif_output.append('changeType: delete') 441 442 # modifying attribute descriptions within the DN 443 elif from_single_pyldapobject[0][1] and to_single_pyldapobject[0][1]: 444 # first line has to be the DN 445 ldif_output.append('dn: %s' % to_single_pyldapobject[0][0]) 446 ldif_output.append('changeType: modify') 447 448 for compAttrDesc, compValues in to_single_pyldapobject[0][1].items (): 449 450 # split attribute description into its components: type and (if any) option. 451 compAttrType = _attrtype(compAttrDesc) 452 if _attropt(compAttrDesc): 453 compAttrOption = ';'+_attropt(compAttrDesc) 454 else: 455 compAttrOption = '' 456 457 # by mapping the selected attribute type to its OID, we compare if the same OID is 458 # set in the referred to LDAP object 459 if easyldap.has_oid_set(easyldap.map_attrtypes2oids(compAttrType)[0],from_single_pyldapobject) and (_attropt(compAttrDesc) in easyldap.get_used_attroptions(compAttrType,from_single_pyldapobject)): 460 for mappedAttrType in easyldap.map_oid2attrtypes(easyldap.map_attrtypes2oids(compAttrType)[0]): 461 if mappedAttrType+compAttrOption in from_single_pyldapobject[0][1].keys(): 462 if from_single_pyldapobject[0][1][mappedAttrType+compAttrOption] != to_single_pyldapobject[0][1][compAttrDesc]: 463 ldif_output.append ('replace: %s' % compAttrDesc) 464 for value in compValues: 465 ldif_output.append ('%s: %s' % (compAttrDesc, value)) 466 ldif_output.append ('-') 467 468 else: 469 ldif_output.append ('add: %s' % compAttrDesc) 470 for value in compValues: 471 ldif_output.append ('%s: %s' % (compAttrDesc, value)) 472 ldif_output.append ('-') 473 474 for compAttrDesc in from_single_pyldapobject[0][1].keys (): 475 if not to_single_pyldapobject[0][1].has_key (compAttrDesc): 476 ldif_output.append ('delete: %s' % compAttrDesc) 477 ldif_output.append ('-') 478 479 else: 480 # both single LDAP objects were empty 481 raise easyLDAP_exceptions.LDAPOBJECTS_EMPTY 482 else: 483 # either of the given objects is not a python-ldap object 484 raise easyLDAP_exceptions.NOT_A_PYTHON_LDAPOBJECT 485 else: 486 # accept only one ldapobject per py-ldap object data list 487 raise easyLDAP_exceptions.NOT_A_single_pyldapobject 488 489 return ldif_output
490
491 -def generate_modlist(from_single_pyldapobject, to_single_pyldapobject):
492 """ 493 Generate a modification list, that can be used with the Python LDAP 494 methods:: 495 496 ldap.ldap_modify() 497 ldap.modify_s() 498 499 The method expects two Python LDAP objects that only contain a single 500 DN each. To create an LDAP modlist it is also a pre-requisite that 501 both LDAP objects share the same DN. 502 503 If this function returns an empty list it means that both Python LDAP 504 objects are identical. 505 506 If this function returns C{None} it means that we met an error on our 507 way. 508 509 @param from_single_pyldapobject: current LDAP object in database 510 @type from_single_pyldapobject: list 511 @param to_single_pyldapobject: LDAP object containing the database changes that shall 512 be represented in the expected Python LDAP stylish list of modifications 513 @type to_single_pyldapobject: list 514 """ 515 easyldap = easyLDAP() 516 modlist = [] 517 518 if (len(from_single_pyldapobject) <= 1) and (len(to_single_pyldapobject) <= 1): 519 520 if (is_pyldapobject(from_single_pyldapobject, strict=False)) and (is_pyldapobject(to_single_pyldapobject, strict=False)): 521 522 # rewrite attribute descriptions to lower case 523 for pyobj in (from_single_pyldapobject, to_single_pyldapobject): 524 for k in pyobj[0][1].keys(): 525 if k != k.lower(): 526 pyobj[0][1][k.lower()] = pyobj[0][1][k] 527 del pyobj[0][1][k] 528 529 for compAttrDesc, compValues in to_single_pyldapobject[0][1].items(): 530 531 # split attribute description into its components: type and (if any) option. 532 compAttrType = _attrtype(compAttrDesc) 533 if _attropt(compAttrDesc): 534 compAttrOption = ';'+_attropt(compAttrDesc) 535 else: 536 compAttrOption = '' 537 538 # by mapping the selected attribute type to its OID, we compare if the same OID is 539 # set in the referred to LDAP object 540 541 if (easyldap.has_oid_set(easyldap.map_attrtypes2oids(compAttrType)[0],from_single_pyldapobject)) and ((_attropt(compAttrDesc) in easyldap.get_used_attroptions(compAttrType,from_single_pyldapobject)) or (not easyldap.get_used_attroptions(compAttrType,from_single_pyldapobject))): 542 for mappedAttrType in easyldap.map_oid2attrtypes(easyldap.map_attrtypes2oids(compAttrType)[0]): 543 if mappedAttrType+compAttrOption in from_single_pyldapobject[0][1].keys(): 544 if from_single_pyldapobject[0][1][mappedAttrType+compAttrOption] != to_single_pyldapobject[0][1][compAttrDesc]: 545 modlist.append ([ldap.MOD_REPLACE, compAttrDesc, compValues]) 546 547 else: 548 modlist.append([ldap.MOD_ADD, compAttrDesc, compValues]) 549 550 for compAttrDesc, compValues in from_single_pyldapobject[0][1].items(): 551 if not compAttrDesc in to_single_pyldapobject[0][1].keys(): 552 modlist.append([ldap.MOD_DELETE, compAttrDesc, compValues]) 553 else: 554 # either of the given objects is not a python-ldap object 555 raise easyLDAP_exceptions.NOT_A_PYTHON_LDAPOBJECT 556 else: 557 # accept only one ldapobject per py-ldap object data list 558 raise easyLDAP_exceptions.NOT_A_SINGLE_LDAPOBJECT 559 560 # the values in modlist have to encoded correctly!!! 561 for modlist_idx in range(len(modlist)): 562 orig_values = modlist[modlist_idx][2] 563 encoded_values = locale2ldapEncode(orig_values, easyldap.LDAPServerCharsetEncoding) 564 modlist[modlist_idx][1] = easyldap._rewrite_attrtype_names(modlist[modlist_idx][1]) 565 for idx in range(len(encoded_values)): 566 modlist[modlist_idx][2][idx] = encoded_values[idx] 567 modlist[modlist_idx] = tuple(modlist[modlist_idx]) 568 569 return modlist
570 571
572 -def get_onelevel_dnlist(dn_list, level):
573 """ 574 Return LDAP DNs that have all the same depth level 575 in an LDAP tree hierarchy. 576 577 @param dn_list: list of LDAP DN strings 578 @type dn_list: list 579 @param level: depth level in the LDAP tree 580 @type level: int 581 """ 582 return [ dn.lower() for dn in dn_list if len(split_dn(dn)) == level ]
583 584
585 -def get_sorted_dnlist(dn_list):
586 """ 587 Sort a DN list so that it can be looked at 588 as an LDAP tree after sorting. 589 590 @param dn_list: list of LDAP DN strings 591 @type dn_list: list 592 """ 593 if dn_list == []: 594 return ([],[]) 595 596 dn_list = [ dn.lower() for dn in dn_list ] 597 598 maxdepth = 0 599 for dn in dn_list: 600 len_dn = len(split_dn(dn)) 601 maxdepth = max(maxdepth, len_dn) 602 603 basedepth = maxdepth 604 for dn in dn_list: 605 len_dn = len(split_dn(dn)) 606 basedepth = min(basedepth, len_dn) 607 608 sorted_dnlist = [ dn for dn in dn_list if len(split_dn(dn)) == basedepth ] 609 sorted_dnlist.sort() 610 611 612 for dn in sorted_dnlist: 613 dn_list.remove(dn) 614 615 level = len(split_dn(sorted_dnlist[0])) +1 616 617 modified = True 618 while dn_list and modified == True: 619 620 modified = False 621 temp_sorted_dnlist = sorted_dnlist 622 for search_dn in temp_sorted_dnlist: 623 624 sub_dnlist = [] 625 for add_dn in [ dn for dn in get_onelevel_dnlist(dn_list, level) if dn.endswith(search_dn) and len(split_dn(dn)) == len(split_dn(search_dn))+1 ]: 626 sub_dnlist.append(add_dn) 627 dn_list.remove(add_dn) 628 629 if sub_dnlist: 630 modified = True 631 sub_dnlist.sort() 632 633 n = sorted_dnlist.index(search_dn)+1 634 sorted_dnlist[n:n] = sub_dnlist 635 636 level += 1 637 638 orphaned_dnlist = dn_list 639 return (sorted_dnlist, orphaned_dnlist)
640 641
642 -def genpasswd(length=8, chars=string.letters + string.digits):
643 """ 644 Generate a random password. 645 646 @param length: password length 647 @type length: int 648 @param chars: choice of characters for the random password 649 @type chars: str 650 """ 651 return ''.join([random.choice(chars) for i in range(length)])
652 653
654 -def split_dn(dn, basedn=None):
655 """ 656 Split a DN into its RDN components. 657 658 @param dn: DN to be split 659 @type dn: str 660 @param basedn: if given, the base DN at the end of the DN will not 661 be split into RDNs 662 @type basedn: str 663 """ 664 append_basedn = False 665 if basedn and dn.lower() == basedn.lower(): 666 return dn 667 668 if basedn and dn.lower().endswith(basedn.lower()): 669 append_basedn = True 670 dn = dn[:-(len(basedn)+1)] 671 672 s = dn.split('=') 673 result = [s[0]] 674 675 i=0 676 while len(s) >= 3: 677 678 pos = s[1].rindex(',') 679 result[i] += '='+s[1][:pos] 680 result.append(s[1][pos+1:]) 681 i += 1 682 del s[1] 683 684 result[i] += '='+s[1] 685 686 if append_basedn: 687 result.append(basedn.lower()) 688 689 return result
690 691
692 -def get_parent_dn(dn, basedn=None):
693 """ 694 Return the parent DN of a given DN. 695 696 If the given DN already is the base DN of the LDAP tree, 697 then the Base DN is returned. 698 699 @param dn: child DN 700 @type dn: str 701 @param basedn: if the given DN equals the base DN then the base DN will 702 be returned 703 @type basedn: str 704 """ 705 dn_split = split_dn(dn, basedn=basedn) 706 return ','.join(dn_split[1:])
707 708
709 -def get_rdn(dn, basedn=None):
710 """ 711 Return the RDN of a given DN. 712 713 If the given DN already is the base DN of the LDAP tree, 714 then the Base DN is returned. 715 716 @param dn: find out RDN of this DN 717 @type dn: str 718 @param basedn: if the given DN equals the base DN then the base DN will 719 be returned 720 @type basedn: str 721 """ 722 dn_split = split_dn(dn, basedn=basedn) 723 return dn_split[0]
724 725
726 -def is_dn_syntax(dn):
727 """ 728 Check if DN has a valid syntax. 729 730 @param dn: DN to be checked for valid syntax 731 @type dn: str 732 """ 733 # TODO: very simple check... 734 if type(dn) != types.StringType: 735 return False 736 if '=' not in dn: 737 return False 738 739 return True
740 741 742
743 -def get_naming_attribute_value(dn):
744 """ 745 Detect the nameing attribute type of a given DN. 746 747 @param dn: detect naming attribute type from this DN 748 @type dn: str 749 """ 750 dn = dn.lower() 751 rdn = dn.split(',')[0] 752 (attr,value) = rdn.split('=') 753 return (attr, value)
754 755
756 -def intersect(l1,l2):
757 """ 758 Find the (mathematical) intersection of two different 759 sets of items. 760 761 @param l1: first list of items for intersection 762 @type l1: list 763 @param l2: second list of items for intersection 764 type l2: list 765 """ 766 intersection = [] 767 768 for i in l1: 769 if i in l2: intersection.append(i) 770 771 return intersection
772 773 774 if __name__=='__main__': 775 pass 776