diff options
Diffstat (limited to 'source4/dsdb')
-rw-r--r-- | source4/dsdb/common/util.c | 31 | ||||
-rw-r--r-- | source4/dsdb/samdb/ldb_modules/acl.c | 101 |
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)) { |