diff options
author | Nadezhda Ivanova <nadezhda.ivanova@postpath.com> | 2010-03-11 23:10:38 +0200 |
---|---|---|
committer | Nadezhda Ivanova <nadezhda.ivanova@postpath.com> | 2010-03-12 00:20:15 +0200 |
commit | 222b955237ed2a0d838738b4bacffc1106af2dc3 (patch) | |
tree | ac5a46114c1b21cb16c6b175efb4cb04fb6e2915 /source4 | |
parent | 24a7f8f2dbae73e862b9b3d4c6f0692054c354b3 (diff) | |
download | samba-222b955237ed2a0d838738b4bacffc1106af2dc3.tar.gz samba-222b955237ed2a0d838738b4bacffc1106af2dc3.tar.bz2 samba-222b955237ed2a0d838738b4bacffc1106af2dc3.zip |
Moved access_check_on_dn from acl module as an utility.
Made this an utility function so it can be used for access checking
outside of the acl ldb module, such as checking validated writes and
control access rights in other protocols (e. g drs)
Diffstat (limited to 'source4')
-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); |