Blame SOURCES/0033-Issue-5442-Search-results-are-different-between-RHDS.patch

3280a9
From 788d7c69a446d1ae324b2c58daaa5d4fd5528748 Mon Sep 17 00:00:00 2001
ef1f48
From: Mark Reynolds <mreynolds@redhat.com>
ef1f48
Date: Wed, 20 Jan 2021 16:42:15 -0500
3280a9
Subject: [PATCH 1/3] Issue 5442 - Search results are different between RHDS10
ef1f48
 and RHDS11
ef1f48
ef1f48
Bug Description:  In 1.4.x we introduced a change that was overly strict about
ef1f48
                  how a search on a non-existent subtree returned its error code.
ef1f48
                  It was changed from returning an error 32 to an error 0 with
ef1f48
                  zero entries returned.
ef1f48
ef1f48
Fix Description:  When finding the entry and processing acl's make sure to
ef1f48
                  gather the aci's that match the resource even if the resource
ef1f48
                  does not exist.  This requires some extra checks when processing
ef1f48
                  the target attribute.
ef1f48
ef1f48
relates: https://github.com/389ds/389-ds-base/issues/4542
ef1f48
ef1f48
Reviewed by: firstyear, elkris, and tbordaz (Thanks!)
ef1f48
ef1f48
Apply Thierry's changes
ef1f48
ef1f48
round 2
ef1f48
ef1f48
Apply more suggestions from Thierry
ef1f48
---
ef1f48
 dirsrvtests/tests/suites/acl/misc_test.py | 108 +++++++-
ef1f48
 ldap/servers/plugins/acl/acl.c            | 296 ++++++++++------------
ef1f48
 ldap/servers/slapd/back-ldbm/findentry.c  |   6 +-
ef1f48
 src/lib389/lib389/_mapped_object.py       |   4 +-
ef1f48
 4 files changed, 239 insertions(+), 175 deletions(-)
ef1f48
ef1f48
diff --git a/dirsrvtests/tests/suites/acl/misc_test.py b/dirsrvtests/tests/suites/acl/misc_test.py
3280a9
index 5f0e3eb72..c640e60ad 100644
ef1f48
--- a/dirsrvtests/tests/suites/acl/misc_test.py
ef1f48
+++ b/dirsrvtests/tests/suites/acl/misc_test.py
3280a9
@@ -12,7 +12,7 @@ import ldap
ef1f48
 import os
ef1f48
 import pytest
ef1f48
 
ef1f48
-from lib389._constants import DEFAULT_SUFFIX, PW_DM
ef1f48
+from lib389._constants import DEFAULT_SUFFIX, PW_DM, DN_DM
ef1f48
 from lib389.idm.user import UserAccount, UserAccounts
ef1f48
 from lib389._mapped_object import DSLdapObject
ef1f48
 from lib389.idm.account import Accounts, Anonymous
3280a9
@@ -408,14 +408,112 @@ def test_do_bind_as_201_distinct_users(topo, clean, aci_of_user):
ef1f48
         user = uas.create_test_user(uid=i, gid=i)
ef1f48
         user.set('userPassword', PW_DM)
ef1f48
 
ef1f48
-    for i in range(len(uas.list())):
ef1f48
-        uas.list()[i].bind(PW_DM)
ef1f48
+    users = uas.list()
ef1f48
+    for user in users:
ef1f48
+        user.bind(PW_DM)
ef1f48
 
ef1f48
     ACLPlugin(topo.standalone).replace("nsslapd-aclpb-max-selected-acls", '220')
ef1f48
     topo.standalone.restart()
ef1f48
 
ef1f48
-    for i in range(len(uas.list())):
ef1f48
-        uas.list()[i].bind(PW_DM)
ef1f48
+    users = uas.list()
ef1f48
+    for user in users:
ef1f48
+        user.bind(PW_DM)
ef1f48
+
ef1f48
+
ef1f48
+def test_info_disclosure(request, topo):
ef1f48
+    """Test that a search returns 32 when base entry does not exist
ef1f48
+
ef1f48
+    :id: f6dec4c2-65a3-41e4-a4c0-146196863333
ef1f48
+    :setup: Standalone Instance
ef1f48
+    :steps:
ef1f48
+        1. Add aci
ef1f48
+        2. Add test user
ef1f48
+        3. Bind as user and search for non-existent entry
ef1f48
+    :expectedresults:
ef1f48
+        1. Success
ef1f48
+        2. Success
ef1f48
+        3. Error 32 is returned
ef1f48
+    """
ef1f48
+
ef1f48
+    ACI_TARGET = "(targetattr = \"*\")(target = \"ldap:///%s\")" % (DEFAULT_SUFFIX)
ef1f48
+    ACI_ALLOW = "(version 3.0; acl \"Read/Search permission for all users\"; allow (read,search)"
ef1f48
+    ACI_SUBJECT = "(userdn=\"ldap:///all\");)"
ef1f48
+    ACI = ACI_TARGET + ACI_ALLOW + ACI_SUBJECT
ef1f48
+
ef1f48
+    # Get current ACi's so we can restore them when we are done
ef1f48
+    suffix = Domain(topo.standalone, DEFAULT_SUFFIX)
ef1f48
+    preserved_acis = suffix.get_attr_vals_utf8('aci')
ef1f48
+
ef1f48
+    def finofaci():
ef1f48
+        domain = Domain(topo.standalone, DEFAULT_SUFFIX)
ef1f48
+        try:
ef1f48
+            domain.remove_all('aci')
ef1f48
+            domain.replace_values('aci', preserved_acis)
ef1f48
+        except:
ef1f48
+            pass
ef1f48
+    request.addfinalizer(finofaci)
ef1f48
+
ef1f48
+    # Remove aci's
ef1f48
+    suffix.remove_all('aci')
ef1f48
+
ef1f48
+    # Add test user
ef1f48
+    USER_DN = "uid=test,ou=people," + DEFAULT_SUFFIX
ef1f48
+    users = UserAccounts(topo.standalone, DEFAULT_SUFFIX)
ef1f48
+    users.create(properties={
ef1f48
+        'uid': 'test',
ef1f48
+        'cn': 'test',
ef1f48
+        'sn': 'test',
ef1f48
+        'uidNumber': '1000',
ef1f48
+        'gidNumber': '2000',
ef1f48
+        'homeDirectory': '/home/test',
ef1f48
+        'userPassword': PW_DM
ef1f48
+    })
ef1f48
+
ef1f48
+    # bind as user
ef1f48
+    conn = UserAccount(topo.standalone, USER_DN).bind(PW_DM)
ef1f48
+
ef1f48
+    # Search fo existing base DN
ef1f48
+    test = Domain(conn, DEFAULT_SUFFIX)
ef1f48
+    try:
ef1f48
+        test.get_attr_vals_utf8_l('dc')
ef1f48
+        assert False
ef1f48
+    except IndexError:
ef1f48
+        pass
ef1f48
+
ef1f48
+    # Search for a non existent bases
ef1f48
+    subtree = Domain(conn, "ou=does_not_exist," + DEFAULT_SUFFIX)
ef1f48
+    try:
ef1f48
+        subtree.get_attr_vals_utf8_l('objectclass')
ef1f48
+    except IndexError:
ef1f48
+        pass
ef1f48
+    subtree = Domain(conn, "ou=also does not exist,ou=does_not_exist," + DEFAULT_SUFFIX)
ef1f48
+    try:
ef1f48
+        subtree.get_attr_vals_utf8_l('objectclass')
ef1f48
+    except IndexError:
ef1f48
+        pass
ef1f48
+    # Try ONE level search instead of BASE
ef1f48
+    try:
ef1f48
+        Accounts(conn, "ou=does_not_exist," + DEFAULT_SUFFIX).filter("(objectclass=top)", ldap.SCOPE_ONELEVEL)
ef1f48
+    except IndexError:
ef1f48
+        pass
ef1f48
+
ef1f48
+    # add aci
ef1f48
+    suffix.add('aci', ACI)
ef1f48
+
ef1f48
+    # Search for a non existent entry which should raise an exception
ef1f48
+    with pytest.raises(ldap.NO_SUCH_OBJECT):
ef1f48
+        conn = UserAccount(topo.standalone, USER_DN).bind(PW_DM)
ef1f48
+        subtree = Domain(conn, "ou=does_not_exist," + DEFAULT_SUFFIX)
ef1f48
+        subtree.get_attr_vals_utf8_l('objectclass')
ef1f48
+    with pytest.raises(ldap.NO_SUCH_OBJECT):
ef1f48
+        conn = UserAccount(topo.standalone, USER_DN).bind(PW_DM)
ef1f48
+        subtree = Domain(conn, "ou=also does not exist,ou=does_not_exist," + DEFAULT_SUFFIX)
ef1f48
+        subtree.get_attr_vals_utf8_l('objectclass')
ef1f48
+    with pytest.raises(ldap.NO_SUCH_OBJECT):
ef1f48
+        conn = UserAccount(topo.standalone, USER_DN).bind(PW_DM)
ef1f48
+        DN = "ou=also does not exist,ou=does_not_exist," + DEFAULT_SUFFIX
ef1f48
+        Accounts(conn, DN).filter("(objectclass=top)", ldap.SCOPE_ONELEVEL, strict=True)
ef1f48
+
ef1f48
 
ef1f48
 if __name__ == "__main__":
3280a9
     CURRENT_FILE = os.path.realpath(__file__)
ef1f48
diff --git a/ldap/servers/plugins/acl/acl.c b/ldap/servers/plugins/acl/acl.c
ef1f48
index 41a909a18..4e811f73a 100644
ef1f48
--- a/ldap/servers/plugins/acl/acl.c
ef1f48
+++ b/ldap/servers/plugins/acl/acl.c
ef1f48
@@ -2111,10 +2111,11 @@ acl__resource_match_aci(Acl_PBlock *aclpb, aci_t *aci, int skip_attrEval, int *a
ef1f48
     aci_right = aci->aci_access;
ef1f48
     res_right = aclpb->aclpb_access;
ef1f48
     if (!(aci_right & res_right)) {
ef1f48
-        /* If we are looking for read/search and the acl has read/search
ef1f48
-        ** then go further because if targets match we may keep that
ef1f48
-        ** acl in  the entry cache list.
ef1f48
-        */
ef1f48
+        /*
ef1f48
+         * If we are looking for read/search and the acl has read/search
ef1f48
+         * then go further because if targets match we may keep that
ef1f48
+         * acl in the entry cache list.
ef1f48
+         */
ef1f48
         if (!((res_right & (SLAPI_ACL_SEARCH | SLAPI_ACL_READ)) &&
ef1f48
               (aci_right & (SLAPI_ACL_SEARCH | SLAPI_ACL_READ)))) {
ef1f48
             matches = ACL_FALSE;
ef1f48
@@ -2122,30 +2123,29 @@ acl__resource_match_aci(Acl_PBlock *aclpb, aci_t *aci, int skip_attrEval, int *a
ef1f48
         }
ef1f48
     }
ef1f48
 
ef1f48
-
ef1f48
-    /* first Let's see if the entry is under the subtree where the
ef1f48
-    ** ACL resides. We can't let somebody affect a target beyond the
ef1f48
-    ** scope of where the ACL resides
ef1f48
-    ** Example: ACL is located in "ou=engineering, o=ace industry, c=us
ef1f48
-    ** but if the target is "o=ace industry, c=us", then we are in trouble.
ef1f48
-    **
ef1f48
-    ** If the aci is in the rootdse and the entry is not, then we do not
ef1f48
-    ** match--ie. acis in the rootdse do NOT apply below...for the moment.
ef1f48
-    **
ef1f48
-    */
ef1f48
+    /*
ef1f48
+     * First Let's see if the entry is under the subtree where the
ef1f48
+     * ACL resides. We can't let somebody affect a target beyond the
ef1f48
+     * scope of where the ACL resides
ef1f48
+     * Example: ACL is located in "ou=engineering, o=ace industry, c=us
ef1f48
+     * but if the target is "o=ace industry, c=us", then we are in trouble.
ef1f48
+     *
ef1f48
+     * If the aci is in the rootdse and the entry is not, then we do not
ef1f48
+     * match--ie. acis in the rootdse do NOT apply below...for the moment.
ef1f48
+     */
ef1f48
     res_ndn = slapi_sdn_get_ndn(aclpb->aclpb_curr_entry_sdn);
ef1f48
     aci_ndn = slapi_sdn_get_ndn(aci->aci_sdn);
ef1f48
-    if (!slapi_sdn_issuffix(aclpb->aclpb_curr_entry_sdn, aci->aci_sdn) || (!slapi_is_rootdse(res_ndn) && slapi_is_rootdse(aci_ndn))) {
ef1f48
-
ef1f48
-        /* cant' poke around */
ef1f48
+    if (!slapi_sdn_issuffix(aclpb->aclpb_curr_entry_sdn, aci->aci_sdn) ||
ef1f48
+        (!slapi_is_rootdse(res_ndn) && slapi_is_rootdse(aci_ndn)))
ef1f48
+    {
ef1f48
+        /* can't poke around */
ef1f48
         matches = ACL_FALSE;
ef1f48
         goto acl__resource_match_aci_EXIT;
ef1f48
     }
ef1f48
 
ef1f48
     /*
ef1f48
-    ** We have a single ACI which we need to find if it applies to
ef1f48
-    ** the resource or not.
ef1f48
-    */
ef1f48
+     * We have a single ACI which we need to find if it applies to the resource or not.
ef1f48
+     */
ef1f48
     if ((aci->aci_type & ACI_TARGET_DN) && (aclpb->aclpb_curr_entry_sdn)) {
ef1f48
         char *avaType;
ef1f48
         struct berval *avaValue;
ef1f48
@@ -2173,25 +2173,23 @@ acl__resource_match_aci(Acl_PBlock *aclpb, aci_t *aci, int skip_attrEval, int *a
ef1f48
         char *avaType;
ef1f48
         struct berval *avaValue;
ef1f48
         char logbuf[1024];
ef1f48
-
ef1f48
-        /* We are evaluating the moddn permission.
ef1f48
-                 * The aci contains target_to and target_from
ef1f48
-                 *
ef1f48
-                 * target_to filter must be checked against the resource ndn that was stored in
ef1f48
-                 * aclpb->aclpb_curr_entry_sdn
ef1f48
-                 *
ef1f48
-                 * target_from filter must be check against the entry ndn that is in aclpb->aclpb_moddn_source_sdn
ef1f48
-                 * (sdn was stored in the pblock)
ef1f48
-                 */
ef1f48
+        /*
ef1f48
+         * We are evaluating the moddn permission.
ef1f48
+         * The aci contains target_to and target_from
ef1f48
+         *
ef1f48
+         * target_to filter must be checked against the resource ndn that was stored in
ef1f48
+         * aclpb->aclpb_curr_entry_sdn
ef1f48
+         *
ef1f48
+         * target_from filter must be check against the entry ndn that is in aclpb->aclpb_moddn_source_sdn
ef1f48
+         * (sdn was stored in the pblock)
ef1f48
+         */
ef1f48
         if (aci->target_to) {
ef1f48
             f = aci->target_to;
ef1f48
             dn_matched = ACL_TRUE;
ef1f48
 
ef1f48
             /* Now check if the filter is a simple or substring filter */
ef1f48
             if (aci->aci_type & ACI_TARGET_MODDN_TO_PATTERN) {
ef1f48
-                /* This is a filter with substring
ef1f48
-                     * e.g. ldap:///uid=*,cn=accounts,dc=example,dc=com
ef1f48
-                     */
ef1f48
+                /* This is a filter with substring e.g. ldap:///uid=*,cn=accounts,dc=example,dc=com */
ef1f48
                 slapi_log_err(SLAPI_LOG_ACL, plugin_name, "acl__resource_match_aci - moddn target_to substring: %s\n",
ef1f48
                               slapi_filter_to_string(f, logbuf, sizeof(logbuf)));
ef1f48
                 if ((rv = acl_match_substring(f, (char *)res_ndn, 0 /* match suffix */)) != ACL_TRUE) {
ef1f48
@@ -2204,9 +2202,7 @@ acl__resource_match_aci(Acl_PBlock *aclpb, aci_t *aci, int skip_attrEval, int *a
ef1f48
                     }
ef1f48
                 }
ef1f48
             } else {
ef1f48
-                /* This is a filter without substring
ef1f48
-                     * e.g. ldap:///cn=accounts,dc=example,dc=com
ef1f48
-                     */
ef1f48
+                /* This is a filter without substring  e.g. ldap:///cn=accounts,dc=example,dc=com */
ef1f48
                 slapi_log_err(SLAPI_LOG_ACL, plugin_name, "acl__resource_match_aci - moddn target_to: %s\n",
ef1f48
                               slapi_filter_to_string(f, logbuf, sizeof(logbuf)));
ef1f48
                 slapi_filter_get_ava(f, &avaType, &avaValue);
ef1f48
@@ -2230,8 +2226,8 @@ acl__resource_match_aci(Acl_PBlock *aclpb, aci_t *aci, int skip_attrEval, int *a
ef1f48
             /* Now check if the filter is a simple or substring filter */
ef1f48
             if (aci->aci_type & ACI_TARGET_MODDN_FROM_PATTERN) {
ef1f48
                 /* This is a filter with substring
ef1f48
-                         * e.g. ldap:///uid=*,cn=accounts,dc=example,dc=com
ef1f48
-                         */
ef1f48
+                 * e.g. ldap:///uid=*,cn=accounts,dc=example,dc=com
ef1f48
+                 */
ef1f48
                 slapi_log_err(SLAPI_LOG_ACL, plugin_name, "acl__resource_match_aci - moddn target_from substring: %s\n",
ef1f48
                               slapi_filter_to_string(f, logbuf, sizeof(logbuf)));
ef1f48
                 if ((rv = acl_match_substring(f, (char *)slapi_sdn_get_dn(aclpb->aclpb_moddn_source_sdn), 0 /* match suffix */)) != ACL_TRUE) {
ef1f48
@@ -2243,11 +2239,8 @@ acl__resource_match_aci(Acl_PBlock *aclpb, aci_t *aci, int skip_attrEval, int *a
ef1f48
                         goto acl__resource_match_aci_EXIT;
ef1f48
                     }
ef1f48
                 }
ef1f48
-
ef1f48
             } else {
ef1f48
-                /* This is a filter without substring
ef1f48
-                         * e.g. ldap:///cn=accounts,dc=example,dc=com
ef1f48
-                         */
ef1f48
+                /* This is a filter without substring  e.g. ldap:///cn=accounts,dc=example,dc=com */
ef1f48
                 slapi_log_err(SLAPI_LOG_ACL, plugin_name, "acl__resource_match_aci - moddn target_from: %s\n",
ef1f48
                               slapi_filter_to_string(f, logbuf, sizeof(logbuf)));
ef1f48
                 if (!slapi_dn_issuffix(slapi_sdn_get_dn(aclpb->aclpb_moddn_source_sdn), avaValue->bv_val)) {
ef1f48
@@ -2269,10 +2262,8 @@ acl__resource_match_aci(Acl_PBlock *aclpb, aci_t *aci, int skip_attrEval, int *a
ef1f48
     }
ef1f48
 
ef1f48
     if (aci->aci_type & ACI_TARGET_PATTERN) {
ef1f48
-
ef1f48
         f = aci->target;
ef1f48
         dn_matched = ACL_TRUE;
ef1f48
-
ef1f48
         if ((rv = acl_match_substring(f, (char *)res_ndn, 0 /* match suffux */)) != ACL_TRUE) {
ef1f48
             dn_matched = ACL_FALSE;
ef1f48
             if (rv == ACL_ERR) {
ef1f48
@@ -2296,7 +2287,7 @@ acl__resource_match_aci(Acl_PBlock *aclpb, aci_t *aci, int skip_attrEval, int *a
ef1f48
 
ef1f48
     /*
ef1f48
      * Is it a (target="ldap://cn=*,($dn),o=sun.com") kind of thing.
ef1f48
-    */
ef1f48
+     */
ef1f48
     if (aci->aci_type & ACI_TARGET_MACRO_DN) {
ef1f48
         /*
ef1f48
          * See if the ($dn) component matches the string and
ef1f48
@@ -2306,8 +2297,7 @@ acl__resource_match_aci(Acl_PBlock *aclpb, aci_t *aci, int skip_attrEval, int *a
ef1f48
          * entry is the same one don't recalculate it--
ef1f48
          * this flag only works for search right now, could
ef1f48
          * also optimise for mods by making it work for mods.
ef1f48
-        */
ef1f48
-
ef1f48
+         */
ef1f48
         if ((aclpb->aclpb_res_type & ACLPB_NEW_ENTRY) == 0) {
ef1f48
             /*
ef1f48
              * Here same entry so just look up the matched value,
ef1f48
@@ -2356,8 +2346,7 @@ acl__resource_match_aci(Acl_PBlock *aclpb, aci_t *aci, int skip_attrEval, int *a
ef1f48
                  * If there is already an entry for this aci in this
ef1f48
                  * aclpb then remove it--it's an old value for a
ef1f48
                  * different entry.
ef1f48
-                */
ef1f48
-
ef1f48
+                 */
ef1f48
                 acl_ht_add_and_freeOld(aclpb->aclpb_macro_ht,
ef1f48
                                        (PLHashNumber)aci->aci_index,
ef1f48
                                        matched_val);
ef1f48
@@ -2381,30 +2370,27 @@ acl__resource_match_aci(Acl_PBlock *aclpb, aci_t *aci, int skip_attrEval, int *a
ef1f48
     }
ef1f48
 
ef1f48
     /*
ef1f48
-    ** Here, if there's a targetfilter field, see if it matches.
ef1f48
-    **
ef1f48
-    ** The commented out code below was an erroneous attempt to skip
ef1f48
-    ** this test.  It is wrong because: 1. you need to store
ef1f48
-    ** whether the last test matched or not (you cannot just assume it did)
ef1f48
-    ** and 2. It may not be the same aci, so the previous matched
ef1f48
-    ** value is a function of the aci.
ef1f48
-    ** May be interesting to build such a cache...but no evidence for
ef1f48
-    ** for that right now. See Bug 383424.
ef1f48
-    **
ef1f48
-    **
ef1f48
-    **   && ((aclpb->aclpb_state & ACLPB_SEARCH_BASED_ON_LIST) ||
ef1f48
-    **    (aclpb->aclpb_res_type & ACLPB_NEW_ENTRY))
ef1f48
-    */
ef1f48
+     * Here, if there's a targetfilter field, see if it matches.
ef1f48
+     *
ef1f48
+     * The commented out code below was an erroneous attempt to skip
ef1f48
+     * this test.  It is wrong because: 1. you need to store
ef1f48
+     * whether the last test matched or not (you cannot just assume it did)
ef1f48
+     * and 2. It may not be the same aci, so the previous matched
ef1f48
+     * value is a function of the aci.
ef1f48
+     * May be interesting to build such a cache...but no evidence for
ef1f48
+     * for that right now. See Bug 383424.
ef1f48
+     *
ef1f48
+     *
ef1f48
+     *   && ((aclpb->aclpb_state & ACLPB_SEARCH_BASED_ON_LIST) ||
ef1f48
+     *    (aclpb->aclpb_res_type & ACLPB_NEW_ENTRY))
ef1f48
+     */
ef1f48
     if (aci->aci_type & ACI_TARGET_FILTER) {
ef1f48
         int filter_matched = ACL_TRUE;
ef1f48
-
ef1f48
         /*
ef1f48
          * Check for macros.
ef1f48
          * For targetfilter we need to fake the lasinfo structure--it's
ef1f48
          * created "naturally" for subjects but not targets.
ef1f48
-        */
ef1f48
-
ef1f48
-
ef1f48
+         */
ef1f48
         if (aci->aci_type & ACI_TARGET_FILTER_MACRO_DN) {
ef1f48
 
ef1f48
             lasInfo *lasinfo = NULL;
ef1f48
@@ -2419,11 +2405,9 @@ acl__resource_match_aci(Acl_PBlock *aclpb, aci_t *aci, int skip_attrEval, int *a
ef1f48
                                                     ACL_EVAL_TARGET_FILTER);
ef1f48
             slapi_ch_free((void **)&lasinfo);
ef1f48
         } else {
ef1f48
-
ef1f48
-
ef1f48
             if (slapi_vattr_filter_test(NULL, aclpb->aclpb_curr_entry,
ef1f48
                                         aci->targetFilter,
ef1f48
-                                        0 /*don't do acess chk*/) != 0) {
ef1f48
+                                        0 /*don't do access check*/) != 0) {
ef1f48
                 filter_matched = ACL_FALSE;
ef1f48
             }
ef1f48
         }
ef1f48
@@ -2450,7 +2434,7 @@ acl__resource_match_aci(Acl_PBlock *aclpb, aci_t *aci, int skip_attrEval, int *a
ef1f48
      * Check to see if we need to evaluate any targetattrfilters.
ef1f48
      * They look as follows:
ef1f48
      * (targetattrfilters="add=sn:(sn=rob) && gn:(gn!=byrne),
ef1f48
-     *                       del=sn:(sn=rob) && gn:(gn=byrne)")
ef1f48
+     *                     del=sn:(sn=rob) && gn:(gn=byrne)")
ef1f48
      *
ef1f48
      * For ADD/DELETE:
ef1f48
      * If theres's a targetattrfilter then each add/del filter
ef1f48
@@ -2458,29 +2442,25 @@ acl__resource_match_aci(Acl_PBlock *aclpb, aci_t *aci, int skip_attrEval, int *a
ef1f48
      * by each value of the attribute in the entry.
ef1f48
      *
ef1f48
      * For MODIFY:
ef1f48
-     *    If there's a targetattrfilter then the add/del filter
ef1f48
+     * If there's a targetattrfilter then the add/del filter
ef1f48
      * must be satisfied by the attribute to be added/deleted.
ef1f48
      * (MODIFY acl is evaluated one value at a time).
ef1f48
      *
ef1f48
      *
ef1f48
-    */
ef1f48
-
ef1f48
+     */
ef1f48
     if (((aclpb->aclpb_access & SLAPI_ACL_ADD) &&
ef1f48
          (aci->aci_type & ACI_TARGET_ATTR_ADD_FILTERS)) ||
ef1f48
         ((aclpb->aclpb_access & SLAPI_ACL_DELETE) &&
ef1f48
-         (aci->aci_type & ACI_TARGET_ATTR_DEL_FILTERS))) {
ef1f48
-
ef1f48
+         (aci->aci_type & ACI_TARGET_ATTR_DEL_FILTERS)))
ef1f48
+    {
ef1f48
         Targetattrfilter **attrFilterArray = NULL;
ef1f48
-
ef1f48
         Targetattrfilter *attrFilter = NULL;
ef1f48
-
ef1f48
         Slapi_Attr *attr_ptr = NULL;
ef1f48
         Slapi_Value *sval;
ef1f48
         const struct berval *attrVal;
ef1f48
         int k;
ef1f48
         int done;
ef1f48
 
ef1f48
-
ef1f48
         if ((aclpb->aclpb_access & SLAPI_ACL_ADD) &&
ef1f48
             (aci->aci_type & ACI_TARGET_ATTR_ADD_FILTERS)) {
ef1f48
 
ef1f48
@@ -2497,28 +2477,20 @@ acl__resource_match_aci(Acl_PBlock *aclpb, aci_t *aci, int skip_attrEval, int *a
ef1f48
 
ef1f48
         while (attrFilterArray && attrFilterArray[num_attrs] && attr_matched) {
ef1f48
             attrFilter = attrFilterArray[num_attrs];
ef1f48
-
ef1f48
             /*
ef1f48
-                 * If this filter applies to an attribute in the entry,
ef1f48
-                 * apply it to the entry.
ef1f48
-                 * Otherwise just ignore it.
ef1f48
-                 *
ef1f48
-                */
ef1f48
-
ef1f48
-            if (slapi_entry_attr_find(aclpb->aclpb_curr_entry,
ef1f48
-                                      attrFilter->attr_str,
ef1f48
-                                      &attr_ptr) == 0) {
ef1f48
-
ef1f48
+             * If this filter applies to an attribute in the entry,
ef1f48
+             * apply it to the entry.
ef1f48
+             * Otherwise just ignore it.
ef1f48
+             *
ef1f48
+             */
ef1f48
+            if (slapi_entry_attr_find(aclpb->aclpb_curr_entry, attrFilter->attr_str, &attr_ptr) == 0) {
ef1f48
                 /*
ef1f48
-                     * This is an applicable filter.
ef1f48
-                     *  The filter is to be appplied to the entry being added
ef1f48
-                     * or deleted.
ef1f48
-                     * The filter needs to be satisfied by _each_ occurence
ef1f48
-                     * of the attribute in the entry--otherwise you
ef1f48
-                     * could satisfy the filter and then put loads of other
ef1f48
-                     * values in on the back of it.
ef1f48
-                     */
ef1f48
-
ef1f48
+                 * This is an applicable filter.
ef1f48
+                 * The filter is to be applied to the entry being added or deleted.
ef1f48
+                 * The filter needs to be satisfied by _each_ occurrence of the
ef1f48
+                 * attribute in the entry--otherwise you could satisfy the filter
ef1f48
+                 * and then put loads of other values in on the back of it.
ef1f48
+                 */
ef1f48
                 sval = NULL;
ef1f48
                 attrVal = NULL;
ef1f48
                 k = slapi_attr_first_value(attr_ptr, &sval);
ef1f48
@@ -2528,12 +2500,11 @@ acl__resource_match_aci(Acl_PBlock *aclpb, aci_t *aci, int skip_attrEval, int *a
ef1f48
 
ef1f48
                     if (acl__make_filter_test_entry(&aclpb->aclpb_filter_test_entry,
ef1f48
                                                     attrFilter->attr_str,
ef1f48
-                                                    (struct berval *)attrVal) == LDAP_SUCCESS) {
ef1f48
-
ef1f48
+                                                    (struct berval *)attrVal) == LDAP_SUCCESS)
ef1f48
+                    {
ef1f48
                         attr_matched = acl__test_filter(aclpb->aclpb_filter_test_entry,
ef1f48
                                                         attrFilter->filter,
ef1f48
-                                                        1 /* Do filter sense evaluation below */
ef1f48
-                                                        );
ef1f48
+                                                        1 /* Do filter sense evaluation below */);
ef1f48
                         done = !attr_matched;
ef1f48
                         slapi_entry_free(aclpb->aclpb_filter_test_entry);
ef1f48
                     }
ef1f48
@@ -2542,19 +2513,19 @@ acl__resource_match_aci(Acl_PBlock *aclpb, aci_t *aci, int skip_attrEval, int *a
ef1f48
                 } /* while */
ef1f48
 
ef1f48
                 /*
ef1f48
-                     * Here, we applied an applicable filter to the entry.
ef1f48
-                     * So if attr_matched is ACL_TRUE then every value
ef1f48
-                     * of the attribute in the entry satisfied the filter.
ef1f48
-                     * Otherwise, attr_matched is ACL_FALSE and not every
ef1f48
-                     * value satisfied the filter, so we will teminate the
ef1f48
-                     * scan of the filter list.
ef1f48
-                     */
ef1f48
+                 * Here, we applied an applicable filter to the entry.
ef1f48
+                 * So if attr_matched is ACL_TRUE then every value
ef1f48
+                 * of the attribute in the entry satisfied the filter.
ef1f48
+                 * Otherwise, attr_matched is ACL_FALSE and not every
ef1f48
+                 * value satisfied the filter, so we will terminate the
ef1f48
+                 * scan of the filter list.
ef1f48
+                 */
ef1f48
             }
ef1f48
 
ef1f48
             num_attrs++;
ef1f48
         } /* while */
ef1f48
 
ef1f48
-/*
ef1f48
+        /*
ef1f48
          * Here, we've applied all the applicable filters to the entry.
ef1f48
          * Each one must have been satisfied by all the values of the attribute.
ef1f48
          * The result of this is stored in attr_matched.
ef1f48
@@ -2585,7 +2556,8 @@ acl__resource_match_aci(Acl_PBlock *aclpb, aci_t *aci, int skip_attrEval, int *a
ef1f48
     } else if (((aclpb->aclpb_access & ACLPB_SLAPI_ACL_WRITE_ADD) &&
ef1f48
                 (aci->aci_type & ACI_TARGET_ATTR_ADD_FILTERS)) ||
ef1f48
                ((aclpb->aclpb_access & ACLPB_SLAPI_ACL_WRITE_DEL) &&
ef1f48
-                (aci->aci_type & ACI_TARGET_ATTR_DEL_FILTERS))) {
ef1f48
+                (aci->aci_type & ACI_TARGET_ATTR_DEL_FILTERS)))
ef1f48
+    {
ef1f48
         /*
ef1f48
          * Here, it's a modify add/del and we have attr filters.
ef1f48
          * So, we need to scan the add/del filter list to find the filter
ef1f48
@@ -2629,11 +2601,10 @@ acl__resource_match_aci(Acl_PBlock *aclpb, aci_t *aci, int skip_attrEval, int *a
ef1f48
          * Otherwise, ignore the targetattrfilters.
ef1f48
          */
ef1f48
         if (found) {
ef1f48
-
ef1f48
             if (acl__make_filter_test_entry(&aclpb->aclpb_filter_test_entry,
ef1f48
                                             aclpb->aclpb_curr_attrEval->attrEval_name,
ef1f48
-                                            aclpb->aclpb_curr_attrVal) == LDAP_SUCCESS) {
ef1f48
-
ef1f48
+                                            aclpb->aclpb_curr_attrVal) == LDAP_SUCCESS)
ef1f48
+            {
ef1f48
                 attr_matched = acl__test_filter(aclpb->aclpb_filter_test_entry,
ef1f48
                                                 attrFilter->filter,
ef1f48
                                                 1 /* Do filter sense evaluation below */
ef1f48
@@ -2651,20 +2622,21 @@ acl__resource_match_aci(Acl_PBlock *aclpb, aci_t *aci, int skip_attrEval, int *a
ef1f48
              * Here this attribute appeared and was matched in a
ef1f48
              * targetattrfilters list, so record this fact so we do
ef1f48
              * not have to scan the targetattr list for the attribute.
ef1f48
-            */
ef1f48
+             */
ef1f48
 
ef1f48
             attr_matched_in_targetattrfilters = 1;
ef1f48
         }
ef1f48
     } /* targetvaluefilters */
ef1f48
 
ef1f48
 
ef1f48
-    /* There are 3 cases  by which acis are selected.
ef1f48
-    ** 1) By scanning the whole list and picking based on the resource.
ef1f48
-    ** 2) By picking a subset of the list which will be used for the whole
ef1f48
-    **    acl evaluation.
ef1f48
-    ** 3) A finer granularity, i.e, a selected list of acls which will be
ef1f48
-    ** used for only that entry's evaluation.
ef1f48
-    */
ef1f48
+    /*
ef1f48
+     * There are 3 cases  by which acis are selected.
ef1f48
+     * 1) By scanning the whole list and picking based on the resource.
ef1f48
+     * 2) By picking a subset of the list which will be used for the whole
ef1f48
+     *    acl evaluation.
ef1f48
+     * 3) A finer granularity, i.e, a selected list of acls which will be
ef1f48
+     * used for only that entry's evaluation.
ef1f48
+     */
ef1f48
     if (!(skip_attrEval) && (aclpb->aclpb_state & ACLPB_SEARCH_BASED_ON_ENTRY_LIST) &&
ef1f48
         (res_right & SLAPI_ACL_SEARCH) &&
ef1f48
         ((aci->aci_access & SLAPI_ACL_READ) || (aci->aci_access & SLAPI_ACL_SEARCH))) {
ef1f48
@@ -2680,7 +2652,6 @@ acl__resource_match_aci(Acl_PBlock *aclpb, aci_t *aci, int skip_attrEval, int *a
ef1f48
         }
ef1f48
     }
ef1f48
 
ef1f48
-
ef1f48
     /* If we are suppose to skip attr eval, then let's skip it */
ef1f48
     if ((aclpb->aclpb_access & SLAPI_ACL_SEARCH) && (!skip_attrEval) &&
ef1f48
         (aclpb->aclpb_res_type & ACLPB_NEW_ENTRY)) {
ef1f48
@@ -2697,9 +2668,10 @@ acl__resource_match_aci(Acl_PBlock *aclpb, aci_t *aci, int skip_attrEval, int *a
ef1f48
         goto acl__resource_match_aci_EXIT;
ef1f48
     }
ef1f48
 
ef1f48
-    /* We need to check again because we don't want to select this handle
ef1f48
-    ** if the right doesn't match for now.
ef1f48
-    */
ef1f48
+    /*
ef1f48
+     * We need to check again because we don't want to select this handle
ef1f48
+     * if the right doesn't match for now.
ef1f48
+     */
ef1f48
     if (!(aci_right & res_right)) {
ef1f48
         matches = ACL_FALSE;
ef1f48
         goto acl__resource_match_aci_EXIT;
ef1f48
@@ -2718,20 +2690,16 @@ acl__resource_match_aci(Acl_PBlock *aclpb, aci_t *aci, int skip_attrEval, int *a
ef1f48
      * rbyrneXXX if we had a proper permission for modrdn eg SLAPI_ACL_MODRDN
ef1f48
      * then we would not need this crappy way of telling it was a MODRDN
ef1f48
      * request ie. SLAPI_ACL_WRITE && !(c_attrEval).
ef1f48
-    */
ef1f48
-
ef1f48
+     */
ef1f48
     c_attrEval = aclpb->aclpb_curr_attrEval;
ef1f48
 
ef1f48
     /*
ef1f48
      * If we've already matched on targattrfilter then do not
ef1f48
      * bother to look at the attrlist.
ef1f48
-    */
ef1f48
-
ef1f48
+     */
ef1f48
     if (!attr_matched_in_targetattrfilters) {
ef1f48
-
ef1f48
         /* match target attr */
ef1f48
-        if ((c_attrEval) &&
ef1f48
-            (aci->aci_type & ACI_TARGET_ATTR)) {
ef1f48
+        if ((c_attrEval) && (aci->aci_type & ACI_TARGET_ATTR)) {
ef1f48
             /* there is a target ATTR */
ef1f48
             Targetattr **attrArray = aci->targetAttr;
ef1f48
             Targetattr *attr = NULL;
ef1f48
@@ -2773,46 +2741,43 @@ acl__resource_match_aci(Acl_PBlock *aclpb, aci_t *aci, int skip_attrEval, int *a
ef1f48
                 matches = (attr_matched ? ACL_TRUE : ACL_FALSE);
ef1f48
             }
ef1f48
 
ef1f48
-
ef1f48
             aclpb->aclpb_state &= ~ACLPB_ATTR_STAR_MATCHED;
ef1f48
             /* figure out how it matched, i.e star matched */
ef1f48
-            if (matches && star_matched && num_attrs == 1 &&
ef1f48
-                !(aclpb->aclpb_state & ACLPB_FOUND_ATTR_RULE))
ef1f48
+            if (matches && star_matched && num_attrs == 1 && !(aclpb->aclpb_state & ACLPB_FOUND_ATTR_RULE)) {
ef1f48
                 aclpb->aclpb_state |= ACLPB_ATTR_STAR_MATCHED;
ef1f48
-            else {
ef1f48
+            } else {
ef1f48
                 /* we are here means that there is a specific
ef1f48
-                ** attr in the rule for this resource.
ef1f48
-                ** We need to avoid this case
ef1f48
-                ** Rule 1: (targetattr = "uid")
ef1f48
-                ** Rule 2: (targetattr = "*")
ef1f48
-                ** we cannot use STAR optimization
ef1f48
-                */
ef1f48
+                 * attr in the rule for this resource.
ef1f48
+                 * We need to avoid this case
ef1f48
+                 * Rule 1: (targetattr = "uid")
ef1f48
+                 * Rule 2: (targetattr = "*")
ef1f48
+                 * we cannot use STAR optimization
ef1f48
+                 */
ef1f48
                 aclpb->aclpb_state |= ACLPB_FOUND_ATTR_RULE;
ef1f48
                 aclpb->aclpb_state &= ~ACLPB_ATTR_STAR_MATCHED;
ef1f48
             }
ef1f48
-        } else if ((c_attrEval) ||
ef1f48
-                   (aci->aci_type & ACI_TARGET_ATTR)) {
ef1f48
+        } else if ((c_attrEval) || (aci->aci_type & ACI_TARGET_ATTR)) {
ef1f48
             if ((aci_right & ACL_RIGHTS_TARGETATTR_NOT_NEEDED) &&
ef1f48
                 (aclpb->aclpb_access & ACL_RIGHTS_TARGETATTR_NOT_NEEDED)) {
ef1f48
                 /*
ef1f48
-            ** Targetattr rule doesn't  make any sense
ef1f48
-            ** in this case. So select this rule
ef1f48
-            ** default: matches = ACL_TRUE;
ef1f48
-            */
ef1f48
+                 * Targetattr rule doesn't make any sense
ef1f48
+                 * in this case. So select this rule
ef1f48
+                 * default: matches = ACL_TRUE;
ef1f48
+                 */
ef1f48
                 ;
ef1f48
-            } else if (aci_right & SLAPI_ACL_WRITE &&
ef1f48
+            } else if ((aci_right & SLAPI_ACL_WRITE) &&
ef1f48
                        (aci->aci_type & ACI_TARGET_ATTR) &&
ef1f48
                        !(c_attrEval) &&
ef1f48
                        (aci->aci_type & ACI_HAS_ALLOW_RULE)) {
ef1f48
                 /* We need to handle modrdn operation.  Modrdn doesn't
ef1f48
-            ** change any attrs but changes the RDN and so (attr=NULL).
ef1f48
-            ** Here we found an acl which has a targetattr but
ef1f48
-            ** the resource doesn't need one. In that case, we should
ef1f48
-            ** consider this acl.
ef1f48
-            ** the opposite is true if it is a deny rule, only a deny without
ef1f48
-            ** any targetattr should deny modrdn
ef1f48
-            ** default: matches = ACL_TRUE;
ef1f48
-            */
ef1f48
+                 * change any attrs but changes the RDN and so (attr=NULL).
ef1f48
+                 * Here we found an acl which has a targetattr but
ef1f48
+                 * the resource doesn't need one. In that case, we should
ef1f48
+                 * consider this acl.
ef1f48
+                 * the opposite is true if it is a deny rule, only a deny without
ef1f48
+                 * any targetattr should deny modrdn
ef1f48
+                 * default: matches = ACL_TRUE;
ef1f48
+                 */
ef1f48
                 ;
ef1f48
             } else {
ef1f48
                 matches = ACL_FALSE;
ef1f48
@@ -2821,16 +2786,16 @@ acl__resource_match_aci(Acl_PBlock *aclpb, aci_t *aci, int skip_attrEval, int *a
ef1f48
     } /* !attr_matched_in_targetattrfilters */
ef1f48
 
ef1f48
     /*
ef1f48
-    ** Here we are testing if we find a entry test rule (which should
ef1f48
-    ** be rare). In that case, just remember it. An entry test rule
ef1f48
-    ** doesn't have "(targetattr)".
ef1f48
-    */
ef1f48
+     * Here we are testing if we find a entry test rule (which should
ef1f48
+     * be rare). In that case, just remember it. An entry test rule
ef1f48
+     * doesn't have "(targetattr)".
ef1f48
+     */
ef1f48
     if ((aclpb->aclpb_state & ACLPB_EVALUATING_FIRST_ATTR) &&
ef1f48
         (!(aci->aci_type & ACI_TARGET_ATTR))) {
ef1f48
         aclpb->aclpb_state |= ACLPB_FOUND_A_ENTRY_TEST_RULE;
ef1f48
     }
ef1f48
 
ef1f48
-/*
ef1f48
+    /*
ef1f48
      * Generic exit point for this routine:
ef1f48
      * matches is ACL_TRUE if the aci matches the target of the resource,
ef1f48
      * ACL_FALSE othrewise.
ef1f48
@@ -2853,6 +2818,7 @@ acl__resource_match_aci_EXIT:
ef1f48
 
ef1f48
     return (matches);
ef1f48
 }
ef1f48
+
ef1f48
 /* Macro to determine if the cached result is valid or not. */
ef1f48
 #define ACL_CACHED_RESULT_VALID(result)          \
ef1f48
     (((result & ACLPB_CACHE_READ_RES_ALLOW) &&   \
ef1f48
diff --git a/ldap/servers/slapd/back-ldbm/findentry.c b/ldap/servers/slapd/back-ldbm/findentry.c
ef1f48
index 6e53a0aea..bff751c88 100644
ef1f48
--- a/ldap/servers/slapd/back-ldbm/findentry.c
ef1f48
+++ b/ldap/servers/slapd/back-ldbm/findentry.c
ef1f48
@@ -93,7 +93,6 @@ find_entry_internal_dn(
ef1f48
     size_t tries = 0;
ef1f48
     int isroot = 0;
ef1f48
     int op_type;
ef1f48
-    char *errbuf = NULL;
ef1f48
 
ef1f48
     /* get the managedsait ldap message control */
ef1f48
     slapi_pblock_get(pb, SLAPI_MANAGEDSAIT, &managedsait);
ef1f48
@@ -207,8 +206,8 @@ find_entry_internal_dn(
ef1f48
                     break;
ef1f48
                 }
ef1f48
                 if (acl_type > 0) {
ef1f48
-                    err = plugin_call_acl_plugin(pb, me->ep_entry, NULL, NULL, acl_type,
ef1f48
-                                                 ACLPLUGIN_ACCESS_DEFAULT, &errbuf);
ef1f48
+                    char *dummy_attr = "1.1";
ef1f48
+                    err = slapi_access_allowed(pb, me->ep_entry, dummy_attr, NULL, acl_type);
ef1f48
                 }
ef1f48
                 if (((acl_type > 0) && err) || (op_type == SLAPI_OPERATION_BIND)) {
ef1f48
                     /*
ef1f48
@@ -237,7 +236,6 @@ find_entry_internal_dn(
ef1f48
         CACHE_RETURN(&inst->inst_cache, &me);
ef1f48
     }
ef1f48
 
ef1f48
-    slapi_ch_free_string(&errbuf);
ef1f48
     slapi_log_err(SLAPI_LOG_TRACE, "find_entry_internal_dn", "<= Not found (%s)\n",
ef1f48
                   slapi_sdn_get_dn(sdn));
ef1f48
     return (NULL);
ef1f48
diff --git a/src/lib389/lib389/_mapped_object.py b/src/lib389/lib389/_mapped_object.py
ef1f48
index c60837601..ca6ea6ef8 100644
ef1f48
--- a/src/lib389/lib389/_mapped_object.py
ef1f48
+++ b/src/lib389/lib389/_mapped_object.py
ef1f48
@@ -1190,7 +1190,7 @@ class DSLdapObjects(DSLogging, DSLints):
ef1f48
         # Now actually commit the creation req
ef1f48
         return co.ensure_state(rdn, properties, self._basedn)
ef1f48
 
ef1f48
-    def filter(self, search, scope=None):
ef1f48
+    def filter(self, search, scope=None, strict=False):
ef1f48
         # This will yield and & filter for objectClass with as many terms as needed.
ef1f48
         if search:
ef1f48
             search_filter = _gen_and([self._get_objectclass_filter(), search])
ef1f48
@@ -1211,5 +1211,7 @@ class DSLdapObjects(DSLogging, DSLints):
ef1f48
             insts = [self._entry_to_instance(dn=r.dn, entry=r) for r in results]
ef1f48
         except ldap.NO_SUCH_OBJECT:
ef1f48
             # There are no objects to select from, se we return an empty array
ef1f48
+            if strict:
ef1f48
+                raise ldap.NO_SUCH_OBJECT
ef1f48
             insts = []
ef1f48
         return insts
ef1f48
-- 
ef1f48
2.26.2
ef1f48