/usr/lib/python3/dist-packages/lib389/mappingTree.py is in python3-lib389 1.3.7.10-1ubuntu1.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 | # --- BEGIN COPYRIGHT BLOCK ---
# Copyright (C) 2015 Red Hat, Inc.
# All rights reserved.
#
# License: GPL (version 3 or any later version).
# See LICENSE for details.
# --- END COPYRIGHT BLOCK ---
import ldap
import ldap.dn
import six
from lib389._constants import *
from lib389.properties import *
from lib389.utils import suffixfilt, normalizeDN
from lib389 import Entry
from lib389.exceptions import NoSuchEntryError, InvalidArgumentError
from lib389._mapped_object import DSLdapObjects, DSLdapObject
class MappingTreeLegacy(object):
'''
classdocs
'''
proxied_methods = 'search_s getEntry'.split()
def __init__(self, conn):
"""
@param conn - a DirSrv instance
"""
self.conn = conn
self.log = conn.log
def __getattr__(self, name):
if name in MappingTree.proxied_methods:
from lib389 import DirSrv
return DirSrv.__getattr__(self.conn, name)
def list(self, suffix=None, bename=None):
'''
Returns a search result of the mapping tree entries with all their
attributes
If 'suffix'/'bename' are specified. It uses 'benamebase' first,
then 'suffix'.
If neither 'suffix' and 'bename' are specified, it returns all
the mapping tree entries
@param suffix - suffix of the backend
@param benamebase - backend common name (e.g. 'userRoot')
@return mapping tree entries
@raise if search fails
'''
if bename:
filt = "(%s=%s)" % (MT_PROPNAME_TO_ATTRNAME[MT_BACKEND], bename)
elif suffix:
filt = "(%s=%s)" % (MT_PROPNAME_TO_ATTRNAME[MT_SUFFIX], suffix)
else:
filt = "(objectclass=%s)" % MT_OBJECTCLASS_VALUE
try:
ents = self.conn.search_s(DN_MAPPING_TREE, ldap.SCOPE_ONELEVEL,
filt)
for ent in ents:
self.log.debug('list: %r' % ent)
except:
raise
return ents
def create(self, suffix=None, bename=None, parent=None):
'''
Create a mapping tree entry (under "cn=mapping tree,cn=config"),
for the 'suffix' and that is stored in 'bename' backend.
'bename' backend must exist before creating the mapping tree entry.
If a 'parent' is provided that means that we are creating a
sub-suffix mapping tree.
@param suffix - suffix mapped by this mapping tree entry. It will
be the common name ('cn') of the entry
@param benamebase - backend common name (e.g. 'userRoot')
@param parent - if provided is a parent suffix of 'suffix'
@return DN of the mapping tree entry
@raise ldap.NO_SUCH_OBJECT - if the backend entry or parent mapping
tree does not exist
ValueError - if missing a parameter,
'''
# Check suffix is provided
if not suffix:
raise ValueError("suffix is mandatory")
else:
nsuffix = normalizeDN(suffix)
# Check backend name is provided
if not bename:
raise ValueError("backend name is mandatory")
# Check that if the parent suffix is provided then
# it exists a mapping tree for it
if parent:
nparent = normalizeDN(parent)
filt = suffixfilt(parent)
try:
entry = self.conn.getEntry(DN_MAPPING_TREE, ldap.SCOPE_SUBTREE,
filt)
pass
except NoSuchEntryError:
raise ValueError("parent suffix has no mapping tree")
else:
nparent = ""
# Check if suffix exists, return
filt = suffixfilt(suffix)
try:
entry = self.conn.getEntry(DN_MAPPING_TREE, ldap.SCOPE_SUBTREE,
filt)
return entry
except ldap.NO_SUCH_OBJECT:
entry = None
#
# Now start the real work
#
# fix me when we can actually used escaped DNs
dn = ','.join(('cn="%s"' % nsuffix, DN_MAPPING_TREE))
entry = Entry(dn)
entry.update({
'objectclass': ['top', 'extensibleObject', MT_OBJECTCLASS_VALUE],
'nsslapd-state': 'backend',
# the value in the dn has to be DN escaped
# internal code will add the quoted value - unquoted value is
# useful for searching.
MT_PROPNAME_TO_ATTRNAME[MT_SUFFIX]: nsuffix,
MT_PROPNAME_TO_ATTRNAME[MT_BACKEND]: bename
})
# possibly add the parent
if parent:
entry.setValues(MT_PROPNAME_TO_ATTRNAME[MT_PARENT_SUFFIX], nparent)
try:
self.log.debug("Creating entry: %s" % entry.dn)
self.log.info("Entry %r" % entry)
self.conn.add_s(entry)
except ldap.LDAPError as e:
raise ldap.LDAPError("Error adding suffix entry " + dn, e)
ret = self.conn._test_entry(dn, ldap.SCOPE_BASE)
return ret
def delete(self, suffix=None, bename=None, name=None):
'''
Delete a mapping tree entry (under "cn=mapping tree,cn=config"),
for the 'suffix' and that is stored in 'benamebase' backend.
'benamebase' backend is not changed by the mapping tree deletion.
If 'name' is specified. It uses it to retrieve the mapping tree
to delete. Else if 'suffix'/'benamebase' are specified. It uses
both to retrieve the mapping tree to delete
@param suffix - suffix mapped by this mapping tree entry. It is
the common name ('cn') of the entry
@param benamebase - backend common name (e.g. 'userRoot')
@param name - DN of the mapping tree entry
@return None
@raise ldap.NO_SUCH_OBJECT - the entry is not found
KeyError if 'name', 'suffix' and
'benamebase' are missing
UnwillingToPerformError - If the mapping tree has
subordinates
'''
if name:
filt = "(objectclass=%s)" % MT_OBJECTCLASS_VALUE
try:
ent = self.conn.getEntry(name, ldap.SCOPE_BASE, filt)
self.log.debug("delete: %s found by its DN" % ent.dn)
except NoSuchEntryError:
raise ldap.NO_SUCH_OBJECT("mapping tree DN not found: %s" %
name)
else:
filt = None
if suffix:
filt = suffixfilt(suffix)
if bename:
if filt:
filt = ("(&(%s=%s)%s)" %
(MT_PROPNAME_TO_ATTRNAME[MT_BACKEND],
bename,
filt))
else:
filt = ("(%s=%s)" %
(MT_PROPNAME_TO_ATTRNAME[MT_BACKEND], bename))
try:
ent = self.conn.getEntry(DN_MAPPING_TREE, ldap.SCOPE_ONELEVEL,
filt)
self.log.debug("delete: %s found by with %s" % (ent.dn, filt))
except NoSuchEntryError:
raise ldap.NO_SUCH_OBJECT("mapping tree DN not found: %s" %
name)
#
# At this point 'ent' contains the mapping tree entry to delete
#
# First Check there is no child (replica, replica agreements)
try:
ents = self.conn.search_s(ent.dn, ldap.SCOPE_SUBTREE,
"objectclass=*")
except:
raise
if len(ents) != 1:
for entry in ents:
self.log.warning("Error: it exists %s under %s" %
(entry.dn, ent.dn))
raise ldap.UNWILLING_TO_PERFORM(
"Unable to delete %s, it is not a leaf" % ent.dn)
else:
for entry in ents:
self.log.warning("Warning: %s (%s)" % (entry.dn, ent.dn))
self.conn.delete_s(ent.dn)
def getProperties(self, suffix=None, bename=None, name=None,
properties=None):
'''
Returns a dictionary of the requested properties.
If properties is missing, it returns all the properties.
The returned properties are those of the 'suffix' and that is
stored in 'benamebase' backend.
If 'name' is specified. It uses it to retrieve the mapping tree
to delete Else if 'suffix'/'benamebase' are specified. It uses
both to retrieve the mapping tree to
If 'name', 'benamebase' and 'suffix' are missing it raise an
exception
@param suffix - suffix mapped by this mapping tree entry.
It is the common name ('cn') of the entry
@param benamebase - backend common name (e.g. 'userRoot')
@param name - DN of the mapping tree entry
@param - properties - list of properties
@return - returns a dictionary of the properties
@raise ValueError - if some name of properties are not valid
KeyError - if some name of properties are not valid
ldap.NO_SUCH_OBJECT - if the mapping tree entry is not found
'''
if name:
filt = "(objectclass=%s)" % MT_OBJECTCLASS_VALUE
try:
ent = self.conn.getEntry(name, ldap.SCOPE_BASE, filt,
list(MT_PROPNAME_TO_ATTRNAME.values())
)
self.log.debug("delete: %s found by its DN" % ent.dn)
except NoSuchEntryError:
raise ldap.NO_SUCH_OBJECT("mapping tree DN not found: %s" %
name)
else:
filt = None
if suffix:
filt = suffixfilt(suffix)
if bename:
if filt:
filt = ("(&(%s=%s)%s)" %
(MT_PROPNAME_TO_ATTRNAME[MT_BACKEND],
bename, filt))
else:
filt = ("(%s=%s)" % (MT_PROPNAME_TO_ATTRNAME[MT_BACKEND],
bename))
try:
ent = self.conn.getEntry(DN_MAPPING_TREE, ldap.SCOPE_ONELEVEL,
filt,
list(MT_PROPNAME_TO_ATTRNAME.values())
)
self.log.debug("delete: %s found by with %s" % (ent.dn, filt))
except NoSuchEntryError:
raise ldap.NO_SUCH_OBJECT("mapping tree DN not found: %s" %
name)
result = {}
attrs = []
if properties:
#
# build the list of attributes we are looking for
for prop_name in properties:
prop_attr = MT_PROPNAME_TO_ATTRNAME[prop_name]
if not prop_attr:
raise ValueError("Improper property name: %s ", prop_name)
self.log.debug("Look for attr %s (property: %s)" %
(prop_attr, prop_name))
attrs.append(prop_attr)
# now look for each attribute from the MT entry
for attr in ent.getAttrs():
# given an attribute name retrieve the property name
props = [k for k, v in six.iteritems(MT_PROPNAME_TO_ATTRNAME)
if v.lower() == attr.lower()]
# If this attribute is present in the MT properties and was
# requested, adds it to result.
if len(props) > 0:
if len(attrs) > 0:
if MT_PROPNAME_TO_ATTRNAME[props[0]] in attrs:
# if the properties was requested
self.log.debug("keep only attribute %s " % (props[0]))
result[props[0]] = ent.getValues(attr)
else:
result[props[0]] = ent.getValues(attr)
return result
def setProperties(self, suffix=None, bename=None, name=None,
properties=None):
raise NotImplemented()
def toSuffix(self, entry=None, name=None):
'''
Return, for a given mapping tree entry, the suffix values.
Suffix values are identical from a LDAP point of views.
Suffix values may be surrounded by ", or containing '\'
escape characters.
@param entry - LDAP entry of the mapping tree
@param name - mapping tree DN
@result list of values of suffix attribute (aka 'cn')
@raise ldap.NO_SUCH_OBJECT - in name is invalid DN
ValueError - entry does not contains the suffix attribute
InvalidArgumentError - if both entry/name are missing
'''
attr_suffix = MT_PROPNAME_TO_ATTRNAME[MT_SUFFIX]
if entry:
if not entry.hasValue(attr_suffix):
raise ValueError("Entry has no %s attribute %r" %
(attr_suffix, entry))
return entry.getValues(attr_suffix)
elif name:
filt = "(objectclass=%s)" % MT_OBJECTCLASS_VALUE
try:
attrs = [attr_suffix]
ent = self.conn.getEntry(name, ldap.SCOPE_BASE, filt, attrs)
self.log.debug("toSuffix: %s found by its DN" % ent.dn)
except NoSuchEntryError:
raise ldap.NO_SUCH_OBJECT("mapping tree DN not found: %s" %
name)
if not ent.hasValue(attr_suffix):
raise ValueError("Entry has no %s attribute %r" %
(attr_suffix, ent))
return ent.getValues(attr_suffix)
else:
raise InvalidArgumentError("entry or name are mandatory")
class MappingTree(DSLdapObject):
"""Mapping tree DSLdapObject with:
- must attributes = ['cn']
- RDN attribute is 'cn'
:param instance: A instance
:type instance: lib389.DirSrv
:param dn: Entry DN
:type dn: str
:param batch: Not implemented
:type batch: bool
"""
_must_attributes = ['cn']
def __init__(self, instance, dn=None, batch=False):
super(MappingTree, self).__init__(instance, dn, batch)
self._rdn_attribute = 'cn'
self._must_attributes = ['cn']
self._create_objectclasses = ['top', 'extensibleObject', MT_OBJECTCLASS_VALUE]
self._protected = False
class MappingTrees(DSLdapObjects):
"""DSLdapObjects that presents Mapping trees
:param instance: A instance
:type instance: lib389.DirSrv
:param batch: Not implemented
:type batch: bool
"""
def __init__(self, instance, batch=False):
super(MappingTrees, self).__init__(instance=instance, batch=batch)
self._objectclasses = [MT_OBJECTCLASS_VALUE]
self._filterattrs = ['cn', 'nsslapd-backend' ]
self._childobject = MappingTree
self._basedn = DN_MAPPING_TREE
|