s4-dsdb: handle search expressions containing extended DNs
authorAndrew Tridgell <tridge@samba.org>
Mon, 1 Aug 2011 07:48:53 +0000 (17:48 +1000)
committerAndrew Tridgell <tridge@samba.org>
Thu, 4 Aug 2011 06:17:25 +0000 (16:17 +1000)
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>

source4/dsdb/samdb/ldb_modules/extended_dn_in.c
source4/dsdb/samdb/ldb_modules/wscript_build

index 494413792c0dae21b5689a1ab1550099c6c4e0c3..6d43fb558f7eedc4f255bf9563c43c3efac4fc54 100644 (file)
@@ -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);
index 26d3019f0413cede0734917e74d2a433358c0b33..857237170fe97d5073190508b3ef3018d73b4b85 100644 (file)
@@ -179,7 +179,7 @@ bld.SAMBA_MODULE('ldb_extended_dn_in',
        init_function='ldb_extended_dn_in_module_init',
        module_init_name='ldb_init_module',
        internal_module=False,
-       deps='ldb talloc samba-util'
+       deps='ldb talloc samba-util DSDB_MODULE_HELPERS'
        )