201 lines
7.6 KiB
Diff
201 lines
7.6 KiB
Diff
From 7ed791beda5d507e15c970a88289f533aa06b2d3 Mon Sep 17 00:00:00 2001
|
|
From: tbordaz <tbordaz@redhat.com>
|
|
Date: Mon, 2 Dec 2024 17:18:32 +0100
|
|
Subject: [PATCH] Issue 6417 - If an entry RDN is identical to the suffix, then
|
|
Entryrdn gets broken during a reindex (#6418)
|
|
|
|
Bug description:
|
|
During a reindex, the entryrdn index is built at the end from
|
|
each entry in the suffix.
|
|
If one entry has a RDN that is identical to the suffix DN,
|
|
then entryrdn_lookup_dn may erroneously return the suffix DN
|
|
as the DN of the entry.
|
|
|
|
Fix description:
|
|
When the lookup entry has no parent (because index is under
|
|
work) the loop lookup the entry using the RDN.
|
|
If this RDN matches the suffix DN, then it exits from the loop
|
|
with the suffix DN.
|
|
Before exiting it checks that the original lookup entryID
|
|
is equal to suffix entryID. If it does not match
|
|
the function fails and then the DN from the entry will be
|
|
built from id2enty
|
|
|
|
fixes: #6417
|
|
|
|
Reviewed by: Pierre Rogier, Simon Pichugin (Thanks !!!)
|
|
---
|
|
.../tests/suites/indexes/entryrdn_test.py | 108 +++++++++++++++++-
|
|
.../back-ldbm/db-mdb/mdb_import_threads.c | 2 +-
|
|
ldap/servers/slapd/back-ldbm/ldbm_entryrdn.c | 11 +-
|
|
3 files changed, 118 insertions(+), 3 deletions(-)
|
|
|
|
diff --git a/dirsrvtests/tests/suites/indexes/entryrdn_test.py b/dirsrvtests/tests/suites/indexes/entryrdn_test.py
|
|
index 345955d4d..7669292ab 100644
|
|
--- a/dirsrvtests/tests/suites/indexes/entryrdn_test.py
|
|
+++ b/dirsrvtests/tests/suites/indexes/entryrdn_test.py
|
|
@@ -11,11 +11,16 @@ import os
|
|
import pytest
|
|
import ldap
|
|
import logging
|
|
+from lib389 import Entry
|
|
from lib389._constants import DEFAULT_BENAME, DEFAULT_SUFFIX
|
|
-from lib389.backend import Backends
|
|
+from lib389.backend import Backends, Backend
|
|
+from lib389.mappingTree import MappingTrees
|
|
+from lib389.configurations.sample import create_base_domain
|
|
+from lib389.idm.domain import Domain
|
|
from lib389.idm.user import UserAccounts, UserAccount
|
|
from lib389.idm.organizationalunit import OrganizationalUnits
|
|
from lib389.topologies import topology_m2 as topo_m2
|
|
+from lib389.topologies import topology_st
|
|
from lib389.agreement import Agreements
|
|
from lib389.utils import ds_is_older, ensure_bytes
|
|
from lib389.tasks import Tasks,ExportTask, ImportTask
|
|
@@ -283,6 +288,107 @@ def test_long_rdn(topo_m2):
|
|
ou.delete()
|
|
assert not ou.exists()
|
|
|
|
+def test_entry_rdn_same_as_suffix(topology_st, request):
|
|
+ """
|
|
+ Test that a reindex is successful even if an entry
|
|
+ has a RDN that is identical to the suffix
|
|
+
|
|
+ :id: 7f5a38e9-b979-4664-b132-81df0e60f38a
|
|
+ :setup: standalone
|
|
+ :steps:
|
|
+ 1. Create a new backend with suffix 'dc=dup_rdn' (ID 1)
|
|
+ 2. Create a dummy entry 'ou=my_org,dc=dup_rdn' (ID 2)
|
|
+ 3. Create the problematic entry 'dc=dup_rdn,dc=dup_rdn' (ID 3)
|
|
+ 4. Create a dummy entry 'ou=my_org,dc=dup_rdn,dc=dup_rdn' (ID 4)
|
|
+ 5. Do an offline reindex
|
|
+ 6. Check that entryrdn contains the key P3 (parent of ID 3)
|
|
+ 7. Check that error log does not contain 'entryrdn_insert_key - Same DN'
|
|
+ :expectedresults:
|
|
+ 1. Should succeed
|
|
+ 2. Should succeed
|
|
+ 3. Should succeed
|
|
+ 4. Should succeed
|
|
+ 5. Should succeed
|
|
+ 6. Should succeed
|
|
+ 7. Should succeed
|
|
+ """
|
|
+ inst = topology_st.standalone
|
|
+
|
|
+ # Create a suffix 'dc=dup_rdn'
|
|
+ be_name = 'domain'
|
|
+ dc_value = 'dup_rdn'
|
|
+ suffix = 'dc=' + dc_value
|
|
+ rdn = 'my_org'
|
|
+ be1 = Backend(inst)
|
|
+ be1.create(properties={
|
|
+ 'cn': be_name,
|
|
+ 'nsslapd-suffix': suffix,
|
|
+ },
|
|
+ create_mapping_tree=False
|
|
+ )
|
|
+
|
|
+ mts = MappingTrees(inst)
|
|
+ mt = mts.create(properties={
|
|
+ 'cn': suffix,
|
|
+ 'nsslapd-state': 'backend',
|
|
+ 'nsslapd-backend': be_name,
|
|
+ })
|
|
+
|
|
+ # Create the domain entry 'dc=dup_rdn'
|
|
+ create_base_domain(inst, suffix)
|
|
+
|
|
+ # Create the org ou=my_org,dc=dup_rdn
|
|
+ ous = OrganizationalUnits(inst, suffix)
|
|
+ ou = ous.create(properties={ 'ou': rdn })
|
|
+
|
|
+ # when reindexing entryrdn the following entry
|
|
+ # (dc=dup_rdn,dc=dup_rdn) Triggers
|
|
+ # this message.
|
|
+ # This is because its RDN (dc=dup_rdn) is also
|
|
+ # the suffix DN
|
|
+ info_message = 'entryrdn_insert_key - Same DN (dn: %s) is already in the entryrdn file with different' % (ou.dn)
|
|
+ log.info("In case if the bug still exist this line should be in the error log")
|
|
+ log.info(" --> " + info_message)
|
|
+
|
|
+ # Create the domain entry 'dc=dup_rdn,dc=dup_rdn'
|
|
+ trigger_entry = suffix + "," + suffix
|
|
+ domain = Domain(inst, dn=trigger_entry)
|
|
+ domain.create(properties={
|
|
+ 'dc': dc_value,
|
|
+ 'description': 'Entry with RDN identical to suffix'
|
|
+ })
|
|
+
|
|
+ # Create the org ou=my_org,dc=dup_rdn,dc=dup_rdn
|
|
+ ous = OrganizationalUnits(inst, trigger_entry)
|
|
+ ou = ous.create(properties={ 'ou': rdn })
|
|
+
|
|
+
|
|
+ # Trigger an offline reindex
|
|
+ log.info('Offline reindex, stopping the server')
|
|
+ topology_st.standalone.stop()
|
|
+
|
|
+ log.info('Reindex all the suffix')
|
|
+ topology_st.standalone.db2index(bename=be_name)
|
|
+
|
|
+ # make sure the key 'P3' (parent of 'dc=dup_rdn,dc=dup_rdn') exists
|
|
+ dbscanout = topology_st.standalone.dbscan(bename=be_name, index='entryrdn')
|
|
+ log.info(dbscanout)
|
|
+ assert(ensure_bytes('P3') in ensure_bytes(dbscanout))
|
|
+
|
|
+ # make sure there is no failure detected/logged in error logs
|
|
+ if topology_st.standalone.get_db_lib() == "mdb":
|
|
+ pattern_str = ".*Inconsistent id2entry database.*"
|
|
+ else:
|
|
+ pattern_str = ".*entryrdn_insert_key - Same DN.*is already in the entryrdn file with different.*$"
|
|
+ assert not topology_st.standalone.ds_error_log.match(pattern_str)
|
|
+
|
|
+
|
|
+ def fin():
|
|
+ topology_st.standalone.restart()
|
|
+ mt.delete()
|
|
+ be1.delete()
|
|
+
|
|
+ request.addfinalizer(fin)
|
|
|
|
if __name__ == "__main__":
|
|
# Run isolated
|
|
diff --git a/ldap/servers/slapd/back-ldbm/db-mdb/mdb_import_threads.c b/ldap/servers/slapd/back-ldbm/db-mdb/mdb_import_threads.c
|
|
index 143f2c9df..65f564aff 100644
|
|
--- a/ldap/servers/slapd/back-ldbm/db-mdb/mdb_import_threads.c
|
|
+++ b/ldap/servers/slapd/back-ldbm/db-mdb/mdb_import_threads.c
|
|
@@ -731,7 +731,7 @@ get_entry_type(WorkerQueueData_t *wqelmt, Slapi_DN *sdn)
|
|
int len = SLAPI_ATTR_UNIQUEID_LENGTH;
|
|
const char *ndn = slapi_sdn_get_ndn(sdn);
|
|
|
|
- if (slapi_be_issuffix(be, sdn)) {
|
|
+ if (slapi_be_issuffix(be, sdn) && (wqelmt->wait_id == 1)) {
|
|
return DNRC_SUFFIX;
|
|
}
|
|
if (PL_strncasecmp(ndn, SLAPI_ATTR_UNIQUEID, len) || ndn[len] != '=') {
|
|
diff --git a/ldap/servers/slapd/back-ldbm/ldbm_entryrdn.c b/ldap/servers/slapd/back-ldbm/ldbm_entryrdn.c
|
|
index 267957a36..8901b790a 100644
|
|
--- a/ldap/servers/slapd/back-ldbm/ldbm_entryrdn.c
|
|
+++ b/ldap/servers/slapd/back-ldbm/ldbm_entryrdn.c
|
|
@@ -1077,7 +1077,16 @@ entryrdn_lookup_dn(backend *be,
|
|
_ENTRYRDN_DEBUG_GOTO_BAIL();
|
|
goto bail;
|
|
}
|
|
- maybesuffix = 1;
|
|
+ if (workid == 1) {
|
|
+ /* The loop (workid) iterates from the starting 'id'
|
|
+ * up to the suffix ID (i.e. '1').
|
|
+ * A corner case (#6417) is if an entry, on the path
|
|
+ * 'id' -> suffix, has the same RDN than the suffix.
|
|
+ * In order to erroneously believe the loop hits the suffix
|
|
+ * we need to check that 'workid' is '1' (suffix)
|
|
+ */
|
|
+ maybesuffix = 1;
|
|
+ }
|
|
} else {
|
|
_entryrdn_cursor_print_error("entryrdn_lookup_dn",
|
|
key.data, data.size, data.ulen, rc);
|
|
--
|
|
2.48.1
|
|
|