This file is indexed.

/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