diff --git a/dirsrvtests/tests/suites/indexes/entryrdn_test.py b/dirsrvtests/tests/suites/indexes/entryrdn_test.py index 345955d4da..05342afcb0 100644 --- a/dirsrvtests/tests/suites/indexes/entryrdn_test.py +++ b/dirsrvtests/tests/suites/indexes/entryrdn_test.py @@ -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 @@ -283,6 +288,74 @@ def test_long_rdn(topo_m2): ou.delete() assert not ou.exists() +def test_duplicate_rdn(topology_st, request): + inst = topology_st.standalone + inst.config.replace('nsslapd-auditfaillog-logging-enabled', 'on') + 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, + }) + + # The order of create is important + # it does not hit the bug in the order + # 1 - 3 - 2 - 4 + + # 1 - Create the domain entry 'dc=com' + create_base_domain(inst, suffix) + + # 2 - Create the org ou=my_org,dc=com + ous = OrganizationalUnits(inst, suffix) + ou = ous.create(properties={ 'ou': rdn }) + #org1 = OrganizationalUnits(inst, DEFAULT_SUFFIX).create(properties={'ou': 'Users'}) + # 'originScope': org1.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) + + # 3 - Create the domain entry 'dc=com,dc=com' + #truc = "dc=dux_rdn,dc=dup_rdn" + truc = "dc=dup_rdn,dc=dup_rdn" + topology_st.standalone.add_s(Entry(( + truc, { + "objectClass": "top", + "objectClass": "domain", + "dc": dc_value, + } + ))) + + # 4 - Create the org ou=my_org,dc=com,dc=com + ous = OrganizationalUnits(inst, truc) + ou = ous.create(properties={ 'ou': rdn }) + + + log.info('Offline reindex, stopping the server') + topology_st.standalone.stop() + + log.info('Reindex all the suffix') + topology_st.standalone.db2index(bename=be_name) + 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 diff --git a/ldap/servers/slapd/back-ldbm/ldbm_entryrdn.c b/ldap/servers/slapd/back-ldbm/ldbm_entryrdn.c index ef79219469..421804a3e7 100644 --- a/ldap/servers/slapd/back-ldbm/ldbm_entryrdn.c +++ b/ldap/servers/slapd/back-ldbm/ldbm_entryrdn.c @@ -987,9 +987,11 @@ entryrdn_lookup_dn(backend *be, char *keybuf = NULL; Slapi_RDN *srdn = NULL; char *orignrdn = NULL; + Slapi_DN origin_rdn_sdn = {0}; char *nrdn = NULL; size_t nrdn_len = 0; ID workid = id; /* starting from the given id */ + ID origin_id = id; rdn_elem *elem = NULL; int maybesuffix = 0; @@ -1028,6 +1030,14 @@ entryrdn_lookup_dn(backend *be, slapi_ch_free_string(&orignrdn); } + /* + * Used to be sure we are not returning the suffix DN by mistake + * If the entryrdn is under creation (reindex), there is a risk to + * return the suffix DN if the rdn, of the lookup entry, is equal to suffix. + * (see #6417) + */ + slapi_sdn_init_dn_byval(&origin_rdn_sdn, nrdn); + /* Setting the bulk fetch buffer */ dblayer_value_free(be, &data); dblayer_value_init(be, &data); @@ -1088,14 +1098,6 @@ entryrdn_lookup_dn(backend *be, /* Iterate over the duplicates to get the direct child's ID */ workid = 0; - if (maybesuffix) { - /* it is a suffix, indeed. done. */ - /* generate sdn to return */ - slapi_rdn_get_dn(srdn, dn); - rc = 0; - _ENTRYRDN_DEBUG_GOTO_BAIL(); - goto bail; - } /* found a parent (there should be just one parent :) */ elem = (rdn_elem *)data.data; if (elem && RDN_IS_REDIRECT(elem)) { @@ -1107,6 +1109,33 @@ entryrdn_lookup_dn(backend *be, data.data = elem; } + if (maybesuffix) { + Slapi_DN sdn_returned; + + /* it is a suffix, indeed. done. */ + /* generate sdn to return */ + slapi_rdn_get_dn(srdn, dn); + + /* Check that if we are returning suffix + * the suffix entryID match the original + * provided entryID + */ + slapi_sdn_init_dn_byval(&sdn_returned, *dn); + if ((slapi_sdn_compare(&sdn_returned, &origin_rdn_sdn) == 0) && + (id_stored_to_internal(elem->rdn_elem_id) != origin_id)) { + /* The origin_id is not the suffixID. + * So we are not looking for the suffix DN + */ + slapi_ch_free_string(dn); + rc = -1; + } else { + rc = 0; + } + slapi_sdn_done(&sdn_returned); + + _ENTRYRDN_DEBUG_GOTO_BAIL(); + goto bail; + } _ENTRYRDN_DUMP_RDN_ELEM(elem); slapi_ch_free_string(&nrdn); nrdn = slapi_ch_strdup(elem->rdn_elem_nrdn_rdn); @@ -1131,6 +1160,7 @@ entryrdn_lookup_dn(backend *be, slapi_rdn_free(&srdn); } slapi_ch_free_string(&nrdn); + slapi_sdn_done(&origin_rdn_sdn); slapi_log_err(SLAPI_LOG_TRACE, "entryrdn_lookup_dn", "<-- entryrdn_lookup_dn\n"); return rc;