mirror of
https://github.com/samba-team/samba.git
synced 2025-03-09 08:58:35 +03:00
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>
This commit is contained in:
parent
d4a1f6a42b
commit
7b5f0a7120
@ -33,6 +33,8 @@
|
|||||||
#include <ldb.h>
|
#include <ldb.h>
|
||||||
#include <ldb_errors.h>
|
#include <ldb_errors.h>
|
||||||
#include <ldb_module.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
|
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;
|
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)
|
static int extended_dn_in_fix(struct ldb_module *module, struct ldb_request *req, struct ldb_dn *dn)
|
||||||
{
|
{
|
||||||
struct extended_search_context *ac;
|
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;
|
bool all_partitions = false;
|
||||||
|
|
||||||
|
ret = extended_dn_fix_filter(module, req);
|
||||||
|
if (ret != LDB_SUCCESS) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
if (!ldb_dn_has_extended(dn)) {
|
if (!ldb_dn_has_extended(dn)) {
|
||||||
/* Move along there isn't anything to see here */
|
/* Move along there isn't anything to see here */
|
||||||
return ldb_next_request(module, req);
|
return ldb_next_request(module, req);
|
||||||
|
@ -179,7 +179,7 @@ bld.SAMBA_MODULE('ldb_extended_dn_in',
|
|||||||
init_function='ldb_extended_dn_in_module_init',
|
init_function='ldb_extended_dn_in_module_init',
|
||||||
module_init_name='ldb_init_module',
|
module_init_name='ldb_init_module',
|
||||||
internal_module=False,
|
internal_module=False,
|
||||||
deps='ldb talloc samba-util'
|
deps='ldb talloc samba-util DSDB_MODULE_HELPERS'
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user