74ca47
From abc9ff876209819c8f0dd7e799f1ab6a1b084fe5 Mon Sep 17 00:00:00 2001
b7d5c1
From: Mark Reynolds <mreynolds@redhat.com>
b7d5c1
Date: Mon, 20 Mar 2017 15:08:45 -0400
b7d5c1
Subject: [PATCH] Issue 49095 - targetattr wildcard evaluation is incorrectly
b7d5c1
 case sensitive
b7d5c1
b7d5c1
Description:  When processing an aci that uses a wildcard targetattr, the
b7d5c1
              comparision should be done using case insensitive functions.
b7d5c1
b7d5c1
https://pagure.io/389-ds-base/issue/49095
b7d5c1
b7d5c1
Reviewed by: firstyear(Thanks!)
b7d5c1
---
b7d5c1
 dirsrvtests/tests/tickets/ticket49095_test.py | 85 +++++++++++++++++++++++++++
b7d5c1
 ldap/servers/plugins/acl/acl.c                | 10 ++--
b7d5c1
 2 files changed, 90 insertions(+), 5 deletions(-)
b7d5c1
 create mode 100644 dirsrvtests/tests/tickets/ticket49095_test.py
b7d5c1
b7d5c1
diff --git a/dirsrvtests/tests/tickets/ticket49095_test.py b/dirsrvtests/tests/tickets/ticket49095_test.py
b7d5c1
new file mode 100644
b7d5c1
index 0000000..04f92b2
b7d5c1
--- /dev/null
b7d5c1
+++ b/dirsrvtests/tests/tickets/ticket49095_test.py
b7d5c1
@@ -0,0 +1,85 @@
b7d5c1
+import time
b7d5c1
+import ldap
b7d5c1
+import logging
b7d5c1
+import pytest
b7d5c1
+from lib389 import DirSrv, Entry, tools, tasks
b7d5c1
+from lib389.tools import DirSrvTools
b7d5c1
+from lib389._constants import *
b7d5c1
+from lib389.properties import *
b7d5c1
+from lib389.tasks import *
b7d5c1
+from lib389.utils import *
b7d5c1
+from lib389.topologies import topology_st as topo
b7d5c1
+
b7d5c1
+DEBUGGING = os.getenv("DEBUGGING", default=False)
b7d5c1
+if DEBUGGING:
b7d5c1
+    logging.getLogger(__name__).setLevel(logging.DEBUG)
b7d5c1
+else:
b7d5c1
+    logging.getLogger(__name__).setLevel(logging.INFO)
b7d5c1
+log = logging.getLogger(__name__)
b7d5c1
+
b7d5c1
+USER_DN = 'uid=testuser,dc=example,dc=com'
b7d5c1
+acis = ['(targetattr != "tele*") (version 3.0;acl "test case";allow (read,compare,search)(userdn = "ldap:///anyone");)',
b7d5c1
+        '(targetattr != "TELE*") (version 3.0;acl "test case";allow (read,compare,search)(userdn = "ldap:///anyone");)',
b7d5c1
+        '(targetattr != "telephonenum*") (version 3.0;acl "test case";allow (read,compare,search)(userdn = "ldap:///anyone");)',
b7d5c1
+        '(targetattr != "TELEPHONENUM*") (version 3.0;acl "test case";allow (read,compare,search)(userdn = "ldap:///anyone");)']
b7d5c1
+
b7d5c1
+
b7d5c1
+def test_ticket49095(topo):
b7d5c1
+    """Check that target attrbiutes with wildcards are case insensitive
b7d5c1
+    """
b7d5c1
+
b7d5c1
+    # Add an entry
b7d5c1
+    try:
b7d5c1
+        topo.standalone.add_s(Entry((USER_DN, {
b7d5c1
+            'objectclass': 'top extensibleObject'.split(),
b7d5c1
+            'uid': 'testuser',
b7d5c1
+            'telephonenumber': '555-555-5555'
b7d5c1
+        })))
b7d5c1
+    except ldap.LDAPError as e:
b7d5c1
+            log.fatal('Failed to add test user: ' + e.message['desc'])
b7d5c1
+            assert False
b7d5c1
+
b7d5c1
+    for aci in acis:
b7d5c1
+        # Add ACI
b7d5c1
+        try:
b7d5c1
+            topo.standalone.modify_s(DEFAULT_SUFFIX,
b7d5c1
+                          [(ldap.MOD_REPLACE, 'aci', aci)])
b7d5c1
+
b7d5c1
+        except ldap.LDAPError as e:
b7d5c1
+            log.fatal('Failed to set aci: ' + aci + ': ' + e.message['desc'])
b7d5c1
+            assert False
b7d5c1
+
b7d5c1
+        # Set Anonymous Bind to test aci
b7d5c1
+        try:
b7d5c1
+            topo.standalone.simple_bind_s("", "")
b7d5c1
+        except ldap.LDAPError as e:
b7d5c1
+            log.fatal('Failed to bind anonymously: ' + e.message['desc'])
b7d5c1
+            assert False
b7d5c1
+
b7d5c1
+        # Search for entry - should not get any results
b7d5c1
+        try:
b7d5c1
+            entry = topo.standalone.search_s(DEFAULT_SUFFIX, ldap.SCOPE_BASE,
b7d5c1
+                                             'telephonenumber=*')
b7d5c1
+            if entry:
b7d5c1
+                log.fatal('The entry was incorrectly returned')
b7d5c1
+                assert False
b7d5c1
+        except ldap.LDAPError as e:
b7d5c1
+            log.fatal('Failed to search anonymously: ' + e.message['desc'])
b7d5c1
+            assert False
b7d5c1
+
b7d5c1
+        # Set root DN Bind so we can update aci's
b7d5c1
+        try:
b7d5c1
+            topo.standalone.simple_bind_s(DN_DM, PASSWORD)
b7d5c1
+        except ldap.LDAPError as e:
b7d5c1
+            log.fatal('Failed to bind anonymously: ' + e.message['desc'])
b7d5c1
+            assert False
b7d5c1
+
b7d5c1
+    log.info("Test Passed")
b7d5c1
+
b7d5c1
+
b7d5c1
+if __name__ == '__main__':
b7d5c1
+    # Run isolated
b7d5c1
+    # -s for DEBUG mode
b7d5c1
+    CURRENT_FILE = os.path.realpath(__file__)
b7d5c1
+    pytest.main("-s %s" % CURRENT_FILE)
b7d5c1
+
b7d5c1
diff --git a/ldap/servers/plugins/acl/acl.c b/ldap/servers/plugins/acl/acl.c
74ca47
index 0a93808..48b8efc 100644
b7d5c1
--- a/ldap/servers/plugins/acl/acl.c
b7d5c1
+++ b/ldap/servers/plugins/acl/acl.c
b7d5c1
@@ -3407,19 +3407,19 @@ acl_match_substring ( Slapi_Filter *f, char *str, int exact_match)
b7d5c1
 	}
b7d5c1
 
b7d5c1
 	/* this assumes that str and the filter components are already
b7d5c1
-	 * normalized. If not, it shoul be done
b7d5c1
+	 * normalized. If not, it should be done
b7d5c1
 	 */
b7d5c1
 	if ( initial != NULL) {
b7d5c1
 		len = strlen(initial);
b7d5c1
 		if (exact_match) {
b7d5c1
-			int rc = strncmp(p, initial, len);
b7d5c1
+			int rc = strncasecmp(p, initial, len);
b7d5c1
 			if (rc) {
b7d5c1
 				return ACL_FALSE;
b7d5c1
 			} else {
b7d5c1
 				p += len;
b7d5c1
 			}  
b7d5c1
 		} else {
b7d5c1
-			p = strstr(p, initial);
b7d5c1
+			p = strcasestr(p, initial);
b7d5c1
 			if (p) {
b7d5c1
 				p += len;
b7d5c1
 			} else {
b7d5c1
@@ -3430,7 +3430,7 @@ acl_match_substring ( Slapi_Filter *f, char *str, int exact_match)
b7d5c1
 
b7d5c1
 	if ( any != NULL) {
b7d5c1
 		for (i = 0;  any && any[i] != NULL; i++) {
b7d5c1
-			p = strstr(p, any[i]);
b7d5c1
+			p = strcasestr(p, any[i]);
b7d5c1
 			if (p) {
b7d5c1
 				p += strlen(any[i]);
b7d5c1
 			} else {
b7d5c1
@@ -3444,7 +3444,7 @@ acl_match_substring ( Slapi_Filter *f, char *str, int exact_match)
b7d5c1
 		len = strlen(final);
b7d5c1
 		tlen = strlen(p);
b7d5c1
 		if (len > tlen) return ACL_FALSE;
b7d5c1
-		if (strcmp(p+tlen-len, final)) return ACL_FALSE;
b7d5c1
+		if (strcasecmp(p+tlen-len, final)) return ACL_FALSE;
b7d5c1
 	}
b7d5c1
 
b7d5c1
 	return ACL_TRUE;
b7d5c1
-- 
b7d5c1
2.9.3
b7d5c1