Skip to content

Commit

Permalink
Issue 6417 - If an entry RDN is identical to the suffix, then Entryrd…
Browse files Browse the repository at this point in the history
…n gets broken during a reindex

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: 389ds#6417

Reviewed by: Pierre Rogier, Simon Pichugin (Thanks !!!)
  • Loading branch information
tbordaz committed Nov 25, 2024
1 parent 144f933 commit 06c2426
Show file tree
Hide file tree
Showing 3 changed files with 111 additions and 2 deletions.
106 changes: 105 additions & 1 deletion dirsrvtests/tests/suites/indexes/entryrdn_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,16 @@
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
Expand Down Expand Up @@ -283,6 +288,105 @@ 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
topology_st.standalone.add_s(Entry((
trigger_entry, {
"objectClass": "top",
"objectClass": "domain",
"dc": dc_value,
}
)))

# 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
assert not topology_st.standalone.ds_error_log.match(".*entryrdn_insert_key - Same DN.*is already in the entryrdn file with different.*$")


def fin():
topology_st.standalone.restart()
mt.delete()
be1.delete()

request.addfinalizer(fin)

if __name__ == "__main__":
# Run isolated
Expand Down
2 changes: 1 addition & 1 deletion ldap/servers/slapd/back-ldbm/db-mdb/mdb_import_threads.c
Original file line number Diff line number Diff line change
Expand Up @@ -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] != '=') {
Expand Down
5 changes: 5 additions & 0 deletions ldap/servers/slapd/back-ldbm/ldbm_entryrdn.c
Original file line number Diff line number Diff line change
Expand Up @@ -1089,6 +1089,11 @@ entryrdn_lookup_dn(backend *be,
/* Iterate over the duplicates to get the direct child's ID */
workid = 0;
if (maybesuffix) {
if (id >= 1) {
/* We built srdn */
rc = -1;
goto bail;
}
/* it is a suffix, indeed. done. */
/* generate sdn to return */
slapi_rdn_get_dn(srdn, dn);
Expand Down

0 comments on commit 06c2426

Please sign in to comment.