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

Source Code for Module easyLDAP.easyLDAP_class_base

   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 
  21  import copy 
  22  import types 
  23  import re 
  24  import pprint 
  25   
  26  # these modules appear in python-ldap 
  27  import ldap, ldap.schema 
  28   
  29  from easyLDAP_bind import * 
  30  import easyLDAP_defaults 
  31   
  32  import easyLDAP_exceptions 
  33  from easyLDAP_exceptions import * 
  34   
  35  easyLDAP_ADDATTR = 0 
  36  easyLDAP_REPLACEATTR = 1 
  37   
  38  SCHEMA_CLASS_MAPPING = ldap.cidict.cidict() 
  39  SCHEMA_ATTRS = SCHEMA_CLASS_MAPPING.keys() 
  40   
  41  _easyLDAP_schema_cache = {} 
  42   
  43  # 
  44  # TODO: 
  45  #   
  46  #   HIGH 
  47  #     o work through little TODOs 
  48  # 
  49  #   MEDIUM 
  50  #     o put ldap schema specific stuff into a separate class 
  51  # 
  52  #   LOW: 
  53  #     o test all templateLDAPSyntaxValues  
  54  # 
  55   
56 -class easyLDAP:
57 58 # for downwards compatibility
59 - def _method_aliases(self):
60 61 from easyLDAP_utils import is_pyldapobject, is_pyldaptree 62 63 self.uidbind = self.uid_bind 64 self.cnbind = self.cn_bind 65 self.anonbind = self.anonymous_bind 66 self.uidbind_norefresh = self.uid_bind_norefresh 67 self.cnbind_norefresh = self.cn_bind_norefresh 68 self.anonbind_norefresh = self.anonymous_bind_norefresh 69 self.map_attrtype2oid = self.map_attrtypes2oids 70 self.get_parentdn = self.get_parent_dn 71 self.get_parentrdn = self.get_parent_rdn 72 self.has_parentdn = self.has_parent_dn 73 self.get_sameleveldns = self.get_samelevel_dns 74 self.get_subleveldns = self.get_sublevel_dns 75 self.get_sublevelrdns = self.get_sublevel_rdns 76 self.get_subtreedns = self.get_subtree_dns 77 self.get_sambaAlgorithmicRidBase = self.get_samba3_algorithmicRidBase 78 self.get_sambaDomainSID = self.get_samba3_domainSID 79 self.is_ldapobject = is_pyldapobject 80 self.is_ldaptree = is_pyldaptree 81 self.get_usedattrtypeoids = self.get_used_attrtype_oids 82 self.get_usedattroptions = self.get_used_attroptions 83 self.map_attrtype2objectclass = self.map_attrtype2objectclasses
84
85 - def __init__(self, bind_dn=None, bind_pw=None, config_defaults=EASY_LDAP, update_schema_cache=False, ldapsession=None):
86 87 self._method_aliases() 88 89 # initializing class attributes 90 self.CONFIG=config_defaults 91 self.LDAPuri=self.CONFIG['URI'].lower() 92 self.LDAPserver=string.split (self.LDAPuri,'//')[1] 93 if not bind_dn: 94 self.BindDN = self.CONFIG['BindDN'] 95 if not bind_pw: 96 self.BindPW = self.CONFIG['BindPW'] 97 self.RootDSE=self.CONFIG['RootDSE'].lower() 98 self.BaseDN=self.CONFIG['BaseDN'].lower() 99 if self.CONFIG['AdminRDN']: 100 self.AdminDN=self.CONFIG['AdminRDN']+','+self.CONFIG['BaseDN'].lower() 101 else: 102 self.AdminDN='' 103 self.PeopleBaseDN = self.GroupsBaseDN = self.HostsBaseDN = self.MailAliasesBaseDN = self.AutomountBaseDN = self.CONFIG['BaseDN'].lower() 104 if self.CONFIG['PeopleRDN']: 105 self.PeopleBaseDN = self.CONFIG['PeopleRDN']+','+self.PeopleBaseDN 106 if self.CONFIG['GroupsRDN']: 107 self.GroupsBaseDN = self.CONFIG['GroupsRDN']+','+self.GroupsBaseDN 108 if self.CONFIG['HostsRDN']: 109 self.HostsBaseDN = self.CONFIG['HostsRDN']+','+self.HostsBaseDN 110 if self.CONFIG['MailAliasesRDN']: 111 self.MailAliasesBaseDN = self.CONFIG['MailAliasesRDN']+','+self.MailAliasesBaseDN 112 if self.CONFIG['AutomountRDN']: 113 self.AutomountBaseDN = self.CONFIG['AutomountRDN']+','+self.AutomountBaseDN 114 115 self.LDAPServerCharsetEncoding=self.CONFIG['ServerCharsetEncoding'] 116 self.posix_availableUidNumbers=self.CONFIG['posix_availableUidNumbers'] 117 self.posix_availableGidNumbers=self.CONFIG['posix_availableGidNumbers'] 118 self.templateLDAPSyntaxValues = { 119 'NO SPECIFIED SYNTAX': { 'default': 'Empty', 'regexp': '.*', }, 120 'Audio': { 'default': 'NOSOUND', 'regexp': '.*', }, 121 'Binary': { 'default': 'Empty_Binary', 'regexp': '.*', }, 122 'Bit String': { 'default': '00000000', 'regexp': '[0-1]+', }, 123 'Boolean': { 'default': 'False', 'regexp': 'TRUE|FALSE', }, 124 'Certificate': { 'default': 'Empty_Certificate', 'regexp': '.*', }, 125 'Certificate List': { 'default': 'Empty_CertificateList', 'regexp': '.*', }, 126 'Certificate Pair': { 'default': 'Empty_CertificatePair', 'regexp': '.*', }, 127 'Country String': { 'default': 'noCountry', 'regexp': '.*', }, 128 'Directory String': { 'default': 'Empty', 'regexp': '.*', }, 129 'Distinguished Name': { 'default': 'cn=DUMMY,%s' % self.BaseDN, 'regexp': '', }, 130 'Facsimile Telephone Number': { 'default': '212-555-555', 'regexp': '^([0-9+]{2,3}|)( |-|)([0-9()]+|)( |-|/| / |)([0-9]+(-| |)[0-9]+)+$', }, 131 'Generalized Time': { 'default': '0', 'regexp': '.*', }, 132 'IA5 String': { 'default': 'Empty', 'regexp': '.*', }, 133 'Integer': { 'default': '-1', 'regexp': '[0-9\-]', }, 134 'JPEG': { 'default': 'NOJPEG', 'regexp': '.*', }, 135 'Name And Optional UID': { 'default': 'Empty', 'regexp': '.*', }, 136 'Numeric String': { 'default': '123456', 'regexp': '[0-9]+', }, 137 'Octet String': { 'default': 'SECRET', 'regexp': '.*', }, 138 'OID': { 'default': '1.2.3.4.5', 'regexp': '([0-9].[0-9.]+[0-9].|[a-zA-Z]+)', }, 139 'OpenLDAP Experimental ACI': { 'default': 'Empty', 'regexp': '.*', }, 140 'Other Mailbox': { 'default': 'someone@not.here.org', 'regexp': '.*', }, 141 'Postal Address': { 'default': 'Empty_Place', 'regexp': '.*', }, 142 'Printable String': { 'default': 'Empty', 'regexp': '.*', }, 143 'RFC2307 Boot Parameter': { 'default': 'Empty', 'regexp': '.*', }, 144 'RFC2307 NIS Netgroup Triple': { 'default': 'Empty', 'regexp': '.*', }, 145 'Supported Algorithm': { 'default': 'Empty', 'regexp': '.*', }, 146 'Telephone Number': { 'default': '212-555-555', 'regexp': '^([0-9+]{2,3}|)( |-|)([0-9()]+|)( |-|/| / |)([0-9]+(-| |)[0-9]+)+$', }, 147 'Telex Number': { 'default': '212-555-555', 'regexp': '^([0-9+]{2,3}|)( |-|)([0-9()]+|)( |-|/| / |)([0-9]+(-| |)[0-9]+)+$', }, 148 'UTC Time': { 'default': 'Mo Mr 22 22:22:22 UTC 2222', 'regexp': '.*', }, 149 } 150 151 if ldapsession is None: 152 self.ldapsession=ldap.initialize(self.LDAPuri) 153 self.ldapsession.set_option(ldap.OPT_DEREF, ldap.DEREF_ALWAYS) 154 155 self.ldapsession.sizelimit = self.CONFIG['SizeLimit'] 156 else: 157 self.ldapsession=ldapsession 158 159 if bind_dn: 160 self.BindDN = bind_dn 161 if bind_pw: 162 self.BindPW = bind_pw 163 if self.BindDN and self.BindPW: 164 # only bind here, no refresh!!! Refresh has to be done within the children classes easyLDAP_object, easyLDAP_tree, etc. 165 self.bind_norefresh(self.BindDN, self.BindPW) 166 167 _schema_cache_key = self.LDAPuri+self.BaseDN 168 if _easyLDAP_schema_cache.has_key(_schema_cache_key) and not update_schema_cache: 169 self.attributeTypes = _easyLDAP_schema_cache[_schema_cache_key]['attributeTypes'] 170 self.attributeTypesDict = _easyLDAP_schema_cache[_schema_cache_key]['attributeTypesDict'] 171 self.oidDict = _easyLDAP_schema_cache[_schema_cache_key]['oidDict'] 172 self.reverseAttributeTypesDict = _easyLDAP_schema_cache[_schema_cache_key]['reverseAttributeTypesDict'] 173 self.objectClasses = _easyLDAP_schema_cache[_schema_cache_key]['objectClasses'] 174 self.objectClassesDict = _easyLDAP_schema_cache[_schema_cache_key]['objectClassesDict'] 175 self.matchingRules = _easyLDAP_schema_cache[_schema_cache_key]['matchingRules'] 176 self.ldapSyntaxes = _easyLDAP_schema_cache[_schema_cache_key]['ldapSyntaxes'] 177 self.ldapSyntaxesDict = _easyLDAP_schema_cache[_schema_cache_key]['ldapSyntaxesDict'] 178 179 else: 180 181 # create virtually empty objectClassesDict 182 self.objectClassesDict = {'top': {'STRUCTURAL': False, 183 'AUXILIARY': False, 184 'MAY': [], 185 'OID': '2.5.6.0', 186 'SUP': [], 187 'DESC': 'WARNING: the LDAP server\'s schema is not loaded', 188 'MUST': ['objectclass'] 189 } 190 } 191 # create virtually empty atributeTypesDict 192 self.attributeTypesDict = {'objectclass': {'EQUALITY': 'objectIdentifierMatch', 193 'NAME': 'objectClass', 194 'ORDERING': '', 195 'COLLECTIVE': False, 196 'OID': '2.5.4.0', 197 'OBSOLETE': False, 198 'SYNTAX': '1.3.6.1.4.1.1466.115.121.1.38', 199 'SUBSTR': '', 200 'SUP': '', 201 'NO-USER-MODIFICATION': False, 202 'SINGLE-VALUE': False, 203 'DESC': 'WARNING: the LDAP server\'s schema is not loaded', 204 } 205 } 206 self.oidDict = {'2.5.4.0': ['objectclass'], } 207 208 self.ldapSyntaxesDict = {'NO SPECIFIED SYNTAX': { 'DEFAULT': 'Empty', 209 'DESC': 'NO SPECIFIED SYNTAX', 210 'REGEXP': '.*', 211 'X-NOT-HUMAN-READABLE': False, }, } 212 213 try: 214 schema = None 215 216 subschema_subentry_dn = self.ldapsession.search_subschemasubentry_s() 217 if subschema_subentry_dn is None: 218 219 subschema_subentry_entry = None 220 schema = None 221 222 else: 223 224 subschema_subentry_entry = self.ldapsession.read_subschemasubentry_s(subschema_subentry_dn, attrs=SCHEMA_ATTRS) 225 schema = ldap.schema.SubSchema(subschema_subentry_entry) 226 227 if schema is None: 228 raise easyLDAP_exceptions.LDAPSCHEMA_NOT_LOADED 229 230 schemas = schema.ldap_entry() 231 232 self.objectClasses=None 233 self.attributeTypes=None 234 self.matchingRules=None 235 self.ldapSyntaxes=None 236 if schemas.has_key('objectClasses'): 237 self.objectClasses=schemas['objectClasses'] 238 if schemas.has_key('attributeTypes'): 239 self.attributeTypes=schemas['attributeTypes'] 240 if schemas.has_key('matchingRules'): 241 self.matchingRules=schemas['matchingRules'] 242 if schemas.has_key('ldapSyntaxes'): 243 self.ldapSyntaxes=schemas['ldapSyntaxes'] 244 self.generate_attributetypes_dict() 245 self.generate_objectclass_dict() 246 self.generate_reverse_attributetypes_dict() 247 self.generate_ldapsyntaxes_dict() 248 249 _easyLDAP_schema_cache[_schema_cache_key] = {} 250 _easyLDAP_schema_cache[_schema_cache_key]['attributeTypes'] = copy.deepcopy(self.attributeTypes) 251 _easyLDAP_schema_cache[_schema_cache_key]['attributeTypesDict'] = copy.deepcopy(self.attributeTypesDict) 252 _easyLDAP_schema_cache[_schema_cache_key]['oidDict'] = copy.deepcopy(self.oidDict) 253 _easyLDAP_schema_cache[_schema_cache_key]['reverseAttributeTypesDict'] = copy.deepcopy(self.reverseAttributeTypesDict) 254 _easyLDAP_schema_cache[_schema_cache_key]['objectClasses'] = copy.deepcopy(self.objectClasses) 255 _easyLDAP_schema_cache[_schema_cache_key]['objectClassesDict'] = copy.deepcopy(self.objectClassesDict) 256 _easyLDAP_schema_cache[_schema_cache_key]['matchingRules'] = copy.deepcopy(self.matchingRules) 257 _easyLDAP_schema_cache[_schema_cache_key]['ldapSyntaxes'] = copy.deepcopy(self.ldapSyntaxes) 258 _easyLDAP_schema_cache[_schema_cache_key]['ldapSyntaxesDict'] = copy.deepcopy(self.ldapSyntaxesDict) 259 260 except ldap.SERVER_DOWN: 261 raise easyLDAP_exceptions.SERVER_UNAVAILABLE
262 263
264 - def __deepcopy__(self, memo):
265 """Creates a deepcopy of the easyLDAP class.""" 266 result = self.__class__() 267 memo[id(self)] = result 268 269 result.LDAPuri = self.LDAPuri 270 result.LDAPserver = self.LDAPserver 271 result.BindDN = self.BindDN 272 result.BindPW = self.BindPW 273 result.BaseDN = self.BaseDN 274 result.AdminDN = self.AdminDN 275 result.PeopleBaseDN = self.PeopleBaseDN 276 result.GroupBaseDN = self.GroupsBaseDN 277 result.HostsBaseDN = self.HostsBaseDN 278 result.MailAliasesBaseDN = self.MailAliasesBaseDN 279 result.AutomountBaseDN = self.AutomountBaseDN 280 result.LDAPServerCharsetEncoding = self.LDAPServerCharsetEncoding 281 result.posix_availableUidNumbers = self.posix_availableUidNumbers 282 result.posix_availableGidNumbers = self.posix_availableGidNumbers 283 if (self.BindDN != '') and self.has_dn(self.BindDN): 284 result.bind_norefresh(self.BindDN, self.BindPW) 285 286 result.EASY_LDAP = copy.deepcopy(self.CONFIG) 287 result.attributeTypes=copy.deepcopy(self.attributeTypes) 288 result.attributeTypesDict=copy.deepcopy(self.attributeTypesDict) 289 result.attributeTypesDict=copy.deepcopy(self.oidDict) 290 result.attributeTypesDict=copy.deepcopy(self.reverseAttributeTypesDict) 291 result.objectClasses=copy.deepcopy(self.objectClasses) 292 result.objectClassesDict=copy.deepcopy(self.objectClassesDict) 293 result.matchingRules=copy.deepcopy(self.matchingRules) 294 result.ldapSyntaxes=copy.deepcopy(self.ldapSyntaxes) 295 result.ldapSyntaxesDict=copy.deepcopy(self.ldapSyntaxesDict) 296 297 return result
298 299
300 - def __del__(self):
301 self.ldapsession.unbind_s()
302 303
304 - def generate_objectclass_dict(self):
305 """ 306 thisClass.generate_objectclass_dict() 307 308 is for class-internal use only. It is evoked once from 309 thisClass.__init__() to generate the python dictionary 310 thisClass.objectClassesDict. 311 312 You should not need to call this method. 313 """ 314 self.objectClassesDict={} 315 for schema_def in self.objectClasses: 316 schema_key = 'OID' 317 elements = [] 318 this_objectClassesDict = {'OID': '','DESC': '', 'SUP': [], 'MUST': [], 'MAY': [], 'AUXILIARY': False, 'STRUCTURAL': False } 319 objectClassNames = [] 320 exprList = string.split(schema_def) 321 exprList.append ('mySTOP') 322 323 for word in exprList: 324 word = string.strip (word,"'") 325 326 if word in ['NAME','DESC','SUP','MUST','MAY','mySTOP']: 327 if schema_key in ['NAME']: 328 schema_key = word 329 continue 330 if schema_key in ['SUP', 'MUST', 'MAY']: 331 this_objectClassesDict[schema_key] = elements 332 elements = [] 333 schema_key = word 334 continue 335 if schema_key in ['OID', 'DESC']: 336 this_objectClassesDict[schema_key] = string.join(elements) 337 elements = [] 338 schema_key = word 339 continue 340 341 if word in ['STRUCTURAL', 'AUXILIARY']: 342 this_objectClassesDict[word]=True 343 continue 344 345 if word not in ['(',')','$']: 346 if schema_key == 'NAME': 347 objectClassNames.append (word.lower()) 348 this_objectClassesDict[schema_key] = word 349 if schema_key in ['MUST', 'MAY', ]: 350 elements.append(word.lower()) 351 if schema_key in ['SUP', ]: 352 elements.append(word.lower()) 353 if schema_key in ['OID', 'DESC']: 354 elements.append (word) 355 356 for objectClassName in objectClassNames: 357 self.objectClassesDict[objectClassName]=this_objectClassesDict
358 359
361 """ 362 thisClass.generate_attributetypes_dict () 363 364 is for class-internal use only. It is evoked once from 365 thisClass.__init__() to generate the python dictionary 366 thisClass.attributeTypesDict. 367 368 You should not need to call this method. 369 """ 370 self.attributeTypesDict={} 371 self.oidDict 372 for schema_def in self.attributeTypes: 373 schema_key = 'OID' 374 elements = [] 375 this_attributeTypesDict = {'OID': '','DESC': '', 'SUP': '', 'SUBSTR': '', 'SYNTAX': '', 'EQUALITY': '', 'ORDERING': '', 376 'OBSOLETE': False, 'COLLECTIVE': False, 'SINGLE-VALUE': False, 'NO-USER-MODIFICATION': False} 377 attributeTypesNames = [] 378 exprList = string.split(schema_def) 379 exprList.append ('mySTOP') 380 381 for word in exprList: 382 word = string.strip (word,"'") 383 if word in ['NAME', 'DESC','SUP','SUBSTR','SYNTAX','EQUALITY', 'ORDERING' 384 'USAGE', 'mySTOP']: 385 if schema_key in ['NAME']: 386 schema_key = word 387 continue 388 else: 389 this_attributeTypesDict[schema_key] = string.join(elements) 390 elements = [] 391 schema_key = word 392 continue 393 394 if word in ['SINGLE-VALUE','OBSOLETE','NO-USER-MODIFICATION','COLLECTIVE']: 395 this_attributeTypesDict[word]=True 396 continue 397 398 if word not in ['(',')','$']: 399 if schema_key == 'NAME': 400 attributeTypesNames.append (word.lower()) 401 this_attributeTypesDict[schema_key] = word 402 elif schema_key == 'SUP': 403 elements.append (word.lower()) 404 else: 405 elements.append (word) 406 407 for attributeTypesName in attributeTypesNames: 408 self.attributeTypesDict[attributeTypesName]=this_attributeTypesDict 409 410 if not self.oidDict.has_key(schema_key): 411 self.oidDict[schema_key] = [] 412 self.oidDict[schema_key].append(attributeTypesName)
413 414
416 417 self.reverseAttributeTypesDict = { 'OID': {}, 'NAME': {}, } 418 for objectClassName, objectClass in self.objectClassesDict.items(): 419 420 # generate a list of all attributes in this objectClass 421 attributeTypeList = objectClass['MUST']+objectClass['MAY'] 422 for attrtype in [ at.lower() for at in attributeTypeList ]: 423 if not self.reverseAttributeTypesDict['NAME'].has_key(attrtype): 424 self.reverseAttributeTypesDict['NAME'][attrtype] = [attrtype] 425 else: 426 self.reverseAttributeTypesDict['NAME'][attrtype].append(objectClassName) 427 428 try: 429 oid = self.map_attrtypes2oids(attrtype)[0] 430 if not self.reverseAttributeTypesDict['OID'].has_key(oid): 431 self.reverseAttributeTypesDict['OID'][oid] = [objectClassName] 432 else: 433 self.reverseAttributeTypesDict['OID'][oid].append(objectClassName) 434 except: 435 pass
436 437
438 - def generate_ldapsyntaxes_dict(self):
439 """ 440 thisClass.generate_ldapsyntaxes__dict () 441 442 is for class-internal use only. It is evoked once from 443 thisClass.__init__() to generate the python dictionary 444 thisClass.ldapSyntaxesDict. 445 446 You should not need to call this method. 447 """ 448 if not self.ldapSyntaxes: 449 return 450 for schema_def in self.ldapSyntaxes: 451 schema_key = 'OID' 452 elements = [] 453 this_ldapSyntaxesDict = {'DESC': '', 'X-NOT-HUMAN-READABLE': False} 454 ldapSyntaxesOIDs = [] 455 exprList = string.split(schema_def) 456 exprList.append ('mySTOP') 457 458 for word in exprList: 459 word = string.strip (word,"'") 460 if word in ['DESC', 'X-NOT-HUMAN-READABLE', 'mySTOP']: 461 if schema_key in ['OID', 'X-NOT-HUMAN-READABLE']: 462 schema_key = word 463 continue 464 if schema_key == 'DESC': 465 this_ldapSyntaxesDict[schema_key] = string.join(elements) 466 elements = [] 467 schema_key = word 468 continue 469 470 if word not in ['(',')','$']: 471 if schema_key == 'OID': 472 ldapSyntaxesOIDs.append (word) 473 if schema_key == 'DESC': 474 elements.append (word) 475 if (schema_key == 'X-NOT-HUMAN-READABLE') and (word == 'TRUE'): 476 this_ldapSyntaxesDict[schema_key]=True 477 478 for ldapSyntaxOID in ldapSyntaxesOIDs: 479 ldapSyntaxName = this_ldapSyntaxesDict['DESC'] 480 if self.templateLDAPSyntaxValues.has_key(ldapSyntaxName): 481 this_ldapSyntaxesDict['DEFAULT'] = self.templateLDAPSyntaxValues[ldapSyntaxName]['default'] 482 this_ldapSyntaxesDict['REGEXP'] = self.templateLDAPSyntaxValues[ldapSyntaxName]['regexp'] 483 else: 484 this_ldapSyntaxesDict['DEFAULT'] = 'Empty' 485 this_ldapSyntaxesDict['REGEXP'] = '.*' 486 self.ldapSyntaxesDict[ldapSyntaxOID]=this_ldapSyntaxesDict
487 488
489 - def _rewrite_attrtype_names(self, attrdesc_list):
490 491 is_string_type = False 492 from easyLDAP_utils import _attrtype, _attropt, to_list_of_strings 493 if type(attrdesc_list) is not types.ListType: 494 is_string_type = True 495 attrdesc_list = to_list_of_strings(attrdesc_list) 496 497 rewrite_attrdesc_list = [] 498 try: 499 for attrdesc in attrdesc_list: 500 501 attrtype = _attrtype(attrdesc) 502 oid = self.map_attrtypes2oids(attrtype)[0] 503 if oid in self.CONFIG['preferredAttributeAliases'].keys(): 504 attrtype = self.CONFIG['preferredAttributeAliases'][oid] 505 elif attrtype.lower() == self.attributeTypesDict[attrtype.lower()]['NAME'].lower(): 506 attrtype = self.attributeTypesDict[attrtype.lower()]['NAME'] 507 else: 508 attrtype = attrtype.lower() 509 attropt = _attropt(attrdesc) 510 511 if not attropt: 512 rewrite_attrdesc_list.append(attrtype) 513 else: 514 rewrite_attrdesc_list.append('%s;%s' % (attrtype, attropt)) 515 516 except KeyError: 517 raise easyLDAP_exceptions.NO_SUCH_ATTRIBUTE 518 519 if is_string_type: 520 return rewrite_attrdesc_list[0] 521 else: 522 return rewrite_attrdesc_list
523 524
525 - def _rewrite_objectclass_names(self, objectclasses_list):
526 527 is_string_type = False 528 from easyLDAP_utils import _attrtype, _attropt, to_list_of_strings 529 if type (objectclasses_list) is not types.ListType: 530 is_string_type = True 531 objectclasses_list = to_list_of_strings(objectclasses_list) 532 533 rewrite_objclasses_list = [] 534 for objclass in objectclasses_list: 535 536 rewrite_objclasses_list.append(self.objectClassesDict[objclass.lower()]['NAME']) 537 538 if is_string_type: 539 return rewrite_objclasses_list[0] 540 else: 541 return rewrite_objclasses_list
542 543
544 - def _rewrite_names_to_fit_ldapschema(self, pyldapobject):
545 546 ### this is our way of creating a case insensivity for schema object classes and attributes 547 result_pyldapobject = [] 548 for ldap_single_object in pyldapobject: 549 ldap_single_object = list(ldap_single_object) 550 551 for (from_attrdesc, to_attrdesc) in zip(ldap_single_object[1].keys(), self._rewrite_attrtype_names(ldap_single_object[1].keys())): 552 if from_attrdesc != to_attrdesc: 553 ldap_single_object[1][to_attrdesc] = ldap_single_object[1][from_attrdesc] 554 del ldap_single_object[1][from_attrdesc] 555 556 ldap_single_object[1]['objectClass'] = self._rewrite_objectclass_names(ldap_single_object[1]['objectClass']) 557 558 result_pyldapobject.append(ldap_single_object) 559 return result_pyldapobject
560 561
562 - def adminbind(self,admin_bind_pw, refresh_cache=True):
563 """ 564 thisClass.adminbind('myADMINPW') 565 566 binds to the LDAP server with administrative access. The LDAP server's 567 admin DN is stored in thisClass.AdminDN, the administrative password 568 is given through the argument 'myADMINPW'. 569 """ 570 success = False 571 try: 572 self.ldapsession.simple_bind_s(self.AdminDN,admin_bind_pw) 573 self.LDAPSERVER_DOWN = False 574 self.BindDN = self.AdminDN 575 self.BindPW = admin_bind_pw 576 success = True 577 except ldap.SERVER_DOWN: 578 self.LDAPSERVER_DOWN=True 579 raise easyLDAP_exceptions.SERVER_UNAVAILABLE 580 except ldap.INVALID_CREDENTIALS: 581 raise_easyldap_exception(err_code=7) 582 583 if refresh_cache: 584 self.refresh_cache() 585 586 return success
587 588
589 - def adminbind_norefresh (self,admin_bind_pw):
590 """ 591 thisClass.bind_norefresh('myDN', 'myPW') 592 593 as the easyLDAP class does not load any objects into 594 the easyLDAP cache, this method is just an alias for 595 this_class.bind() 596 """ 597 return self.adminbind(admin_bind_pw=admin_bind_pw, refresh_cache=False)
598 599
600 - def bind(self, bind_dn, bind_pw, refresh_cache=True):
601 """ 602 thisClass.bind('myDN', 'myPW') 603 604 binds to the LDAP server with the given credentials 'myDN' 605 and 'myPW'. 606 """ 607 success = False 608 try: 609 self.ldapsession.simple_bind_s(bind_dn,bind_pw) 610 self.BindDN = bind_dn 611 self.BindPW = bind_pw 612 success = True 613 except ldap.SERVER_DOWN: 614 raise easyLDAP_exceptions.SERVER_UNAVAILABLE 615 except ldap.INVALID_CREDENTIALS: 616 raise easyLDAP_exceptions.ACCESS_DENIED 617 618 if refresh_cache: 619 self.refresh_cache() 620 621 return success
622 623
624 - def bind_norefresh (self, bind_dn, bind_pw):
625 """ 626 thisClass.bind_norefresh('myDN', 'myPW') 627 628 as the easyLDAP class does not load any objects into 629 the easyLDAP cache, this method is just an alias for 630 this_class.bind() 631 """ 632 return self.bind(bind_dn, bind_pw, refresh_cache=False)
633 634
635 - def uid_bind (self, bind_uid, bind_pw, refresh_cache=True):
636 """ 637 thisClass.uid_bind('myUID', 'myPW') 638 639 binds to the LDAP server. This method tries to find the UID's 640 corresponding DN in the LDAP tree starting at thisClass.BaseDN. 641 642 Binding by UID will fail if the given UID 'myUID' is not unique 643 to the specified LDAP tree. 644 """ 645 my_bind_dn = self.map_uid2dn (bind_uid) 646 return self.bind(bind_dn=my_bind_dn, bind_pw=bind_pw, refresh_cache=refresh_cache)
647 648
649 - def uid_bind_norefresh (self, bind_uid, bind_pw):
650 """ 651 thisClass.uid_bind_norefresh('myUID', 'myPW') 652 653 as the easyLDAP class does not load any objects into 654 the easyLDAP cache, this method is just an alias for 655 this_class.bind() 656 """ 657 return self.uid_bind(bind_uid, bind_pw, refresh_cache=False)
658 659
660 - def cn_bind(self, bind_cn, bind_pw, refresh_cache=True):
661 """ 662 thisClass.cnbind('myCN', 'myPW') 663 664 binds to the LDAP server. This method tries to find the cn's 665 corresponding DN in the LDAP tree starting at thisClass.BaseDN. 666 667 Binding by CN (Common Name) will fail if the given cn 'myCN' is 668 not unique to the specified LDAP tree. 669 """ 670 my_bind_dn = self.map_cn2dn (bind_cn) 671 return self.bind(my_bind_dn, bind_pw, refresh_cache=refresh_cache)
672 673
674 - def cn_bind_norefresh(self, bind_cn, bind_pw):
675 """ 676 thisClass.uid_bind_norefresh('myDN', 'myPW') 677 678 as the easyLDAP class does not load any objects into 679 the easyLDAP cache, this method is just an alias for 680 this_class.bind() 681 """ 682 return self.cn_bind(bind_cn, bind_pw, refresh_cache=False)
683 684
685 - def anonymous_bind(self, refresh_cache=True):
686 """ 687 thisClass.anonbind() 688 689 tries an anonymous bind to the LDAP server. 690 """ 691 success = False 692 try: 693 self.ldapsession.simple_bind_s('','') 694 self.BindDN = '' 695 self.BindPW = '' 696 success = True 697 698 except ldap.SERVER_DOWN: 699 raise easyLDAP_exceptions.SERVER_UNAVAILABLE 700 701 if refresh_cache: 702 self.refresh_cache() 703 704 return success
705 706
707 - def anonymous_bind_norefresh(self):
708 """ 709 thisClass.anonymous_norefresh() 710 711 tries an anonymous bind to the LDAP server. 712 """ 713 return self.anonymous_bind(refresh_cache=False)
714 715
716 - def is_pyldapobject(self, ldap_data_dict):
717 """ 718 thisClass.is_ldapobject('myLDAP_DATA') 719 720 returns True, if the given data structure conforms to the 721 python-ldap data format and only contains data of a single DN. 722 """ 723 from easyLDAP_utils import is_pyldapobject 724 return is_pyldapobject(ldap_data_dict)
725 726
727 - def is_pyldaptree(self, ldap_data_dict):
728 """ 729 thisClass.is_ldaptree('myLDAP_DATA') 730 731 returns True, if the given data structure conforms to the 732 python-ldap data format and the hierarchical structure is 733 tree-like. 734 """ 735 from easyLDAP_utils import is_pyldaptree 736 return is_pyldaptree(ldap_data_dict)
737 738
739 - def is_singlevalueattr(self, this_attr):
740 """ 741 thisClass.is_singlevalueattr('myATTRIBUTE') 742 743 tests if the SINGLE-VALUE flag is set for the LDAP attribute 744 'myATTRIBUTE'. 745 """ 746 from easyLDAP_utils import _attrtype 747 return self.attributeTypesDict[_attrtype(this_attr).lower()]['SINGLE-VALUE']
748 749
750 - def is_obsoleteattr(self, this_attr):
751 """ 752 thisClass.is_obsoleteattr('myATTRIBUTE') 753 754 tests if the OBSOLETE flag is set for the LDAP attribute 755 'myATTRIBUTE'. 756 """ 757 from easyLDAP_utils import _attrtype 758 return self.attributeTypesDict[_attrtype(this_attr).lower()]['OBSOLETE']
759 760
761 - def is_nousermodattr(self, this_attr):
762 """ 763 thisClass.is_nousermodattr('myATTRIBUTE') 764 765 tests if the NO-USER-MODIFICATION flag is set for the LDAP 766 attribute 'myATTRIBUTE'. 767 """ 768 from easyLDAP_utils import _attrtype 769 return self.attributeTypesDict[_attrtype(this_attr).lower()]['NO-USER-MODIFICATION']
770 771
772 - def is_collectiveattr(self, this_attr):
773 """ 774 thisClass.is_collectiveattr('myATTRIBUTE') 775 776 tests if the COLLECTIVE flag is set for the LDAP attribute 777 'myATTRIBUTE'. 778 """ 779 from easyLDAP_utils import _attrtype 780 return self.attributeTypesDict[_attrtype(this_attr).lower()]['COLLECTIVE']
781 782
783 - def get_objectclasses(self, capitalize=False):
784 """ 785 thisClass.get_objectclasses() 786 787 returns a list of all objectClasses that are known to the 788 server's LDAP schema. 789 """ 790 if capitalize: 791 return [ self.objectClassesDict[obc]['NAME'] for obc in self.objectClassesDict.keys() ] 792 else: 793 return self.objectClassesDict.keys()
794 795
796 - def get_attributetypes(self, capitalize=False):
797 """ 798 thisClass.get_attributetypes() 799 800 returns a list of all attirbuteTypes that are known the 801 server's LDAP schema. 802 """ 803 if capitalize: 804 return [ at['NAME'] for at in self.attributeTypesDict ] 805 else: 806 return self.attributeTypesDict.keys()
807 808
809 - def check_objectclass_dependencies(self, objectclass_list):
810 """ 811 check_objectclass_dependencies ('myOBJECT_CLASS'|['myOBJECT_CLASS1', 812 'myOBJECT_CLASS2']) 813 814 checks if and what objectClasses are needed before adding them 815 to an LDAP directory. The dependencies are derived from the 816 server's LDAP schema. 817 818 The method returns a list of ObjectClasses, including those 819 that were given to the method and those that are needed 820 to complete the set. 821 """ 822 from easyLDAP_utils import to_list_of_strings 823 # if there is just one objectClass string convert it to ListType, objectclasses are lower case 824 these_objectClasses = [ obc.lower() for obc in to_list_of_strings(objectclass_list) ] 825 826 # we will return at least what we got 827 checkedObjectClasses = these_objectClasses 828 for this_objectClass in these_objectClasses: 829 830 if self.is_valid_objectclass(this_objectClass): 831 832 # add superior objectClasses to the string that we wil return 833 superiorObjectClasses = self._rewrite_objectclass_names(self.objectClassesDict[this_objectClass.lower()]['SUP']) 834 for superiorObjectClass in superiorObjectClasses: 835 if superiorObjectClass.lower() not in [ objc.lower() for objc in checkedObjectClasses ]: 836 checkedObjectClasses.append(superiorObjectClass) 837 838 # done 839 return checkedObjectClasses
840 841
842 - def map_objectclass2attr(self, objectclass):
843 """ 844 thisClass.map_objectclass2attr ('myOBJECT_CLASS') 845 846 returns all attributes that are mentioned in the server's 847 LDAP schema for objectClass 'myOBJECT_CLASS'. 848 """ 849 return self.objectClassesDict[objectclass.lower()]['MUST']+self.objectClassesDict[objectclass.lower()]['MAY']
850 851
852 - def map_attrtype2objectclasses(self, attrtype):
853 """ 854 thisClass.map_attrtype2objectclass ('myATTRTYPE') 855 856 returns a lists of objectClasses that the given attribute 857 'myATTRTYPE' occurs in. This list is derived from the 858 server's LDAP schema. 859 """ 860 from easyLDAP_utils import _attrtype 861 resultObjectClasses = [] 862 863 # use attribute's OID as reference instead of the attribute's name 864 oid = self.map_attrtypes2oids(_attrtype(attrtype))[0] 865 if oid in self.reverseAttributeTypesDict['OID'].keys(): 866 resultObjectClasses = self.reverseAttributeTypesDict['OID'][oid] 867 868 # the attribute obviously was not known to the server's LDAP schema... 869 if len (resultObjectClasses) == 0: 870 raise easyLDAP_exceptions.NO_SUCH_ATTRIBUTE 871 872 return resultObjectClasses
873 874
875 - def is_valid_objectclass(self, objectclass):
876 """ 877 thisClass.is_valid_objectclass('myOBJECTCLASS') 878 879 tests if the given objectClass 'myOBJECTCLASS' is a valid 880 objectClass according to the server's LDAP schema. 881 """ 882 return (objectclass.lower() in [ oc for oc in self.objectClassesDict.keys() ])
883
884 - def is_valid_attrtype(self, attrtype):
885 """ 886 thisClass.is_valid_attrtype('myATTRTYPE') 887 888 tests if the given attribute type 'myATTRTYPE' is a valid 889 attribute type according to the server's LDAP schema. 890 """ 891 return (attrtype.lower() in [ at for at in self.attributeTypesDict.keys() ])
892 893
894 - def has_valid_attrtype(self, attrdesc):
895 """ 896 thisClass.has_valid_attrtype('myATTRDESC') 897 898 tests if the given attribute 'myATTRDESC' has a valid attributeType 899 according to the server's LDAP schema. 900 """ 901 from easyLDAP_utils import _attrtype 902 if self.map_attrtype2objectclass(_attrtype(attrdesc)) > 0: 903 return True 904 return False
905 906
907 - def has_oid_set(self, oid, pyldapobject):
908 """ 909 thisClass.has_oid_set('myOID'[, mySINGLELDAPOBJECT]) 910 911 checks if the given OID 'myOID' is set in the cached 912 easyLDAP object. If so, the method's result is True. 913 914 Another LDAP object than the one currently cached 915 can be analyzed by passing 'mySINGLELDAPOBJECT'. The 916 lengths of the passed LDAP object has to be 1. 917 """ 918 from easyLDAP_utils import is_pyldapobject 919 if is_pyldapobject(pyldapobject): 920 if oid in self.get_used_attrtype_oids(pyldapobject): 921 return True 922 923 return False
924 925
926 - def get_used_attrtype_oids(self, pyldapobject):
927 """ 928 thisClass.get_used_attrtype_oids() 929 930 returns a list of those attribute OIDs, that are currently 931 used in the cached easyLDAP object. This list is taken from 932 the server's LDAP schema. If - by some reason - the easyLDAP 933 object cache is, an empty list is returned. 934 935 Another LDAP object than the one currently cached 936 can be analyzed by passing 'mySINGLELDAPOBJECT'. The 937 lengths of the passed LDAP object has to be 1. 938 """ 939 from easyLDAP_utils import _attrtype, _unique 940 oidList=[] 941 for key in [ at.lower() for at in pyldapobject[0][1].keys() ]: 942 oidList.append (self.attributeTypesDict[_attrtype(key)]['OID']) 943 return _unique(oidList)
944 945
946 - def map_attrtypes2oids (self, attribute_types_list):
947 """ 948 thisClass.map_attrtypes2oids('myATTRIBUTELIST') 949 950 maps the given attributes in 'myATTRIBUTELIST' 951 to a list of their unequivocal OIDs. If the mapping 952 fails, an empty list is returned. 953 """ 954 from easyLDAP_utils import _attrtype, to_list_of_strings 955 OIDList = [] 956 if type(attribute_types_list) is not types.ListType: 957 attribute_types_list = to_list_of_strings(attribute_types_list) 958 attribute_types_list = [ at.lower() for at in attribute_types_list ] 959 960 for myAttr in attribute_types_list: 961 if self.is_valid_attrtype(_attrtype(myAttr)): 962 OIDList.append(self.attributeTypesDict[_attrtype(myAttr)]['OID']) 963 else: 964 # no such attribute 965 raise easyLDAP_exceptions.NO_SUCH_ATTRIBUTE 966 967 return OIDList
968 969
970 - def map_oid2attrtypes (self, oid):
971 """ 972 thisClass.map_oid2attrtypes('myOID') 973 974 maps the given OID 'myOID' to a list of their 975 possible ATTRIBUTEs according to the LDAP server's 976 LDAP schema. If the mapping fails, an empty list 977 is returned. 978 """ 979 ATTRList = [] 980 if type(oid) is types.StringType: 981 for attrtype, dict in self.attributeTypesDict.items(): 982 if oid == dict['OID']: 983 ATTRList.append(attrtype) 984 985 return ATTRList
986 987
988 - def get_used_attrtypes(self,pyldapobject, capitalize=False):
989 """ 990 thisClass.get_used_attrtypes([mySINGLELDAPOBJECT]) 991 992 returns a list of attribute types that are used in the current easyLDAP 993 object. If - by some reason - the cache is empty, an empty list 994 is returned. 995 996 Another LDAP object than the one currently cached 997 can be analyzed by passing 'mySINGLELDAPOBJECT'. The 998 lengths of the passed LDAP object has to be 1. 999 """ 1000 from easyLDAP_utils import _attrtype, _unique, is_pyldapobject 1001 if is_pyldapobject(pyldapobject, strict=False): 1002 if capitalize: 1003 return _unique(self._rewrite_attrtype_names(pyldapobject[0][1].keys())) 1004 else: 1005 return _unique([ _attrtype(key).lower() for key in pyldapobject[0][1].keys() ]) 1006 else: 1007 raise easyLDAP_exceptions.NOT_A_PYTHON_LDAPOBJECT
1008 1009
1010 - def get_used_attroptions(self,attrdesc,pyldapobject):
1011 """ 1012 thisClass.get_used_attroptions('myATTRDESC', [mySINGLELDAPOBJECT]) 1013 1014 returns a list of all attribute options used with attribute type 1015 same as in 'myATTRDESC'. The comparison is performed on an OID 1016 basis. So, if an alias of an 'myATTRDESC' is used, it will 1017 be taken into account. 1018 """ 1019 from easyLDAP_utils import _attrtype, _attropt, _unique, is_pyldapobject 1020 if is_pyldapobject(pyldapobject): 1021 1022 try: 1023 if self.has_oid_set(self.map_attrtypes2oids(_attrtype(attrdesc))[0],pyldapobject): 1024 attrTypeAliases = self.get_attrtype_aliases(_attrtype(attrdesc)) 1025 return _unique([ _attropt(key) for key in pyldapobject[0][1].keys() if _attrtype(key) in attrTypeAliases ]) 1026 1027 else: 1028 # none of the mapped attributes is set 1029 raise easyLDAP_exceptions.ATTRIBUTE_NOT_SET 1030 1031 except IndexError: 1032 # given attribute could not be mapped to an OID in LDAP schema 1033 raise easyLDAP_exceptions.NO_SUCH_ATTRIBUTE 1034 1035 else: 1036 raise easyLDAP_exceptions.NOT_A_PYTHON_LDAPOBJECT
1037 1038
1039 - def get_attrtype_aliases(self,attrtype, capitalize=False):
1040 """ 1041 thisClass.get_attrtypealiases('myATTRTYPE') 1042 1043 returns a list of attribute types that are treated as aliases in 1044 the LDAP server's schema. 1045 """ 1046 from easyLDAP_utils import _attrtype 1047 if capitalize: 1048 return [ self.attributeTypesDict[attrtype_alias]['NAME'] for attrtype_alias in self.map_oid2attrtypes(self.map_attrtypes2oids(_attrtype(attrtype))[0]) ] 1049 else: 1050 return [ attrtype_alias for attrtype_alias in self.map_oid2attrtypes(self.map_attrtypes2oids(_attrtype(attrtype))[0]) ]
1051 1052
1053 - def map_attrtype2ldapsyntax(self, this_attrtype):
1054 """ 1055 thisClass.map_attrtype2ldapsyntax('myATTRTYPE') 1056 1057 returns the LDAPSyntax for the given attribute 'myATTRTYPE'. Using 1058 the dictionary thisClass.templateLDAPSyntaxValues will help you 1059 to generate a default value for new attribute values: 1060 1061 print thisClass.templateLDAPSyntaxValues[ 1062 thisClass.map_attrtype2ldapsyntax['myATTRTYPE'] 1063 ] 1064 """ 1065 from easyLDAP_utils import _attrtype 1066 if not self.ldapSyntaxesDict: return None 1067 try: 1068 self.attributeTypesDict[_attrtype(this_attrtype).lower()] 1069 attrSyntaxOID = self.attributeTypesDict[_attrtype(this_attrtype).lower()]['SYNTAX'] 1070 if attrSyntaxOID == '': 1071 return self.ldapSyntaxesDict['NO SPECIFIED SYNTAX'] 1072 else: 1073 attrSyntaxOID = string.split(attrSyntaxOID, '{')[0] 1074 return self.ldapSyntaxesDict[attrSyntaxOID] 1075 except KeyError: 1076 raise easyLDAP_exceptions.NO_SUCH_ATTRIBUTE
1077 1078
1079 - def map_attrtype2ldapsyntaxname(self, this_attrtype):
1080 """ 1081 thisClass.map_attrtype2ldapsyntax('myATTRTYPE') 1082 1083 returns the LDAPSyntax for the given attribute 'myATTRTYPE'. Using 1084 the dictionary thisClass.templateLDAPSyntaxValues will help you 1085 to generate a default value for new attribute values: 1086 1087 print thisClass.templateLDAPSyntaxValues[ 1088 thisClass.map_attrtype2ldapsyntax['myATTRTYPE'] 1089 ] 1090 """ 1091 from easyLDAP_utils import _attrtype 1092 if not self.ldapSyntaxesDict: return None 1093 try: 1094 self.attributeTypesDict[_attrtype(this_attrtype).lower()] 1095 attrSyntaxOID = self.attributeTypesDict[_attrtype(this_attrtype).lower()]['SYNTAX'] 1096 if attrSyntaxOID == '': 1097 return 'NO SPECIFIED SYNTAX' 1098 else: 1099 attrSyntaxOID = string.split(attrSyntaxOID, '{')[0] 1100 return self.ldapSyntaxesDict[attrSyntaxOID]['DESC'] 1101 except KeyError: 1102 raise easyLDAP_exceptions.NO_SUCH_ATTRIBUTE
1103 1104
1105 - def map_attrtype2ldapsyntaxoid(self, this_attrtype):
1106 """ 1107 thisClass.map_attrtype2ldapsyntaxoid('myATTRTYPE') 1108 1109 returns the LDAPSyntax's OID for the given attribute type 1110 'myATTRTYPE'. 1111 """ 1112 from easyLDAP_utils import _attrtype 1113 if self.has_valid_attrtype(this_attrtype): 1114 attrSyntaxOID = self.attributeTypesDict[_attrtype(this_attrtype).lower()]['SYNTAX'] 1115 if attrSyntaxOID == '': 1116 return 'NO SPECIFIED SYNTAX' 1117 else: 1118 return attrSyntaxOID.split('{')[0] 1119 else: 1120 raise easyLDAP_exceptions.NO_SUCH_ATTRIBUTE
1121
1122 - def map_attrtype2valuemaxlen(self, this_attrtype):
1123 """ 1124 thisClass.map_attrtype2ldapsyntaxoid('myATTRTYPE') 1125 1126 returns the LDAPSyntax's OID for the given attribute type 1127 'myATTRTYPE'. 1128 """ 1129 from easyLDAP_utils import _attrtype 1130 if self.has_valid_attrtype(this_attrtype): 1131 attrSyntaxOID = self.attributeTypesDict[_attrtype(this_attrtype).lower()]['SYNTAX'] 1132 if '{' in attrSyntaxOID: 1133 return attrSyntaxOID.split('{')[1].rstrip('}') 1134 return 0 1135 else: 1136 raise easyLDAP_exceptions.NO_SUCH_ATTRIBUTE
1137 1138
1139 - def attrtype_needs_objectclass(self, attr):
1140 """ 1141 attrtype_needs_objectclass('myATTRIBUTE') 1142 1143 returns True if the easyLDAP object in cache needs an additional 1144 objectClass before adding the LDAP attribute 'myATTRIBUTE'. If 1145 the objectClass dependencies are already all solved, it returns False. 1146 1147 The pseudo-boolean funtcion returns None, if there is no such 1148 attribute in the server's LDAP schema. 1149 """ 1150 neededObjectClasses = [] 1151 setObjectClasses = [] 1152 setObjectClasses = self.get_used_objectclasses() 1153 if 'ABSTRACT' in setObjectClasses: 1154 return False 1155 neededObjectClasses = self.map_attrtype2objectclasses(attr) 1156 if len (neededObjectClasses) > 0: 1157 for neededObjectClass in neededObjectClasses: 1158 1159 if neededObjectClass in setObjectClasses: 1160 # we just need one objectClass that is required by the attribute 1161 return False 1162 return True 1163 else: 1164 # attribute not known to the server 1165 raise easyLDAP_exceptions.NO_SUCH_ATTRIBUTE
1166 1167
1168 - def search(self, filter='(objectClass=*)', scope=ldap.SCOPE_SUBTREE, base='',retrieve_data=False):
1169 """ 1170 thisClass.search(filter='MyFILTER', scope=myLDAPSCOPE, base='myLDAPSEARCHBASEDN') 1171 1172 performs a raw ldap.search request and returns the DNs of objects the search filter applies to. 1173 """ 1174 from easyLDAP_utils import ldapDictionaryDecode 1175 1176 dn_list = [] 1177 if not base: 1178 base = self.CONFIG['BaseDN'] 1179 try: 1180 search = ldapDictionaryDecode(self.ldapsession.search_s(base, scope, filter), config_defaults=self.CONFIG) 1181 if search and not retrieve_data: 1182 dn_list = [ obj[0] for obj in search ] 1183 return dn_list 1184 1185 return search 1186 1187 except ldap.SERVER_DOWN: 1188 raise easyLDAP_exceptions.SERVER_UNAVAILABLE
1189 1190
1191 - def map_uidNumber2uid(self, uid_number):
1192 """ 1193 thisClass.map_uidNumber2uid ('myUIDNUMBER') 1194 1195 transforms the given uidNumber 'myUIDNUMBER' to the corresponding uid. 1196 The search is started at base DN thisClass.BaseDN. 1197 """ 1198 from easyLDAP_utils import ldapDictionaryDecode 1199 1200 try: 1201 if type(uid_number) is types.ListType: 1202 uid_number = str(uid_number[0]) 1203 else: 1204 uid_number = str(uid_number) 1205 uidnumbersearch = ldapDictionaryDecode(self.ldapsession.search_s(self.BaseDN, ldap.SCOPE_SUBTREE,'(&(objectClass=posixAccount)(uidNumber='+uid_number+'))'), config_defaults=self.CONFIG) 1206 1207 if len(uidnumbersearch) > 1: 1208 # given gidnumber is not unique in the ldap tree 1209 raise easyLDAP_exceptions.MULTIPLE_DNs_FOR_UID 1210 1211 elif len(uidnumbersearch) == 0: 1212 # no such UIDNUMBER 1213 raise easyLDAP_exceptions.NO_SUCH_POSIXACCOUNT 1214 1215 else: 1216 uid = uidnumbersearch[0][1]['uid'][0] 1217 1218 return uid 1219 1220 except ldap.SERVER_DOWN: 1221 raise easyLDAP_exceptions.SERVER_UNAVAILABLE
1222 1223
1224 - def map_gid2gidNumber(self, gid):
1225 """ 1226 thisClass.map_gid2gidNumber ('myGID') 1227 1228 transforms the given gid 'myGID' to the corresponding gidNumber. 1229 The search is started at base DN thisClass.BaseDN. 1230 """ 1231 from easyLDAP_utils import ldapDictionaryDecode 1232 1233 try: 1234 if type(this_gid) is types.ListType: 1235 gid = str(this_gid[0]) 1236 else: 1237 gid = str(this_gid) 1238 gidsearch = ldapDictionaryDecode(self.ldapsession.search_s(self.BaseDN, ldap.SCOPE_SUBTREE,'(&(objectClass=posixGroup)(cn='+gid+'))'), config_defaults=self.CONFIG) 1239 1240 if len(gidsearch) > 1: 1241 # given gid is not unique in the ldap tree 1242 raise easyLDAP_exceptions.MULTIPLE_DNs_FOR_GID 1243 1244 elif len(gidsearch) == 0: 1245 # no such GID 1246 raise easyLDAP_exceptions.NO_SUCH_POSIXGROUP 1247 1248 else: 1249 if gidsearch[0][1].has_key('gidNumber'): 1250 gidNumber = int(gidsearch[0][1]['gidNumber'][0]) 1251 return gidNumber 1252 else: 1253 # the found gid does not have a gidNumber attribute 1254 self.raise_easyldap_exception(err_code=27) 1255 except ldap.SERVER_DOWN: 1256 raise easyLDAP_exceptions.SERVER_UNAVAILABLE
1257 1258
1259 - def map_gidNumber2gid(self, gid_number):
1260 """ 1261 thisClass.map_gidNumber2gid ('myGIDNUMBER') 1262 1263 transforms the given gidNumber 'myGIDNUMBER' to the corresponding gid. 1264 The search is started at base DN thisClass.BaseDN. 1265 """ 1266 from easyLDAP_utils import ldapDictionaryDecode 1267 1268 try: 1269 if type(gid_number) is types.ListType: 1270 gid_number = str(gid_number[0]) 1271 else: 1272 gid_number = str(gid_number) 1273 gidnumbersearch = ldapDictionaryDecode(self.ldapsession.search_s(self.BaseDN, ldap.SCOPE_SUBTREE,'(&(objectClass=posixGroup)(gidNumber='+gidnumber+'))'), config_defaults=self.CONFIG) 1274 1275 if len(gidnumbersearch) > 1: 1276 # given gidnumber is not unique in the ldap tree 1277 raise easyLDAP_exceptions.MULTIPLE_DNs_FOR_GID 1278 1279 elif len(gidnumbersearch) == 0: 1280 # no such GIDNUMBER 1281 raise easyLDAP_exceptions.NO_SUCH_POSIXGROUP 1282 1283 else: 1284 cn = gidnumbersearch[0][1]['cn'][0] 1285 return cn 1286 1287 except ldap.SERVER_DOWN: 1288 raise easyLDAP_exceptions.SERVER_UNAVAILABLE
1289 1290
1291 - def map_uid2dn(self, uid, searchbase=None, scope=ldap.SCOPE_SUBTREE):
1292 """ 1293 thisClass.map_uid2dn ('myUID') 1294 1295 transforms the given uid 'myUID' - if unique - to the corresponding 1296 DN in the LDAP tree. The search is started at base DN thisClass.BaseDN. 1297 """ 1298 from easyLDAP_utils import ldapDictionaryDecode 1299 1300 if searchbase is None: 1301 searchbase = self.BaseDN 1302 1303 res = ldapDictionaryDecode(self.ldapsession.search_s(searchbase, scope, 'uid='+uid,None), config_defaults=self.CONFIG) 1304 1305 if len(res) < 1: 1306 return None 1307 1308 elif len(res) == 1: 1309 return ( res[0][0] ) 1310 1311 elif len(res) > 1: 1312 raise easyLDAP_exceptions.MULTIPLE_DNs_FOR_UID
1313 1314
1315 - def map_gid2dn(self, gid, searchbase=None, scope=ldap.SCOPE_SUBTREE):
1316 """ 1317 thisClass.map_gid2dn ('myGID') 1318 1319 transforms the given gid 'myGID' - if unique - to the corresponding 1320 DN in the LDAP tree. The search is started at base DN thisClass.BaseDN. 1321 """ 1322 from easyLDAP_utils import ldapDictionaryDecode 1323 1324 if searchbase == '': 1325 searchbase = self.BaseDN 1326 res=ldapDictionaryDecode(self.ldapsession.search_s(searchbase, scope, 'cn='+gid,None), config_defaults=self.CONFIG) 1327 1328 if len(res) < 1: 1329 return None 1330 1331 elif len(res) == 1: 1332 return ( res[0][0] ) 1333 1334 elif len(res) > 1: 1335 raise easyLDAP_exceptions.MULTIPLE_DNs_FOR_UID
1336 1337
1338 - def map_cn2dn(self, cn, searchbase=None, scope=ldap.SCOPE_SUBTREE):
1339 """ 1340 thisClass.map_cn2dn ('myCN') 1341 1342 transforms the given common name 'myCN' - if unique - to the 1343 corresponding DN in the LDAP tree. The search is started at 1344 base DN thisClass.BaseDN. 1345 """ 1346 from easyLDAP_utils import ldapDictionaryDecode 1347 1348 if searchbase is None: 1349 searchbase = self.BaseDN 1350 res=ldapDictionaryDecode(self.ldapsession.search_s(searchbase, scope, 'cn='+cn, None), config_defaults=self.CONFIG) 1351 1352 if len(res) < 1: 1353 return None 1354 1355 elif len(res) == 1: 1356 return ( res[0][0] ) 1357 1358 elif len(res) > 1: 1359 raise easyLDAP_exceptions.MULTIPLE_DNs_FOR_CN
1360 1361
1362 - def map_ou2dn(self, ou, searchbase=None, scope=ldap.SCOPE_SUBTREE):
1363 """ 1364 thisClass.map_ou2dn ('myOU', 'mySUBTREE') 1365 1366 transforms the given organizationalUnit 'myOU' - if unique - to the 1367 corresponding DN in the LDAP tree. The search is started at 1368 base DN thisClass.BaseDN. 1369 """ 1370 from easyLDAP_utils import ldapDictionaryDecode 1371 1372 if searchbase is None: 1373 searchbase = self.BaseDN 1374 res = ldapDictionaryDecode(self.ldapsession.search_s(searchbase, scope, '(&(objectClass=organizationalUnit)(ou='+ou+'))',None), config_defaults=self.CONFIG) 1375 1376 if len(res) < 1: 1377 return None 1378 1379 elif len(res) == 1: 1380 return ( res[0][0] ) 1381 1382 elif len(res) > 1: 1383 raise easyLDAP_exceptions.MULTIPLE_DNs_FOR_OU
1384 1385
1386 - def map_dn2ufn(self, dn, searchbase=None):
1387 """ 1388 thisClass.map_dn2ufn ('myDN'): 1389 1390 tries to map a given \'myDN\' to a user-friendly DN. This 1391 method is taken directly from python-ldap. 1392 """ 1393 if searchbase is None: 1394 searchbase = self.BaseDN 1395 #return ldap.dn2ufn(this_dn) 1396 return ''
1397 1398
1399 - def map_uid2posixgroups (self, uid, searchbase=None, scope=ldap.SCOPE_SUBTREE):
1400 """ 1401 thisClass.map_uid2posixgroups ('myUID'[,'mySUBTREE']) 1402 1403 find all ldap groups that the given uid 'myUID' is a posix member of. 1404 As a result the method returns a list of posixGroup DNs. 1405 The search is started at base DN thisClass.BaseDN if not otherswise 1406 specified in 'mySUBTREE'. 1407 """ 1408 from easyLDAP_utils import ldapDictionaryDecode 1409 1410 if searchbase is None: 1411 searchbase = self.BaseDN 1412 res = ldapDictionaryDecode(self.ldapsession.search_s(searchbase, scope, 'memberUid='+this_uid,None), config_defaults=self.CONFIG) 1413 1414 if len(res) < 1: 1415 return None 1416 1417 elif len(res) >= 1: 1418 return ( [obj[0] for obj in res] )
1419 1420
1421 - def map_uid2uniquemembergroups(self,uid,searchbase=None, user_searchbase=None, group_searchbase=None, scope=ldap.SCOPE_SUBTREE):
1422 """ 1423 thisClass.map_uid2uniquemembergroups ('myUID'[,'mySUBTREE']) 1424 1425 find all groups that the given uid 'myUID' is a unique member of. 1426 As a result the method returns a list of posixGroup DNs. 1427 The search is started at base DN thisClass.BaseDN if not otherswise 1428 specified in 'mySUBTREE'. 1429 """ 1430 from easyLDAP_utils import ldapDictionaryDecode 1431 1432 if searchbase is None: 1433 if user_searchbase is None: 1434 user_searchbase = self.BaseDN 1435 if group_searchbase is None: 1436 group_searchbase = self.BaseDN 1437 else: 1438 user_searchbase = group_searchbase = searchbase 1439 1440 userDn = self.map_uid2dn(uid, searchbase=user_searchbase) 1441 if userDn is not None: 1442 # searching for substrings in a dn is a bit more tricky than searching for substrings in strings 1443 # ldap libs do not support the search of a substring in attributes of dn type 1444 # however this can be worked around with the following hack... 1445 1446 # search for all relevant object classes (groupOfNames, groupOfUniqueNames) 1447 searchres=ldapDictionaryDecode(self.ldapsession.search_s(this_subtree, ldap.SCOPE_SUBTREE, '(|(objectClass=groupOfNames)(objectClass=groupOfUniqueNames))',None), config_defaults=self.CONFIG) 1448 1449 if len(searchres) < 1: 1450 return None 1451 1452 elif len(searchres) >= 1: 1453 res = copy.deepcopy(searchres) 1454 for obj in searchres: 1455 # presume that the uid does not appear in the groups unique members' list 1456 uid_in_group = False 1457 1458 # find a uid in the list of unique_members... 1459 unique_members = [] 1460 if obj[1].has_key('member'): 1461 unique_members = unique_members + obj[1]['member'] 1462 if obj[1].has_key('uniqueMember'): 1463 unique_members = unique_members + obj[1]['uniqueMember'] 1464 1465 for unique_member in unique_members: 1466 if re.match ('^uid=%s,.*' % uid,unique_member): 1467 uid_in_group = True 1468 1469 if not uid_in_group: 1470 res.remove(obj) 1471 1472 return [obj[0] for obj in res] 1473 else: 1474 return None
1475 1476
1477 - def has_dn(self, dn, searchbase=None, scope=ldap.SCOPE_SUBTREE):
1478 """ 1479 thisClass.has_dn ('myDN') 1480 1481 checks, if the given distinguished name \'myDN\' exists in 1482 the server\'s LDAP directory. The searches starts with the 1483 thisClass.BaseDN. 1484 """ 1485 from easyLDAP_utils import ldapDictionaryDecode 1486 1487 try: 1488 searchtest = ldapDictionaryDecode(self.ldapsession.search_s(dn, scope, 'objectClass=*'), config_defaults=self.CONFIG) 1489 return True 1490 except ldap.NO_SUCH_OBJECT: 1491 return False 1492 except ldap.INVALID_DN_SYNTAX: 1493 raise easyLDAP_exceptions.INVALID_DN_SYNTAX
1494 1495
1496 - def get_basedn(self):
1497 """ 1498 thisClass.get_basedn () 1499 1500 returns the absolute DN of the currently 1501 cached easyLDAP object/tree/subtree 1502 from the LDAP server's directory tree. 1503 """ 1504 return self.BaseDN
1505 1506
1507 - def get_people_basedn(self):
1508 """ 1509 thisClass.get_people_basedn () 1510 1511 """ 1512 return self.PeopleBaseDN
1513 1514
1515 - def get_groups_basedn(self):
1516 """ 1517 thisClass.get_groups_basedn () 1518 1519 """ 1520 return self.GroupsBaseDN
1521 1522
1523 - def get_hosts_basedn(self):
1524 """ 1525 thisClass.get_hosts_basedn () 1526 1527 """ 1528 return self.HostsBaseDN
1529 1530
1531 - def get_admin_dn(self):
1532 """ 1533 thisClass.get_admin_dn () 1534 1535 """ 1536 return self.AdminDN
1537 1538
1539 - def get_parent_dn(self, dn):
1540 """ 1541 thisClass.get_parent_dn ('myDN') 1542 1543 returns the parent absolute DN of 'myDN' 1544 from the LDAP server's directory tree. 1545 """ 1546 from easyLDAP_utils import split_dn, is_dn_syntax 1547 1548 if is_dn_syntax(dn): 1549 if dn.lower().endswith(self.RootDSE): 1550 pass 1551 else: 1552 raise easyLDAP_exceptions.NO_CHILD_OF_ROOTDSE 1553 else: 1554 raise easyLDAP_exceptions.INVALID_DN_SYNTAX 1555 1556 parent = split_dn(dn.lower(), basedn=self.BaseDN) 1557 if dn.lower() != self.BaseDN: 1558 del parent[0] 1559 1560 return string.join(parent, ',')
1561 1562
1563 - def get_parent_rdn(self, dn):
1564 """ 1565 thisClass.get_parent_rdn ('myDN') 1566 1567 returns the parent relative DN of 'myDN' 1568 from the LDAP server's directory tree. 1569 """ 1570 parent_dn = get_parent_dn(dn) 1571 return split_dn(parent_dn)[0]
1572 1573
1574 - def has_parent_dn (self, dn):
1575 """ 1576 thisClass.has_parent_dn ('myDN') 1577 1578 tests the existence of the referred object with a 1579 live search request to the LDAP server. 1580 """ 1581 from easyLDAP_utils import ldapDictionaryDecode 1582 1583 parent_dn = self.get_parent_dn (dn) 1584 try: 1585 ldap_search = ldapDictionaryDecode(self.ldapsession.search_s(parent_dn, ldap.SCOPE_ONELEVEL, 'objectClass=*'), config_defaults=self.CONFIG) 1586 return True 1587 except ldap.NO_SUCH_OBJECT: 1588 return False
1589 1590
1591 - def get_samelevel_dns(self, dn, use_cache=False):
1592 """ 1593 thisClass.get_samelevel_dns ('myDN') 1594 1595 returns a list with distinguished names that exist on the same level 1596 as the given DN 'myDN'. 1597 1598 If the DN 'myDN' is alone on its level, it will be the only item 1599 in the list. 1600 1601 If the returned list is empty, an error occurred. 1602 """ 1603 from easyLDAP_utils import ldapDictionaryDecode 1604 1605 dnList = [] 1606 1607 if use_cache: 1608 pass 1609 1610 else: 1611 try: 1612 if self.has_parent_dn(dn): 1613 dn_search = ldapDictionaryDecode(self.ldapsession.search_s(self.get_parent_dn(dn),ldap.SCOPE_ONELEVEL,'objectClass=*'), config_defaults=self.CONFIG) 1614 for object in dn_search: 1615 dnList.append(object[0].lower()) 1616 dnList.remove(dn.lower()) 1617 except ldap.SERVER_DOWN: 1618 raise easyLDAP_exceptions.SERVER_UNAVAILABLE 1619 1620 return dnList
1621 1622
1623 - def get_sublevel_dns(self, dn, use_cache=False):
1624 """ 1625 thisClass.get_subleveldns ('myDN') 1626 1627 returns a list with distinguished names that exist exactly below 1628 the given DN 'myDN'. 1629 1630 If the easyLDAP object has no objects on its sublevel, the result will 1631 be an empty list. If an LDAP error occurs, the list will also be empty! 1632 """ 1633 from easyLDAP_utils import ldapDictionaryDecode 1634 1635 dnList = [] 1636 1637 if use_cache: 1638 pass 1639 1640 else: 1641 try: 1642 dn_search = ldapDictionaryDecode(self.ldapsession.search_s(dn,ldap.SCOPE_ONELEVEL,'objectClass=*'), config_defaults=self.CONFIG) 1643 for object in dn_search: 1644 dnList.append(object[0].lower()) 1645 except ldap.SERVER_DOWN: 1646 raise easyLDAP_exceptions.SERVER_UNAVAILABLE 1647 1648 return dnList
1649 1650
1651 - def get_sublevel_rdns(self, dn, use_cache=False):
1652 """ 1653 thisClass.get_sublevelrdns ('myDN') 1654 1655 returns a list with reduced distinguished names that exist exactly below 1656 the given DN 'myDN'. 1657 1658 If the easyLDAP object has no objects on its sublevel, the result will 1659 be an empty list. If an LDAP error occurs, the list will also be empty! 1660 """ 1661 from easyLDAP_utils import ldapDictionaryDecode 1662 1663 dnList = [] 1664 1665 if use_cache: 1666 pass 1667 1668 else: 1669 try: 1670 dn_search = ldapDictionaryDecode(self.ldapsession.search_s(dn,ldap.SCOPE_ONELEVEL,'objectClass=*'), config_defaults=self.CONFIG) 1671 for object in dn_search: 1672 dnList.append(string.split(object[0].lower(),',')[0]) 1673 except ldap.SERVER_DOWN: 1674 raise easyLDAP_exceptions.SERVER_UNAVAILABLE 1675 1676 return dnList
1677 1678
1679 - def get_subtree_dns(self, dn, use_cache=False):
1680 """ 1681 thisClass.get_subtree_dns (this_dn) 1682 1683 returns a tree of all distinguished names that exists below 1684 the given DN 'myDN'. 1685 1686 If the easyLDAP object has no objects on its sublevel, 1687 the result will be an empty list. If an LDAP error occurs, 1688 the list will also be empty! 1689 """ 1690 from easyLDAP_utils import ldapDictionaryDecode 1691 1692 dnList = [] 1693 1694 if use_cache: 1695 pass 1696 1697 else: 1698 try: 1699 dn_search = ldapDictionaryDecode(self.ldapsession.search_s(dn,ldap.SCOPE_SUBTREE,'objectClass=*'), config_defaults=self.CONFIG) 1700 for object in dn_search: 1701 dnList.append(object[0].lower()) 1702 dnList.remove(this_dn.lower()) 1703 except ldap.SERVER_DOWN: 1704 raise easyLDAP_exceptions.SERVER_UNAVAILABLE 1705 1706 return dnList
1707 1708
1709 - def has_samba2_schema(self):
1710 1711 return self.is_valid_objectclass('sambaAccount')
1712 1713
1714 - def has_samba3_schema(self):
1715 1716 return self.is_valid_objectclass('sambaSamAccount')
1717 1718
1719 - def get_samba3_algorithmicRidBase(self, this_domain):
1720 """ 1721 thisClass.get_samba3_algorithmicRidBase('myDOMAIN') 1722 1723 searches the LDAP tree starting at thisClass.BaseDN for 1724 the algorithmic RID base of Samba domain 'myDOMAIN'. 1725 """ 1726 from easyLDAP_utils import ldapDictionaryDecode 1727 1728 # this only works in Samba 3.x 1729 if self.has_samba3_schema(): 1730 1731 # the ldap server might be offline or unavailable 1732 try: 1733 domainLDAPSearch = ldapDictionaryDecode (self.ldapsession.search_s(self.BaseDN,ldap.SCOPE_SUBTREE,'objectClass=sambaDomain'), config_defaults=self.CONFIG) 1734 for domain in domainLDAPSearch: 1735 if (len(domain[1]['sambaDomainName']) == 1) and (domain[1]['sambaDomainName'][0].upper() == this_domain.upper()): 1736 return int(domain[1]['sambaAlgorithmicRidBase'][0]) 1737 1738 # domain not known to LDAP server 1739 return None 1740 1741 except ldap.SERVER_DOWN: 1742 1743 # server is unavailable 1744 raise easyLDAP_exceptions.SERVER_UNAVAILABLE 1745 1746 # if only Samba 2.x or no samba schema is available on the LDAP server we fail 1747 else: 1748 raise easyLDAP_exceptions.SAMBA3_ONLY
1749 1750
1751 - def get_samba3_domainSID(self, domain):
1752 """ 1753 thisClass.get_samba3_domainSID('myDOMAIN') 1754 1755 searches the LDAP tree starting at thisClass.BaseDN for 1756 the Samba PDC's sambaDomainName entry. When the method 1757 can find it, then it will extract the domain's SID. 1758 """ 1759 from easyLDAP_utils import ldapDictionaryDecode 1760 1761 # this only works in Samba 3.x 1762 if self.has_samba3_schema(): 1763 1764 # the ldap server might be offline or unavailable 1765 try: 1766 domainLDAPSearch = ldapDictionaryDecode(self.ldapsession.search_s(self.BaseDN,ldap.SCOPE_SUBTREE,'objectClass=sambaDomain'), config_defaults=self.CONFIG) 1767 for domain in domainLDAPSearch: 1768 if (len(domain[1]['sambaDomainName']) == 1) and (domain[1]['sambaDomainName'][0].upper() == this_domain.upper()): 1769 return domain[1]['sambaSID'][0] 1770 1771 # domain not known to LDAP server 1772 return None 1773 1774 except ldap.SERVER_DOWN: 1775 1776 # server is unavailable 1777 raise easyLDAP_exceptions.SERVER_UNAVAILABLE 1778 1779 # if only Samba 2.x or no samba schema is available on the LDAP server we fail 1780 else: 1781 raise easyLDAP_exceptions.SAMBA3_ONLY
1782 1783
1784 - def find_newUidNumber(self, min_uidNumber=None, max_uidNumber=None, searchbase=None, cached_searchresult=None):
1785 """ 1786 self.find_newUidNumber (minUID,maxUID,myPEOPLEBASEDN) 1787 1788 live searches the connected LDAP server for the lowest 1789 vacant uidNumber between minUID and maxUID. 1790 1791 If myPEOPLEBASEDN is not specified, the easyLDAP 1792 thisClass.PeoplebaseDN is presumed. 1793 1794 The method only checks vacant uidNumber in the connected 1795 LDAP tree. Other sources for posixUserIDs (/etc/passwd, 1796 NIS, etc.) are not taken into consideration! 1797 1798 If an error occurs or no vacant uidNumber can be found, 1799 the method returns '-1'. 1800 """ 1801 from easyLDAP_utils import ldapDictionaryDecode 1802 1803 if searchbase is None: 1804 searchbase = self.PeopleBaseDN 1805 1806 my_min = min_uidNumber or self.posix_availableUidNumbers['min'] 1807 my_max = max_uidNumber or self.posix_availableUidNumbers['max'] 1808 1809 if 0 < int(my_min) < int(my_max): 1810 try: 1811 if cached_searchresult is None: 1812 searchresult = ldapDictionaryDecode(self.ldapsession.search_s(searchbase,ldap.SCOPE_SUBTREE,'uidNumber=*'), config_defaults=self.CONFIG) 1813 else: 1814 searchresult = cached_searchresult 1815 1816 uidList = [] 1817 for obj in searchresult: 1818 try: 1819 uidList.append(int(obj[1]['uidNumber'][0])) 1820 except ValueError: 1821 continue 1822 searchUID = int(my_min) 1823 while (searchUID in uidList) and (searchUID <= my_max): 1824 searchUID += 1 1825 1826 if searchUID <= my_max: 1827 return searchUID 1828 else: 1829 # no vacant uid found 1830 raise easyLDAP_exception.NO_VACANT_UIDNUMBER 1831 1832 except ldap.SERVER_DOWN: 1833 # server down 1834 raise easyLDAP_exceptions.SERVER_UNAVAILABLE 1835 1836 else: 1837 # the given uid range is faulty 1838 raise easyLDAP_exceptions.UIDNUMBER_RANGE_FAULTY
1839 1840
1841 - def find_newGidNumber(self, min_gidNumber=None, max_gidNumber=None, searchbase=None, cached_searchresult=None):
1842 """ 1843 self.find_newGidNumber(minGID,maxGID,myGROUPSBASEDN) 1844 1845 searches the connected LDAP server for the lowest 1846 vacant gidNumber between minGID and maxGID. 1847 1848 If myGROUPSBASEDN is not specified, the easyLDAP 1849 thisClass.GroupBaseDN is presumed. 1850 1851 The method only checks vacant gidNumber in the connected 1852 LDAP tree. Other sources for posixGroupIDs (/etc/groups, 1853 NIS, etc.) are not taken into consideration! 1854 1855 If an error occurs or no vacant gidNumber can be found, 1856 the method returns '-1'. 1857 """ 1858 from easyLDAP_utils import ldapDictionaryDecode 1859 1860 if searchbase is None: 1861 searchbase = self.GroupsBaseDN 1862 1863 my_min = min_gidNumber or self.posix_availableGidNumbers['min'] 1864 my_max = max_gidNumber or self.posix_availableGidNumbers['max'] 1865 1866 if 0 < int(my_min) < int(my_max): 1867 try: 1868 if cached_searchresult is None: 1869 searchresult = ldapDictionaryDecode(self.ldapsession.search_s(searchbase,ldap.SCOPE_SUBTREE,'&(objectClass=posixGroup)(gidNumber=*)'), config_defaults=self.CONFIG) 1870 else: 1871 searchresult = cached_searchresult 1872 1873 gidList = [] 1874 for obj in searchresult: 1875 try: 1876 gidList.append(int(obj[1]['gidNumber'][0])) 1877 except ValueError: 1878 continue 1879 1880 searchGID = int(my_min) 1881 while (searchGID in gidList) and (searchGID <= my_max): 1882 searchGID += 1 1883 1884 if searchGID <= my_max: 1885 return searchGID 1886 else: 1887 # no vacant gid found 1888 raise easyLDAP_exception.NO_VACANT_GIDNUMBER 1889 1890 except ldap.SERVER_DOWN: 1891 # server is down 1892 raise easyLDAP_exceptions.SERVER_UNAVAILABLE 1893 1894 else: 1895 # the given gid range is faulty 1896 raise easyLDAP_exceptions.GIDNUMBER_RANGE_FAULTY
1897 1898
1899 - def show_objectclass(self, this_objectclass):
1900 """ 1901 thisClass.show_objectclass ('myOBJECT_CLASS'): 1902 1903 displays an objectClass's schema in a user-friendly manner... 1904 """ 1905 flagDict = {'SINGLE-VALUE': 'sv', 'OBSOLETE': 'obs', 'NO-USER-MODIFICATION': 'num', 'COLLECTIVE': 'col'} 1906 1907 if self.objectClassesDict.has_key(this_objectclass): 1908 print 1909 print 'objectClass:', this_objectclass 1910 print '------------' 1911 for key in ['OID','DESC','SUP','MUST','MAY','STRUCTURAL', 'AUXILIARY']: 1912 1913 # go through all keys of the objectClassesDict directory 1914 # either the keys content is a string, a Boolean expr or ListType 1915 if type(self.objectClassesDict[this_objectclass][key]) is types.ListType: 1916 sortedAttributes = self.objectClassesDict[this_objectclass][key] 1917 1918 # process all attributes in list 1919 for listindex in range (0, len(sortedAttributes)): 1920 1921 try: 1922 attr = self.objectClassesDict[this_objectclass][key][listindex] 1923 oid = self.map_attrtypes2oids(attr) 1924 syntax = self.map_attrtype2ldapsyntax(attr) 1925 1926 # some attributes (e.g. top) do not have an OID, so care for them 1927 except easyLDAP_exceptions.NO_SUCH_ATTRIBUTE: 1928 oid = ['NONE'] 1929 syntax = ['NONE'] 1930 1931 # also test for flags 1932 try: 1933 flags = '' 1934 for flagKey in flagDict.keys(): 1935 if self.attributeTypesDict[attr][flagKey]: 1936 flags = flags + '+' + flagDict[flagKey] + ',' 1937 else: 1938 flags = flags + '-' + flagDict[flagKey] + ',' 1939 flags = string.rstrip(flags,',') 1940 except KeyError: 1941 flags = 'NONE' 1942 1943 print '%s: %s (OID: %s, Syntax: %s, Flags: %s)' % (key, attr, oid[0], syntax, flags) 1944 1945 else: 1946 1947 print '%s: %s' % (key, self.objectClassesDict[this_objectclass][key]) 1948 print 1949 1950 return True 1951 1952 else: 1953 # no such objectClass 1954 raise easyLDAP_exceptions.NO_SUCH_OBJECTCLASS
1955 1956
1957 - def get_cache_reference(self, dn, scope=ldap.SCOPE_BASE):
1958 """ 1959 thisClass.get_cache_reference() 1960 1961 commits a search operation on the LDAP server with 1962 starting with thisClass.ObjectCacheBaseDN as the base DN. 1963 The result of this operation can be compared to the 1964 current content of the easyLDAP cache to figure out 1965 what changes have been made to the object in cache 1966 by easyLDAP methods. 1967 1968 If an error occurs, an empty list will be returned. 1969 """ 1970 from easyLDAP_utils import ldapDictionaryDecode 1971 1972 1973 cache_reference = [(dn,{})] 1974 try: 1975 cache_reference = ldapDictionaryDecode(self.ldapsession.search_s(dn,scope,'objectClass=*'), config_defaults=self.CONFIG) 1976 return cache_reference 1977 except ldap.NO_SUCH_OBJECT: 1978 # TODO: check if the parent DN exists!!! otherwise really throw an error here and abort operation 1979 return cache_reference 1980 except ldap.SERVER_DOWN: 1981 raise easyLDAP_exceptions.SERVER_UNAVAILABLE
1982 1983
1984 - def refresh_cache(self):
1985 """ 1986 dummy method, will be used in classes easyLDAP_object, easyLDAP_tree, etc. 1987 """ 1988 return True
1989 1990 if __name__=='__main__': 1991 pass 1992