[SCM] Samba Shared Repository - branch master updated

Stefan Metzmacher metze at samba.org
Wed Oct 21 08:49:03 UTC 2020


The branch, master has been updated
       via  7223f6453b1 s4:dsdb:acl_read: Implement "List Object" mode feature
       via  ffc0bdc6d49 s4:dsdb:util: add dsdb_do_list_object() helper
       via  e1529bedb2b s4:dsdb:acl_read: defer LDB_ERR_NO_SUCH_OBJECT
       via  faff8e6c897 s4:dsdb:acl_read: make use of aclread_check_object_visible() for the search base
       via  c4a3028de72 s4:dsdb:acl_read: fully set up 'struct aclread_context' before the search base acl check
       via  d2dd7c2a5c1 s4:dsdb:acl_read: introduce aclread_check_object_visible() helper
       via  06d13440673 s4:dsdb:tests: add AclVisibiltyTests
       via  80347deb544 python/tests: add DynamicTestCase setUpDynamicTestCases() infrastructure
      from  6aa396b0cd1 ctdb-common: Avoid aliasing errors during code optimization

https://git.samba.org/?p=samba.git;a=shortlog;h=master


- Log -----------------------------------------------------------------
commit 7223f6453b1b38c933c9480c637ffd06d9f39b97
Author: Stefan Metzmacher <metze at samba.org>
Date:   Tue Oct 13 12:43:39 2020 +0200

    s4:dsdb:acl_read: Implement "List Object" mode feature
    
    See [MS-ADTS] 5.1.3.3.6 Checking Object Visibility
    
    I tried to avoid any possible overhead for the common cases:
    
    - SEC_ADS_LIST (List Children) is already granted by default
    - fDoListObject is off by default
    
    Overhead is only added if the administrator turned on
    the fDoListObject feature and removed SEC_ADS_LIST (List Children)
    from a parent object.
    
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=14531
    
    Signed-off-by: Stefan Metzmacher <metze at samba.org>
    Reviewed-by: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>
    
    Autobuild-User(master): Stefan Metzmacher <metze at samba.org>
    Autobuild-Date(master): Wed Oct 21 08:48:02 UTC 2020 on sn-devel-184

commit ffc0bdc6d49e88da1ee408956365da163ff3e1b2
Author: Stefan Metzmacher <metze at samba.org>
Date:   Tue Oct 6 11:21:34 2020 +0200

    s4:dsdb:util: add dsdb_do_list_object() helper
    
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=14531
    
    Signed-off-by: Stefan Metzmacher <metze at samba.org>
    Reviewed-by: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>

commit e1529bedb2b6c8553e69a42537ac0cffd03af6d6
Author: Stefan Metzmacher <metze at samba.org>
Date:   Mon Oct 12 17:59:34 2020 +0200

    s4:dsdb:acl_read: defer LDB_ERR_NO_SUCH_OBJECT
    
    We may need to return child objects even if the base dn
    is invisible.
    
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=14531
    
    Signed-off-by: Stefan Metzmacher <metze at samba.org>
    Reviewed-by: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>

commit faff8e6c89777c38443e561235073c336cfb2e9c
Author: Stefan Metzmacher <metze at samba.org>
Date:   Tue Oct 6 15:10:33 2020 +0200

    s4:dsdb:acl_read: make use of aclread_check_object_visible() for the search base
    
    We should only have one place to do access checks.
    
    Use 'git show -w' to see the minimal diff.
    
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=14531
    
    Signed-off-by: Stefan Metzmacher <metze at samba.org>
    Reviewed-by: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>

commit c4a3028de726d6708f57d02f9162a4d62d1b6ae7
Author: Stefan Metzmacher <metze at samba.org>
Date:   Tue Oct 6 15:10:33 2020 +0200

    s4:dsdb:acl_read: fully set up 'struct aclread_context' before the search base acl check
    
    This makes further change much easier.
    
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=14531
    
    Signed-off-by: Stefan Metzmacher <metze at samba.org>
    Reviewed-by: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>

commit d2dd7c2a5c1f8ee30f0f3b41f933d082b0c75f7c
Author: Stefan Metzmacher <metze at samba.org>
Date:   Tue Oct 6 15:07:19 2020 +0200

    s4:dsdb:acl_read: introduce aclread_check_object_visible() helper
    
    In future this will do more than aclread_check_parent(),
    if we implement fDoListObject and SEC_ADS_LIST_OBJECT handling.
    
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=14531
    
    Signed-off-by: Stefan Metzmacher <metze at samba.org>
    Reviewed-by: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>

commit 06d134406739e76b97273db3023855150dbaebbc
Author: Stefan Metzmacher <metze at samba.org>
Date:   Wed Oct 7 13:21:06 2020 +0200

    s4:dsdb:tests: add AclVisibiltyTests
    
    This tests a sorts of combinations in order to
    demonstrate the visibility of objects depending on:
    
    - with or without fDoListObject
    - with or without explicit DENY ACEs
    - A hierachy of objects with 4 levels from the base dn
    - SEC_ADS_LIST (List Children)
    - SEC_ADS_LIST_LIST_OBJECT (List Object)
    - SEC_ADS_READ_PROP
    - all possible scopes and basedns
    
    This demonstrates that NO_SUCH_OBJECT doesn't depend purely
    on the visibility of the base dn, it's still possible to
    get children returned und an invisible base dn.
    
    It also demonstrates the additional behavior with "List Object" mode.
    See [MS-ADTS] 5.1.3.3.6 Checking Object Visibility
    
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=14531
    
    Signed-off-by: Stefan Metzmacher <metze at samba.org>
    Reviewed-by: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>

commit 80347deb544b38be6c6814e5d1b82e48ebe83fd1
Author: Stefan Metzmacher <metze at samba.org>
Date:   Mon Apr 20 20:00:51 2020 +0200

    python/tests: add DynamicTestCase setUpDynamicTestCases() infrastructure
    
    This can be used in order to run a sepcific test (coded just once)
    with an autogenerated set of arguments.
    
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=14531
    
    Pair-Programmed-With: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>
    
    Signed-off-by: Stefan Metzmacher <metze at samba.org>
    Signed-off-by: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>

-----------------------------------------------------------------------

Summary of changes:
 python/samba/tests/__init__.py            |  27 +++
 source4/dsdb/samdb/ldb_modules/acl_read.c | 185 +++++++++++++----
 source4/dsdb/samdb/ldb_modules/util.c     |  21 ++
 source4/dsdb/tests/python/acl.py          | 321 +++++++++++++++++++++++++++++-
 source4/selftest/tests.py                 |   2 +-
 5 files changed, 514 insertions(+), 42 deletions(-)


Changeset truncated at 500 lines:

diff --git a/python/samba/tests/__init__.py b/python/samba/tests/__init__.py
index 7f7e68d961c..a5a8acdcc41 100644
--- a/python/samba/tests/__init__.py
+++ b/python/samba/tests/__init__.py
@@ -61,10 +61,37 @@ BINDIR = os.path.abspath(os.path.join(os.path.dirname(__file__),
 
 HEXDUMP_FILTER = bytearray([x if ((len(repr(chr(x))) == 3) and (x < 127)) else ord('.') for x in range(256)])
 
+def DynamicTestCase(cls):
+    cls.setUpDynamicTestCases()
+    return cls
 
 class TestCase(unittest.TestCase):
     """A Samba test case."""
 
+    @classmethod
+    def generate_dynamic_test(cls, fnname, suffix, *args):
+        """
+        fnname is something like "test_dynamic_sum"
+        suffix is something like "1plus2"
+        argstr could be (1, 2)
+
+        This would generate a test case called
+        "test_dynamic_sum_1plus2(self)" that
+        calls
+        self._test_dynamic_sum_with_args(1, 2)
+        """
+        def fn(self):
+            getattr(self, "_%s_with_args" % fnname)(*args)
+        setattr(cls, "%s_%s" % (fnname, suffix), fn)
+
+    @classmethod
+    def setUpDynamicTestCases(cls):
+        """This can be implemented in order to call cls.generate_dynamic_test()
+        In order to implement autogenerated testcase permutations.
+        """
+        msg = "%s needs setUpDynamicTestCases() if @DynamicTestCase is used!" % (cls)
+        raise Exception(msg)
+
     def setUp(self):
         super(TestCase, self).setUp()
         test_debug_level = os.getenv("TEST_DEBUG_LEVEL")
diff --git a/source4/dsdb/samdb/ldb_modules/acl_read.c b/source4/dsdb/samdb/ldb_modules/acl_read.c
index 7249a1a6c11..b221dcde445 100644
--- a/source4/dsdb/samdb/ldb_modules/acl_read.c
+++ b/source4/dsdb/samdb/ldb_modules/acl_read.c
@@ -52,6 +52,11 @@ struct aclread_context {
 	bool added_objectClass;
 	bool indirsync;
 
+	bool do_list_object_initialized;
+	bool do_list_object;
+	bool base_invisible;
+	uint64_t num_entries;
+
 	/* cache on the last parent we checked in this search */
 	struct ldb_dn *last_parent_dn;
 	int last_parent_check_ret;
@@ -154,6 +159,100 @@ static int aclread_check_parent(struct aclread_context *ac,
 	return ret;
 }
 
+static int aclread_check_object_visible(struct aclread_context *ac,
+					struct ldb_message *msg,
+					struct ldb_request *req)
+{
+	uint32_t instanceType;
+	int ret;
+
+	/* get the object instance type */
+	instanceType = ldb_msg_find_attr_as_uint(msg,
+						 "instanceType", 0);
+	if (instanceType & INSTANCE_TYPE_IS_NC_HEAD) {
+		/*
+		 * NC_HEAD objects are always visible
+		 */
+		return LDB_SUCCESS;
+	}
+
+	ret = aclread_check_parent(ac, msg, req);
+	if (ret == LDB_SUCCESS) {
+		/*
+		 * SEC_ADS_LIST (List Children) alone
+		 * on the parent is enough to make the
+		 * object visible.
+		 */
+		return LDB_SUCCESS;
+	}
+	if (ret != LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS) {
+		return ret;
+	}
+
+	if (!ac->do_list_object_initialized) {
+		/*
+		 * We only call dsdb_do_list_object() once
+		 * and only when needed in order to
+		 * check the dSHeuristics for fDoListObject.
+		 */
+		ac->do_list_object = dsdb_do_list_object(ac->module, ac, req);
+		ac->do_list_object_initialized = true;
+	}
+
+	if (ac->do_list_object) {
+		TALLOC_CTX *frame = talloc_stackframe();
+		struct ldb_dn *parent_dn = NULL;
+
+		/*
+		 * Here we're in "List Object" mode (fDoListObject=true).
+		 *
+		 * If SEC_ADS_LIST (List Children) is not
+		 * granted on the parent, we need to check if
+		 * SEC_ADS_LIST_OBJECT (List Object) is granted
+		 * on the parent and also on the object itself.
+		 *
+		 * We could optimize this similar to aclread_check_parent(),
+		 * but that would require quite a bit of restructuring,
+		 * so that we cache the granted access bits instead
+		 * of just the result for 'SEC_ADS_LIST (List Children)'.
+		 *
+		 * But as this is the uncommon case and
+		 * 'SEC_ADS_LIST (List Children)' is most likely granted
+		 * on most of the objects, we'll just implement what
+		 * we have to.
+		 */
+
+		parent_dn = ldb_dn_get_parent(frame, msg->dn);
+		if (parent_dn == NULL) {
+			TALLOC_FREE(frame);
+			return ldb_oom(ldb_module_get_ctx(ac->module));
+		}
+		ret = dsdb_module_check_access_on_dn(ac->module,
+						     frame,
+						     parent_dn,
+						     SEC_ADS_LIST_OBJECT,
+						     NULL, req);
+		if (ret != LDB_SUCCESS) {
+			TALLOC_FREE(frame);
+			return ret;
+		}
+		ret = dsdb_module_check_access_on_dn(ac->module,
+						     frame,
+						     msg->dn,
+						     SEC_ADS_LIST_OBJECT,
+						     NULL, req);
+		if (ret != LDB_SUCCESS) {
+			TALLOC_FREE(frame);
+			return ret;
+		}
+
+		TALLOC_FREE(frame);
+		return LDB_SUCCESS;
+	}
+
+	return LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS;
+}
+
 /*
  * The sd returned from this function is valid until the next call on
  * this module context
@@ -466,7 +565,6 @@ static int aclread_callback(struct ldb_request *req, struct ldb_reply *ares)
 	struct security_descriptor *sd = NULL;
 	struct dom_sid *sid = NULL;
 	TALLOC_CTX *tmp_ctx;
-	uint32_t instanceType;
 	const struct dsdb_class *objectclass;
 	bool suppress_result = false;
 
@@ -509,14 +607,12 @@ static int aclread_callback(struct ldb_request *req, struct ldb_reply *ares)
 		}
 
 		sid = samdb_result_dom_sid(tmp_ctx, msg, "objectSid");
-		/* get the object instance type */
-		instanceType = ldb_msg_find_attr_as_uint(msg,
-							 "instanceType", 0);
-		if (!ldb_dn_is_null(msg->dn) && !(instanceType & INSTANCE_TYPE_IS_NC_HEAD))
-		{
-			/* the object has a parent, so we have to check for visibility */
-			ret = aclread_check_parent(ac, msg, req);
-			
+		if (!ldb_dn_is_null(msg->dn)) {
+			/*
+			 * this is a real object, so we have
+			 * to check for visibility
+			 */
+			ret = aclread_check_object_visible(ac, msg, req);
 			if (ret == LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS) {
 				talloc_free(tmp_ctx);
 				return LDB_SUCCESS;
@@ -697,10 +793,21 @@ static int aclread_callback(struct ldb_request *req, struct ldb_reply *ares)
 		}
 		talloc_free(tmp_ctx);
 
+		ac->num_entries++;
 		return ldb_module_send_entry(ac->req, ret_msg, ares->controls);
 	case LDB_REPLY_REFERRAL:
 		return ldb_module_send_referral(ac->req, ares->referral);
 	case LDB_REPLY_DONE:
+		if (ac->base_invisible && ac->num_entries == 0) {
+			/*
+			 * If the base is invisible and we didn't
+			 * returned any object, we need to return
+			 * NO_SUCH_OBJECT.
+			 */
+			return ldb_module_done(ac->req,
+					       NULL, NULL,
+					       LDB_ERR_NO_SUCH_OBJECT);
+		}
 		return ldb_module_done(ac->req, ares->controls,
 					ares->response, LDB_SUCCESS);
 
@@ -728,7 +835,6 @@ static int aclread_search(struct ldb_module *module, struct ldb_request *req)
 	static const char * const _all_attrs[] = { "*", NULL };
 	bool all_attrs = false;
 	const char * const *attrs = NULL;
-	uint32_t instanceType;
 	static const char *acl_attrs[] = {
 		"instanceType",
 		NULL
@@ -749,36 +855,6 @@ static int aclread_search(struct ldb_module *module, struct ldb_request *req)
 		return ldb_next_request(module, req);
 	}
 
-	/* check accessibility of base */
-	if (!ldb_dn_is_null(req->op.search.base)) {
-		ret = dsdb_module_search_dn(module, req, &res, req->op.search.base,
-					    acl_attrs,
-					    DSDB_FLAG_NEXT_MODULE |
-					    DSDB_FLAG_AS_SYSTEM |
-					    DSDB_SEARCH_SHOW_RECYCLED,
-					    req);
-		if (ret != LDB_SUCCESS) {
-			return ldb_error(ldb, ret,
-					"acl_read: Error retrieving instanceType for base.");
-		}
-		instanceType = ldb_msg_find_attr_as_uint(res->msgs[0],
-							"instanceType", 0);
-		if (instanceType != 0 && !(instanceType & INSTANCE_TYPE_IS_NC_HEAD))
-		{
-			/* the object has a parent, so we have to check for visibility */
-			struct ldb_dn *parent_dn = ldb_dn_get_parent(req, req->op.search.base);
-			ret = dsdb_module_check_access_on_dn(module,
-							     req,
-							     parent_dn,
-							     SEC_ADS_LIST,
-							     NULL, req);
-			if (ret == LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS) {
-				return ldb_module_done(req, NULL, NULL, LDB_ERR_NO_SUCH_OBJECT);
-			} else if (ret != LDB_SUCCESS) {
-				return ldb_module_done(req, NULL, NULL, ret);
-			}
-		}
-	}
 	ac = talloc_zero(req, struct aclread_context);
 	if (ac == NULL) {
 		return ldb_oom(ldb);
@@ -851,6 +927,35 @@ static int aclread_search(struct ldb_module *module, struct ldb_request *req)
 	}
 
 	ac->attrs = req->op.search.attrs;
+
+	/* check accessibility of base */
+	if (!ldb_dn_is_null(req->op.search.base)) {
+		ret = dsdb_module_search_dn(module, req, &res, req->op.search.base,
+					    acl_attrs,
+					    DSDB_FLAG_NEXT_MODULE |
+					    DSDB_FLAG_AS_SYSTEM |
+					    DSDB_SEARCH_SHOW_RECYCLED,
+					    req);
+		if (ret != LDB_SUCCESS) {
+			return ldb_error(ldb, ret,
+					"acl_read: Error retrieving instanceType for base.");
+		}
+		ret = aclread_check_object_visible(ac, res->msgs[0], req);
+		if (ret == LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS) {
+			if (req->op.search.scope == LDB_SCOPE_BASE) {
+				return ldb_module_done(req, NULL, NULL,
+						       LDB_ERR_NO_SUCH_OBJECT);
+			}
+			/*
+			 * Defer LDB_ERR_NO_SUCH_OBJECT,
+			 * we may return sub objects
+			 */
+			ac->base_invisible = true;
+		} else if (ret != LDB_SUCCESS) {
+			return ldb_module_done(req, NULL, NULL, ret);
+		}
+	}
+
 	ret = ldb_build_search_req_ex(&down_req,
 				      ldb, ac,
 				      req->op.search.base,
diff --git a/source4/dsdb/samdb/ldb_modules/util.c b/source4/dsdb/samdb/ldb_modules/util.c
index 8bc17030500..0e8b72233f4 100644
--- a/source4/dsdb/samdb/ldb_modules/util.c
+++ b/source4/dsdb/samdb/ldb_modules/util.c
@@ -1412,6 +1412,27 @@ bool dsdb_user_password_support(struct ldb_module *module,
 	return result;
 }
 
+bool dsdb_do_list_object(struct ldb_module *module,
+			 TALLOC_CTX *mem_ctx,
+			 struct ldb_request *parent)
+{
+	TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
+	bool result;
+	const struct ldb_val *hr_val = dsdb_module_find_dsheuristics(module,
+								     tmp_ctx,
+								     parent);
+	if (hr_val == NULL || hr_val->length < DS_HR_DOLISTOBJECT) {
+		result = false;
+	} else if (hr_val->data[DS_HR_DOLISTOBJECT -1] == '1') {
+		result = true;
+	} else {
+		result = false;
+	}
+
+	talloc_free(tmp_ctx);
+	return result;
+}
+
 /*
   show the chain of requests, useful for debugging async requests
  */
diff --git a/source4/dsdb/tests/python/acl.py b/source4/dsdb/tests/python/acl.py
index 33810ac6895..a859196ee94 100755
--- a/source4/dsdb/tests/python/acl.py
+++ b/source4/dsdb/tests/python/acl.py
@@ -10,6 +10,7 @@ import re
 sys.path.insert(0, "bin/python")
 import samba
 
+from samba.tests import DynamicTestCase
 from samba.tests.subunitrun import SubunitOptions, TestProgram
 from samba.common import get_string
 
@@ -17,7 +18,7 @@ import samba.getopt as options
 from samba.join import DCJoinContext
 
 from ldb import (
-    SCOPE_BASE, SCOPE_SUBTREE, LdbError, ERR_NO_SUCH_OBJECT,
+    SCOPE_BASE, SCOPE_ONELEVEL, SCOPE_SUBTREE, LdbError, ERR_NO_SUCH_OBJECT,
     ERR_UNWILLING_TO_PERFORM, ERR_INSUFFICIENT_ACCESS_RIGHTS)
 from ldb import ERR_CONSTRAINT_VIOLATION
 from ldb import ERR_OPERATIONS_ERROR
@@ -2189,6 +2190,324 @@ class AclSPNTests(AclTests):
     def test_spn_rodc(self):
         self.dc_spn_test(self.rodcctx)
 
+# tests SEC_ADS_LIST vs. SEC_ADS_LIST_OBJECT
+ at DynamicTestCase
+class AclVisibiltyTests(AclTests):
+
+    envs = {
+        "No": False,
+        "Do": True,
+    }
+    modes = {
+        "Allow": False,
+        "Deny": True,
+    }
+    perms = {
+        "nn": 0,
+        "Cn": security.SEC_ADS_LIST,
+        "nO": security.SEC_ADS_LIST_OBJECT,
+        "CO": security.SEC_ADS_LIST | security.SEC_ADS_LIST_OBJECT,
+    }
+
+    @classmethod
+    def setUpDynamicTestCases(cls):
+        for le in cls.envs.keys():
+            for lm in cls.modes.keys():
+                for l1 in cls.perms.keys():
+                    for l2 in cls.perms.keys():
+                        for l3 in cls.perms.keys():
+                            tname = "%s_%s_%s_%s_%s" % (le, lm, l1, l2, l3)
+                            ve = cls.envs[le]
+                            vm = cls.modes[lm]
+                            v1 = cls.perms[l1]
+                            v2 = cls.perms[l2]
+                            v3 = cls.perms[l3]
+                            targs = (tname, ve, vm, v1, v2, v3)
+                            cls.generate_dynamic_test("test_visibility",
+                                                      tname, *targs)
+        return
+
+    def setUp(self):
+        super(AclVisibiltyTests, self).setUp()
+
+        strict_checking = samba.tests.env_get_var_value('STRICT_CHECKING', allow_missing=True)
+        if strict_checking is None:
+            strict_checking = '1'
+        self.strict_checking = bool(int(strict_checking))
+
+        # Get the old "dSHeuristics" if it was set
+        self.dsheuristics = self.ldb_admin.get_dsheuristics()
+        # Reset the "dSHeuristics" as they were before
+        self.addCleanup(self.ldb_admin.set_dsheuristics, self.dsheuristics)
+
+        # Domain Admins and SYSTEM get full access
+        self.sddl_dacl = "D:PAI(A;;RPWPCRCCDCLCLORCWOWDSDDTSW;;;DA)(A;;RPWPCRCCDCLCLORCWOWDSDDTSW;;;SY)"
+        self.set_dacl_control = ["sd_flags:1:%d" % security.SECINFO_DACL]
+
+        self.level_idxs = [ 1, 2, 3, 4 ]
+        self.oul1 = "OU=acl_visibility_oul1"
+        self.oul1_dn_str = "%s,%s" % (self.oul1, self.base_dn)
+        self.oul2 = "OU=oul2,%s" % self.oul1
+        self.oul2_dn_str = "%s,%s" % (self.oul2, self.base_dn)
+        self.oul3 = "OU=oul3,%s" % self.oul2
+        self.oul3_dn_str = "%s,%s" % (self.oul3, self.base_dn)
+        self.user_name = "acl_visibility_user"
+        self.user_dn_str = "CN=%s,%s" % (self.user_name, self.oul3_dn_str)
+        delete_force(self.ldb_admin, self.user_dn_str)
+        delete_force(self.ldb_admin, self.oul3_dn_str)
+        delete_force(self.ldb_admin, self.oul2_dn_str)
+        delete_force(self.ldb_admin, self.oul1_dn_str)
+        self.ldb_admin.create_ou(self.oul1_dn_str)
+        self.sd_utils.modify_sd_on_dn(self.oul1_dn_str,
+                                      self.sddl_dacl,
+                                      controls=self.set_dacl_control)
+        self.ldb_admin.create_ou(self.oul2_dn_str)
+        self.sd_utils.modify_sd_on_dn(self.oul2_dn_str,
+                                      self.sddl_dacl,
+                                      controls=self.set_dacl_control)
+        self.ldb_admin.create_ou(self.oul3_dn_str)
+        self.sd_utils.modify_sd_on_dn(self.oul3_dn_str,
+                                      self.sddl_dacl,
+                                      controls=self.set_dacl_control)
+
+        self.ldb_admin.newuser(self.user_name, self.user_pass, userou=self.oul3)
+        self.user_sid = self.sd_utils.get_object_sid(self.user_dn_str)
+        self.ldb_user = self.get_ldb_connection(self.user_name, self.user_pass)
+
+    def tearDown(self):
+        super(AclVisibiltyTests, self).tearDown()
+        delete_force(self.ldb_admin, self.user_dn_str)
+        delete_force(self.ldb_admin, self.oul3_dn_str)
+        delete_force(self.ldb_admin, self.oul2_dn_str)
+        delete_force(self.ldb_admin, self.oul1_dn_str)
+
+        del self.ldb_user
+
+    def _test_visibility_with_args(self,
+                                   tname,
+                                   fDoListObject,
+                                   modeDeny,
+                                   l1_allow,
+                                   l2_allow,
+                                   l3_allow):
+        l1_deny = 0
+        l2_deny = 0
+        l3_deny = 0
+        if modeDeny:
+            l1_deny = ~l1_allow
+            l2_deny = ~l2_allow
+            l3_deny = ~l3_allow
+        print("Testing: fDoListObject=%s, modeDeny=%s, l1_allow=0x%02x, l2_allow=0x%02x, l3_allow=0x%02x)" % (
+              fDoListObject, modeDeny, l1_allow, l2_allow, l3_allow))
+        if fDoListObject:
+            self.ldb_admin.set_dsheuristics("001")
+        else:
+            self.ldb_admin.set_dsheuristics("000")
+
+        def _generate_dacl(allow, deny):
+            dacl = self.sddl_dacl
+            drights = ""
+            if deny & security.SEC_ADS_LIST:
+                drights += "LC"
+            if deny & security.SEC_ADS_LIST_OBJECT:
+                drights += "LO"
+            if len(drights) > 0:
+                dacl += "(D;;%s;;;%s)" % (drights, self.user_sid)
+            arights = ""
+            if allow & security.SEC_ADS_LIST:
+                arights += "LC"
+            if allow & security.SEC_ADS_LIST_OBJECT:
+                arights += "LO"
+            if len(arights) > 0:
+                dacl += "(A;;%s;;;%s)" % (arights, self.user_sid)
+            print("dacl: %s" % dacl)
+            return dacl
+
+        l1_dacl = _generate_dacl(l1_allow, l1_deny)
+        l2_dacl = _generate_dacl(l2_allow, l2_deny)
+        l3_dacl = _generate_dacl(l3_allow, l3_deny)
+        self.sd_utils.modify_sd_on_dn(self.oul1_dn_str,
+                                      l1_dacl,
+                                      controls=self.set_dacl_control)
+        self.sd_utils.modify_sd_on_dn(self.oul2_dn_str,
+                                      l2_dacl,
+                                      controls=self.set_dacl_control)
+        self.sd_utils.modify_sd_on_dn(self.oul3_dn_str,
+                                      l3_dacl,
+                                      controls=self.set_dacl_control)
+
+        def _generate_levels(_l1_allow,
+                             _l1_deny,
+                             _l2_allow,
+                             _l2_deny,
+                             _l3_allow,
+                             _l3_deny):


-- 
Samba Shared Repository



More information about the samba-cvs mailing list