summaryrefslogtreecommitdiff
path: root/source4/dsdb/samdb/ldb_modules/extended_dn_in.c
diff options
context:
space:
mode:
authorAndrew Tridgell <tridge@samba.org>2011-08-01 17:48:53 +1000
committerAndrew Tridgell <tridge@samba.org>2011-08-04 16:17:25 +1000
commit7b5f0a7120c91989976d2f946ad1af9d6dc934c7 (patch)
treece41b7b66aeaea1bc58981ee479a4ae158a17ff7 /source4/dsdb/samdb/ldb_modules/extended_dn_in.c
parentd4a1f6a42b06a5d63a789cad438cfde693df24a7 (diff)
downloadsamba-7b5f0a7120c91989976d2f946ad1af9d6dc934c7.tar.gz
samba-7b5f0a7120c91989976d2f946ad1af9d6dc934c7.tar.bz2
samba-7b5f0a7120c91989976d2f946ad1af9d6dc934c7.zip
s4-dsdb: handle search expressions containing extended DNs
this allows for searches like member=<SID=S-1-2-3> Pair-Programmed-With: Andrew Bartlett <abartlet@samba.org> Pair-Programmed-With: Amitay Isaacs <amitay@gmail.com>
Diffstat (limited to 'source4/dsdb/samdb/ldb_modules/extended_dn_in.c')
-rw-r--r--source4/dsdb/samdb/ldb_modules/extended_dn_in.c166
1 files changed, 166 insertions, 0 deletions
diff --git a/source4/dsdb/samdb/ldb_modules/extended_dn_in.c b/source4/dsdb/samdb/ldb_modules/extended_dn_in.c
index 494413792c..6d43fb558f 100644
--- a/source4/dsdb/samdb/ldb_modules/extended_dn_in.c
+++ b/source4/dsdb/samdb/ldb_modules/extended_dn_in.c
@@ -33,6 +33,8 @@
#include <ldb.h>
#include <ldb_errors.h>
#include <ldb_module.h>
+#include "dsdb/samdb/samdb.h"
+#include "util.h"
/*
TODO: if relax is not set then we need to reject the fancy RMD_* and
@@ -261,6 +263,165 @@ static int extended_base_callback(struct ldb_request *req, struct ldb_reply *are
return LDB_SUCCESS;
}
+
+struct extended_dn_filter_ctx {
+ bool test_only;
+ bool matched;
+ struct ldb_module *module;
+ struct ldb_request *req;
+ struct dsdb_schema *schema;
+};
+
+/*
+ called on all nodes in the parse tree
+ */
+static int extended_dn_filter_callback(struct ldb_parse_tree *tree, void *private_context)
+{
+ struct extended_dn_filter_ctx *filter_ctx;
+ int ret;
+ struct ldb_dn *dn;
+ const struct ldb_val *sid_val, *guid_val;
+ const char *no_attrs[] = { NULL };
+ struct ldb_result *res;
+ const char *expression;
+ const struct dsdb_attribute *attribute;
+
+ if (tree->operation != LDB_OP_EQUALITY) {
+ return LDB_SUCCESS;
+ }
+
+ filter_ctx = talloc_get_type_abort(private_context, struct extended_dn_filter_ctx);
+
+ attribute = dsdb_attribute_by_lDAPDisplayName(filter_ctx->schema, tree->u.equality.attr);
+ if (attribute == NULL) {
+ return LDB_SUCCESS;
+ }
+
+ if (attribute->dn_format != DSDB_NORMAL_DN) {
+ return LDB_SUCCESS;
+ }
+
+ /* add one_way_link check here */
+
+
+ if (memchr(tree->u.equality.value.data, '<', tree->u.equality.value.length) == NULL) {
+ /* its definately not a magic DN */
+ return LDB_SUCCESS;
+ }
+
+ dn = ldb_dn_from_ldb_val(filter_ctx, ldb_module_get_ctx(filter_ctx->module), &tree->u.equality.value);
+ if (dn == NULL) {
+ /* testing against windows shows that we don't raise
+ an error here */
+ return LDB_SUCCESS;
+ }
+
+ sid_val = ldb_dn_get_extended_component(dn, "SID");
+ guid_val = ldb_dn_get_extended_component(dn, "GUID");
+
+ if (sid_val == NULL && guid_val == NULL) {
+ return LDB_SUCCESS;
+ }
+
+ if (filter_ctx->test_only) {
+ filter_ctx->matched = true;
+ return LDB_SUCCESS;
+ }
+
+
+ /*
+ prioritise the GUID - we have had instances of
+ duplicate SIDs in the database in the
+ ForeignSecurityPrinciples due to provision errors
+ */
+ if (guid_val) {
+ expression = talloc_asprintf(filter_ctx, "objectGUID=%s", ldb_binary_encode(filter_ctx, *guid_val));
+ } else {
+ expression = talloc_asprintf(filter_ctx, "objectSID=%s", ldb_binary_encode(filter_ctx, *sid_val));
+ }
+
+ ret = dsdb_module_search(filter_ctx->module,
+ filter_ctx,
+ &res,
+ NULL,
+ LDB_SCOPE_SUBTREE,
+ no_attrs,
+ DSDB_FLAG_NEXT_MODULE |
+ DSDB_SEARCH_SHOW_DELETED |
+ DSDB_SEARCH_SEARCH_ALL_PARTITIONS,
+ filter_ctx->req,
+ "%s", expression);
+ if (ret != LDB_SUCCESS) {
+ return LDB_SUCCESS;
+ }
+ if (res->count != 1) {
+ return LDB_SUCCESS;
+ }
+
+ /* replace the search expression element with the matching DN */
+ tree->u.equality.value.data = (uint8_t *)talloc_strdup(tree, ldb_dn_get_linearized(res->msgs[0]->dn));
+ if (tree->u.equality.value.data == NULL) {
+ return ldb_oom(ldb_module_get_ctx(filter_ctx->module));
+ }
+ tree->u.equality.value.length = strlen((const char *)tree->u.equality.value.data);
+ talloc_free(res);
+
+ filter_ctx->matched = true;
+ return LDB_SUCCESS;
+}
+
+/*
+ fix the parse tree to change any extended DN components to their
+ caconical form
+ */
+static int extended_dn_fix_filter(struct ldb_module *module, struct ldb_request *req)
+{
+ struct extended_dn_filter_ctx *filter_ctx;
+ int ret;
+
+ filter_ctx = talloc_zero(req, struct extended_dn_filter_ctx);
+ if (filter_ctx == NULL) {
+ return ldb_module_oom(module);
+ }
+
+ /* first pass through the existing tree to see if anything
+ needs to be modified. Filtering DNs on the input side is rare,
+ so this avoids copying the parse tree in most cases */
+ filter_ctx->test_only = true;
+ filter_ctx->matched = false;
+ filter_ctx->module = module;
+ filter_ctx->req = req;
+ filter_ctx->schema = dsdb_get_schema(ldb_module_get_ctx(module), filter_ctx);
+
+ ret = ldb_parse_tree_walk(req->op.search.tree, extended_dn_filter_callback, filter_ctx);
+ if (ret != LDB_SUCCESS) {
+ talloc_free(filter_ctx);
+ return ret;
+ }
+
+ if (!filter_ctx->matched) {
+ /* nothing matched, no need for a new parse tree */
+ talloc_free(filter_ctx);
+ return LDB_SUCCESS;
+ }
+
+ filter_ctx->test_only = false;
+ filter_ctx->matched = false;
+
+ ret = ldb_parse_tree_walk(req->op.search.tree, extended_dn_filter_callback, filter_ctx);
+ if (ret != LDB_SUCCESS) {
+ talloc_free(filter_ctx);
+ return ret;
+ }
+
+ talloc_free(filter_ctx);
+ return LDB_SUCCESS;
+}
+
+/*
+ fix DNs and filter expressions to cope with the semantics of
+ extended DNs
+ */
static int extended_dn_in_fix(struct ldb_module *module, struct ldb_request *req, struct ldb_dn *dn)
{
struct extended_search_context *ac;
@@ -280,6 +441,11 @@ static int extended_dn_in_fix(struct ldb_module *module, struct ldb_request *req
};
bool all_partitions = false;
+ ret = extended_dn_fix_filter(module, req);
+ if (ret != LDB_SUCCESS) {
+ return ret;
+ }
+
if (!ldb_dn_has_extended(dn)) {
/* Move along there isn't anything to see here */
return ldb_next_request(module, req);