s3:ntlm_auth: make logs more consistent with length check
[Samba.git] / source4 / dsdb / samdb / ldb_modules / extended_dn_in.c
blob8c6f4740ddb055d65d331955b58ceb54d358cecf
1 /*
2 ldb database library
4 Copyright (C) Simo Sorce 2005-2008
5 Copyright (C) Andrew Bartlett <abartlet@samba.org> 2007-2008
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program. If not, see <http://www.gnu.org/licenses/>.
22 * Name: ldb
24 * Component: ldb extended dn control module
26 * Description: this module interprets DNs of the form <SID=S-1-2-4456> into normal DNs.
28 * Authors: Simo Sorce
29 * Andrew Bartlett
32 #include "includes.h"
33 #include <ldb.h>
34 #include <ldb_errors.h>
35 #include <ldb_module.h>
36 #include "dsdb/samdb/samdb.h"
37 #include "dsdb/samdb/ldb_modules/util.h"
38 #include "lib/ldb-samba/ldb_matching_rules.h"
40 #undef strncasecmp
43 TODO: if relax is not set then we need to reject the fancy RMD_* and
44 DELETED extended DN codes
47 /* search */
48 struct extended_search_context {
49 struct ldb_module *module;
50 struct ldb_request *req;
51 struct ldb_parse_tree *tree;
52 struct ldb_dn *basedn;
53 struct ldb_dn *dn;
54 char *wellknown_object;
55 int extended_type;
58 static const char *wkattr[] = {
59 "wellKnownObjects",
60 "otherWellKnownObjects",
61 NULL
64 static const struct ldb_module_ops ldb_extended_dn_in_openldap_module_ops;
66 /* An extra layer of indirection because LDB does not allow the original request to be altered */
68 static int extended_final_callback(struct ldb_request *req, struct ldb_reply *ares)
70 int ret = LDB_ERR_OPERATIONS_ERROR;
71 struct extended_search_context *ac;
72 ac = talloc_get_type(req->context, struct extended_search_context);
74 if (ares->error != LDB_SUCCESS) {
75 ret = ldb_module_done(ac->req, ares->controls,
76 ares->response, ares->error);
77 } else {
78 switch (ares->type) {
79 case LDB_REPLY_ENTRY:
81 ret = ldb_module_send_entry(ac->req, ares->message, ares->controls);
82 break;
83 case LDB_REPLY_REFERRAL:
85 ret = ldb_module_send_referral(ac->req, ares->referral);
86 break;
87 case LDB_REPLY_DONE:
89 ret = ldb_module_done(ac->req, ares->controls,
90 ares->response, ares->error);
91 break;
94 return ret;
97 static int extended_base_callback(struct ldb_request *req, struct ldb_reply *ares)
99 struct extended_search_context *ac;
100 struct ldb_request *down_req;
101 struct ldb_message_element *el;
102 int ret;
103 unsigned int i, j;
104 size_t wkn_len = 0;
105 char *valstr = NULL;
106 const char *found = NULL;
108 ac = talloc_get_type(req->context, struct extended_search_context);
110 if (!ares) {
111 return ldb_module_done(ac->req, NULL, NULL,
112 LDB_ERR_OPERATIONS_ERROR);
114 if (ares->error != LDB_SUCCESS) {
115 return ldb_module_done(ac->req, ares->controls,
116 ares->response, ares->error);
119 switch (ares->type) {
120 case LDB_REPLY_ENTRY:
121 if (ac->basedn) {
122 /* we have more than one match! This can
123 happen as S-1-5-17 appears twice in a
124 normal provision. We need to return
125 NO_SUCH_OBJECT */
126 const char *str = talloc_asprintf(req, "Duplicate base-DN matches found for '%s'",
127 ldb_dn_get_extended_linearized(req, ac->dn, 1));
128 ldb_set_errstring(ldb_module_get_ctx(ac->module), str);
129 return ldb_module_done(ac->req, NULL, NULL,
130 LDB_ERR_NO_SUCH_OBJECT);
133 if (!ac->wellknown_object) {
134 ac->basedn = talloc_steal(ac, ares->message->dn);
135 break;
138 wkn_len = strlen(ac->wellknown_object);
140 for (j=0; wkattr[j]; j++) {
142 el = ldb_msg_find_element(ares->message, wkattr[j]);
143 if (!el) {
144 ac->basedn = NULL;
145 continue;
148 for (i=0; i < el->num_values; i++) {
149 valstr = talloc_strndup(ac,
150 (const char *)el->values[i].data,
151 el->values[i].length);
152 if (!valstr) {
153 ldb_oom(ldb_module_get_ctx(ac->module));
154 return ldb_module_done(ac->req, NULL, NULL,
155 LDB_ERR_OPERATIONS_ERROR);
158 if (strncasecmp(valstr, ac->wellknown_object, wkn_len) != 0) {
159 talloc_free(valstr);
160 continue;
163 found = &valstr[wkn_len];
164 break;
166 if (found) {
167 break;
171 if (!found) {
172 break;
175 ac->basedn = ldb_dn_new(ac, ldb_module_get_ctx(ac->module), found);
176 talloc_free(valstr);
177 if (!ac->basedn) {
178 ldb_oom(ldb_module_get_ctx(ac->module));
179 return ldb_module_done(ac->req, NULL, NULL,
180 LDB_ERR_OPERATIONS_ERROR);
183 break;
185 case LDB_REPLY_REFERRAL:
186 break;
188 case LDB_REPLY_DONE:
190 if (!ac->basedn) {
191 const char *str = talloc_asprintf(req, "Base-DN '%s' not found",
192 ldb_dn_get_extended_linearized(req, ac->dn, 1));
193 ldb_set_errstring(ldb_module_get_ctx(ac->module), str);
194 return ldb_module_done(ac->req, NULL, NULL,
195 LDB_ERR_NO_SUCH_OBJECT);
198 switch (ac->req->operation) {
199 case LDB_SEARCH:
200 ret = ldb_build_search_req_ex(&down_req,
201 ldb_module_get_ctx(ac->module), ac->req,
202 ac->basedn,
203 ac->req->op.search.scope,
204 ac->tree,
205 ac->req->op.search.attrs,
206 ac->req->controls,
207 ac, extended_final_callback,
208 ac->req);
209 LDB_REQ_SET_LOCATION(down_req);
210 break;
211 case LDB_ADD:
213 struct ldb_message *add_msg = ldb_msg_copy_shallow(ac, ac->req->op.add.message);
214 if (!add_msg) {
215 ldb_oom(ldb_module_get_ctx(ac->module));
216 return ldb_module_done(ac->req, NULL, NULL,
217 LDB_ERR_OPERATIONS_ERROR);
220 add_msg->dn = ac->basedn;
222 ret = ldb_build_add_req(&down_req,
223 ldb_module_get_ctx(ac->module), ac->req,
224 add_msg,
225 ac->req->controls,
226 ac, extended_final_callback,
227 ac->req);
228 LDB_REQ_SET_LOCATION(down_req);
229 break;
231 case LDB_MODIFY:
233 struct ldb_message *mod_msg = ldb_msg_copy_shallow(ac, ac->req->op.mod.message);
234 if (!mod_msg) {
235 ldb_oom(ldb_module_get_ctx(ac->module));
236 return ldb_module_done(ac->req, NULL, NULL,
237 LDB_ERR_OPERATIONS_ERROR);
240 mod_msg->dn = ac->basedn;
242 ret = ldb_build_mod_req(&down_req,
243 ldb_module_get_ctx(ac->module), ac->req,
244 mod_msg,
245 ac->req->controls,
246 ac, extended_final_callback,
247 ac->req);
248 LDB_REQ_SET_LOCATION(down_req);
249 break;
251 case LDB_DELETE:
252 ret = ldb_build_del_req(&down_req,
253 ldb_module_get_ctx(ac->module), ac->req,
254 ac->basedn,
255 ac->req->controls,
256 ac, extended_final_callback,
257 ac->req);
258 LDB_REQ_SET_LOCATION(down_req);
259 break;
260 case LDB_RENAME:
261 ret = ldb_build_rename_req(&down_req,
262 ldb_module_get_ctx(ac->module), ac->req,
263 ac->basedn,
264 ac->req->op.rename.newdn,
265 ac->req->controls,
266 ac, extended_final_callback,
267 ac->req);
268 LDB_REQ_SET_LOCATION(down_req);
269 break;
270 default:
271 return ldb_module_done(ac->req, NULL, NULL, LDB_ERR_OPERATIONS_ERROR);
274 if (ret != LDB_SUCCESS) {
275 return ldb_module_done(ac->req, NULL, NULL, ret);
278 return ldb_next_request(ac->module, down_req);
280 talloc_free(ares);
281 return LDB_SUCCESS;
286 windows ldap searches don't allow a baseDN with more
287 than one extended component, or an extended
288 component and a string DN
290 We only enforce this over ldap, not for internal
291 use, as there are just too many places where we
292 internally want to use a DN that has come from a
293 search with extended DN enabled, or comes from a DRS
294 naming context.
296 Enforcing this would also make debugging samba much
297 harder, as we'd need to use ldb_dn_minimise() in a
298 lot of places, and that would lose the DN string
299 which is so useful for working out what a request is
302 static bool ldb_dn_match_allowed(struct ldb_dn *dn, struct ldb_request *req)
304 int num_components = ldb_dn_get_comp_num(dn);
305 int num_ex_components = ldb_dn_get_extended_comp_num(dn);
307 if (num_ex_components == 0) {
308 return true;
311 if ((num_components != 0 || num_ex_components != 1) &&
312 ldb_req_is_untrusted(req)) {
313 return false;
315 return true;
319 struct extended_dn_filter_ctx {
320 bool test_only;
321 bool matched;
322 struct ldb_module *module;
323 struct ldb_request *req;
324 struct dsdb_schema *schema;
325 uint32_t dsdb_flags;
329 create a always non-matching node from a equality node
331 static void set_parse_tree_false(struct ldb_parse_tree *tree)
333 const char *attr = tree->u.equality.attr;
334 struct ldb_val value = tree->u.equality.value;
335 tree->operation = LDB_OP_EXTENDED;
336 tree->u.extended.attr = attr;
337 tree->u.extended.value = value;
338 tree->u.extended.rule_id = SAMBA_LDAP_MATCH_ALWAYS_FALSE;
339 tree->u.extended.dnAttributes = 0;
343 called on all nodes in the parse tree
345 static int extended_dn_filter_callback(struct ldb_parse_tree *tree, void *private_context)
347 struct extended_dn_filter_ctx *filter_ctx;
348 int ret;
349 struct ldb_dn *dn = NULL;
350 const struct ldb_val *sid_val, *guid_val;
351 const char *no_attrs[] = { NULL };
352 struct ldb_result *res;
353 const struct dsdb_attribute *attribute = NULL;
354 bool has_extended_component = false;
355 enum ldb_scope scope;
356 struct ldb_dn *base_dn;
357 const char *expression;
358 uint32_t dsdb_flags;
360 if (tree->operation != LDB_OP_EQUALITY && tree->operation != LDB_OP_EXTENDED) {
361 return LDB_SUCCESS;
364 filter_ctx = talloc_get_type_abort(private_context, struct extended_dn_filter_ctx);
366 if (filter_ctx->test_only && filter_ctx->matched) {
367 /* the tree already matched */
368 return LDB_SUCCESS;
371 if (!filter_ctx->schema) {
372 /* Schema not setup yet */
373 return LDB_SUCCESS;
375 if (tree->operation == LDB_OP_EQUALITY) {
376 attribute = dsdb_attribute_by_lDAPDisplayName(filter_ctx->schema, tree->u.equality.attr);
377 } else if (tree->operation == LDB_OP_EXTENDED) {
378 attribute = dsdb_attribute_by_lDAPDisplayName(filter_ctx->schema, tree->u.extended.attr);
380 if (attribute == NULL) {
381 return LDB_SUCCESS;
384 if (attribute->dn_format != DSDB_NORMAL_DN) {
385 return LDB_SUCCESS;
388 if (tree->operation == LDB_OP_EQUALITY) {
389 has_extended_component = (memchr(tree->u.equality.value.data, '<',
390 tree->u.equality.value.length) != NULL);
391 } else if (tree->operation == LDB_OP_EXTENDED) {
392 has_extended_component = (memchr(tree->u.extended.value.data, '<',
393 tree->u.extended.value.length) != NULL);
397 * Don't turn it into an extended DN if we're talking to OpenLDAP.
398 * We just check the module_ops pointer instead of adding a private
399 * pointer and a boolean to tell us the exact same thing.
401 if (!has_extended_component) {
402 if (!attribute->one_way_link) {
403 return LDB_SUCCESS;
406 if (ldb_module_get_ops(filter_ctx->module) == &ldb_extended_dn_in_openldap_module_ops) {
407 return LDB_SUCCESS;
411 if (tree->operation == LDB_OP_EQUALITY) {
412 dn = ldb_dn_from_ldb_val(filter_ctx, ldb_module_get_ctx(filter_ctx->module), &tree->u.equality.value);
413 } else if (tree->operation == LDB_OP_EXTENDED
414 && (strcmp(tree->u.extended.rule_id, SAMBA_LDAP_MATCH_RULE_TRANSITIVE_EVAL) == 0)) {
415 dn = ldb_dn_from_ldb_val(filter_ctx, ldb_module_get_ctx(filter_ctx->module), &tree->u.extended.value);
417 if (dn == NULL) {
418 /* testing against windows shows that we don't raise
419 an error here */
420 return LDB_SUCCESS;
423 guid_val = ldb_dn_get_extended_component(dn, "GUID");
424 sid_val = ldb_dn_get_extended_component(dn, "SID");
427 * Is the attribute indexed? By treating confidential attributes
428 * as unindexed, we force searches to go through the unindexed
429 * search path, avoiding observable timing differences.
431 if (!guid_val && !sid_val &&
432 (attribute->searchFlags & SEARCH_FLAG_ATTINDEX) &&
433 !(attribute->searchFlags & SEARCH_FLAG_CONFIDENTIAL))
435 /* if it is indexed, then fixing the string DN will do
436 no good here, as we will not find the attribute in
437 the index. So for now fall through to a standard DN
438 component comparison */
439 return LDB_SUCCESS;
442 if (filter_ctx->test_only) {
443 /* we need to copy the tree */
444 filter_ctx->matched = true;
445 return LDB_SUCCESS;
448 if (!ldb_dn_match_allowed(dn, filter_ctx->req)) {
449 /* we need to make this element of the filter always
450 be false */
451 set_parse_tree_false(tree);
452 return LDB_SUCCESS;
455 dsdb_flags = filter_ctx->dsdb_flags | DSDB_FLAG_NEXT_MODULE;
457 if (guid_val) {
458 expression = talloc_asprintf(filter_ctx, "objectGUID=%s", ldb_binary_encode(filter_ctx, *guid_val));
459 scope = LDB_SCOPE_SUBTREE;
460 base_dn = NULL;
461 dsdb_flags |= DSDB_SEARCH_SEARCH_ALL_PARTITIONS;
462 } else if (sid_val) {
463 expression = talloc_asprintf(filter_ctx, "objectSID=%s", ldb_binary_encode(filter_ctx, *sid_val));
464 scope = LDB_SCOPE_SUBTREE;
465 base_dn = NULL;
466 dsdb_flags |= DSDB_SEARCH_SEARCH_ALL_PARTITIONS;
467 } else {
468 /* fallback to searching using the string DN as the base DN */
469 expression = "objectClass=*";
470 base_dn = dn;
471 scope = LDB_SCOPE_BASE;
474 ret = dsdb_module_search(filter_ctx->module,
475 filter_ctx,
476 &res,
477 base_dn,
478 scope,
479 no_attrs,
480 dsdb_flags,
481 filter_ctx->req,
482 "%s", expression);
483 if (scope == LDB_SCOPE_BASE && ret == LDB_ERR_NO_SUCH_OBJECT) {
484 /* note that this will need to change for multi-domain
485 support */
486 set_parse_tree_false(tree);
487 return LDB_SUCCESS;
490 if (ret != LDB_SUCCESS) {
491 return LDB_SUCCESS;
495 if (res->count != 1) {
496 return LDB_SUCCESS;
499 /* replace the search expression element with the matching DN */
500 if (tree->operation == LDB_OP_EQUALITY) {
501 tree->u.equality.value.data =
502 (uint8_t *)talloc_strdup(tree, ldb_dn_get_extended_linearized(tree, res->msgs[0]->dn, 1));
503 if (tree->u.equality.value.data == NULL) {
504 return ldb_oom(ldb_module_get_ctx(filter_ctx->module));
506 tree->u.equality.value.length = strlen((const char *)tree->u.equality.value.data);
507 } else if (tree->operation == LDB_OP_EXTENDED) {
508 tree->u.extended.value.data =
509 (uint8_t *)talloc_strdup(tree, ldb_dn_get_extended_linearized(tree, res->msgs[0]->dn, 1));
510 if (tree->u.extended.value.data == NULL) {
511 return ldb_oom(ldb_module_get_ctx(filter_ctx->module));
513 tree->u.extended.value.length = strlen((const char *)tree->u.extended.value.data);
515 talloc_free(res);
517 filter_ctx->matched = true;
518 return LDB_SUCCESS;
522 fix the parse tree to change any extended DN components to their
523 canonical form
525 static int extended_dn_fix_filter(struct ldb_module *module,
526 struct ldb_request *req,
527 uint32_t default_dsdb_flags,
528 struct ldb_parse_tree **down_tree)
530 struct extended_dn_filter_ctx *filter_ctx;
531 int ret;
533 *down_tree = NULL;
535 filter_ctx = talloc_zero(req, struct extended_dn_filter_ctx);
536 if (filter_ctx == NULL) {
537 return ldb_module_oom(module);
540 /* first pass through the existing tree to see if anything
541 needs to be modified. Filtering DNs on the input side is rare,
542 so this avoids copying the parse tree in most cases */
543 filter_ctx->test_only = true;
544 filter_ctx->matched = false;
545 filter_ctx->module = module;
546 filter_ctx->req = req;
547 filter_ctx->schema = dsdb_get_schema(ldb_module_get_ctx(module), filter_ctx);
548 filter_ctx->dsdb_flags= default_dsdb_flags;
550 ret = ldb_parse_tree_walk(req->op.search.tree, extended_dn_filter_callback, filter_ctx);
551 if (ret != LDB_SUCCESS) {
552 talloc_free(filter_ctx);
553 return ret;
556 if (!filter_ctx->matched) {
557 /* nothing matched, no need for a new parse tree */
558 talloc_free(filter_ctx);
559 return LDB_SUCCESS;
562 filter_ctx->test_only = false;
563 filter_ctx->matched = false;
565 *down_tree = ldb_parse_tree_copy_shallow(req, req->op.search.tree);
566 if (*down_tree == NULL) {
567 return ldb_oom(ldb_module_get_ctx(module));
570 ret = ldb_parse_tree_walk(*down_tree, extended_dn_filter_callback, filter_ctx);
571 if (ret != LDB_SUCCESS) {
572 talloc_free(filter_ctx);
573 return ret;
576 talloc_free(filter_ctx);
577 return LDB_SUCCESS;
581 fix DNs and filter expressions to cope with the semantics of
582 extended DNs
584 static int extended_dn_in_fix(struct ldb_module *module, struct ldb_request *req, struct ldb_dn *dn)
586 struct extended_search_context *ac;
587 struct ldb_request *down_req = NULL;
588 struct ldb_parse_tree *down_tree = NULL;
589 int ret;
590 struct ldb_dn *base_dn = NULL;
591 enum ldb_scope base_dn_scope = LDB_SCOPE_BASE;
592 const char *base_dn_filter = NULL;
593 const char * const *base_dn_attrs = NULL;
594 char *wellknown_object = NULL;
595 static const char *no_attr[] = {
596 NULL
598 uint32_t dsdb_flags = DSDB_FLAG_AS_SYSTEM | DSDB_SEARCH_SHOW_EXTENDED_DN;
600 if (ldb_request_get_control(req, LDB_CONTROL_SHOW_DELETED_OID)) {
601 dsdb_flags |= DSDB_SEARCH_SHOW_DELETED;
603 if (ldb_request_get_control(req, LDB_CONTROL_SHOW_RECYCLED_OID)) {
604 dsdb_flags |= DSDB_SEARCH_SHOW_RECYCLED;
606 if (ldb_request_get_control(req, DSDB_CONTROL_DBCHECK)) {
607 dsdb_flags |= DSDB_SEARCH_SHOW_RECYCLED;
610 if (req->operation == LDB_SEARCH) {
611 ret = extended_dn_fix_filter(module, req, dsdb_flags, &down_tree);
612 if (ret != LDB_SUCCESS) {
613 return ret;
617 if (!ldb_dn_has_extended(dn)) {
618 /* Move along there isn't anything to see here */
619 if (down_tree == NULL) {
620 down_req = req;
621 } else {
622 ret = ldb_build_search_req_ex(&down_req,
623 ldb_module_get_ctx(module), req,
624 req->op.search.base,
625 req->op.search.scope,
626 down_tree,
627 req->op.search.attrs,
628 req->controls,
629 req, dsdb_next_callback,
630 req);
631 if (ret != LDB_SUCCESS) {
632 return ret;
634 LDB_REQ_SET_LOCATION(down_req);
637 return ldb_next_request(module, down_req);
638 } else {
639 /* It looks like we need to map the DN */
640 const struct ldb_val *sid_val, *guid_val, *wkguid_val;
642 if (!ldb_dn_match_allowed(dn, req)) {
643 return ldb_error(ldb_module_get_ctx(module),
644 LDB_ERR_INVALID_DN_SYNTAX, "invalid number of DN components");
647 sid_val = ldb_dn_get_extended_component(dn, "SID");
648 guid_val = ldb_dn_get_extended_component(dn, "GUID");
649 wkguid_val = ldb_dn_get_extended_component(dn, "WKGUID");
652 prioritise the GUID - we have had instances of
653 duplicate SIDs in the database in the
654 ForeignSecurityPrincipals due to provision errors
656 if (guid_val) {
657 dsdb_flags |= DSDB_SEARCH_SEARCH_ALL_PARTITIONS;
658 base_dn = NULL;
659 base_dn_filter = talloc_asprintf(req, "(objectGUID=%s)",
660 ldb_binary_encode(req, *guid_val));
661 if (!base_dn_filter) {
662 return ldb_oom(ldb_module_get_ctx(module));
664 base_dn_scope = LDB_SCOPE_SUBTREE;
665 base_dn_attrs = no_attr;
667 } else if (sid_val) {
668 dsdb_flags |= DSDB_SEARCH_SEARCH_ALL_PARTITIONS;
669 base_dn = NULL;
670 base_dn_filter = talloc_asprintf(req, "(objectSid=%s)",
671 ldb_binary_encode(req, *sid_val));
672 if (!base_dn_filter) {
673 return ldb_oom(ldb_module_get_ctx(module));
675 base_dn_scope = LDB_SCOPE_SUBTREE;
676 base_dn_attrs = no_attr;
678 } else if (wkguid_val) {
679 char *wkguid_dup;
680 char *tail_str;
681 char *p;
683 wkguid_dup = talloc_strndup(req, (char *)wkguid_val->data, wkguid_val->length);
685 p = strchr(wkguid_dup, ',');
686 if (!p) {
687 return ldb_error(ldb_module_get_ctx(module), LDB_ERR_INVALID_DN_SYNTAX,
688 "Invalid WKGUID format");
691 p[0] = '\0';
692 p++;
694 wellknown_object = talloc_asprintf(req, "B:32:%s:", wkguid_dup);
695 if (!wellknown_object) {
696 return ldb_oom(ldb_module_get_ctx(module));
699 tail_str = p;
701 base_dn = ldb_dn_new(req, ldb_module_get_ctx(module), tail_str);
702 talloc_free(wkguid_dup);
703 if (!base_dn) {
704 return ldb_oom(ldb_module_get_ctx(module));
706 base_dn_filter = talloc_strdup(req, "(objectClass=*)");
707 if (!base_dn_filter) {
708 return ldb_oom(ldb_module_get_ctx(module));
710 base_dn_scope = LDB_SCOPE_BASE;
711 base_dn_attrs = wkattr;
712 } else {
713 return ldb_error(ldb_module_get_ctx(module), LDB_ERR_INVALID_DN_SYNTAX,
714 "Invalid extended DN component");
717 ac = talloc_zero(req, struct extended_search_context);
718 if (ac == NULL) {
719 return ldb_oom(ldb_module_get_ctx(module));
722 ac->module = module;
723 ac->req = req;
724 ac->tree = (down_tree != NULL) ? down_tree : req->op.search.tree;
725 ac->dn = dn;
726 ac->basedn = NULL; /* Filled in if the search finds the DN by SID/GUID etc */
727 ac->wellknown_object = wellknown_object;
729 /* If the base DN was an extended DN (perhaps a well known
730 * GUID) then search for that, so we can proceed with the original operation */
732 ret = ldb_build_search_req(&down_req,
733 ldb_module_get_ctx(module), ac,
734 base_dn,
735 base_dn_scope,
736 base_dn_filter,
737 base_dn_attrs,
738 NULL,
739 ac, extended_base_callback,
740 req);
741 LDB_REQ_SET_LOCATION(down_req);
742 if (ret != LDB_SUCCESS) {
743 return ldb_operr(ldb_module_get_ctx(module));
746 ret = dsdb_request_add_controls(down_req, dsdb_flags);
747 if (ret != LDB_SUCCESS) {
748 return ret;
751 /* perform the search */
752 return ldb_next_request(module, down_req);
756 static int extended_dn_in_search(struct ldb_module *module, struct ldb_request *req)
758 return extended_dn_in_fix(module, req, req->op.search.base);
761 static int extended_dn_in_modify(struct ldb_module *module, struct ldb_request *req)
763 return extended_dn_in_fix(module, req, req->op.mod.message->dn);
766 static int extended_dn_in_del(struct ldb_module *module, struct ldb_request *req)
768 return extended_dn_in_fix(module, req, req->op.del.dn);
771 static int extended_dn_in_rename(struct ldb_module *module, struct ldb_request *req)
773 return extended_dn_in_fix(module, req, req->op.rename.olddn);
776 static const struct ldb_module_ops ldb_extended_dn_in_module_ops = {
777 .name = "extended_dn_in",
778 .search = extended_dn_in_search,
779 .modify = extended_dn_in_modify,
780 .del = extended_dn_in_del,
781 .rename = extended_dn_in_rename,
784 static const struct ldb_module_ops ldb_extended_dn_in_openldap_module_ops = {
785 .name = "extended_dn_in_openldap",
786 .search = extended_dn_in_search,
787 .modify = extended_dn_in_modify,
788 .del = extended_dn_in_del,
789 .rename = extended_dn_in_rename,
792 int ldb_extended_dn_in_module_init(const char *version)
794 int ret;
795 LDB_MODULE_CHECK_VERSION(version);
796 ret = ldb_register_module(&ldb_extended_dn_in_openldap_module_ops);
797 if (ret != LDB_SUCCESS) {
798 return ret;
800 return ldb_register_module(&ldb_extended_dn_in_module_ops);