diff options
Diffstat (limited to 'source4/dsdb')
-rw-r--r-- | source4/dsdb/common/dsdb_access.c | 181 | ||||
-rw-r--r-- | source4/dsdb/config.mk | 3 | ||||
-rw-r--r-- | source4/dsdb/samdb/ldb_modules/acl.c | 175 |
3 files changed, 202 insertions, 157 deletions
diff --git a/source4/dsdb/common/dsdb_access.c b/source4/dsdb/common/dsdb_access.c new file mode 100644 index 0000000000..1f8b795a7b --- /dev/null +++ b/source4/dsdb/common/dsdb_access.c @@ -0,0 +1,181 @@ +/* + ldb database library + + Copyright (C) Nadezhda Ivanova 2010 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +/* + * Name: dsdb_access + * + * Description: utility functions for access checking on objects + * + * Authors: Nadezhda Ivanova + */ + +#include "includes.h" +#include "events/events.h" +#include "ldb.h" +#include "ldb_errors.h" +#include "../lib/util/util_ldb.h" +#include "../lib/crypto/crypto.h" +#include "libcli/security/security.h" +#include "librpc/gen_ndr/ndr_security.h" +#include "librpc/gen_ndr/ndr_misc.h" +#include "../libds/common/flags.h" +#include "libcli/ldap/ldap_ndr.h" +#include "param/param.h" +#include "libcli/auth/libcli_auth.h" +#include "librpc/gen_ndr/ndr_drsblobs.h" +#include "system/locale.h" +#include "auth/auth.h" +#include "lib/util/tsort.h" + +void dsdb_acl_debug(struct security_descriptor *sd, + struct security_token *token, + struct ldb_dn *dn, + bool denied, + int level) +{ + if (denied) { + DEBUG(level, ("Access on %s denied", ldb_dn_get_linearized(dn))); + } else { + DEBUG(level, ("Access on %s granted", ldb_dn_get_linearized(dn))); + } + + DEBUG(level,("Security context: %s\n", + ndr_print_struct_string(0,(ndr_print_fn_t)ndr_print_security_token,"", token))); + DEBUG(level,("Security descriptor: %s\n", + ndr_print_struct_string(0,(ndr_print_fn_t)ndr_print_security_descriptor,"", sd))); +} + +int dsdb_get_sd_from_ldb_message(TALLOC_CTX *mem_ctx, + struct ldb_message *acl_res, + struct security_descriptor **sd) +{ + struct ldb_message_element *sd_element; + enum ndr_err_code ndr_err; + + sd_element = ldb_msg_find_element(acl_res, "nTSecurityDescriptor"); + if (!sd_element) { + *sd = NULL; + return LDB_SUCCESS; + } + *sd = talloc(mem_ctx, struct security_descriptor); + if(!*sd) { + return LDB_ERR_OPERATIONS_ERROR; + } + ndr_err = ndr_pull_struct_blob(&sd_element->values[0], *sd, NULL, *sd, + (ndr_pull_flags_fn_t)ndr_pull_security_descriptor); + + if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { + return LDB_ERR_OPERATIONS_ERROR; + } + + return LDB_SUCCESS; +} + +int dsdb_get_dom_sid_from_ldb_message(TALLOC_CTX *mem_ctx, + struct ldb_message *acl_res, + struct dom_sid **sid) +{ + struct ldb_message_element *sid_element; + enum ndr_err_code ndr_err; + + sid_element = ldb_msg_find_element(acl_res, "objectSid"); + if (!sid_element) { + *sid = NULL; + return LDB_SUCCESS; + } + *sid = talloc(mem_ctx, struct dom_sid); + if(!*sid) { + return LDB_ERR_OPERATIONS_ERROR; + } + ndr_err = ndr_pull_struct_blob(&sid_element->values[0], *sid, NULL, *sid, + (ndr_pull_flags_fn_t)ndr_pull_dom_sid); + + if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { + return LDB_ERR_OPERATIONS_ERROR; + } + + return LDB_SUCCESS; +} + +int dsdb_check_access_on_dn(struct ldb_context *ldb, + TALLOC_CTX *mem_ctx, + struct ldb_dn *dn, + uint32_t access, + const struct GUID *guid) +{ + int ret; + struct ldb_result *acl_res; + struct security_descriptor *sd = NULL; + struct dom_sid *sid = NULL; + struct object_tree *root = NULL; + struct object_tree *new_node = NULL; + NTSTATUS status; + uint32_t access_granted; + static const char *acl_attrs[] = { + "nTSecurityDescriptor", + "objectSid", + NULL + }; + + struct auth_session_info *session_info + = (struct auth_session_info *)ldb_get_opaque(ldb, "sessionInfo"); + if(!session_info) { + return LDB_ERR_OPERATIONS_ERROR; + } + + 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 = dsdb_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 = dsdb_get_dom_sid_from_ldb_message(mem_ctx, acl_res->msgs[0], &sid); + if (ret != LDB_SUCCESS) { + return LDB_ERR_OPERATIONS_ERROR; + } + + if (guid) { + if (!insert_in_object_tree(mem_ctx, guid, access, &root, &new_node)) { + return LDB_ERR_OPERATIONS_ERROR; + } + } + status = sec_access_check_ds(sd, session_info->security_token, + access, + &access_granted, + root, + sid); + if (!NT_STATUS_IS_OK(status)) { + dsdb_acl_debug(sd, + session_info->security_token, + dn, + true, + 10); + return LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS; + } + return LDB_SUCCESS; +} diff --git a/source4/dsdb/config.mk b/source4/dsdb/config.mk index 9a1cee979f..356f732ee3 100644 --- a/source4/dsdb/config.mk +++ b/source4/dsdb/config.mk @@ -26,7 +26,8 @@ PRIVATE_DEPENDENCIES = LIBLDB NDR_DRSBLOBS LIBCLI_LDAP_NDR UTIL_LDB LIBCLI_AUTH SAMDB_COMMON_OBJ_FILES = $(addprefix $(dsdbsrcdir)/common/, \ util.o \ - dsdb_dn.o) \ + dsdb_dn.o \ + dsdb_access.o) \ ../libds/common/flag_mapping.o $(eval $(call proto_header_template,$(dsdbsrcdir)/common/proto.h,$(SAMDB_COMMON_OBJ_FILES:.o=.c))) diff --git a/source4/dsdb/samdb/ldb_modules/acl.c b/source4/dsdb/samdb/ldb_modules/acl.c index e7665c792f..4bc8b82bdd 100644 --- a/source4/dsdb/samdb/ldb_modules/acl.c +++ b/source4/dsdb/samdb/ldb_modules/acl.c @@ -156,32 +156,6 @@ done: return ldb_next_init(module); } -static int get_sd_from_ldb_message(TALLOC_CTX *mem_ctx, - struct ldb_message *acl_res, - struct security_descriptor **sd) -{ - struct ldb_message_element *sd_element; - enum ndr_err_code ndr_err; - - sd_element = ldb_msg_find_element(acl_res, "nTSecurityDescriptor"); - if (!sd_element) { - *sd = NULL; - return LDB_SUCCESS; - } - *sd = talloc(mem_ctx, struct security_descriptor); - if(!*sd) { - return LDB_ERR_OPERATIONS_ERROR; - } - ndr_err = ndr_pull_struct_blob(&sd_element->values[0], *sd, NULL, *sd, - (ndr_pull_flags_fn_t)ndr_pull_security_descriptor); - - if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { - return LDB_ERR_OPERATIONS_ERROR; - } - - return LDB_SUCCESS; -} - static const struct GUID *get_oc_guid_from_message(struct ldb_module *module, struct ldb_message *msg) { @@ -197,106 +171,6 @@ static const struct GUID *get_oc_guid_from_message(struct ldb_module *module, (char *)oc_el->values[oc_el->num_values-1].data); } -static int get_dom_sid_from_ldb_message(TALLOC_CTX *mem_ctx, - struct ldb_message *acl_res, - struct dom_sid **sid) -{ - struct ldb_message_element *sid_element; - enum ndr_err_code ndr_err; - - sid_element = ldb_msg_find_element(acl_res, "objectSid"); - if (!sid_element) { - *sid = NULL; - return LDB_SUCCESS; - } - *sid = talloc(mem_ctx, struct dom_sid); - if(!*sid) { - return LDB_ERR_OPERATIONS_ERROR; - } - ndr_err = ndr_pull_struct_blob(&sid_element->values[0], *sid, NULL, *sid, - (ndr_pull_flags_fn_t)ndr_pull_dom_sid); - - if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { - return LDB_ERR_OPERATIONS_ERROR; - } - - return LDB_SUCCESS; -} - - -static void acl_debug(struct security_descriptor *sd, - struct security_token *token, - struct ldb_dn *dn, - bool denied, - int level) -{ - if (denied) { - DEBUG(level, ("Access on %s denied", ldb_dn_get_linearized(dn))); - } else { - DEBUG(level, ("Access on %s granted", ldb_dn_get_linearized(dn))); - } - - DEBUG(level,("Security context: %s\n", - ndr_print_struct_string(0,(ndr_print_fn_t)ndr_print_security_token,"", token))); - DEBUG(level,("Security descriptor: %s\n", - ndr_print_struct_string(0,(ndr_print_fn_t)ndr_print_security_descriptor,"", sd))); -} - -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, @@ -455,12 +329,12 @@ static int acl_allowedAttributes(struct ldb_module *module, return LDB_SUCCESS; } - ret = get_sd_from_ldb_message(mem_ctx, sd_msg, &sd); + ret = dsdb_get_sd_from_ldb_message(mem_ctx, sd_msg, &sd); if (ret != LDB_SUCCESS) { return ret; } - ret = get_dom_sid_from_ldb_message(mem_ctx, sd_msg, &sid); + ret = dsdb_get_dom_sid_from_ldb_message(mem_ctx, sd_msg, &sid); if (ret != LDB_SUCCESS) { return ret; @@ -577,11 +451,11 @@ static int acl_childClassesEffective(struct ldb_module *module, ldb_msg_remove_attr(msg, "allowedChildClassesEffective"); oc_el = ldb_msg_find_element(sd_msg, "objectClass"); - ret = get_sd_from_ldb_message(msg, sd_msg, &sd); + ret = dsdb_get_sd_from_ldb_message(msg, sd_msg, &sd); if (ret != LDB_SUCCESS) { return ret; } - ret = get_dom_sid_from_ldb_message(msg, sd_msg, &sid); + ret = dsdb_get_dom_sid_from_ldb_message(msg, sd_msg, &sid); if (ret != LDB_SUCCESS) { return ret; @@ -654,11 +528,11 @@ static int acl_sDRightsEffective(struct ldb_module *module, } else { /* Get the security descriptor from the message */ - ret = get_sd_from_ldb_message(msg, sd_msg, &sd); + ret = dsdb_get_sd_from_ldb_message(msg, sd_msg, &sd); if (ret != LDB_SUCCESS) { return ret; } - ret = get_dom_sid_from_ldb_message(msg, sd_msg, &sid); + ret = dsdb_get_dom_sid_from_ldb_message(msg, sd_msg, &sid); if (ret != LDB_SUCCESS) { return ret; @@ -702,8 +576,6 @@ static int acl_add(struct ldb_module *module, struct ldb_request *req) struct ldb_context *ldb; struct ldb_message_element *oc_el; const struct GUID *guid; - struct object_tree *root = NULL; - struct object_tree *new_node = NULL; struct ldb_control *as_system = ldb_request_get_control(req, LDB_CONTROL_AS_SYSTEM_OID); if (as_system != NULL) { @@ -734,16 +606,10 @@ static int acl_add(struct ldb_module *module, struct ldb_request *req) guid = class_schemaid_guid_by_lDAPDisplayName(dsdb_get_schema(ldb), (char *)oc_el->values[oc_el->num_values-1].data); - - if (!insert_in_object_tree(req, guid, SEC_ADS_CREATE_CHILD, &root, &new_node)) { - return LDB_ERR_OPERATIONS_ERROR; - } - - ret = check_access_on_dn(module, req, parent, SEC_ADS_CREATE_CHILD, root); + ret = dsdb_check_access_on_dn(ldb, req, parent, SEC_ADS_CREATE_CHILD, guid); if (ret != LDB_SUCCESS) { return ret; } - return ldb_next_request(module, req); } @@ -793,7 +659,7 @@ static int acl_modify(struct ldb_module *module, struct ldb_request *req) return ret; } - ret = get_sd_from_ldb_message(req, acl_res->msgs[0], &sd); + ret = dsdb_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; @@ -809,7 +675,7 @@ static int acl_modify(struct ldb_module *module, struct ldb_request *req) goto fail; } - ret = get_dom_sid_from_ldb_message(req, acl_res->msgs[0], &sid); + ret = dsdb_get_dom_sid_from_ldb_message(req, acl_res->msgs[0], &sid); if (ret != LDB_SUCCESS) { return LDB_ERR_OPERATIONS_ERROR; } @@ -862,7 +728,7 @@ static int acl_modify(struct ldb_module *module, struct ldb_request *req) 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, + dsdb_acl_debug(sd, acl_user_token(module), req->op.mod.message->dn, true, @@ -881,7 +747,7 @@ static int acl_modify(struct ldb_module *module, struct ldb_request *req) 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, + dsdb_acl_debug(sd, acl_user_token(module), req->op.mod.message->dn, true, @@ -921,7 +787,7 @@ static int acl_delete(struct ldb_module *module, struct ldb_request *req) } ldb = ldb_module_get_ctx(module); /* first check if we have delete object right */ - ret = check_access_on_dn(module, req, req->op.del.dn, SEC_STD_DELETE, NULL); + ret = dsdb_check_access_on_dn(ldb, req, req->op.del.dn, SEC_STD_DELETE, NULL); if (ret == LDB_SUCCESS) { return ldb_next_request(module, req); } @@ -935,7 +801,7 @@ static int acl_delete(struct ldb_module *module, struct ldb_request *req) return ldb_module_done(req, NULL, NULL, LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS); } - ret = check_access_on_dn(module, req, parent, SEC_ADS_DELETE_CHILD, NULL); + ret = dsdb_check_access_on_dn(ldb, req, parent, SEC_ADS_DELETE_CHILD, NULL); if (ret != LDB_SUCCESS) { return ret; } @@ -1013,7 +879,7 @@ static int acl_rename(struct ldb_module *module, struct ldb_request *req) return LDB_ERR_OPERATIONS_ERROR; }; - ret = get_sd_from_ldb_message(req, acl_res->msgs[0], &sd); + ret = dsdb_get_sd_from_ldb_message(req, acl_res->msgs[0], &sd); if (ret != LDB_SUCCESS) { return LDB_ERR_OPERATIONS_ERROR; @@ -1022,7 +888,7 @@ static int acl_rename(struct ldb_module *module, struct ldb_request *req) if (!sd) { return LDB_SUCCESS; } - ret = get_dom_sid_from_ldb_message(req, acl_res->msgs[0], &sid); + ret = dsdb_get_dom_sid_from_ldb_message(req, acl_res->msgs[0], &sid); if (ret != LDB_SUCCESS) { return LDB_ERR_OPERATIONS_ERROR; } @@ -1036,7 +902,7 @@ static int acl_rename(struct ldb_module *module, struct ldb_request *req) 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, + dsdb_acl_debug(sd, acl_user_token(module), req->op.rename.olddn, true, @@ -1066,11 +932,8 @@ static int acl_rename(struct ldb_module *module, struct ldb_request *req) 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); + + ret = dsdb_check_access_on_dn(ldb, req, newparent, SEC_ADS_CREATE_CHILD, guid); if (ret != LDB_SUCCESS) { DEBUG(10,("acl:access_denied renaming %s", ldb_dn_get_linearized(req->op.rename.olddn))); return ret; @@ -1087,7 +950,7 @@ static int acl_rename(struct ldb_module *module, struct ldb_request *req) 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); + ret = dsdb_check_access_on_dn(ldb, 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); |