summaryrefslogtreecommitdiff
path: root/source4/dsdb
diff options
context:
space:
mode:
Diffstat (limited to 'source4/dsdb')
-rw-r--r--source4/dsdb/common/util.c31
-rw-r--r--source4/dsdb/samdb/ldb_modules/acl.c101
2 files changed, 131 insertions, 1 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)) {