perform a SEC_FLAG_MAXIMUM_ALLOWED access check
*/
static uint32_t access_check_max_allowed(const struct security_descriptor *sd,
- const struct security_token *token)
+ const struct security_token *token,
+ enum implicit_owner_rights implicit_owner_rights)
{
uint32_t denied = 0, granted = 0;
bool am_owner = false;
if (sd->dacl == NULL) {
if (security_token_has_sid(token, sd->owner_sid)) {
- granted |= SEC_STD_WRITE_DAC | SEC_STD_READ_CONTROL;
+ switch (implicit_owner_rights) {
+ case IMPLICIT_OWNER_READ_CONTROL_AND_WRITE_DAC_RIGHTS:
+ granted |= SEC_STD_WRITE_DAC;
+ FALL_THROUGH;
+ case IMPLICIT_OWNER_READ_CONTROL_RIGHTS:
+ granted |= SEC_STD_READ_CONTROL;
+ break;
+ }
}
return granted;
}
}
if (am_owner && !have_owner_rights_ace) {
- granted |= SEC_STD_WRITE_DAC|SEC_STD_READ_CONTROL;
+ switch (implicit_owner_rights) {
+ case IMPLICIT_OWNER_READ_CONTROL_AND_WRITE_DAC_RIGHTS:
+ granted |= SEC_STD_WRITE_DAC;
+ FALL_THROUGH;
+ case IMPLICIT_OWNER_READ_CONTROL_RIGHTS:
+ granted |= SEC_STD_READ_CONTROL;
+ break;
+ }
}
for (i = 0;i<sd->dacl->num_aces; i++) {
return granted & ~denied;
}
-/*
- The main entry point for access checking. If returning ACCESS_DENIED
- this function returns the denied bits in the uint32_t pointed
- to by the access_granted pointer.
-*/
-NTSTATUS se_access_check(const struct security_descriptor *sd,
- const struct security_token *token,
- uint32_t access_desired,
- uint32_t *access_granted)
+static NTSTATUS se_access_check_implicit_owner(const struct security_descriptor *sd,
+ const struct security_token *token,
+ uint32_t access_desired,
+ uint32_t *access_granted,
+ enum implicit_owner_rights implicit_owner_rights)
{
uint32_t i;
uint32_t bits_remaining;
if (access_desired & SEC_FLAG_MAXIMUM_ALLOWED) {
uint32_t orig_access_desired = access_desired;
- access_desired |= access_check_max_allowed(sd, token);
+ access_desired |= access_check_max_allowed(sd, token, implicit_owner_rights);
access_desired &= ~SEC_FLAG_MAXIMUM_ALLOWED;
*access_granted = access_desired;
bits_remaining = access_desired;
}
}
if (am_owner && !have_owner_rights_ace) {
- bits_remaining &= ~(SEC_STD_WRITE_DAC | SEC_STD_READ_CONTROL);
+ switch (implicit_owner_rights) {
+ case IMPLICIT_OWNER_READ_CONTROL_AND_WRITE_DAC_RIGHTS:
+ bits_remaining &= ~SEC_STD_WRITE_DAC;
+ FALL_THROUGH;
+ case IMPLICIT_OWNER_READ_CONTROL_RIGHTS:
+ bits_remaining &= ~SEC_STD_READ_CONTROL;
+ break;
+ }
}
/* check each ace in turn. */
return NT_STATUS_OK;
}
+/*
+ The main entry point for access checking. If returning ACCESS_DENIED
+ this function returns the denied bits in the uint32_t pointed
+ to by the access_granted pointer.
+*/
+NTSTATUS se_access_check(const struct security_descriptor *sd,
+ const struct security_token *token,
+ uint32_t access_desired,
+ uint32_t *access_granted)
+{
+ return se_access_check_implicit_owner(sd,
+ token,
+ access_desired,
+ access_granted,
+ IMPLICIT_OWNER_READ_CONTROL_AND_WRITE_DAC_RIGHTS);
+}
+
/*
The main entry point for access checking FOR THE FILE SERVER ONLY !
If returning ACCESS_DENIED this function returns the denied bits in
if (!priv_open_requested) {
/* Fall back to generic se_access_check(). */
- return se_access_check(sd,
- token,
- access_desired,
- access_granted);
+ return se_access_check_implicit_owner(sd,
+ token,
+ access_desired,
+ access_granted,
+ IMPLICIT_OWNER_READ_CONTROL_AND_WRITE_DAC_RIGHTS);
}
/*
if (access_desired & SEC_FLAG_MAXIMUM_ALLOWED) {
uint32_t orig_access_desired = access_desired;
- access_desired |= access_check_max_allowed(sd, token);
+ access_desired |= access_check_max_allowed(sd, token, true);
access_desired &= ~SEC_FLAG_MAXIMUM_ALLOWED;
if (security_token_has_privilege(token, SEC_PRIV_BACKUP)) {
access_desired));
}
- status = se_access_check(sd,
- token,
- access_desired,
- access_granted);
+ status = se_access_check_implicit_owner(sd,
+ token,
+ access_desired,
+ access_granted,
+ IMPLICIT_OWNER_READ_CONTROL_AND_WRITE_DAC_RIGHTS);
if (!NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) {
return status;
return NT_STATUS_OK;
}
-/**
- * @brief Perform directoryservice (DS) related access checks for a given user
- *
- * Perform DS access checks for the user represented by its security_token, on
- * the provided security descriptor. If an tree associating GUID and access
- * required is provided then object access (OA) are checked as well. *
- * @param[in] sd The security descritor against which the required
- * access are requested
- *
- * @param[in] token The security_token associated with the user to
- * test
- *
- * @param[in] access_desired A bitfield of rights that must be granted for the
- * given user in the specified SD.
- *
- * If one
- * of the entry in the tree grants all the requested rights for the given GUID
- * FIXME
- * tree can be null if not null it's the
- * Lots of code duplication, it will be united in just one
- * function eventually */
-
-NTSTATUS sec_access_check_ds(const struct security_descriptor *sd,
- const struct security_token *token,
- uint32_t access_desired,
- uint32_t *access_granted,
- struct object_tree *tree,
- struct dom_sid *replace_sid)
+NTSTATUS sec_access_check_ds_implicit_owner(const struct security_descriptor *sd,
+ const struct security_token *token,
+ uint32_t access_desired,
+ uint32_t *access_granted,
+ struct object_tree *tree,
+ struct dom_sid *replace_sid,
+ enum implicit_owner_rights implicit_owner_rights)
{
uint32_t i;
uint32_t bits_remaining;
/* handle the maximum allowed flag */
if (access_desired & SEC_FLAG_MAXIMUM_ALLOWED) {
- access_desired |= access_check_max_allowed(sd, token);
+ access_desired |= access_check_max_allowed(sd, token, implicit_owner_rights);
access_desired &= ~SEC_FLAG_MAXIMUM_ALLOWED;
*access_granted = access_desired;
bits_remaining = access_desired;
/* the owner always gets SEC_STD_WRITE_DAC and SEC_STD_READ_CONTROL */
if ((bits_remaining & (SEC_STD_WRITE_DAC|SEC_STD_READ_CONTROL)) &&
security_token_has_sid(token, sd->owner_sid)) {
- bits_remaining &= ~(SEC_STD_WRITE_DAC|SEC_STD_READ_CONTROL);
+ switch (implicit_owner_rights) {
+ case IMPLICIT_OWNER_READ_CONTROL_AND_WRITE_DAC_RIGHTS:
+ bits_remaining &= ~SEC_STD_WRITE_DAC;
+ FALL_THROUGH;
+ case IMPLICIT_OWNER_READ_CONTROL_RIGHTS:
+ bits_remaining &= ~SEC_STD_READ_CONTROL;
+ break;
+ }
}
/* SEC_PRIV_TAKE_OWNERSHIP grants SEC_STD_WRITE_OWNER */
return NT_STATUS_OK;
}
+
+/**
+ * @brief Perform directoryservice (DS) related access checks for a given user
+ *
+ * Perform DS access checks for the user represented by its security_token, on
+ * the provided security descriptor. If an tree associating GUID and access
+ * required is provided then object access (OA) are checked as well. *
+ * @param[in] sd The security descritor against which the required
+ * access are requested
+ *
+ * @param[in] token The security_token associated with the user to
+ * test
+ *
+ * @param[in] access_desired A bitfield of rights that must be granted for the
+ * given user in the specified SD.
+ *
+ * If one
+ * of the entry in the tree grants all the requested rights for the given GUID
+ * FIXME
+ * tree can be null if not null it's the
+ * Lots of code duplication, it will be united in just one
+ * function eventually */
+
+NTSTATUS sec_access_check_ds(const struct security_descriptor *sd,
+ const struct security_token *token,
+ uint32_t access_desired,
+ uint32_t *access_granted,
+ struct object_tree *tree,
+ struct dom_sid *replace_sid)
+{
+ return sec_access_check_ds_implicit_owner(sd,
+ token,
+ access_desired,
+ access_granted,
+ tree,
+ replace_sid,
+ IMPLICIT_OWNER_READ_CONTROL_RIGHTS);
+}
uint32_t access_desired,
uint32_t *access_granted);
+NTSTATUS sec_access_check_ds_implicit_owner(const struct security_descriptor *sd,
+ const struct security_token *token,
+ uint32_t access_desired,
+ uint32_t *access_granted,
+ struct object_tree *tree,
+ struct dom_sid *replace_sid,
+ enum implicit_owner_rights implicit_owner_rights);
+
/* modified access check for the purposes of DS security
* Lots of code duplication, it will be united in just one
* function eventually */
SEC_ADS_GENERIC_READ |
SEC_ADS_GENERIC_ALL_DS);
+ /*
+ * Rights implicitly granted to a user who is an owner of the security
+ * descriptor being processed.
+ */
+ typedef enum {
+ IMPLICIT_OWNER_READ_CONTROL_RIGHTS,
+ IMPLICIT_OWNER_READ_CONTROL_AND_WRITE_DAC_RIGHTS
+ } implicit_owner_rights;
+
/***************************************************************/
/* WELL KNOWN SIDS */
if (ret == LDB_SUCCESS) {
flags |= SECINFO_OWNER | SECINFO_GROUP;
}
- ret = acl_check_access_on_attribute(module,
- msg,
- sd,
- sid,
- SEC_STD_WRITE_DAC,
- attr,
- objectclass);
+ ret = acl_check_access_on_attribute_implicit_owner(
+ module,
+ msg,
+ sd,
+ sid,
+ SEC_STD_WRITE_DAC,
+ attr,
+ objectclass,
+ IMPLICIT_OWNER_READ_CONTROL_AND_WRITE_DAC_RIGHTS);
if (ret == LDB_SUCCESS) {
flags |= SECINFO_DACL;
}
uint32_t sd_flags = dsdb_request_sd_flags(req, NULL);
uint32_t access_mask = 0;
+ bool block_owner_rights;
+ enum implicit_owner_rights implicit_owner_rights;
+
if (sd_flags & (SECINFO_OWNER|SECINFO_GROUP)) {
access_mask |= SEC_STD_WRITE_OWNER;
}
access_mask |= SEC_FLAG_SYSTEM_SECURITY;
}
- ret = acl_check_access_on_attribute(module,
- tmp_ctx,
- sd,
- sid,
- access_mask,
- attr,
- objectclass);
+ block_owner_rights = !dsdb_module_am_administrator(module);
+
+ if (block_owner_rights) {
+ block_owner_rights = dsdb_block_owner_implicit_rights(module,
+ req,
+ req);
+ }
+ if (block_owner_rights) {
+ block_owner_rights = samdb_find_attribute(ldb,
+ acl_res->msgs[0],
+ "objectclass",
+ "computer");
+ }
+
+ implicit_owner_rights = block_owner_rights ?
+ IMPLICIT_OWNER_READ_CONTROL_RIGHTS :
+ IMPLICIT_OWNER_READ_CONTROL_AND_WRITE_DAC_RIGHTS;
+
+ ret = acl_check_access_on_attribute_implicit_owner(module,
+ tmp_ctx,
+ sd,
+ sid,
+ access_mask,
+ attr,
+ objectclass,
+ implicit_owner_rights);
if (ret != LDB_SUCCESS) {
ldb_asprintf_errstring(ldb_module_get_ctx(module),
"Object %s has no write dacl access\n",
return LDB_SUCCESS;
}
- ret = acl_check_access_on_attribute(ac->module, mem_ctx, sd, sid,
- access_mask, attr, objectclass);
+ ret = acl_check_access_on_attribute_implicit_owner(ac->module, mem_ctx, sd, sid,
+ access_mask, attr, objectclass,
+ IMPLICIT_OWNER_READ_CONTROL_RIGHTS);
if (ret == LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS) {
return ret;
continue;
}
- ret = acl_check_access_on_attribute(ac->module,
- tmp_ctx,
- sd,
- sid,
- access_mask,
- attr,
- objectclass);
+ ret = acl_check_access_on_attribute_implicit_owner(ac->module,
+ tmp_ctx,
+ sd,
+ sid,
+ access_mask,
+ attr,
+ objectclass,
+ IMPLICIT_OWNER_READ_CONTROL_RIGHTS);
/*
* Dirsync control needs the replpropertymetadata attribute
guid);
}
-int acl_check_access_on_attribute(struct ldb_module *module,
- TALLOC_CTX *mem_ctx,
- struct security_descriptor *sd,
- struct dom_sid *rp_sid,
- uint32_t access_mask,
- const struct dsdb_attribute *attr,
- const struct dsdb_class *objectclass)
+int acl_check_access_on_attribute_implicit_owner(struct ldb_module *module,
+ TALLOC_CTX *mem_ctx,
+ struct security_descriptor *sd,
+ struct dom_sid *rp_sid,
+ uint32_t access_mask,
+ const struct dsdb_attribute *attr,
+ const struct dsdb_class *objectclass,
+ enum implicit_owner_rights implicit_owner_rights)
{
int ret;
NTSTATUS status;
goto fail;
}
- status = sec_access_check_ds(sd, token,
- access_mask,
- &access_granted,
- root,
- rp_sid);
+ status = sec_access_check_ds_implicit_owner(sd, token,
+ access_mask,
+ &access_granted,
+ root,
+ rp_sid,
+ implicit_owner_rights);
if (!NT_STATUS_IS_OK(status)) {
ret = LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS;
}
return ldb_operr(ldb_module_get_ctx(module));
}
+int acl_check_access_on_attribute(struct ldb_module *module,
+ TALLOC_CTX *mem_ctx,
+ struct security_descriptor *sd,
+ struct dom_sid *rp_sid,
+ uint32_t access_mask,
+ const struct dsdb_attribute *attr,
+ const struct dsdb_class *objectclass)
+{
+ return acl_check_access_on_attribute_implicit_owner(module,
+ mem_ctx,
+ sd,
+ rp_sid,
+ access_mask,
+ attr,
+ objectclass,
+ IMPLICIT_OWNER_READ_CONTROL_RIGHTS);
+}
+
int acl_check_access_on_objectclass(struct ldb_module *module,
TALLOC_CTX *mem_ctx,
struct security_descriptor *sd,
struct netlogon_samlogon_response;
#include "librpc/gen_ndr/misc.h"
+#include "librpc/gen_ndr/security.h"
#include "dsdb/samdb/ldb_modules/util_proto.h"
#include "dsdb/common/util.h"
#include "../libcli/netlogon/netlogon.h"
desc_sddl = self.sd_utils.get_sd_as_sddl(group_dn)
self.assertEqual(desc_sddl, sddl)
sddl = "O:AUG:AUD:AI(D;;CC;;;LG)"
- self.sd_utils.modify_sd_on_dn(group_dn, sddl)
+ try:
+ self.sd_utils.modify_sd_on_dn(group_dn, sddl)
+ except LdbError as e:
+ self.fail(str(e))
desc_sddl = self.sd_utils.get_sd_as_sddl(group_dn)
self.assertEqual(desc_sddl, sddl)
self.assertFalse("ID" in desc_sddl)
for x in re.findall(r"\(.*?\)", mod):
self.assertFalse(x in desc_sddl)
- self.sd_utils.modify_sd_on_dn(group_dn, "D:" + moded)
+ try:
+ self.sd_utils.modify_sd_on_dn(group_dn, "D:" + moded)
+ except LdbError as e:
+ self.fail(str(e))
desc_sddl = self.sd_utils.get_sd_as_sddl(group_dn)
self.assertFalse("ID" in desc_sddl)
for x in re.findall(r"\(.*?\)", mod):
desc_sddl = self.sd_utils.get_sd_as_sddl(group_dn)
mod = mod.replace(";CI;", ";CIID;")
self.assertTrue(mod in desc_sddl)
- self.sd_utils.modify_sd_on_dn(group_dn, "D:" + moded)
+ try:
+ self.sd_utils.modify_sd_on_dn(group_dn, "D:" + moded)
+ except LdbError as e:
+ self.fail(str(e))
desc_sddl = self.sd_utils.get_sd_as_sddl(group_dn)
self.assertTrue(moded in desc_sddl)
self.assertTrue(mod in desc_sddl)
desc_sddl = self.sd_utils.get_sd_as_sddl(group_dn)
mod = mod.replace(";OI;", ";OIIOID;") # change it how it's gonna look like
self.assertTrue(mod in desc_sddl)
- self.sd_utils.modify_sd_on_dn(group_dn, "D:" + moded)
+ try:
+ self.sd_utils.modify_sd_on_dn(group_dn, "D:" + moded)
+ except LdbError as e:
+ self.fail(str(e))
desc_sddl = self.sd_utils.get_sd_as_sddl(group_dn)
self.assertTrue(moded in desc_sddl)
self.assertTrue(mod in desc_sddl)
desc_sddl = self.sd_utils.get_sd_as_sddl(group_dn)
mod = mod.replace(";CI;", ";CIID;") # change it how it's gonna look like
self.assertTrue(mod in desc_sddl)
- self.sd_utils.modify_sd_on_dn(group_dn, "D:" + moded)
+ try:
+ self.sd_utils.modify_sd_on_dn(group_dn, "D:" + moded)
+ except LdbError as e:
+ self.fail(str(e))
desc_sddl = self.sd_utils.get_sd_as_sddl(group_dn)
self.assertTrue(moded in desc_sddl)
self.assertTrue(mod in desc_sddl)
desc_sddl = self.sd_utils.get_sd_as_sddl(group_dn)
mod = mod.replace(";OI;", ";OIIOID;") # change it how it's gonna look like
self.assertTrue(mod in desc_sddl)
- self.sd_utils.modify_sd_on_dn(group_dn, "D:" + moded)
+ try:
+ self.sd_utils.modify_sd_on_dn(group_dn, "D:" + moded)
+ except LdbError as e:
+ self.fail(str(e))
desc_sddl = self.sd_utils.get_sd_as_sddl(group_dn)
self.assertTrue(moded in desc_sddl)
self.assertTrue(mod in desc_sddl)
desc_sddl = self.sd_utils.get_sd_as_sddl(group_dn)
mod = mod.replace(";CI;", ";CIID;") # change it how it's gonna look like
self.assertTrue(mod in desc_sddl)
- self.sd_utils.modify_sd_on_dn(group_dn, "D:" + moded)
+ try:
+ self.sd_utils.modify_sd_on_dn(group_dn, "D:" + moded)
+ except LdbError as e:
+ self.fail(str(e))
desc_sddl = self.sd_utils.get_sd_as_sddl(group_dn)
self.assertTrue(moded in desc_sddl)
self.assertTrue(mod in desc_sddl)
desc_sddl = self.sd_utils.get_sd_as_sddl(group_dn)
mod = mod.replace(";OI;", ";OIIOID;") # change it how it's gonna look like
self.assertTrue(mod in desc_sddl)
- self.sd_utils.modify_sd_on_dn(group_dn, "D:(OA;OI;WP;bf967a39-0de6-11d0-a285-00aa003049e2;;DU)" + moded)
+ try:
+ self.sd_utils.modify_sd_on_dn(group_dn, "D:(OA;OI;WP;bf967a39-0de6-11d0-a285-00aa003049e2;;DU)" + moded)
+ except LdbError as e:
+ self.fail(str(e))
desc_sddl = self.sd_utils.get_sd_as_sddl(group_dn)
self.assertTrue(moded in desc_sddl)
self.assertTrue(mod in desc_sddl)
desc_sddl = self.sd_utils.get_sd_as_sddl(group_dn)
self.assertTrue("(D;ID;WP;;;AU)" in desc_sddl)
self.assertTrue("(D;CIIOID;WP;;;CO)" in desc_sddl)
- self.sd_utils.modify_sd_on_dn(group_dn, "D:" + moded)
+ try:
+ self.sd_utils.modify_sd_on_dn(group_dn, "D:" + moded)
+ except LdbError as e:
+ self.fail(str(e))
desc_sddl = self.sd_utils.get_sd_as_sddl(group_dn)
self.assertTrue(moded in desc_sddl)
self.assertTrue("(D;ID;WP;;;DA)" in desc_sddl)