diff options
-rw-r--r-- | source4/dsdb/samdb/ldb_modules/acl_read.c | 307 | ||||
-rw-r--r-- | source4/dsdb/samdb/ldb_modules/config.mk | 11 | ||||
-rw-r--r-- | source4/dsdb/samdb/ldb_modules/samba_dsdb.c | 1 | ||||
-rw-r--r-- | source4/dsdb/samdb/ldb_modules/wscript_build | 8 |
4 files changed, 327 insertions, 0 deletions
diff --git a/source4/dsdb/samdb/ldb_modules/acl_read.c b/source4/dsdb/samdb/ldb_modules/acl_read.c new file mode 100644 index 0000000000..49d9095d1c --- /dev/null +++ b/source4/dsdb/samdb/ldb_modules/acl_read.c @@ -0,0 +1,307 @@ +/* + ldb database library + + Copyright (C) Simo Sorce 2006-2008 + 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: ldb + * + * Component: ldb ACL Read module + * + * Description: Module that performs authorisation access checks on read requests + * Only DACL checks implemented at this point + * + * Author: Nadezhda Ivanova + */ + +#include "includes.h" +#include "ldb_module.h" +#include "auth/auth.h" +#include "libcli/security/security.h" +#include "dsdb/samdb/samdb.h" +#include "librpc/gen_ndr/ndr_security.h" +#include "param/param.h" +#include "dsdb/samdb/ldb_modules/util.h" + + +struct aclread_context { + struct ldb_module *module; + struct ldb_request *req; + const char * const *attrs; + const struct dsdb_schema *schema; +}; + +struct aclread_private { + bool enabled; +}; + +static int aclread_callback(struct ldb_request *req, struct ldb_reply *ares) +{ + struct ldb_context *ldb; + struct aclread_context *ac; + struct ldb_result *acl_res; + struct ldb_message_element *parent; + static const char *acl_attrs[] = { + "nTSecurityDescriptor", + "objectSid", + "parentGUID", + NULL + }; + int i, ret; + struct security_descriptor *sd; + struct dom_sid *sid = NULL; + TALLOC_CTX *tmp_ctx; + ac = talloc_get_type(req->context, struct aclread_context); + ldb = ldb_module_get_ctx(ac->module); + if (!ares) { + return ldb_module_done(ac->req, NULL, NULL, LDB_ERR_OPERATIONS_ERROR ); + } + if (ares->error != LDB_SUCCESS) { + return ldb_module_done(ac->req, ares->controls, + ares->response, ares->error); + } + tmp_ctx = talloc_new(ac); + switch (ares->type) { + case LDB_REPLY_ENTRY: + ret = dsdb_module_search_dn(ac->module, tmp_ctx, &acl_res, ares->message->dn, + acl_attrs, + DSDB_FLAG_NEXT_MODULE | + DSDB_SEARCH_SHOW_DELETED); + if (ret != LDB_SUCCESS) { + goto fail; + } + ret = dsdb_get_sd_from_ldb_message(ldb, tmp_ctx, acl_res->msgs[0], &sd); + if (ret != LDB_SUCCESS) { + DEBUG(10, ("acl_read: cannot get descriptor\n")); + ret = LDB_ERR_OPERATIONS_ERROR; + goto fail; + } + sid = samdb_result_dom_sid(tmp_ctx, acl_res->msgs[0], "objectSid"); + /* get the parent guid */ + parent = ldb_msg_find_element(acl_res->msgs[0], "parentGUID"); + if (parent) { + /* the object has a parent, so we have to check for visibility */ + struct GUID parent_guid = samdb_result_guid(acl_res->msgs[0], "parentGUID"); + ret = dsdb_module_check_access_on_guid(ac->module, + tmp_ctx, + &parent_guid, + SEC_ADS_LIST, + NULL); + if (ret == LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS) { + talloc_free(tmp_ctx); + return LDB_SUCCESS; + } else if (ret != LDB_SUCCESS) { + goto fail; + } + } + /* for every element in the message check RP */ + i = 0; + while (i < ares->message->num_elements) { + char *p, *new_attr; + const struct dsdb_attribute *attr; + p = strchr(ares->message->elements[i].name, ';'); + if (!p) { + attr = dsdb_attribute_by_lDAPDisplayName(ac->schema, + ares->message->elements[i].name); + } else { + new_attr = talloc_strndup(tmp_ctx, + ares->message->elements[i].name, + (size_t)(p -ares->message->elements[i].name)); + if (!new_attr) { + ldb_oom(ldb); + ret = LDB_ERR_OPERATIONS_ERROR; + goto fail; + } + attr = dsdb_attribute_by_lDAPDisplayName(ac->schema, + new_attr); + talloc_free(new_attr); + } + + if (!attr) { + DEBUG(2, ("acl_read: cannot find attribute %s in schema\n", + ares->message->elements[i].name)); + ret = LDB_ERR_OPERATIONS_ERROR; + goto fail; + } + /* nTSecurityDescriptor is a special case */ + if (ldb_attr_cmp("nTSecurityDescriptor", + ares->message->elements[i].name) == 0) { + ret = acl_check_access_on_attribute(ac->module, + tmp_ctx, + sd, + sid, + SEC_FLAG_SYSTEM_SECURITY, + attr); + } else { + ret = acl_check_access_on_attribute(ac->module, + tmp_ctx, + sd, + sid, + SEC_ADS_READ_PROP, + attr); + } + if (ret == LDB_SUCCESS) { + i++; + } else if (ret == LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS) { + /* do not return this entry if attribute is + part of the search filter */ + if (dsdb_attr_in_parse_tree(ac->req->op.search.tree, + ares->message->elements[i].name)) { + talloc_free(tmp_ctx); + return LDB_SUCCESS; + } + ldb_msg_remove_attr(ares->message, ares->message->elements[i].name); + } else { + goto fail; + } + } + talloc_free(tmp_ctx); + return ldb_module_send_entry(ac->req, ares->message, ares->controls); + case LDB_REPLY_REFERRAL: + return ldb_module_send_referral(ac->req, ares->referral); + case LDB_REPLY_DONE: + return ldb_module_done(ac->req, ares->controls, + ares->response, LDB_SUCCESS); + + } + return LDB_SUCCESS; +fail: + talloc_free(tmp_ctx); + return ldb_module_done(ac->req, NULL, NULL, ret); +} + + +static int aclread_search(struct ldb_module *module, struct ldb_request *req) +{ + struct ldb_context *ldb; + int ret; + bool block_anonymous; + struct aclread_context *ac; + struct ldb_request *down_req; + struct ldb_control *as_system = ldb_request_get_control(req, LDB_CONTROL_AS_SYSTEM_OID); + struct ldb_control *apply_access = ldb_request_get_control(req, DSDB_CONTROL_SEARCH_APPLY_ACCESS); + struct auth_session_info *session_info; + struct ldb_result *res; + struct ldb_message_element *parent; + struct aclread_private *p; + static const char *acl_attrs[] = { + "parentGUID", + NULL + }; + ldb = ldb_module_get_ctx(module); + p = talloc_get_type(ldb_module_get_private(module), struct aclread_private); + if (apply_access != NULL) { + apply_access->critical = 0; + } + /* skip access checks if we are system or system control is supplied + * or this is not LDAP server request */ + if (!p || !p->enabled || + dsdb_module_am_system(module) + || as_system || !apply_access) { + return ldb_next_request(module, req); + } + /* no checks on special dn */ + if (ldb_dn_is_special(req->op.search.base)) { + return ldb_next_request(module, req); + } + /* allow all access to rootDSE */ + if (req->op.search.scope == LDB_SCOPE_BASE && ldb_dn_is_null(req->op.search.base)) { + return ldb_next_request(module, req); + } + + session_info = (struct auth_session_info *)ldb_get_opaque(ldb, "sessionInfo"); + if (session_info && security_token_is_anonymous(session_info->security_token)) { + block_anonymous = dsdb_block_anonymous_ops(module, req); + if (block_anonymous) { + return ldb_error(ldb, LDB_ERR_OPERATIONS_ERROR, + "This request is not allowed to an anonymous connection."); + } + } + + /* check accessibility of base */ + if (!ldb_dn_is_null(req->op.search.base)) { + ret = dsdb_module_search_dn(module, req, &res, req->op.search.base, + acl_attrs, + DSDB_FLAG_NEXT_MODULE | + DSDB_SEARCH_SHOW_DELETED); + if (ret != LDB_SUCCESS) { + return ldb_error(ldb, ret, + "acl_read: Error retrieving SD for base."); + } + + parent = ldb_msg_find_element(res->msgs[0], "parentGUID"); + if (parent) { + /* the object has a parent, so we have to check for visibility */ + struct GUID parent_guid = samdb_result_guid(res->msgs[0], "parentGUID"); + ret = dsdb_module_check_access_on_guid(module, + req, + &parent_guid, + SEC_ADS_LIST, + NULL); + if (ret == LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS) { + return ldb_module_done(req, NULL, NULL, LDB_ERR_NO_SUCH_OBJECT); + } else if (ret != LDB_SUCCESS) { + return ldb_module_done(req, NULL, NULL, ret); + } + } + } + ac = talloc_zero(req, struct aclread_context); + if (ac == NULL) { + return ldb_oom(ldb); + } + ac->module = module; + ac->req = req; + ac->schema = dsdb_get_schema(ldb, req); + if (!ac->schema) { + return ldb_operr(ldb); + } + + ret = ldb_build_search_req_ex(&down_req, + ldb, ac, + req->op.search.base, + req->op.search.scope, + req->op.search.tree, + req->op.search.attrs, + req->controls, + ac, aclread_callback, + req); + + if (ret != LDB_SUCCESS) { + return LDB_ERR_OPERATIONS_ERROR; + } + + return ldb_next_request(module, down_req); +} + +static int aclread_init(struct ldb_module *module) +{ + struct ldb_context *ldb = ldb_module_get_ctx(module); + struct aclread_private *p = talloc_zero(module, struct aclread_private); + if (p == NULL) { + return ldb_module_oom(module); + } + p->enabled = lpcfg_parm_bool(ldb_get_opaque(ldb, "loadparm"), NULL, "acl", "search", false); + ldb_module_set_private(module, p); + return ldb_next_init(module); +} + +_PUBLIC_ const struct ldb_module_ops ldb_aclread_module_ops = { + .name = "aclread", + .search = aclread_search, + .init_context = aclread_init +}; diff --git a/source4/dsdb/samdb/ldb_modules/config.mk b/source4/dsdb/samdb/ldb_modules/config.mk index 93ce5645b7..442481fc6b 100644 --- a/source4/dsdb/samdb/ldb_modules/config.mk +++ b/source4/dsdb/samdb/ldb_modules/config.mk @@ -452,3 +452,14 @@ INIT_FUNCTION = LDB_MODULE(validate_update) ################################################ ldb_validate_update_OBJ_FILES = $(dsdbsrcdir)/samdb/ldb_modules/validate_update.o + +################################################ +# Start MODULE ldb_aclread +[MODULE::ldb_aclread] +PRIVATE_DEPENDENCIES = LIBTALLOC LIBEVENTS LIBSECURITY SAMDB +SUBSYSTEM = LIBLDB +INIT_FUNCTION = LDB_MODULE(aclread) +# End MODULE ldb_acl +################################################ + +ldb_acl_OBJ_FILES = $(dsdbsrcdir)/samdb/ldb_modules/acl_read.o diff --git a/source4/dsdb/samdb/ldb_modules/samba_dsdb.c b/source4/dsdb/samdb/ldb_modules/samba_dsdb.c index 1c5abbe23e..4d0f9465b0 100644 --- a/source4/dsdb/samdb/ldb_modules/samba_dsdb.c +++ b/source4/dsdb/samdb/ldb_modules/samba_dsdb.c @@ -164,6 +164,7 @@ static int samba_dsdb_init(struct ldb_module *module) */ static const char *modules_list[] = {"resolve_oids", "rootdse", + "aclread", "lazy_commit", "paged_results", "ranged_results", diff --git a/source4/dsdb/samdb/ldb_modules/wscript_build b/source4/dsdb/samdb/ldb_modules/wscript_build index f6b5c28456..e455ae9249 100644 --- a/source4/dsdb/samdb/ldb_modules/wscript_build +++ b/source4/dsdb/samdb/ldb_modules/wscript_build @@ -331,3 +331,11 @@ bld.SAMBA_MODULE('ldb_lazy_commit', init_function='LDB_MODULE(lazy_commit)', deps='SAMDB' ) + +bld.SAMBA_MODULE('ldb_aclread', + source='acl_read.c', + subsystem='ldb', + init_function='LDB_MODULE(aclread)', + internal_module=not bld.CONFIG_SET('USING_SYSTEM_LDB'), + deps='talloc LIBEVENTS LIBSECURITY SAMDB' + ) |