From 9a5cc120421e5d8b60897a9d49e2eef820eff598 Mon Sep 17 00:00:00 2001 From: Andrew Bartlett Date: Fri, 23 Feb 2024 15:32:06 +1300 Subject: [PATCH] python/samba/samdb: Only do caching of well known DNs in dbcheck The fact that get_wellknown_dn() returned a cached DN that could not be modified safely was unexpected, particularly given that other similar routines did not do that. The use case given at the time this was written by Matthieu Patou in 6122acad0f1a7bc23b6f58862c16968e13da979d was dbcheck, so move the cache there, and name it clearly. dbcheck is the only case that uses this rotuine in an inner loop. Signed-off-by: Andrew Bartlett Reviewed-by: Jo Sutton --- python/samba/dbchecker.py | 33 +++++++++++++++++++++++++-------- python/samba/samdb.py | 15 +-------------- 2 files changed, 26 insertions(+), 22 deletions(-) diff --git a/python/samba/dbchecker.py b/python/samba/dbchecker.py index e07afdc239b..53d0030e941 100644 --- a/python/samba/dbchecker.py +++ b/python/samba/dbchecker.py @@ -56,6 +56,8 @@ def dump_attr_values(vals): class dbcheck(object): """check a SAM database for errors""" + hash_well_known = {} + def __init__(self, samdb, samdb_schema=None, verbose=False, fix=False, yes=False, quiet=False, in_transaction=False, quick_membership_checks=False, @@ -130,9 +132,9 @@ class dbcheck(object): self.link_id_cache = {} self.name_map = {} try: - base_dn = "CN=DnsAdmins,%s" % samdb.get_wellknown_dn( - samdb.get_default_basedn(), - dsdb.DS_GUID_USERS_CONTAINER) + base_dn = "CN=DnsAdmins,%s" % self.get_wellknown_dn_cached( + samdb.get_default_basedn(), + dsdb.DS_GUID_USERS_CONTAINER) res = samdb.search(base=base_dn, scope=ldb.SCOPE_BASE, attrs=["objectSid"]) dnsadmins_sid = ndr_unpack(security.dom_sid, res[0]["objectSid"][0]) @@ -171,8 +173,8 @@ class dbcheck(object): for nc in self.ncs: try: - dn = self.samdb.get_wellknown_dn(ldb.Dn(self.samdb, nc.decode('utf8')), - dsdb.DS_GUID_DELETED_OBJECTS_CONTAINER) + dn = self.get_wellknown_dn_cached(ldb.Dn(self.samdb, nc.decode('utf8')), + dsdb.DS_GUID_DELETED_OBJECTS_CONTAINER) self.deleted_objects_containers.append(dn) except KeyError: self.ncs_lacking_deleted_containers.append(ldb.Dn(self.samdb, nc.decode('utf8'))) @@ -243,6 +245,21 @@ class dbcheck(object): if enum != ldb.ERR_NO_SUCH_OBJECT: raise + def get_wellknown_dn_cached(self, nc_root, wkguid): + h_nc = self.hash_well_known.get(str(nc_root)) + dn = None + if h_nc is not None: + dn = h_nc.get(wkguid) + if dn is None: + dn = self.samdb.get_wellknown_dn(nc_root, wkguid) + if dn is None: + return dn + if h_nc is None: + self.hash_well_known[str(nc_root)] = {} + h_nc = self.hash_well_known[str(nc_root)] + h_nc[wkguid] = dn + return dn + def check_database(self, DN=None, scope=ldb.SCOPE_SUBTREE, controls=None, attrs=None): """perform a database check, returning the number of errors found""" @@ -945,7 +962,7 @@ newSuperior: %s""" % (str(from_dn), str(to_rdn), str(to_base))) self.samdb.transaction_start() try: nc_root = self.samdb.get_nc_root(obj.dn) - lost_and_found = self.samdb.get_wellknown_dn(nc_root, dsdb.DS_GUID_LOSTANDFOUND_CONTAINER) + lost_and_found = self.get_wellknown_dn_cached(nc_root, dsdb.DS_GUID_LOSTANDFOUND_CONTAINER) new_dn = ldb.Dn(self.samdb, str(obj.dn)) new_dn.remove_base_components(len(new_dn) - 1) if self.do_rename(obj.dn, new_dn, lost_and_found, ["show_deleted:0", "relax:0"], @@ -2369,8 +2386,8 @@ newSuperior: %s""" % (str(from_dn), str(to_rdn), str(to_base))) nc_dn = self.samdb.get_nc_root(obj.dn) try: - deleted_objects_dn = self.samdb.get_wellknown_dn(nc_dn, - samba.dsdb.DS_GUID_DELETED_OBJECTS_CONTAINER) + deleted_objects_dn = self.get_wellknown_dn_cached(nc_dn, + samba.dsdb.DS_GUID_DELETED_OBJECTS_CONTAINER) except KeyError: # We have no deleted objects DN for schema, and we check for this above for the other # NCs diff --git a/python/samba/samdb.py b/python/samba/samdb.py index 9bbec435062..769ae65d9c4 100644 --- a/python/samba/samdb.py +++ b/python/samba/samdb.py @@ -53,7 +53,6 @@ class SamDB(samba.Ldb): """The SAM database.""" hash_oid_name = {} - hash_well_known = {} class _CleanUpOnError: def __init__(self, samdb, dn): @@ -1220,19 +1219,7 @@ schemaUpdateNow: 1 return dsdb._dsdb_get_nc_root(self, dn) def get_wellknown_dn(self, nc_root, wkguid): - h_nc = self.hash_well_known.get(str(nc_root)) - dn = None - if h_nc is not None: - dn = h_nc.get(wkguid) - if dn is None: - dn = dsdb._dsdb_get_wellknown_dn(self, nc_root, wkguid) - if dn is None: - return dn - if h_nc is None: - self.hash_well_known[str(nc_root)] = {} - h_nc = self.hash_well_known[str(nc_root)] - h_nc[wkguid] = dn - return dn + return dsdb._dsdb_get_wellknown_dn(self, nc_root, wkguid) def set_minPwdAge(self, value): if not isinstance(value, bytes):