static int check_access_on_dn(struct ldb_module *module, TALLOC_CTX *mem_ctx, struct ldb_dn *dn, uint32_t access, struct object_tree *tree) { int ret; struct ldb_context *ldb = ldb_module_get_ctx(module); struct ldb_result *acl_res; struct security_descriptor *sd = NULL; struct dom_sid *sid = NULL; NTSTATUS status; uint32_t access_granted; static const char *acl_attrs[] = { "nTSecurityDescriptor", "objectSid", NULL }; ret = ldb_search(ldb, mem_ctx, &acl_res, dn, LDB_SCOPE_BASE, acl_attrs, NULL); /* we sould be able to find the parent */ if (ret != LDB_SUCCESS) { DEBUG(10,("acl: failed to find object %s\n", ldb_dn_get_linearized(dn))); return ret; } ret = get_sd_from_ldb_message(mem_ctx, acl_res->msgs[0], &sd); if (ret != LDB_SUCCESS) { return LDB_ERR_OPERATIONS_ERROR; } /* Theoretically we pass the check if the object has no sd */ if (!sd) { return LDB_SUCCESS; } ret = get_dom_sid_from_ldb_message(mem_ctx, acl_res->msgs[0], &sid); if (ret != LDB_SUCCESS) { return LDB_ERR_OPERATIONS_ERROR; } status = sec_access_check_ds(sd, acl_user_token(module), access, &access_granted, tree, sid); if (!NT_STATUS_IS_OK(status)) { acl_debug(sd, acl_user_token(module), dn, true, 10); return LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS; } return LDB_SUCCESS; }
static 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, struct dsdb_attribute *attr) { int ret; NTSTATUS status; uint32_t access_granted; struct object_tree *root = NULL; struct object_tree *new_node = NULL; TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx); struct security_token *token = acl_user_token(module); if (attr) { if (!GUID_all_zero(&attr->attributeSecurityGUID)) { if (!insert_in_object_tree(tmp_ctx, &attr->attributeSecurityGUID, access, &root, &new_node)) { DEBUG(10, ("acl_search: cannot add to object tree securityGUID\n")); goto fail; } if (!insert_in_object_tree(tmp_ctx, &attr->schemaIDGUID, access, &new_node, &new_node)) { DEBUG(10, ("acl_search: cannot add to object tree attributeGUID\n")); goto fail; } } else { if (!insert_in_object_tree(tmp_ctx, &attr->schemaIDGUID, access, &root, &new_node)) { DEBUG(10, ("acl_search: cannot add to object tree attributeGUID\n")); goto fail; } } } status = sec_access_check_ds(sd, token, access, &access_granted, root, rp_sid); if (!NT_STATUS_IS_OK(status)) { ret = LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS; } else { ret = LDB_SUCCESS; } return ret; fail: return LDB_ERR_OPERATIONS_ERROR; }
static int acl_check_access_on_class(struct ldb_module *module, TALLOC_CTX *mem_ctx, struct security_descriptor *sd, struct dom_sid *rp_sid, uint32_t access, const char *class_name) { int ret; struct ldb_context *ldb = ldb_module_get_ctx(module); NTSTATUS status; uint32_t access_granted; struct object_tree *root = NULL; struct object_tree *new_node = NULL; struct GUID *guid; const struct dsdb_schema *schema = dsdb_get_schema(ldb); TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx); struct security_token *token = acl_user_token(module); if (class_name) { guid = class_schemaid_guid_by_lDAPDisplayName(schema, class_name); if (!guid) { DEBUG(10, ("acl_search: cannot find class %s\n", class_name)); goto fail; } if (!insert_in_object_tree(tmp_ctx, guid, access, &root, &new_node)) { DEBUG(10, ("acl_search: cannot add to object tree guid\n")); goto fail; } } status = sec_access_check_ds(sd, token, access, &access_granted, root, rp_sid); if (!NT_STATUS_IS_OK(status)) { ret = LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS; } else { ret = LDB_SUCCESS; } return ret; fail: return LDB_ERR_OPERATIONS_ERROR; }
int dsdb_check_access_on_dn_internal(struct ldb_context *ldb, struct ldb_result *acl_res, TALLOC_CTX *mem_ctx, struct security_token *token, struct ldb_dn *dn, uint32_t access_mask, const struct GUID *guid) { struct security_descriptor *sd = NULL; struct dom_sid *sid = NULL; struct object_tree *root = NULL; NTSTATUS status; uint32_t access_granted; int ret; ret = dsdb_get_sd_from_ldb_message(ldb, mem_ctx, acl_res->msgs[0], &sd); if (ret != LDB_SUCCESS) { return ldb_operr(ldb); } sid = samdb_result_dom_sid(mem_ctx, acl_res->msgs[0], "objectSid"); if (guid) { if (!insert_in_object_tree(mem_ctx, guid, access_mask, NULL, &root)) { return ldb_operr(ldb); } } status = sec_access_check_ds(sd, token, access_mask, &access_granted, root, sid); if (!NT_STATUS_IS_OK(status)) { dsdb_acl_debug(sd, token, dn, true, 10); ldb_asprintf_errstring(ldb, "dsdb_access: Access check failed on %s", ldb_dn_get_linearized(dn)); return LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS; } return LDB_SUCCESS; }
static int acl_rename(struct ldb_module *module, struct ldb_request *req) { int ret; struct ldb_dn *oldparent = ldb_dn_get_parent(req, req->op.rename.olddn); struct ldb_dn *newparent = ldb_dn_get_parent(req, req->op.rename.newdn); struct ldb_context *ldb; struct security_descriptor *sd = NULL; struct dom_sid *sid = NULL; struct ldb_result *acl_res; const struct GUID *guid; struct object_tree *root = NULL; struct object_tree *new_node = NULL; TALLOC_CTX *tmp_ctx = talloc_new(req); NTSTATUS status; uint32_t access_granted; static const char *acl_attrs[] = { "nTSecurityDescriptor", "objectClass", "objectSid", NULL }; DEBUG(10, ("ldb:acl_rename: %s\n", ldb_dn_get_linearized(req->op.rename.olddn))); if (what_is_user(module) == SECURITY_SYSTEM) { return ldb_next_request(module, req); } if (ldb_dn_is_special(req->op.rename.olddn)) { return ldb_next_request(module, req); } ldb = ldb_module_get_ctx(module); /* TODO search to include deleted objects */ ret = ldb_search(ldb, req, &acl_res, req->op.rename.olddn, LDB_SCOPE_BASE, acl_attrs, NULL); /* we sould be able to find the parent */ if (ret != LDB_SUCCESS) { DEBUG(10,("acl: failed to find object %s\n", ldb_dn_get_linearized(req->op.rename.olddn))); return ret; } guid = get_oc_guid_from_message(module,acl_res->msgs[0]); if (!insert_in_object_tree(tmp_ctx, guid, SEC_ADS_WRITE_PROP, &root, &new_node)) { return LDB_ERR_OPERATIONS_ERROR; }; guid = attribute_schemaid_guid_by_lDAPDisplayName(dsdb_get_schema(ldb), "name"); if (!insert_in_object_tree(tmp_ctx, guid, SEC_ADS_WRITE_PROP, &new_node, &new_node)) { return LDB_ERR_OPERATIONS_ERROR; }; ret = get_sd_from_ldb_message(req, acl_res->msgs[0], &sd); if (ret != LDB_SUCCESS) { return LDB_ERR_OPERATIONS_ERROR; } /* Theoretically we pass the check if the object has no sd */ if (!sd) { return LDB_SUCCESS; } ret = get_dom_sid_from_ldb_message(req, acl_res->msgs[0], &sid); if (ret != LDB_SUCCESS) { return LDB_ERR_OPERATIONS_ERROR; } status = sec_access_check_ds(sd, acl_user_token(module), SEC_ADS_WRITE_PROP, &access_granted, root, sid); if (!NT_STATUS_IS_OK(status)) { DEBUG(10, ("Object %s nas no wp on name\n", ldb_dn_get_linearized(req->op.rename.olddn))); acl_debug(sd, acl_user_token(module), req->op.rename.olddn, true, 10); return LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS; } if (ldb_dn_compare(oldparent, newparent) == 0) { /* regular rename, not move, nothing more to do */ return ldb_next_request(module, req); } /* What exactly to do in this case? It would fail anyway.. */ if ((ldb_dn_compare(req->op.rename.newdn, (ldb_get_schema_basedn(ldb))) == 0) || (ldb_dn_compare(req->op.rename.newdn, (ldb_get_config_basedn(ldb))) == 0) || (ldb_dn_compare(req->op.rename.newdn, (ldb_get_root_basedn(ldb))) == 0)) { DEBUG(10,("acl:moving as an NC\n")); return LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS; } /* new parent should have create child */ talloc_free(tmp_ctx); tmp_ctx = talloc_new(req); root = NULL; new_node = NULL; guid = get_oc_guid_from_message(module,acl_res->msgs[0]); if (!guid) { DEBUG(10,("acl:renamed object has no object class\n")); return ldb_module_done(req, NULL, NULL, LDB_ERR_OPERATIONS_ERROR); } if (!insert_in_object_tree(tmp_ctx, guid, SEC_ADS_CREATE_CHILD, &root, &new_node)) { return LDB_ERR_OPERATIONS_ERROR; } ret = check_access_on_dn(module, req, newparent, SEC_ADS_CREATE_CHILD, root); if (ret != LDB_SUCCESS) { DEBUG(10,("acl:access_denied renaming %s", ldb_dn_get_linearized(req->op.rename.olddn))); return ret; } /* do we have delete object on the object? */ status = sec_access_check_ds(sd, acl_user_token(module), SEC_STD_DELETE, &access_granted, NULL, sid); if (NT_STATUS_IS_OK(status)) { return ldb_next_request(module, req); } /* what about delete child on the current parent */ ret = check_access_on_dn(module, req, oldparent, SEC_ADS_DELETE_CHILD, NULL); if (ret != LDB_SUCCESS) { DEBUG(10,("acl:access_denied renaming %s", ldb_dn_get_linearized(req->op.rename.olddn))); return ldb_module_done(req, NULL, NULL, ret); } return ldb_next_request(module, req); }
static int acl_modify(struct ldb_module *module, struct ldb_request *req) { int ret; struct ldb_context *ldb = ldb_module_get_ctx(module); const struct dsdb_schema *schema = dsdb_get_schema(ldb); int i; bool modify_sd = false; const struct GUID *guid; uint32_t access_granted; struct object_tree *root = NULL; struct object_tree *new_node = NULL; NTSTATUS status; struct ldb_result *acl_res; struct security_descriptor *sd; struct dom_sid *sid = NULL; TALLOC_CTX *tmp_ctx = talloc_new(req); static const char *acl_attrs[] = { "nTSecurityDescriptor", "objectClass", "objectSid", NULL }; /* Don't print this debug statement if elements[0].name is going to be NULL */ if(req->op.mod.message->num_elements > 0) { DEBUG(10, ("ldb:acl_modify: %s\n", req->op.mod.message->elements[0].name)); } if (what_is_user(module) == SECURITY_SYSTEM) { return ldb_next_request(module, req); } if (ldb_dn_is_special(req->op.mod.message->dn)) { return ldb_next_request(module, req); } ret = ldb_search(ldb, req, &acl_res, req->op.mod.message->dn, LDB_SCOPE_BASE, acl_attrs, NULL); if (ret != LDB_SUCCESS) { return ret; } ret = get_sd_from_ldb_message(req, acl_res->msgs[0], &sd); if (ret != LDB_SUCCESS) { DEBUG(10, ("acl_modify: cannot get descriptor\n")); return ret; } /* Theoretically we pass the check if the object has no sd */ if (!sd) { return LDB_SUCCESS; } guid = get_oc_guid_from_message(module,acl_res->msgs[0]); if (!guid) { DEBUG(10, ("acl_modify: cannot get guid\n")); goto fail; } ret = get_dom_sid_from_ldb_message(req, acl_res->msgs[0], &sid); if (ret != LDB_SUCCESS) { return LDB_ERR_OPERATIONS_ERROR; } if (!insert_in_object_tree(tmp_ctx, guid, SEC_ADS_WRITE_PROP, &root, &new_node)) { DEBUG(10, ("acl_modify: cannot add to object tree\n")); goto fail; } for (i=0; i < req->op.mod.message->num_elements; i++){ const struct dsdb_attribute *attr; /* clearTextPassword is not in schema */ if (strcmp("clearTextPassword", req->op.mod.message->elements[i].name) == 0) { attr = dsdb_attribute_by_lDAPDisplayName(schema, "unicodePwd"); } else { attr = dsdb_attribute_by_lDAPDisplayName(schema, req->op.mod.message->elements[i].name); } if (strcmp("nTSecurityDescriptor", req->op.mod.message->elements[i].name) == 0) { modify_sd = true; } else { if (!attr) { DEBUG(10, ("acl_modify: cannot find attribute %s\n", req->op.mod.message->elements[i].name)); goto fail; } if (!insert_in_object_tree(tmp_ctx, &attr->attributeSecurityGUID, SEC_ADS_WRITE_PROP, &new_node, &new_node)) { DEBUG(10, ("acl_modify: cannot add to object tree securityGUID\n")); goto fail; } if (!insert_in_object_tree(tmp_ctx, &attr->schemaIDGUID, SEC_ADS_WRITE_PROP, &new_node, &new_node)) { DEBUG(10, ("acl_modify: cannot add to object tree attributeGUID\n")); goto fail; } } } if (root->num_of_children > 0) { status = sec_access_check_ds(sd, acl_user_token(module), SEC_ADS_WRITE_PROP, &access_granted, root, sid); if (!NT_STATUS_IS_OK(status)) { DEBUG(10, ("Object %s nas no write property access\n", ldb_dn_get_linearized(req->op.mod.message->dn))); acl_debug(sd, acl_user_token(module), req->op.mod.message->dn, true, 10); talloc_free(tmp_ctx); return LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS; } } if (modify_sd) { status = sec_access_check_ds(sd, acl_user_token(module), SEC_STD_WRITE_DAC, &access_granted, NULL, sid); if (!NT_STATUS_IS_OK(status)) { DEBUG(10, ("Object %s nas no write dacl access\n", ldb_dn_get_linearized(req->op.mod.message->dn))); acl_debug(sd, acl_user_token(module), req->op.mod.message->dn, true, 10); talloc_free(tmp_ctx); return LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS; } } talloc_free(tmp_ctx); return ldb_next_request(module, req); fail: talloc_free(tmp_ctx); return LDB_ERR_OPERATIONS_ERROR; }