From b15f35b573817b0e39425ae05962a9b1028bdc32 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Tue, 13 Oct 2020 12:43:39 +0200 Subject: 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 Reviewed-by: Douglas Bagnall Autobuild-User(master): Stefan Metzmacher Autobuild-Date(master): Wed Oct 21 08:48:02 UTC 2020 on sn-devel-184 (cherry picked from commit 7223f6453b1b38c933c9480c637ffd06d9f39b97) --- selftest/knownfail.d/ldap-acl-visibility | 50 ------------------- source4/dsdb/samdb/ldb_modules/acl_read.c | 79 ++++++++++++++++++++++++++++++- 2 files changed, 78 insertions(+), 51 deletions(-) delete mode 100644 selftest/knownfail.d/ldap-acl-visibility diff --git a/selftest/knownfail.d/ldap-acl-visibility b/selftest/knownfail.d/ldap-acl-visibility deleted file mode 100644 index b580b2e8cae..00000000000 --- a/selftest/knownfail.d/ldap-acl-visibility +++ /dev/null @@ -1,50 +0,0 @@ -^samba4.ldap.acl.python.*.__main__.AclVisibiltyTests.test_visibility_Do_Allow_CO_CO_nO -^samba4.ldap.acl.python.*.__main__.AclVisibiltyTests.test_visibility_Do_Allow_CO_Cn_nO -^samba4.ldap.acl.python.*.__main__.AclVisibiltyTests.test_visibility_Do_Allow_CO_nO_CO -^samba4.ldap.acl.python.*.__main__.AclVisibiltyTests.test_visibility_Do_Allow_CO_nO_nO -^samba4.ldap.acl.python.*.__main__.AclVisibiltyTests.test_visibility_Do_Allow_CO_nn_nO -^samba4.ldap.acl.python.*.__main__.AclVisibiltyTests.test_visibility_Do_Allow_Cn_CO_nO -^samba4.ldap.acl.python.*.__main__.AclVisibiltyTests.test_visibility_Do_Allow_Cn_Cn_nO -^samba4.ldap.acl.python.*.__main__.AclVisibiltyTests.test_visibility_Do_Allow_Cn_nO_CO -^samba4.ldap.acl.python.*.__main__.AclVisibiltyTests.test_visibility_Do_Allow_Cn_nO_nO -^samba4.ldap.acl.python.*.__main__.AclVisibiltyTests.test_visibility_Do_Allow_Cn_nn_nO -^samba4.ldap.acl.python.*.__main__.AclVisibiltyTests.test_visibility_Do_Allow_nO_CO_CO -^samba4.ldap.acl.python.*.__main__.AclVisibiltyTests.test_visibility_Do_Allow_nO_CO_Cn -^samba4.ldap.acl.python.*.__main__.AclVisibiltyTests.test_visibility_Do_Allow_nO_CO_nO -^samba4.ldap.acl.python.*.__main__.AclVisibiltyTests.test_visibility_Do_Allow_nO_CO_nn -^samba4.ldap.acl.python.*.__main__.AclVisibiltyTests.test_visibility_Do_Allow_nO_Cn_nO -^samba4.ldap.acl.python.*.__main__.AclVisibiltyTests.test_visibility_Do_Allow_nO_nO_CO -^samba4.ldap.acl.python.*.__main__.AclVisibiltyTests.test_visibility_Do_Allow_nO_nO_Cn -^samba4.ldap.acl.python.*.__main__.AclVisibiltyTests.test_visibility_Do_Allow_nO_nO_nO -^samba4.ldap.acl.python.*.__main__.AclVisibiltyTests.test_visibility_Do_Allow_nO_nO_nn -^samba4.ldap.acl.python.*.__main__.AclVisibiltyTests.test_visibility_Do_Allow_nO_nn_nO -^samba4.ldap.acl.python.*.__main__.AclVisibiltyTests.test_visibility_Do_Allow_nn_CO_nO -^samba4.ldap.acl.python.*.__main__.AclVisibiltyTests.test_visibility_Do_Allow_nn_Cn_nO -^samba4.ldap.acl.python.*.__main__.AclVisibiltyTests.test_visibility_Do_Allow_nn_nO_CO -^samba4.ldap.acl.python.*.__main__.AclVisibiltyTests.test_visibility_Do_Allow_nn_nO_nO -^samba4.ldap.acl.python.*.__main__.AclVisibiltyTests.test_visibility_Do_Allow_nn_nn_nO -^samba4.ldap.acl.python.*.__main__.AclVisibiltyTests.test_visibility_Do_Deny_CO_CO_nO -^samba4.ldap.acl.python.*.__main__.AclVisibiltyTests.test_visibility_Do_Deny_CO_Cn_nO -^samba4.ldap.acl.python.*.__main__.AclVisibiltyTests.test_visibility_Do_Deny_CO_nO_CO -^samba4.ldap.acl.python.*.__main__.AclVisibiltyTests.test_visibility_Do_Deny_CO_nO_nO -^samba4.ldap.acl.python.*.__main__.AclVisibiltyTests.test_visibility_Do_Deny_CO_nn_nO -^samba4.ldap.acl.python.*.__main__.AclVisibiltyTests.test_visibility_Do_Deny_Cn_CO_nO -^samba4.ldap.acl.python.*.__main__.AclVisibiltyTests.test_visibility_Do_Deny_Cn_Cn_nO -^samba4.ldap.acl.python.*.__main__.AclVisibiltyTests.test_visibility_Do_Deny_Cn_nO_CO -^samba4.ldap.acl.python.*.__main__.AclVisibiltyTests.test_visibility_Do_Deny_Cn_nO_nO -^samba4.ldap.acl.python.*.__main__.AclVisibiltyTests.test_visibility_Do_Deny_Cn_nn_nO -^samba4.ldap.acl.python.*.__main__.AclVisibiltyTests.test_visibility_Do_Deny_nO_CO_CO -^samba4.ldap.acl.python.*.__main__.AclVisibiltyTests.test_visibility_Do_Deny_nO_CO_Cn -^samba4.ldap.acl.python.*.__main__.AclVisibiltyTests.test_visibility_Do_Deny_nO_CO_nO -^samba4.ldap.acl.python.*.__main__.AclVisibiltyTests.test_visibility_Do_Deny_nO_CO_nn -^samba4.ldap.acl.python.*.__main__.AclVisibiltyTests.test_visibility_Do_Deny_nO_Cn_nO -^samba4.ldap.acl.python.*.__main__.AclVisibiltyTests.test_visibility_Do_Deny_nO_nO_CO -^samba4.ldap.acl.python.*.__main__.AclVisibiltyTests.test_visibility_Do_Deny_nO_nO_Cn -^samba4.ldap.acl.python.*.__main__.AclVisibiltyTests.test_visibility_Do_Deny_nO_nO_nO -^samba4.ldap.acl.python.*.__main__.AclVisibiltyTests.test_visibility_Do_Deny_nO_nO_nn -^samba4.ldap.acl.python.*.__main__.AclVisibiltyTests.test_visibility_Do_Deny_nO_nn_nO -^samba4.ldap.acl.python.*.__main__.AclVisibiltyTests.test_visibility_Do_Deny_nn_CO_nO -^samba4.ldap.acl.python.*.__main__.AclVisibiltyTests.test_visibility_Do_Deny_nn_Cn_nO -^samba4.ldap.acl.python.*.__main__.AclVisibiltyTests.test_visibility_Do_Deny_nn_nO_CO -^samba4.ldap.acl.python.*.__main__.AclVisibiltyTests.test_visibility_Do_Deny_nn_nO_nO -^samba4.ldap.acl.python.*.__main__.AclVisibiltyTests.test_visibility_Do_Deny_nn_nn_nO diff --git a/source4/dsdb/samdb/ldb_modules/acl_read.c b/source4/dsdb/samdb/ldb_modules/acl_read.c index d3cd5d5e1bd..f3acf08c021 100644 --- a/source4/dsdb/samdb/ldb_modules/acl_read.c +++ b/source4/dsdb/samdb/ldb_modules/acl_read.c @@ -50,6 +50,8 @@ struct aclread_context { bool added_objectClass; bool indirsync; + bool do_list_object_initialized; + bool do_list_object; bool base_invisible; uint64_t num_entries; @@ -160,6 +162,7 @@ static int aclread_check_object_visible(struct aclread_context *ac, struct ldb_request *req) { uint32_t instanceType; + int ret; /* get the object instance type */ instanceType = ldb_msg_find_attr_as_uint(msg, @@ -171,7 +174,81 @@ static int aclread_check_object_visible(struct aclread_context *ac, return LDB_SUCCESS; } - return aclread_check_parent(ac, msg, req); + 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; } /* -- cgit v1.2.1