From 005ab538217fb7ce17b1c25fe5a001d4bcf7bac3 Mon Sep 17 00:00:00 2001 From: eabdullin Date: Thu, 11 Sep 2025 06:24:07 +0000 Subject: [PATCH] import OL 389-ds-base-1.4.3.39-15.module+el8.10.0+90661+20343f81 --- ...iq-allow-specifying-match-rules-in-t.patch | 45 ++ ...ilter-is-not-fully-applying-matching.patch | 399 ++++++++++++++++++ SPECS/389-ds-base.spec | 7 +- 3 files changed, 450 insertions(+), 1 deletion(-) create mode 100644 SOURCES/0048-Issue-6857-uiduniq-allow-specifying-match-rules-in-t.patch create mode 100644 SOURCES/0049-Issue-6859-str2filter-is-not-fully-applying-matching.patch diff --git a/SOURCES/0048-Issue-6857-uiduniq-allow-specifying-match-rules-in-t.patch b/SOURCES/0048-Issue-6857-uiduniq-allow-specifying-match-rules-in-t.patch new file mode 100644 index 0000000..3bf50aa --- /dev/null +++ b/SOURCES/0048-Issue-6857-uiduniq-allow-specifying-match-rules-in-t.patch @@ -0,0 +1,45 @@ +From 2b73c3596e724f314b0e09cf6209e0151260f7e5 Mon Sep 17 00:00:00 2001 +From: Alexander Bokovoy +Date: Wed, 9 Jul 2025 12:08:09 +0300 +Subject: [PATCH] Issue 6857 - uiduniq: allow specifying match rules in the + filter + +Allow uniqueness plugin to work with attributes where uniqueness should +be enforced using different matching rule than the one defined for the +attribute itself. + +Since uniqueness plugin configuration can contain multiple attributes, +add matching rule right to the attribute as it is used in the LDAP rule +(e.g. 'attribute:caseIgnoreMatch:' to force 'attribute' to be searched +with case-insensitive matching rule instead of the original matching +rule. + +Fixes: https://github.com/389ds/389-ds-base/issues/6857 + +Signed-off-by: Alexander Bokovoy +--- + ldap/servers/plugins/uiduniq/uid.c | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/ldap/servers/plugins/uiduniq/uid.c b/ldap/servers/plugins/uiduniq/uid.c +index 5b763b551..15cf88477 100644 +--- a/ldap/servers/plugins/uiduniq/uid.c ++++ b/ldap/servers/plugins/uiduniq/uid.c +@@ -1031,7 +1031,14 @@ preop_add(Slapi_PBlock *pb) + } + + for (i = 0; attrNames && attrNames[i]; i++) { ++ char *attr_match = strchr(attrNames[i], ':'); ++ if (attr_match != NULL) { ++ attr_match[0] = '\0'; ++ } + err = slapi_entry_attr_find(e, attrNames[i], &attr); ++ if (attr_match != NULL) { ++ attr_match[0] = ':'; ++ } + if (!err) { + /* + * Passed all the requirements - this is an operation we +-- +2.49.0 + diff --git a/SOURCES/0049-Issue-6859-str2filter-is-not-fully-applying-matching.patch b/SOURCES/0049-Issue-6859-str2filter-is-not-fully-applying-matching.patch new file mode 100644 index 0000000..b6f8a92 --- /dev/null +++ b/SOURCES/0049-Issue-6859-str2filter-is-not-fully-applying-matching.patch @@ -0,0 +1,399 @@ +From 3ba73d2aa55f18ff73d4b3901ce101133745effc Mon Sep 17 00:00:00 2001 +From: Mark Reynolds +Date: Wed, 9 Jul 2025 14:18:50 -0400 +Subject: [PATCH] Issue 6859 - str2filter is not fully applying matching rules + +Description: + +When we have an extended filter, one with a MR applied, it is ignored during +internal searches: + + "(cn:CaseExactMatch:=Value)" + +For internal searches we use str2filter() and it doesn't fully apply extended +search filter matching rules + +Also needed to update attr uniqueness plugin to apply this change for mod +operations (previously only Adds were correctly handling these attribute +filters) + +Relates: https://github.com/389ds/389-ds-base/issues/6857 +Relates: https://github.com/389ds/389-ds-base/issues/6859 + +Reviewed by: spichugi & tbordaz(Thanks!!) +--- + .../tests/suites/plugins/attruniq_test.py | 295 +++++++++++++++++- + ldap/servers/plugins/uiduniq/uid.c | 7 + + ldap/servers/slapd/plugin_mr.c | 2 +- + ldap/servers/slapd/str2filter.c | 8 + + 4 files changed, 309 insertions(+), 3 deletions(-) + +diff --git a/dirsrvtests/tests/suites/plugins/attruniq_test.py b/dirsrvtests/tests/suites/plugins/attruniq_test.py +index b190e0ec1..b338f405f 100644 +--- a/dirsrvtests/tests/suites/plugins/attruniq_test.py ++++ b/dirsrvtests/tests/suites/plugins/attruniq_test.py +@@ -1,5 +1,5 @@ + # --- BEGIN COPYRIGHT BLOCK --- +-# Copyright (C) 2021 Red Hat, Inc. ++# Copyright (C) 2025 Red Hat, Inc. + # All rights reserved. + # + # License: GPL (version 3 or any later version). +@@ -80,4 +80,295 @@ def test_modrdn_attr_uniqueness(topology_st): + log.debug(excinfo.value) + + log.debug('Move user2 to group1') +- user2.rename(f'uid={user2.rdn}', group1.dn) +\ No newline at end of file ++ ++ user2.rename(f'uid={user2.rdn}', group1.dn) ++ ++ # Cleanup for next test ++ user1.delete() ++ user2.delete() ++ attruniq.disable() ++ attruniq.delete() ++ ++ ++def test_multiple_attr_uniqueness(topology_st): ++ """ Test that attribute uniqueness works properly with multiple attributes ++ ++ :id: c49aa5c1-7e65-45fd-b064-55e0b815e9bc ++ :setup: Standalone instance ++ :steps: ++ 1. Setup attribute uniqueness plugin to ensure uniqueness of attributes 'mail' and 'mailAlternateAddress' ++ 2. Add user with unique 'mail=non-uniq@value.net' and 'mailAlternateAddress=alt-mail@value.net' ++ 3. Try adding another user with 'mail=non-uniq@value.net' ++ 4. Try adding another user with 'mailAlternateAddress=alt-mail@value.net' ++ 5. Try adding another user with 'mail=alt-mail@value.net' ++ 6. Try adding another user with 'mailAlternateAddress=non-uniq@value.net' ++ :expectedresults: ++ 1. Success ++ 2. Success ++ 3. Should raise CONSTRAINT_VIOLATION ++ 4. Should raise CONSTRAINT_VIOLATION ++ 5. Should raise CONSTRAINT_VIOLATION ++ 6. Should raise CONSTRAINT_VIOLATION ++ """ ++ attruniq = AttributeUniquenessPlugin(topology_st.standalone, dn="cn=attruniq,cn=plugins,cn=config") ++ ++ try: ++ log.debug(f'Setup PLUGIN_ATTR_UNIQUENESS plugin for {MAIL_ATTR_VALUE} attribute for the group2') ++ attruniq.create(properties={'cn': 'attruniq'}) ++ attruniq.add_unique_attribute('mail') ++ attruniq.add_unique_attribute('mailAlternateAddress') ++ attruniq.add_unique_subtree(DEFAULT_SUFFIX) ++ attruniq.enable_all_subtrees() ++ log.debug(f'Enable PLUGIN_ATTR_UNIQUENESS plugin as "ON"') ++ attruniq.enable() ++ except ldap.LDAPError as e: ++ log.fatal('test_multiple_attribute_uniqueness: Failed to configure plugin for "mail": error {}'.format(e.args[0]['desc'])) ++ assert False ++ ++ topology_st.standalone.restart() ++ ++ users = UserAccounts(topology_st.standalone, DEFAULT_SUFFIX) ++ ++ testuser1 = users.create_test_user(100,100) ++ testuser1.add('objectclass', 'extensibleObject') ++ testuser1.add('mail', MAIL_ATTR_VALUE) ++ testuser1.add('mailAlternateAddress', MAIL_ATTR_VALUE_ALT) ++ ++ testuser2 = users.create_test_user(200, 200) ++ testuser2.add('objectclass', 'extensibleObject') ++ ++ with pytest.raises(ldap.CONSTRAINT_VIOLATION): ++ testuser2.add('mail', MAIL_ATTR_VALUE) ++ ++ with pytest.raises(ldap.CONSTRAINT_VIOLATION): ++ testuser2.add('mailAlternateAddress', MAIL_ATTR_VALUE_ALT) ++ ++ with pytest.raises(ldap.CONSTRAINT_VIOLATION): ++ testuser2.add('mail', MAIL_ATTR_VALUE_ALT) ++ ++ with pytest.raises(ldap.CONSTRAINT_VIOLATION): ++ testuser2.add('mailAlternateAddress', MAIL_ATTR_VALUE) ++ ++ # Cleanup ++ testuser1.delete() ++ testuser2.delete() ++ attruniq.disable() ++ attruniq.delete() ++ ++ ++def test_exclude_subtrees(topology_st): ++ """ Test attribute uniqueness with exclude scope ++ ++ :id: 43d29a60-40e1-4ebd-b897-6ef9f20e9f27 ++ :setup: Standalone instance ++ :steps: ++ 1. Setup and enable attribute uniqueness plugin for telephonenumber unique attribute ++ 2. Create subtrees and test users ++ 3. Add a unique attribute to a user within uniqueness scope ++ 4. Add exclude subtree ++ 5. Try to add existing value attribute to an entry within uniqueness scope ++ 6. Try to add existing value attribute to an entry within exclude scope ++ 7. Remove the attribute from affected entries ++ 8. Add a unique attribute to a user within exclude scope ++ 9. Try to add existing value attribute to an entry within uniqueness scope ++ 10. Try to add existing value attribute to another entry within uniqueness scope ++ 11. Remove the attribute from affected entries ++ 12. Add another exclude subtree ++ 13. Add a unique attribute to a user within uniqueness scope ++ 14. Try to add existing value attribute to an entry within uniqueness scope ++ 15. Try to add existing value attribute to an entry within exclude scope ++ 16. Try to add existing value attribute to an entry within another exclude scope ++ 17. Clean up entries ++ :expectedresults: ++ 1. Success ++ 2. Success ++ 3. Success ++ 4. Success ++ 5. Should raise CONSTRAINT_VIOLATION ++ 6. Success ++ 7. Success ++ 8. Success ++ 9. Success ++ 10. Should raise CONSTRAINT_VIOLATION ++ 11. Success ++ 12. Success ++ 13. Success ++ 14. Should raise CONSTRAINT_VIOLATION ++ 15. Success ++ 16. Success ++ 17. Success ++ """ ++ log.info('Setup attribute uniqueness plugin') ++ attruniq = AttributeUniquenessPlugin(topology_st.standalone, dn="cn=attruniq,cn=plugins,cn=config") ++ attruniq.create(properties={'cn': 'attruniq'}) ++ attruniq.add_unique_attribute('telephonenumber') ++ attruniq.add_unique_subtree(DEFAULT_SUFFIX) ++ attruniq.enable_all_subtrees() ++ attruniq.enable() ++ topology_st.standalone.restart() ++ ++ log.info('Create subtrees container') ++ containers = nsContainers(topology_st.standalone, DEFAULT_SUFFIX) ++ cont1 = containers.create(properties={'cn': EXCLUDED_CONTAINER_CN}) ++ cont2 = containers.create(properties={'cn': EXCLUDED_BIS_CONTAINER_CN}) ++ cont3 = containers.create(properties={'cn': ENFORCED_CONTAINER_CN}) ++ ++ log.info('Create test users') ++ users = UserAccounts(topology_st.standalone, DEFAULT_SUFFIX, ++ rdn='cn={}'.format(ENFORCED_CONTAINER_CN)) ++ users_excluded = UserAccounts(topology_st.standalone, DEFAULT_SUFFIX, ++ rdn='cn={}'.format(EXCLUDED_CONTAINER_CN)) ++ users_excluded2 = UserAccounts(topology_st.standalone, DEFAULT_SUFFIX, ++ rdn='cn={}'.format(EXCLUDED_BIS_CONTAINER_CN)) ++ ++ user1 = users.create(properties={'cn': USER_1_CN, ++ 'uid': USER_1_CN, ++ 'sn': USER_1_CN, ++ 'uidNumber': '1', ++ 'gidNumber': '11', ++ 'homeDirectory': '/home/{}'.format(USER_1_CN)}) ++ user2 = users.create(properties={'cn': USER_2_CN, ++ 'uid': USER_2_CN, ++ 'sn': USER_2_CN, ++ 'uidNumber': '2', ++ 'gidNumber': '22', ++ 'homeDirectory': '/home/{}'.format(USER_2_CN)}) ++ user3 = users_excluded.create(properties={'cn': USER_3_CN, ++ 'uid': USER_3_CN, ++ 'sn': USER_3_CN, ++ 'uidNumber': '3', ++ 'gidNumber': '33', ++ 'homeDirectory': '/home/{}'.format(USER_3_CN)}) ++ user4 = users_excluded2.create(properties={'cn': USER_4_CN, ++ 'uid': USER_4_CN, ++ 'sn': USER_4_CN, ++ 'uidNumber': '4', ++ 'gidNumber': '44', ++ 'homeDirectory': '/home/{}'.format(USER_4_CN)}) ++ ++ UNIQUE_VALUE = '1234' ++ ++ try: ++ log.info('Create user with unique attribute') ++ user1.add('telephonenumber', UNIQUE_VALUE) ++ assert user1.present('telephonenumber', UNIQUE_VALUE) ++ ++ log.info('Add exclude subtree') ++ attruniq.add_exclude_subtree(EXCLUDED_CONTAINER_DN) ++ topology_st.standalone.restart() ++ ++ log.info('Verify an already used attribute value cannot be added within the same subtree') ++ with pytest.raises(ldap.CONSTRAINT_VIOLATION): ++ user2.add('telephonenumber', UNIQUE_VALUE) ++ ++ log.info('Verify an entry with same attribute value can be added within exclude subtree') ++ user3.add('telephonenumber', UNIQUE_VALUE) ++ assert user3.present('telephonenumber', UNIQUE_VALUE) ++ ++ log.info('Cleanup unique attribute values') ++ user1.remove_all('telephonenumber') ++ user3.remove_all('telephonenumber') ++ ++ log.info('Add a unique value to an entry in excluded scope') ++ user3.add('telephonenumber', UNIQUE_VALUE) ++ assert user3.present('telephonenumber', UNIQUE_VALUE) ++ ++ log.info('Verify the same value can be added to an entry within uniqueness scope') ++ user1.add('telephonenumber', UNIQUE_VALUE) ++ assert user1.present('telephonenumber', UNIQUE_VALUE) ++ ++ log.info('Verify that yet another same value cannot be added to another entry within uniqueness scope') ++ with pytest.raises(ldap.CONSTRAINT_VIOLATION): ++ user2.add('telephonenumber', UNIQUE_VALUE) ++ ++ log.info('Cleanup unique attribute values') ++ user1.remove_all('telephonenumber') ++ user3.remove_all('telephonenumber') ++ ++ log.info('Add another exclude subtree') ++ attruniq.add_exclude_subtree(EXCLUDED_BIS_CONTAINER_DN) ++ topology_st.standalone.restart() ++ ++ user1.add('telephonenumber', UNIQUE_VALUE) ++ log.info('Verify an already used attribute value cannot be added within the same subtree') ++ with pytest.raises(ldap.CONSTRAINT_VIOLATION): ++ user2.add('telephonenumber', UNIQUE_VALUE) ++ ++ log.info('Verify an already used attribute can be added to an entry in exclude scope') ++ user3.add('telephonenumber', UNIQUE_VALUE) ++ assert user3.present('telephonenumber', UNIQUE_VALUE) ++ user4.add('telephonenumber', UNIQUE_VALUE) ++ assert user4.present('telephonenumber', UNIQUE_VALUE) ++ ++ finally: ++ log.info('Clean up users, containers and attribute uniqueness plugin') ++ user1.delete() ++ user2.delete() ++ user3.delete() ++ user4.delete() ++ cont1.delete() ++ cont2.delete() ++ cont3.delete() ++ attruniq.disable() ++ attruniq.delete() ++ ++ ++def test_matchingrule_attr(topology_st): ++ """ Test list extension MR attribute. Check for "cn" using CES (versus it ++ being defined as CIS) ++ ++ :id: 5cde4342-6fa3-4225-b23d-0af918981075 ++ :setup: Standalone instance ++ :steps: ++ 1. Setup and enable attribute uniqueness plugin to use CN attribute ++ with a matching rule of CaseExactMatch. ++ 2. Add user with CN value is lowercase ++ 3. Add second user with same lowercase CN which should be rejected ++ 4. Add second user with same CN value but with mixed case ++ 5. Modify second user replacing CN value to lc which should be rejected ++ ++ :expectedresults: ++ 1. Success ++ 2. Success ++ 3. Success ++ 4. Success ++ 5. Success ++ """ ++ ++ inst = topology_st.standalone ++ ++ attruniq = AttributeUniquenessPlugin(inst, ++ dn="cn=attribute uniqueness,cn=plugins,cn=config") ++ attruniq.add_unique_attribute('cn:CaseExactMatch:') ++ attruniq.enable_all_subtrees() ++ attruniq.enable() ++ inst.restart() ++ ++ users = UserAccounts(inst, DEFAULT_SUFFIX) ++ users.create(properties={'cn': "common_name", ++ 'uid': "uid_name", ++ 'sn': "uid_name", ++ 'uidNumber': '1', ++ 'gidNumber': '11', ++ 'homeDirectory': '/home/uid_name'}) ++ ++ log.info('Add entry with the exact CN value which should be rejected') ++ with pytest.raises(ldap.CONSTRAINT_VIOLATION): ++ users.create(properties={'cn': "common_name", ++ 'uid': "uid_name2", ++ 'sn': "uid_name2", ++ 'uidNumber': '11', ++ 'gidNumber': '111', ++ 'homeDirectory': '/home/uid_name2'}) ++ ++ log.info('Add entry with the mixed case CN value which should be allowed') ++ user = users.create(properties={'cn': "Common_Name", ++ 'uid': "uid_name2", ++ 'sn': "uid_name2", ++ 'uidNumber': '11', ++ 'gidNumber': '111', ++ 'homeDirectory': '/home/uid_name2'}) ++ ++ log.info('Mod entry with exact case CN value which should be rejected') ++ with pytest.raises(ldap.CONSTRAINT_VIOLATION): ++ user.replace('cn', 'common_name') +diff --git a/ldap/servers/plugins/uiduniq/uid.c b/ldap/servers/plugins/uiduniq/uid.c +index 15cf88477..5a0d61b86 100644 +--- a/ldap/servers/plugins/uiduniq/uid.c ++++ b/ldap/servers/plugins/uiduniq/uid.c +@@ -1179,6 +1179,10 @@ preop_modify(Slapi_PBlock *pb) + for (; mods && *mods; mods++) { + mod = *mods; + for (i = 0; attrNames && attrNames[i]; i++) { ++ char *attr_match = strchr(attrNames[i], ':'); ++ if (attr_match != NULL) { ++ attr_match[0] = '\0'; ++ } + if ((slapi_attr_type_cmp(mod->mod_type, attrNames[i], 1) == 0) && /* mod contains target attr */ + (mod->mod_op & LDAP_MOD_BVALUES) && /* mod is bval encoded (not string val) */ + (mod->mod_bvalues && mod->mod_bvalues[0]) && /* mod actually contains some values */ +@@ -1187,6 +1191,9 @@ preop_modify(Slapi_PBlock *pb) + { + addMod(&checkmods, &checkmodsCapacity, &modcount, mod); + } ++ if (attr_match != NULL) { ++ attr_match[0] = ':'; ++ } + } + } + if (modcount == 0) { +diff --git a/ldap/servers/slapd/plugin_mr.c b/ldap/servers/slapd/plugin_mr.c +index 6cf88b7de..f40c9a39b 100644 +--- a/ldap/servers/slapd/plugin_mr.c ++++ b/ldap/servers/slapd/plugin_mr.c +@@ -624,7 +624,7 @@ attempt_mr_filter_create(mr_filter_t *f, struct slapdplugin *mrp, Slapi_PBlock * + int rc; + IFP mrf_create = NULL; + f->mrf_match = NULL; +- pblock_init(pb); ++ slapi_pblock_init(pb); + if (!(rc = slapi_pblock_set(pb, SLAPI_PLUGIN, mrp)) && + !(rc = slapi_pblock_get(pb, SLAPI_PLUGIN_MR_FILTER_CREATE_FN, &mrf_create)) && + mrf_create != NULL && +diff --git a/ldap/servers/slapd/str2filter.c b/ldap/servers/slapd/str2filter.c +index 9fdc500f7..5620b7439 100644 +--- a/ldap/servers/slapd/str2filter.c ++++ b/ldap/servers/slapd/str2filter.c +@@ -344,6 +344,14 @@ str2simple(char *str, int unescape_filter) + return NULL; /* error */ + } else { + f->f_choice = LDAP_FILTER_EXTENDED; ++ if (f->f_mr_oid) { ++ /* apply the MR indexers */ ++ rc = plugin_mr_filter_create(&f->f_mr); ++ if (rc) { ++ slapi_filter_free(f, 1); ++ return NULL; /* error */ ++ } ++ } + } + } else if (str_find_star(value) == NULL) { + f->f_choice = LDAP_FILTER_EQUALITY; +-- +2.49.0 + diff --git a/SPECS/389-ds-base.spec b/SPECS/389-ds-base.spec index abd9991..66d39ad 100644 --- a/SPECS/389-ds-base.spec +++ b/SPECS/389-ds-base.spec @@ -52,7 +52,7 @@ ExcludeArch: i686 Summary: 389 Directory Server (base) Name: 389-ds-base Version: 1.4.3.39 -Release: %{?relprefix}14%{?prerel}%{?dist} +Release: %{?relprefix}15%{?prerel}%{?dist} License: GPL-3.0-or-later WITH GPL-3.0-389-ds-base-exception AND (0BSD OR Apache-2.0 OR MIT) AND (Apache-2.0 OR Apache-2.0 WITH LLVM-exception OR MIT) AND (Apache-2.0 OR BSD-2-Clause OR MIT) AND (Apache-2.0 OR BSL-1.0) AND (Apache-2.0 OR LGPL-2.1-or-later OR MIT) AND (Apache-2.0 OR MIT OR Zlib) AND (Apache-2.0 OR MIT) AND (MIT OR Apache-2.0) AND Unicode-3.0 AND (MIT OR Unlicense) AND Apache-2.0 AND BSD-3-Clause AND MIT AND MPL-2.0 URL: https://www.port389.org Group: System Environment/Daemons @@ -345,6 +345,8 @@ Patch44: 0044-Issue-6571-2nd-Nested-group-does-not-receive-memberO.patc Patch45: 0045-Issue-6698-NPE-after-configuring-invalid-filtered-ro.patch Patch46: 0046-Issue-6686-CLI-Re-enabling-user-accounts-that-reache.patch Patch47: 0047-Issue-6302-Allow-to-run-replication-status-without-a.patch +Patch48: 0048-Issue-6857-uiduniq-allow-specifying-match-rules-in-t.patch +Patch49: 0049-Issue-6859-str2filter-is-not-fully-applying-matching.patch #Patch100: cargo.patch @@ -970,6 +972,9 @@ exit 0 %doc README.md %changelog +* Mon Aug 18 2025 Viktor Ashirov - 1.4.3.39-15 +- Resolves: RHEL-109028 - Allow Uniqueness plugin to search uniqueness attributes using custom matching rules [rhel-8.10.z] + * Thu Jun 5 2025 Viktor Ashirov - 1.4.3.39-14 - Reverts: RHEL-80704 - Increased memory consumption caused by NDN cache [rhel-8.10.z] - Resolves: RHEL-95442 - ns-slapd[xxxx]: segfault at 10d7d0d0 ip 00007ff734050cdb sp 00007ff6de9f1430 error 6 in libslapd.so.0.1.0[7ff733ec0000+1b3000] [rhel-8.10.z]