diff options
author | Andrew Bartlett <abartlet@samba.org> | 2017-06-13 15:23:14 +1200 |
---|---|---|
committer | Andrew Bartlett <abartlet@samba.org> | 2017-06-16 07:39:24 +0200 |
commit | aafc1c28289933e05d7434c79c0dda2caef0fde8 (patch) | |
tree | a15cb4cbbb93493cc20e4dcf7953c9e73077822d | |
parent | f7bcf7b972044ae0749e567a16d222d218ffaf5f (diff) | |
download | samba-aafc1c28289933e05d7434c79c0dda2caef0fde8.tar.gz |
dsdb: Remember the last ACL we read during a search and what it expanded to
It may well be the same as the next one we need to check, so we can
avoid parsing it again.
Signed-off-by: Andrew Bartlett <abartlet@samba.org>
Reviewed-by: Douglas Bagnall <douglas.bagnall@catalyst.net.nz>
Autobuild-User(master): Andrew Bartlett <abartlet@samba.org>
Autobuild-Date(master): Fri Jun 16 07:39:24 CEST 2017 on sn-devel-144
-rw-r--r-- | source4/dsdb/samdb/ldb_modules/acl_read.c | 83 |
1 files changed, 81 insertions, 2 deletions
diff --git a/source4/dsdb/samdb/ldb_modules/acl_read.c b/source4/dsdb/samdb/ldb_modules/acl_read.c index 6a85b6865b4..3c9cf7c0672 100644 --- a/source4/dsdb/samdb/ldb_modules/acl_read.c +++ b/source4/dsdb/samdb/ldb_modules/acl_read.c @@ -58,6 +58,10 @@ struct aclread_context { struct aclread_private { bool enabled; + + /* cache of the last SD we read during any search */ + struct security_descriptor *sd_cached; + struct ldb_val sd_cached_blob; }; static void aclread_mark_inaccesslible(struct ldb_message_element *el) { @@ -149,6 +153,81 @@ static int aclread_check_parent(struct aclread_context *ac, return ret; } +/* + * The sd returned from this function is valid until the next call on + * this module context + * + * This helper function uses a cache on the module private data to + * speed up repeated use of the same SD. + */ + +static int aclread_get_sd_from_ldb_message(struct aclread_context *ac, + struct ldb_message *acl_res, + struct security_descriptor **sd) +{ + struct ldb_message_element *sd_element; + struct ldb_context *ldb = ldb_module_get_ctx(ac->module); + struct aclread_private *private_data + = talloc_get_type(ldb_module_get_private(ac->module), + struct aclread_private); + enum ndr_err_code ndr_err; + + sd_element = ldb_msg_find_element(acl_res, "nTSecurityDescriptor"); + if (sd_element == NULL) { + return ldb_error(ldb, LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS, + "nTSecurityDescriptor is missing"); + } + + if (sd_element->num_values != 1) { + return ldb_operr(ldb); + } + + /* + * The time spent in ndr_pull_security_descriptor() is quite + * expensive, so we check if this is the same binary blob as last + * time, and if so return the memory tree from that previous parse. + */ + + if (private_data->sd_cached != NULL && + private_data->sd_cached_blob.data != NULL && + ldb_val_equal_exact(&sd_element->values[0], + &private_data->sd_cached_blob)) { + *sd = private_data->sd_cached; + return LDB_SUCCESS; + } + + *sd = talloc(private_data, struct security_descriptor); + if(!*sd) { + return ldb_oom(ldb); + } + ndr_err = ndr_pull_struct_blob(&sd_element->values[0], *sd, *sd, + (ndr_pull_flags_fn_t)ndr_pull_security_descriptor); + + if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { + TALLOC_FREE(*sd); + return ldb_operr(ldb); + } + + talloc_unlink(private_data, private_data->sd_cached_blob.data); + if (ac->added_nTSecurityDescriptor) { + private_data->sd_cached_blob = sd_element->values[0]; + talloc_steal(private_data, sd_element->values[0].data); + } else { + private_data->sd_cached_blob = ldb_val_dup(private_data, + &sd_element->values[0]); + if (private_data->sd_cached_blob.data == NULL) { + TALLOC_FREE(*sd); + return ldb_operr(ldb); + } + } + + talloc_unlink(private_data, private_data->sd_cached); + private_data->sd_cached = *sd; + + return LDB_SUCCESS; +} + + static int aclread_callback(struct ldb_request *req, struct ldb_reply *ares) { struct ldb_context *ldb; @@ -157,7 +236,7 @@ static int aclread_callback(struct ldb_request *req, struct ldb_reply *ares) struct ldb_message *msg; int ret, num_of_attrs = 0; unsigned int i, k = 0; - struct security_descriptor *sd; + struct security_descriptor *sd = NULL; struct dom_sid *sid = NULL; TALLOC_CTX *tmp_ctx; uint32_t instanceType; @@ -176,7 +255,7 @@ static int aclread_callback(struct ldb_request *req, struct ldb_reply *ares) switch (ares->type) { case LDB_REPLY_ENTRY: msg = ares->message; - ret = dsdb_get_sd_from_ldb_message(ldb, tmp_ctx, msg, &sd); + ret = aclread_get_sd_from_ldb_message(ac, msg, &sd); if (ret != LDB_SUCCESS) { ldb_debug_set(ldb, LDB_DEBUG_FATAL, "acl_read: cannot get descriptor of %s: %s\n", |