You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
193 lines
8.2 KiB
193 lines
8.2 KiB
From 9501c34df01e35f483201a4bba12a93091b2b13f Mon Sep 17 00:00:00 2001
|
|
From: progier389 <progier@redhat.com>
|
|
Date: Thu, 13 Jun 2024 15:17:36 +0200
|
|
Subject: [PATCH] Issue 5772 - ONE LEVEL search fails to return sub-suffixes
|
|
(#6219)
|
|
|
|
Problem: ONE LEVEL scoped search fails to return sub-suffixes entries
|
|
Reason: When such search is done, a one level search is done on the main suffix and base search are done on any matching sub-suffix. But main suffix is processed search (to ensure that parent entries are returned before children ones when searching subtree) and ldbm_back_search change the filter to (&(parentid=xxx)old_filter) so the filter test reject the entry on the sub-suffixes.
|
|
Solution: Revert the backend list when doing one level search so that the sub-suffixes are processed first
|
|
and restore the base dn for the main suffix.
|
|
Alternative rejected: reset the filter when discivering a sub-suffix. Not so easy because filter is altered by the rewriteres.
|
|
And systematic duplication is an useless overhead if there is no matching sub-suffixes (which is the usual case)
|
|
|
|
Issue: #5772
|
|
|
|
Reviewed by: @tbordaz, @droideck (Thanks!)
|
|
|
|
(cherry picked from commit 407bdaa00d1da9f5ff53d66a2e012b17ad658907)
|
|
---
|
|
.../suites/mapping_tree/regression_test.py | 36 +++++++++++++++++-
|
|
ldap/servers/slapd/filterentry.c | 38 ++++++++++++++++++-
|
|
ldap/servers/slapd/opshared.c | 22 ++++++++++-
|
|
3 files changed, 92 insertions(+), 4 deletions(-)
|
|
|
|
diff --git a/dirsrvtests/tests/suites/mapping_tree/regression_test.py b/dirsrvtests/tests/suites/mapping_tree/regression_test.py
|
|
index f4877da2b..c3fc2c0a2 100644
|
|
--- a/dirsrvtests/tests/suites/mapping_tree/regression_test.py
|
|
+++ b/dirsrvtests/tests/suites/mapping_tree/regression_test.py
|
|
@@ -92,7 +92,6 @@ EXPECTED_ENTRIES = (("dc=parent", 39), ("dc=child1,dc=parent", 13), ("dc=child2,
|
|
@pytest.mark.skipif(not has_orphan_attribute, reason = "compatibility attribute not yet implemented in this version")
|
|
def test_sub_suffixes(topo, orphan_param):
|
|
""" check the entries found on suffix/sub-suffix
|
|
- used int
|
|
|
|
:id: 5b4421c2-d851-11ec-a760-482ae39447e5
|
|
:feature: mapping-tree
|
|
@@ -122,8 +121,41 @@ def test_sub_suffixes(topo, orphan_param):
|
|
log.info(f'Verifying domain component entries count for search under {suffix} ...')
|
|
entries = topo.standalone.search_s(suffix, ldap.SCOPE_SUBTREE, "(dc=*)")
|
|
assert len(entries) == expected
|
|
- log.info('Found {expected} domain component entries as expected while searching {suffix}')
|
|
+ log.info(f'Found {expected} domain component entries as expected while searching {suffix}')
|
|
|
|
log.info('Test PASSED')
|
|
|
|
|
|
+def test_one_level_search_on_sub_suffixes(topo):
|
|
+ """ Perform one level scoped search accross suffix and sub-suffix
|
|
+
|
|
+ :id: 92f3139e-280e-11ef-a989-482ae39447e5
|
|
+ :feature: mapping-tree
|
|
+ :setup: Standalone instance with 3 additional backends:
|
|
+ dc=parent, dc=child1,dc=parent, dc=childr21,dc=parent
|
|
+ :steps:
|
|
+ 1. Perform a ONE LEVEL search on dc=parent
|
|
+ 2. Check that all expected entries have been returned
|
|
+ 3. Check that only the expected entries have been returned
|
|
+ :expectedresults:
|
|
+ 1. Success
|
|
+ 2. each expected dn should be in the result set
|
|
+ 3. Number of returned entries should be the same as the number of expected entries
|
|
+ """
|
|
+ expected_dns = ( 'dc=child1,dc=parent',
|
|
+ 'dc=child2,dc=parent',
|
|
+ 'ou=accounting,dc=parent',
|
|
+ 'ou=product development,dc=parent',
|
|
+ 'ou=product testing,dc=parent',
|
|
+ 'ou=human resources,dc=parent',
|
|
+ 'ou=payroll,dc=parent',
|
|
+ 'ou=people,dc=parent',
|
|
+ 'ou=groups,dc=parent', )
|
|
+ entries = topo.standalone.search_s("dc=parent", ldap.SCOPE_ONELEVEL, "(objectClass=*)",
|
|
+ attrlist=("dc","ou"), escapehatch='i am sure')
|
|
+ log.info(f'one level search on dc=parent returned the following entries: {entries}')
|
|
+ dns = [ entry.dn for entry in entries ]
|
|
+ for dn in expected_dns:
|
|
+ assert dn in dns
|
|
+ assert len(entries) == len(expected_dns)
|
|
+
|
|
diff --git a/ldap/servers/slapd/filterentry.c b/ldap/servers/slapd/filterentry.c
|
|
index 4de4aa66e..d2c7e3082 100644
|
|
--- a/ldap/servers/slapd/filterentry.c
|
|
+++ b/ldap/servers/slapd/filterentry.c
|
|
@@ -240,6 +240,36 @@ slapi_filter_test_ext(
|
|
}
|
|
|
|
|
|
+static const char *
|
|
+filter_type_as_string(int filter_type)
|
|
+{
|
|
+ switch (filter_type) {
|
|
+ case LDAP_FILTER_AND:
|
|
+ return "&";
|
|
+ case LDAP_FILTER_OR:
|
|
+ return "|";
|
|
+ case LDAP_FILTER_NOT:
|
|
+ return "!";
|
|
+ case LDAP_FILTER_EQUALITY:
|
|
+ return "=";
|
|
+ case LDAP_FILTER_SUBSTRINGS:
|
|
+ return "*";
|
|
+ case LDAP_FILTER_GE:
|
|
+ return ">=";
|
|
+ case LDAP_FILTER_LE:
|
|
+ return "<=";
|
|
+ case LDAP_FILTER_PRESENT:
|
|
+ return "=*";
|
|
+ case LDAP_FILTER_APPROX:
|
|
+ return "~";
|
|
+ case LDAP_FILTER_EXT:
|
|
+ return "EXT";
|
|
+ default:
|
|
+ return "?";
|
|
+ }
|
|
+}
|
|
+
|
|
+
|
|
int
|
|
test_ava_filter(
|
|
Slapi_PBlock *pb,
|
|
@@ -253,7 +283,13 @@ test_ava_filter(
|
|
{
|
|
int rc;
|
|
|
|
- slapi_log_err(SLAPI_LOG_FILTER, "test_ava_filter", "=>\n");
|
|
+ if (slapi_is_loglevel_set(SLAPI_LOG_FILTER)) {
|
|
+ char *val = slapi_berval_get_string_copy(&ava->ava_value);
|
|
+ char buf[BUFSIZ];
|
|
+ slapi_log_err(SLAPI_LOG_FILTER, "test_ava_filter", "=> AVA: %s%s%s\n",
|
|
+ ava->ava_type, filter_type_as_string(ftype), escape_string(val, buf));
|
|
+ slapi_ch_free_string(&val);
|
|
+ }
|
|
|
|
*access_check_done = 0;
|
|
|
|
diff --git a/ldap/servers/slapd/opshared.c b/ldap/servers/slapd/opshared.c
|
|
index f77043afa..540597f45 100644
|
|
--- a/ldap/servers/slapd/opshared.c
|
|
+++ b/ldap/servers/slapd/opshared.c
|
|
@@ -219,6 +219,7 @@ cache_return_target_entry(Slapi_PBlock *pb, Slapi_Backend *be, Slapi_Operation *
|
|
operation_set_target_entry_id(operation, 0);
|
|
}
|
|
}
|
|
+
|
|
/*
|
|
* Returns: 0 - if the operation is successful
|
|
* < 0 - if operation fails.
|
|
@@ -481,6 +482,20 @@ op_shared_search(Slapi_PBlock *pb, int send_result)
|
|
while (be_list[index] && be_list[index + 1]) {
|
|
index++;
|
|
}
|
|
+ if (scope == LDAP_SCOPE_ONELEVEL) {
|
|
+ /*
|
|
+ * ONE LEVEL searches may ends up on multiple backends
|
|
+ * with a ONE LEVEL search on a suffix and a BASE search on its
|
|
+ * subsuffixes. Because LDAP_SCOPE_ONELEVEL rewrite the filter
|
|
+ * the backends should be reversed so that the BASE search(es)
|
|
+ * are done first (with the original filter).
|
|
+ */
|
|
+ for (int idx = 0; idx <= index/2; idx++) {
|
|
+ be = be_list[index-idx];
|
|
+ be_list[index-idx] = be_list[idx];
|
|
+ be_list[idx] = be;
|
|
+ }
|
|
+ }
|
|
be = be_list[index];
|
|
} else {
|
|
be = NULL;
|
|
@@ -779,7 +794,6 @@ op_shared_search(Slapi_PBlock *pb, int send_result)
|
|
(slapi_sdn_get_ndn_len(basesdn) == 0)) {
|
|
int tmp_scope = LDAP_SCOPE_BASE;
|
|
slapi_pblock_set(pb, SLAPI_SEARCH_SCOPE, &tmp_scope);
|
|
-
|
|
if (free_sdn) {
|
|
slapi_pblock_get(pb, SLAPI_SEARCH_TARGET_SDN, &sdn);
|
|
slapi_sdn_free(&sdn);
|
|
@@ -790,6 +804,12 @@ op_shared_search(Slapi_PBlock *pb, int send_result)
|
|
} else if (slapi_sdn_issuffix(basesdn, be_suffix)) {
|
|
int tmp_scope = LDAP_SCOPE_ONELEVEL;
|
|
slapi_pblock_set(pb, SLAPI_SEARCH_SCOPE, &tmp_scope);
|
|
+ if (free_sdn) {
|
|
+ slapi_pblock_get(pb, SLAPI_SEARCH_TARGET_SDN, &sdn);
|
|
+ slapi_sdn_free(&sdn);
|
|
+ sdn = slapi_sdn_dup(basesdn);
|
|
+ slapi_pblock_set(pb, SLAPI_SEARCH_TARGET_SDN, (void *)sdn);
|
|
+ }
|
|
} else {
|
|
slapi_sdn_done(&monitorsdn);
|
|
goto next_be;
|
|
--
|
|
2.45.2
|
|
|