summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--source4/dsdb/common/util.c31
-rw-r--r--source4/dsdb/samdb/ldb_modules/acl.c101
-rwxr-xr-xsource4/lib/ldb/tests/python/acl.py108
3 files changed, 234 insertions, 6 deletions
diff --git a/source4/dsdb/common/util.c b/source4/dsdb/common/util.c
index 515d96d085..80736b1712 100644
--- a/source4/dsdb/common/util.c
+++ b/source4/dsdb/common/util.c
@@ -2514,6 +2514,37 @@ int dsdb_find_sid_by_dn(struct ldb_context *ldb,
return LDB_SUCCESS;
}
+/*
+ use a SID to find a DN
+ */
+int dsdb_find_dn_by_sid(struct ldb_context *ldb,
+ TALLOC_CTX *mem_ctx,
+ struct dom_sid *sid, struct ldb_dn **dn)
+{
+ int ret;
+ struct ldb_result *res;
+ const char *attrs[] = { NULL };
+ char *sid_str = dom_sid_string(mem_ctx, sid);
+
+ if (!sid_str) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ ret = dsdb_search(ldb, mem_ctx, &res, NULL, LDB_SCOPE_SUBTREE, attrs,
+ DSDB_SEARCH_SEARCH_ALL_PARTITIONS |
+ DSDB_SEARCH_SHOW_EXTENDED_DN |
+ DSDB_SEARCH_ONE_ONLY,
+ "objectSID=%s", sid_str);
+ talloc_free(sid_str);
+ if (ret != LDB_SUCCESS) {
+ return ret;
+ }
+
+ *dn = talloc_steal(mem_ctx, res->msgs[0]->dn);
+ talloc_free(res);
+
+ return LDB_SUCCESS;
+}
/*
load a repsFromTo blob list for a given partition GUID
diff --git a/source4/dsdb/samdb/ldb_modules/acl.c b/source4/dsdb/samdb/ldb_modules/acl.c
index ccc7edf218..b2aeb2adb7 100644
--- a/source4/dsdb/samdb/ldb_modules/acl.c
+++ b/source4/dsdb/samdb/ldb_modules/acl.c
@@ -654,6 +654,95 @@ static int acl_add(struct ldb_module *module, struct ldb_request *req)
return ldb_next_request(module, req);
}
+/* checks for validated writes */
+static int acl_check_self_write(struct ldb_request *req,
+ struct security_descriptor *sd,
+ struct security_token *token,
+ const char *self_write,
+ struct dom_sid *sid)
+{
+ struct GUID right;
+ NTSTATUS status;
+ uint32_t access_granted;
+ struct object_tree *root = NULL;
+ struct object_tree *new_node = NULL;
+ TALLOC_CTX *tmp_ctx = talloc_new(req);
+
+ GUID_from_string(self_write, &right);
+
+ if (!insert_in_object_tree(tmp_ctx, &right, SEC_ADS_SELF_WRITE,
+ &root, &new_node)) {
+ DEBUG(10, ("acl_modify: cannot add to object tree\n"));
+ talloc_free(tmp_ctx);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ status = sec_access_check_ds(sd, token,
+ SEC_ADS_SELF_WRITE,
+ &access_granted,
+ root,
+ sid);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(10, ("Object %s has no self membershipself write right\n",
+ ldb_dn_get_linearized(req->op.mod.message->dn)));
+ dsdb_acl_debug(sd, token,
+ req->op.mod.message->dn,
+ true,
+ 10);
+ talloc_free(tmp_ctx);
+ return LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS;
+ }
+
+ return LDB_SUCCESS;
+}
+
+/* ckecks if modifications are allowed on "Member" attribute */
+static int acl_check_self_membership(struct ldb_module *module,
+ struct ldb_request *req,
+ struct security_descriptor *sd,
+ struct dom_sid *sid,
+ const struct GUID *oc_guid,
+ const struct dsdb_attribute *attr)
+{
+ int ret, i;
+ TALLOC_CTX *tmp_ctx = talloc_new(req);
+ struct ldb_context *ldb = ldb_module_get_ctx(module);
+ struct ldb_dn *user_dn;
+ struct ldb_message_element *member_el;
+ /* if we have wp, we can do whatever we like */
+ if (acl_check_access_on_attribute(module,
+ req,
+ sd,
+ sid,
+ SEC_ADS_WRITE_PROP,
+ attr) == LDB_SUCCESS) {
+ return LDB_SUCCESS;
+ }
+ /* if we are adding/deleting ourselves, check for self membership */
+ ret = dsdb_find_dn_by_sid(ldb, req, acl_user_token(module)->user_sid, &user_dn);
+ if (ret != LDB_SUCCESS) {
+ return ret;
+ }
+ member_el = ldb_msg_find_element(req->op.mod.message, "Member");
+ if (!member_el) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ /* user can only remove oneself */
+ if (member_el->num_values == 0) {
+ return LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS;
+ }
+ for (i = 0; i < member_el->num_values; i++) {
+ if (strcasecmp((const char *)member_el->values[i].data,
+ ldb_dn_get_extended_linearized(tmp_ctx, user_dn, 1)) != 0) {
+ return LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS;
+ }
+ }
+ talloc_free(tmp_ctx);
+ return acl_check_self_write(req, sd, acl_user_token(module),
+ GUID_DRS_SELF_MEMBERSHIP,
+ sid);
+}
+
static int acl_modify(struct ldb_module *module, struct ldb_request *req)
{
int ret;
@@ -753,8 +842,18 @@ static int acl_modify(struct ldb_module *module, struct ldb_request *req)
if (ldb_attr_cmp("nTSecurityDescriptor", req->op.mod.message->elements[i].name) == 0) {
modify_sd = true;
+ }
+ else if (ldb_attr_cmp("Member", req->op.mod.message->elements[i].name) == 0) {
+ ret = acl_check_self_membership(module,
+ req,
+ sd,
+ sid,
+ guid,
+ attr);
+ if (ret != LDB_SUCCESS) {
+ return ret;
+ }
} else {
-
if (!insert_in_object_tree(tmp_ctx,
&attr->attributeSecurityGUID, SEC_ADS_WRITE_PROP,
&new_node, &new_node)) {
diff --git a/source4/lib/ldb/tests/python/acl.py b/source4/lib/ldb/tests/python/acl.py
index cf061cfe93..514edf87a2 100755
--- a/source4/lib/ldb/tests/python/acl.py
+++ b/source4/lib/ldb/tests/python/acl.py
@@ -151,7 +151,7 @@ url: www.example.com
dn: """ + group_dn + """
objectClass: group
sAMAccountName: """ + group_dn.split(",")[0][3:] + """
-groupType: 4
+groupType: 2147483650
url: www.example.com
"""
if desc:
@@ -345,23 +345,36 @@ class AclModifyTests(AclTests):
def setUp(self):
super(AclModifyTests, self).setUp()
self.user_with_wp = "acl_mod_user1"
+ self.user_with_sm = "acl_mod_user2"
+ self.user_with_group_sm = "acl_mod_user3"
self.create_enable_user(self.user_with_wp)
+ self.create_enable_user(self.user_with_sm)
+ self.create_enable_user(self.user_with_group_sm)
self.ldb_user = self.get_ldb_connection(self.user_with_wp, self.user_pass)
- self.user_sid = self.get_object_sid(self.get_user_dn(self.user_with_wp))
+ self.ldb_user2 = self.get_ldb_connection(self.user_with_sm, self.user_pass)
+ self.ldb_user3 = self.get_ldb_connection(self.user_with_group_sm, self.user_pass)
+ self.user_sid = self.get_object_sid( self.get_user_dn(self.user_with_wp))
+ self.create_group(self.ldb_admin, "CN=test_modify_group2,CN=Users," + self.base_dn)
+ self.create_group(self.ldb_admin, "CN=test_modify_group3,CN=Users," + self.base_dn)
+ self.create_test_user(self.ldb_admin, self.get_user_dn("test_modify_user2"))
def tearDown(self):
super(AclModifyTests, self).tearDown()
self.delete_force(self.ldb_admin, self.get_user_dn("test_modify_user1"))
self.delete_force(self.ldb_admin, "CN=test_modify_group1,CN=Users," + self.base_dn)
+ self.delete_force(self.ldb_admin, "CN=test_modify_group2,CN=Users," + self.base_dn)
+ self.delete_force(self.ldb_admin, "CN=test_modify_group3,CN=Users," + self.base_dn)
self.delete_force(self.ldb_admin, "OU=test_modify_ou1," + self.base_dn)
self.delete_force(self.ldb_admin, self.get_user_dn(self.user_with_wp))
+ self.delete_force(self.ldb_admin, self.get_user_dn(self.user_with_sm))
+ self.delete_force(self.ldb_admin, self.get_user_dn(self.user_with_group_sm))
+ self.delete_force(self.ldb_admin, self.get_user_dn("test_modify_user2"))
def test_modify_u1(self):
"""5 Modify one attribute if you have DS_WRITE_PROPERTY for it"""
mod = "(OA;;WP;bf967953-0de6-11d0-a285-00aa003049e2;;%s)" % str(self.user_sid)
# First test object -- User
print "Testing modify on User object"
- #self.delete_force(self.ldb_admin, self.get_user_dn("test_modify_user1"))
self.create_test_user(self.ldb_admin, self.get_user_dn("test_modify_user1"))
self.dacl_add_ace(self.get_user_dn("test_modify_user1"), mod)
ldif = """
@@ -375,7 +388,6 @@ displayName: test_changed"""
self.assertEqual(res[0]["displayName"][0], "test_changed")
# Second test object -- Group
print "Testing modify on Group object"
- #self.delete_force(self.ldb_admin, "CN=test_modify_group1,CN=Users," + self.base_dn)
self.create_group(self.ldb_admin, "CN=test_modify_group1,CN=Users," + self.base_dn)
self.dacl_add_ace("CN=test_modify_group1,CN=Users," + self.base_dn, mod)
ldif = """
@@ -400,7 +412,7 @@ displayName: test_changed"""
res = self.ldb_admin.search(self.base_dn, expression="(distinguishedName=%s)" % str("OU=test_modify_ou1," + self.base_dn))
self.assertEqual(res[0]["displayName"][0], "test_changed")
- def test_modify_u2(self):
+ def _test_modify_u2(self):
"""6 Modify two attributes as you have DS_WRITE_PROPERTY granted only for one of them"""
mod = "(OA;;WP;bf967953-0de6-11d0-a285-00aa003049e2;;%s)" % str(self.user_sid)
# First test object -- User
@@ -565,6 +577,92 @@ adminDescription: blah blah blah"""
% self.get_user_dn(self.user_with_wp), attrs=["adminDescription"] )
self.assertEqual(res[0]["adminDescription"][0], "blah blah blah")
+ def test_modify_u5(self):
+ """12 test self membership"""
+ ldif = """
+dn: CN=test_modify_group2,CN=Users,""" + self.base_dn + """
+changetype: modify
+add: Member
+Member: """ + self.get_user_dn(self.user_with_sm)
+#the user has no rights granted, this should fail
+ try:
+ self.ldb_user2.modify_ldif(ldif)
+ except LdbError, (num, _):
+ self.assertEquals(num, ERR_INSUFFICIENT_ACCESS_RIGHTS)
+ else:
+ # This 'modify' operation should always throw ERR_INSUFFICIENT_ACCESS_RIGHTS
+ self.fail()
+
+#grant self-membership, should be able to add himself
+ user_sid = self.get_object_sid(self.get_user_dn(self.user_with_sm))
+ mod = "(OA;;SW;bf9679c0-0de6-11d0-a285-00aa003049e2;;%s)" % str(user_sid)
+ self.dacl_add_ace("CN=test_modify_group2,CN=Users," + self.base_dn, mod)
+ self.ldb_user2.modify_ldif(ldif)
+ res = self.ldb_admin.search( self.base_dn, expression="(distinguishedName=%s)" \
+ % ("CN=test_modify_group2,CN=Users," + self.base_dn), attrs=["Member"])
+ self.assertEqual(res[0]["Member"][0], self.get_user_dn(self.user_with_sm))
+#but not other users
+ ldif = """
+dn: CN=test_modify_group2,CN=Users,""" + self.base_dn + """
+changetype: modify
+add: Member
+Member: CN=test_modify_user2,CN=Users,""" + self.base_dn
+ try:
+ self.ldb_user2.modify_ldif(ldif)
+ except LdbError, (num, _):
+ self.assertEquals(num, ERR_INSUFFICIENT_ACCESS_RIGHTS)
+ else:
+ self.fail()
+
+ def test_modify_u6(self):
+ """13 test self membership"""
+ ldif = """
+dn: CN=test_modify_group2,CN=Users,""" + self.base_dn + """
+changetype: modify
+add: Member
+Member: """ + self.get_user_dn(self.user_with_sm) + """
+Member: CN=test_modify_user2,CN=Users,""" + self.base_dn
+
+#grant self-membership, should be able to add himself but not others at the same time
+ user_sid = self.get_object_sid(self.get_user_dn(self.user_with_sm))
+ mod = "(OA;;SW;bf9679c0-0de6-11d0-a285-00aa003049e2;;%s)" % str(user_sid)
+ self.dacl_add_ace("CN=test_modify_group2,CN=Users," + self.base_dn, mod)
+ try:
+ self.ldb_user2.modify_ldif(ldif)
+ except LdbError, (num, _):
+ self.assertEquals(num, ERR_INSUFFICIENT_ACCESS_RIGHTS)
+ else:
+ self.fail()
+
+ def test_modify_u7(self):
+ """13 User with WP modifying Member"""
+#a second user is given write property permission
+ user_sid = self.get_object_sid(self.get_user_dn(self.user_with_wp))
+ mod = "(OA;;WP;;;%s)" % str(user_sid)
+ self.dacl_add_ace("CN=test_modify_group2,CN=Users," + self.base_dn, mod)
+ ldif = """
+dn: CN=test_modify_group2,CN=Users,""" + self.base_dn + """
+changetype: modify
+add: Member
+Member: """ + self.get_user_dn(self.user_with_wp)
+ self.ldb_user.modify_ldif(ldif)
+ res = self.ldb_admin.search( self.base_dn, expression="(distinguishedName=%s)" \
+ % ("CN=test_modify_group2,CN=Users," + self.base_dn), attrs=["Member"])
+ self.assertEqual(res[0]["Member"][0], self.get_user_dn(self.user_with_wp))
+ ldif = """
+dn: CN=test_modify_group2,CN=Users,""" + self.base_dn + """
+changetype: modify
+delete: Member"""
+ self.ldb_user.modify_ldif(ldif)
+ ldif = """
+dn: CN=test_modify_group2,CN=Users,""" + self.base_dn + """
+changetype: modify
+add: Member
+Member: CN=test_modify_user2,CN=Users,""" + self.base_dn
+ self.ldb_user.modify_ldif(ldif)
+ res = self.ldb_admin.search( self.base_dn, expression="(distinguishedName=%s)" \
+ % ("CN=test_modify_group2,CN=Users," + self.base_dn), attrs=["Member"])
+ self.assertEqual(res[0]["Member"][0], "CN=test_modify_user2,CN=Users," + self.base_dn)
#enable these when we have search implemented
class AclSearchTests(AclTests):