df45f75265a2ae8efbafbf81c4df0c62a97f2d48
[obnox/samba/samba-obnox.git] / source4 / dsdb / samdb / ldb_modules / extended_dn_in.c
1 /* 
2    ldb database library
3
4    Copyright (C) Simo Sorce 2005-2008
5    Copyright (C) Andrew Bartlett <abartlet@samba.org> 2007-2008
6
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.
11    
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.
16    
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/>.
19 */
20
21 /*
22  *  Name: ldb
23  *
24  *  Component: ldb extended dn control module
25  *
26  *  Description: this module interprets DNs of the form <SID=S-1-2-4456> into normal DNs.
27  *
28  *  Authors: Simo Sorce
29  *           Andrew Bartlett
30  */
31
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
39 /*
40   TODO: if relax is not set then we need to reject the fancy RMD_* and
41   DELETED extended DN codes
42  */
43
44 /* search */
45 struct extended_search_context {
46         struct ldb_module *module;
47         struct ldb_request *req;
48         struct ldb_dn *basedn;
49         struct ldb_dn *dn;
50         char *wellknown_object;
51         int extended_type;
52 };
53
54 static const char *wkattr[] = {
55         "wellKnownObjects",
56         "otherWellKnownObjects",
57         NULL
58 };
59
60 static const struct ldb_module_ops ldb_extended_dn_in_openldap_module_ops;
61
62 /* An extra layer of indirection because LDB does not allow the original request to be altered */
63
64 static int extended_final_callback(struct ldb_request *req, struct ldb_reply *ares)
65 {
66         int ret = LDB_ERR_OPERATIONS_ERROR;
67         struct extended_search_context *ac;
68         ac = talloc_get_type(req->context, struct extended_search_context);
69
70         if (ares->error != LDB_SUCCESS) {
71                 ret = ldb_module_done(ac->req, ares->controls,
72                                       ares->response, ares->error);
73         } else {
74                 switch (ares->type) {
75                 case LDB_REPLY_ENTRY:
76                         
77                         ret = ldb_module_send_entry(ac->req, ares->message, ares->controls);
78                         break;
79                 case LDB_REPLY_REFERRAL:
80                         
81                         ret = ldb_module_send_referral(ac->req, ares->referral);
82                         break;
83                 case LDB_REPLY_DONE:
84                         
85                         ret = ldb_module_done(ac->req, ares->controls,
86                                               ares->response, ares->error);
87                         break;
88                 }
89         }
90         return ret;
91 }
92
93 static int extended_base_callback(struct ldb_request *req, struct ldb_reply *ares)
94 {
95         struct extended_search_context *ac;
96         struct ldb_request *down_req;
97         struct ldb_message_element *el;
98         int ret;
99         unsigned int i, j;
100         size_t wkn_len = 0;
101         char *valstr = NULL;
102         const char *found = NULL;
103
104         ac = talloc_get_type(req->context, struct extended_search_context);
105
106         if (!ares) {
107                 return ldb_module_done(ac->req, NULL, NULL,
108                                         LDB_ERR_OPERATIONS_ERROR);
109         }
110         if (ares->error != LDB_SUCCESS) {
111                 return ldb_module_done(ac->req, ares->controls,
112                                         ares->response, ares->error);
113         }
114
115         switch (ares->type) {
116         case LDB_REPLY_ENTRY:
117                 if (ac->basedn) {
118                         /* we have more than one match! This can
119                            happen as S-1-5-17 appears twice in a
120                            normal provision. We need to return
121                            NO_SUCH_OBJECT */
122                         const char *str = talloc_asprintf(req, "Duplicate base-DN matches found for '%s'",
123                                                           ldb_dn_get_extended_linearized(req, ac->dn, 1));
124                         ldb_set_errstring(ldb_module_get_ctx(ac->module), str);
125                         return ldb_module_done(ac->req, NULL, NULL,
126                                                LDB_ERR_NO_SUCH_OBJECT);
127                 }
128
129                 if (!ac->wellknown_object) {
130                         ac->basedn = talloc_steal(ac, ares->message->dn);
131                         break;
132                 }
133
134                 wkn_len = strlen(ac->wellknown_object);
135
136                 for (j=0; wkattr[j]; j++) {
137
138                         el = ldb_msg_find_element(ares->message, wkattr[j]);
139                         if (!el) {
140                                 ac->basedn = NULL;
141                                 continue;
142                         }
143
144                         for (i=0; i < el->num_values; i++) {
145                                 valstr = talloc_strndup(ac,
146                                                         (const char *)el->values[i].data,
147                                                         el->values[i].length);
148                                 if (!valstr) {
149                                         ldb_oom(ldb_module_get_ctx(ac->module));
150                                         return ldb_module_done(ac->req, NULL, NULL,
151                                                         LDB_ERR_OPERATIONS_ERROR);
152                                 }
153
154                                 if (strncasecmp(valstr, ac->wellknown_object, wkn_len) != 0) {
155                                         talloc_free(valstr);
156                                         continue;
157                                 }
158
159                                 found = &valstr[wkn_len];
160                                 break;
161                         }
162                         if (found) {
163                                 break;
164                         }
165                 }
166
167                 if (!found) {
168                         break;
169                 }
170
171                 ac->basedn = ldb_dn_new(ac, ldb_module_get_ctx(ac->module), found);
172                 talloc_free(valstr);
173                 if (!ac->basedn) {
174                         ldb_oom(ldb_module_get_ctx(ac->module));
175                         return ldb_module_done(ac->req, NULL, NULL,
176                                                LDB_ERR_OPERATIONS_ERROR);
177                 }
178
179                 break;
180
181         case LDB_REPLY_REFERRAL:
182                 break;
183
184         case LDB_REPLY_DONE:
185
186                 if (!ac->basedn) {
187                         const char *str = talloc_asprintf(req, "Base-DN '%s' not found",
188                                                           ldb_dn_get_extended_linearized(req, ac->dn, 1));
189                         ldb_set_errstring(ldb_module_get_ctx(ac->module), str);
190                         return ldb_module_done(ac->req, NULL, NULL,
191                                                LDB_ERR_NO_SUCH_OBJECT);
192                 }
193
194                 switch (ac->req->operation) {
195                 case LDB_SEARCH:
196                         ret = ldb_build_search_req_ex(&down_req,
197                                                       ldb_module_get_ctx(ac->module), ac->req,
198                                                       ac->basedn,
199                                                       ac->req->op.search.scope,
200                                                       ac->req->op.search.tree,
201                                                       ac->req->op.search.attrs,
202                                                       ac->req->controls,
203                                                       ac, extended_final_callback, 
204                                                       ac->req);
205                         LDB_REQ_SET_LOCATION(down_req);
206                         break;
207                 case LDB_ADD:
208                 {
209                         struct ldb_message *add_msg = ldb_msg_copy_shallow(ac, ac->req->op.add.message);
210                         if (!add_msg) {
211                                 ldb_oom(ldb_module_get_ctx(ac->module));
212                                 return ldb_module_done(ac->req, NULL, NULL,
213                                                        LDB_ERR_OPERATIONS_ERROR);
214                         }
215                         
216                         add_msg->dn = ac->basedn;
217
218                         ret = ldb_build_add_req(&down_req,
219                                                 ldb_module_get_ctx(ac->module), ac->req,
220                                                 add_msg, 
221                                                 ac->req->controls,
222                                                 ac, extended_final_callback, 
223                                                 ac->req);
224                         LDB_REQ_SET_LOCATION(down_req);
225                         break;
226                 }
227                 case LDB_MODIFY:
228                 {
229                         struct ldb_message *mod_msg = ldb_msg_copy_shallow(ac, ac->req->op.mod.message);
230                         if (!mod_msg) {
231                                 ldb_oom(ldb_module_get_ctx(ac->module));
232                                 return ldb_module_done(ac->req, NULL, NULL,
233                                                        LDB_ERR_OPERATIONS_ERROR);
234                         }
235                         
236                         mod_msg->dn = ac->basedn;
237
238                         ret = ldb_build_mod_req(&down_req,
239                                                 ldb_module_get_ctx(ac->module), ac->req,
240                                                 mod_msg, 
241                                                 ac->req->controls,
242                                                 ac, extended_final_callback, 
243                                                 ac->req);
244                         LDB_REQ_SET_LOCATION(down_req);
245                         break;
246                 }
247                 case LDB_DELETE:
248                         ret = ldb_build_del_req(&down_req,
249                                                 ldb_module_get_ctx(ac->module), ac->req,
250                                                 ac->basedn, 
251                                                 ac->req->controls,
252                                                 ac, extended_final_callback, 
253                                                 ac->req);
254                         LDB_REQ_SET_LOCATION(down_req);
255                         break;
256                 case LDB_RENAME:
257                         ret = ldb_build_rename_req(&down_req,
258                                                    ldb_module_get_ctx(ac->module), ac->req,
259                                                    ac->basedn, 
260                                                    ac->req->op.rename.newdn,
261                                                    ac->req->controls,
262                                                    ac, extended_final_callback, 
263                                                    ac->req);
264                         LDB_REQ_SET_LOCATION(down_req);
265                         break;
266                 default:
267                         return ldb_module_done(ac->req, NULL, NULL, LDB_ERR_OPERATIONS_ERROR);
268                 }
269                 
270                 if (ret != LDB_SUCCESS) {
271                         return ldb_module_done(ac->req, NULL, NULL, ret);
272                 }
273
274                 return ldb_next_request(ac->module, down_req);
275         }
276         talloc_free(ares);
277         return LDB_SUCCESS;
278 }
279
280
281 /*
282   windows ldap searchs don't allow a baseDN with more
283   than one extended component, or an extended
284   component and a string DN
285
286   We only enforce this over ldap, not for internal
287   use, as there are just too many places where we
288   internally want to use a DN that has come from a
289   search with extended DN enabled, or comes from a DRS
290   naming context.
291
292   Enforcing this would also make debugging samba much
293   harder, as we'd need to use ldb_dn_minimise() in a
294   lot of places, and that would lose the DN string
295   which is so useful for working out what a request is
296   for
297 */
298 static bool ldb_dn_match_allowed(struct ldb_dn *dn, struct ldb_request *req)
299 {
300         int num_components = ldb_dn_get_comp_num(dn);
301         int num_ex_components = ldb_dn_get_extended_comp_num(dn);
302
303         if (num_ex_components == 0) {
304                 return true;
305         }
306
307         if ((num_components != 0 || num_ex_components != 1) &&
308             ldb_req_is_untrusted(req)) {
309                 return false;
310         }
311         return true;
312 }
313
314
315 struct extended_dn_filter_ctx {
316         bool test_only;
317         bool matched;
318         struct ldb_module *module;
319         struct ldb_request *req;
320         struct dsdb_schema *schema;
321 };
322
323 /*
324   create a always non-matching node from a equality node
325  */
326 static void set_parse_tree_false(struct ldb_parse_tree *tree)
327 {
328         const char *attr = tree->u.equality.attr;
329         struct ldb_val value = tree->u.equality.value;
330         tree->operation = LDB_OP_EXTENDED;
331         tree->u.extended.attr = attr;
332         tree->u.extended.value = value;
333         tree->u.extended.rule_id = SAMBA_LDAP_MATCH_ALWAYS_FALSE;
334         tree->u.extended.dnAttributes = 0;
335 }
336
337 /*
338   called on all nodes in the parse tree
339  */
340 static int extended_dn_filter_callback(struct ldb_parse_tree *tree, void *private_context)
341 {
342         struct extended_dn_filter_ctx *filter_ctx;
343         int ret;
344         struct ldb_dn *dn;
345         const struct ldb_val *sid_val, *guid_val;
346         const char *no_attrs[] = { NULL };
347         struct ldb_result *res;
348         const struct dsdb_attribute *attribute;
349         bool has_extended_component;
350         enum ldb_scope scope;
351         struct ldb_dn *base_dn;
352         const char *expression;
353         uint32_t dsdb_flags;
354
355         if (tree->operation != LDB_OP_EQUALITY) {
356                 return LDB_SUCCESS;
357         }
358
359         filter_ctx = talloc_get_type_abort(private_context, struct extended_dn_filter_ctx);
360
361         if (filter_ctx->test_only && filter_ctx->matched) {
362                 /* the tree already matched */
363                 return LDB_SUCCESS;
364         }
365
366         if (!filter_ctx->schema) {
367                 /* Schema not setup yet */
368                 return LDB_SUCCESS;
369         }
370         attribute = dsdb_attribute_by_lDAPDisplayName(filter_ctx->schema, tree->u.equality.attr);
371         if (attribute == NULL) {
372                 return LDB_SUCCESS;
373         }
374
375         if (attribute->dn_format != DSDB_NORMAL_DN) {
376                 return LDB_SUCCESS;
377         }
378
379         has_extended_component = (memchr(tree->u.equality.value.data, '<',
380                                          tree->u.equality.value.length) != NULL);
381
382         /*
383          * Don't turn it into an extended DN if we're talking to OpenLDAP.
384          * We just check the module_ops pointer instead of adding a private
385          * pointer and a boolean to tell us the exact same thing.
386          */
387         if (!has_extended_component) {
388                 if (!attribute->one_way_link ||
389                     ldb_module_get_ops(filter_ctx->module) == &ldb_extended_dn_in_openldap_module_ops)
390                 return LDB_SUCCESS;
391         }
392
393         dn = ldb_dn_from_ldb_val(filter_ctx, ldb_module_get_ctx(filter_ctx->module), &tree->u.equality.value);
394         if (dn == NULL) {
395                 /* testing against windows shows that we don't raise
396                    an error here */
397                 return LDB_SUCCESS;
398         }
399
400         guid_val = ldb_dn_get_extended_component(dn, "GUID");
401         sid_val  = ldb_dn_get_extended_component(dn, "SID");
402
403         if (!guid_val && !sid_val && (attribute->searchFlags & SEARCH_FLAG_ATTINDEX)) {
404                 /* if it is indexed, then fixing the string DN will do
405                    no good here, as we will not find the attribute in
406                    the index. So for now fall through to a standard DN
407                    component comparison */
408                 return LDB_SUCCESS;
409         }
410
411         if (filter_ctx->test_only) {
412                 /* we need to copy the tree */
413                 filter_ctx->matched = true;
414                 return LDB_SUCCESS;
415         }
416
417         if (!ldb_dn_match_allowed(dn, filter_ctx->req)) {
418                 /* we need to make this element of the filter always
419                    be false */
420                 set_parse_tree_false(tree);
421                 return LDB_SUCCESS;
422         }
423
424         dsdb_flags = DSDB_FLAG_NEXT_MODULE |
425                 DSDB_FLAG_AS_SYSTEM |
426                 DSDB_SEARCH_SHOW_RECYCLED |
427                 DSDB_SEARCH_SHOW_EXTENDED_DN;
428
429         if (guid_val) {
430                 expression = talloc_asprintf(filter_ctx, "objectGUID=%s", ldb_binary_encode(filter_ctx, *guid_val));
431                 scope = LDB_SCOPE_SUBTREE;
432                 base_dn = NULL;
433                 dsdb_flags |= DSDB_SEARCH_SEARCH_ALL_PARTITIONS;
434         } else if (sid_val) {
435                 expression = talloc_asprintf(filter_ctx, "objectSID=%s", ldb_binary_encode(filter_ctx, *sid_val));
436                 scope = LDB_SCOPE_SUBTREE;
437                 base_dn = NULL;
438                 dsdb_flags |= DSDB_SEARCH_SEARCH_ALL_PARTITIONS;
439         } else {
440                 /* fallback to searching using the string DN as the base DN */
441                 expression = "objectClass=*";
442                 base_dn = dn;
443                 scope = LDB_SCOPE_BASE;
444         }
445
446         ret = dsdb_module_search(filter_ctx->module,
447                                  filter_ctx,
448                                  &res,
449                                  base_dn,
450                                  scope,
451                                  no_attrs,
452                                  dsdb_flags,
453                                  filter_ctx->req,
454                                  "%s", expression);
455         if (scope == LDB_SCOPE_BASE && ret == LDB_ERR_NO_SUCH_OBJECT) {
456                 /* note that this will need to change for multi-domain
457                    support */
458                 set_parse_tree_false(tree);
459                 return LDB_SUCCESS;
460         }
461
462         if (ret != LDB_SUCCESS) {
463                 return LDB_SUCCESS;
464         }
465
466
467         if (res->count != 1) {
468                 return LDB_SUCCESS;
469         }
470
471         /* replace the search expression element with the matching DN */
472         tree->u.equality.value.data = (uint8_t *)talloc_strdup(tree,
473                                                                ldb_dn_get_extended_linearized(tree, res->msgs[0]->dn, 1));
474         if (tree->u.equality.value.data == NULL) {
475                 return ldb_oom(ldb_module_get_ctx(filter_ctx->module));
476         }
477         tree->u.equality.value.length = strlen((const char *)tree->u.equality.value.data);
478         talloc_free(res);
479
480         filter_ctx->matched = true;
481         return LDB_SUCCESS;
482 }
483
484 /*
485   fix the parse tree to change any extended DN components to their
486   caconical form
487  */
488 static int extended_dn_fix_filter(struct ldb_module *module, struct ldb_request *req)
489 {
490         struct extended_dn_filter_ctx *filter_ctx;
491         int ret;
492
493         filter_ctx = talloc_zero(req, struct extended_dn_filter_ctx);
494         if (filter_ctx == NULL) {
495                 return ldb_module_oom(module);
496         }
497
498         /* first pass through the existing tree to see if anything
499            needs to be modified. Filtering DNs on the input side is rare,
500            so this avoids copying the parse tree in most cases */
501         filter_ctx->test_only = true;
502         filter_ctx->matched   = false;
503         filter_ctx->module    = module;
504         filter_ctx->req       = req;
505         filter_ctx->schema    = dsdb_get_schema(ldb_module_get_ctx(module), filter_ctx);
506
507         ret = ldb_parse_tree_walk(req->op.search.tree, extended_dn_filter_callback, filter_ctx);
508         if (ret != LDB_SUCCESS) {
509                 talloc_free(filter_ctx);
510                 return ret;
511         }
512
513         if (!filter_ctx->matched) {
514                 /* nothing matched, no need for a new parse tree */
515                 talloc_free(filter_ctx);
516                 return LDB_SUCCESS;
517         }
518
519         filter_ctx->test_only = false;
520         filter_ctx->matched   = false;
521
522         req->op.search.tree = ldb_parse_tree_copy_shallow(req, req->op.search.tree);
523         if (req->op.search.tree == NULL) {
524                 return ldb_oom(ldb_module_get_ctx(module));
525         }
526
527         ret = ldb_parse_tree_walk(req->op.search.tree, extended_dn_filter_callback, filter_ctx);
528         if (ret != LDB_SUCCESS) {
529                 talloc_free(filter_ctx);
530                 return ret;
531         }
532
533         talloc_free(filter_ctx);
534         return LDB_SUCCESS;
535 }
536
537 /*
538   fix DNs and filter expressions to cope with the semantics of
539   extended DNs
540  */
541 static int extended_dn_in_fix(struct ldb_module *module, struct ldb_request *req, struct ldb_dn *dn)
542 {
543         struct extended_search_context *ac;
544         struct ldb_request *down_req;
545         int ret;
546         struct ldb_dn *base_dn = NULL;
547         enum ldb_scope base_dn_scope = LDB_SCOPE_BASE;
548         const char *base_dn_filter = NULL;
549         const char * const *base_dn_attrs = NULL;
550         char *wellknown_object = NULL;
551         static const char *no_attr[] = {
552                 NULL
553         };
554         bool all_partitions = false;
555
556         if (req->operation == LDB_SEARCH) {
557                 ret = extended_dn_fix_filter(module, req);
558                 if (ret != LDB_SUCCESS) {
559                         return ret;
560                 }
561         }
562
563         if (!ldb_dn_has_extended(dn)) {
564                 /* Move along there isn't anything to see here */
565                 return ldb_next_request(module, req);
566         } else {
567                 /* It looks like we need to map the DN */
568                 const struct ldb_val *sid_val, *guid_val, *wkguid_val;
569                 uint32_t dsdb_flags = 0;
570
571                 if (!ldb_dn_match_allowed(dn, req)) {
572                         return ldb_error(ldb_module_get_ctx(module),
573                                          LDB_ERR_INVALID_DN_SYNTAX, "invalid number of DN components");
574                 }
575
576                 sid_val = ldb_dn_get_extended_component(dn, "SID");
577                 guid_val = ldb_dn_get_extended_component(dn, "GUID");
578                 wkguid_val = ldb_dn_get_extended_component(dn, "WKGUID");
579
580                 /*
581                   prioritise the GUID - we have had instances of
582                   duplicate SIDs in the database in the
583                   ForeignSecurityPrinciples due to provision errors
584                  */
585                 if (guid_val) {
586                         all_partitions = true;
587                         base_dn = NULL;
588                         base_dn_filter = talloc_asprintf(req, "(objectGUID=%s)",
589                                                          ldb_binary_encode(req, *guid_val));
590                         if (!base_dn_filter) {
591                                 return ldb_oom(ldb_module_get_ctx(module));
592                         }
593                         base_dn_scope = LDB_SCOPE_SUBTREE;
594                         base_dn_attrs = no_attr;
595
596                 } else if (sid_val) {
597                         all_partitions = true;
598                         base_dn = NULL;
599                         base_dn_filter = talloc_asprintf(req, "(objectSid=%s)",
600                                                          ldb_binary_encode(req, *sid_val));
601                         if (!base_dn_filter) {
602                                 return ldb_oom(ldb_module_get_ctx(module));
603                         }
604                         base_dn_scope = LDB_SCOPE_SUBTREE;
605                         base_dn_attrs = no_attr;
606
607                 } else if (wkguid_val) {
608                         char *wkguid_dup;
609                         char *tail_str;
610                         char *p;
611
612                         wkguid_dup = talloc_strndup(req, (char *)wkguid_val->data, wkguid_val->length);
613
614                         p = strchr(wkguid_dup, ',');
615                         if (!p) {
616                                 return ldb_error(ldb_module_get_ctx(module), LDB_ERR_INVALID_DN_SYNTAX,
617                                                  "Invalid WKGUID format");
618                         }
619
620                         p[0] = '\0';
621                         p++;
622
623                         wellknown_object = talloc_asprintf(req, "B:32:%s:", wkguid_dup);
624                         if (!wellknown_object) {
625                                 return ldb_oom(ldb_module_get_ctx(module));
626                         }
627
628                         tail_str = p;
629
630                         base_dn = ldb_dn_new(req, ldb_module_get_ctx(module), tail_str);
631                         talloc_free(wkguid_dup);
632                         if (!base_dn) {
633                                 return ldb_oom(ldb_module_get_ctx(module));
634                         }
635                         base_dn_filter = talloc_strdup(req, "(objectClass=*)");
636                         if (!base_dn_filter) {
637                                 return ldb_oom(ldb_module_get_ctx(module));
638                         }
639                         base_dn_scope = LDB_SCOPE_BASE;
640                         base_dn_attrs = wkattr;
641                 } else {
642                         return ldb_error(ldb_module_get_ctx(module), LDB_ERR_INVALID_DN_SYNTAX,
643                                          "Invalid extended DN component");
644                 }
645
646                 ac = talloc_zero(req, struct extended_search_context);
647                 if (ac == NULL) {
648                         return ldb_oom(ldb_module_get_ctx(module));
649                 }
650                 
651                 ac->module = module;
652                 ac->req = req;
653                 ac->dn = dn;
654                 ac->basedn = NULL;  /* Filled in if the search finds the DN by SID/GUID etc */
655                 ac->wellknown_object = wellknown_object;
656                 
657                 /* If the base DN was an extended DN (perhaps a well known
658                  * GUID) then search for that, so we can proceed with the original operation */
659
660                 ret = ldb_build_search_req(&down_req,
661                                            ldb_module_get_ctx(module), ac,
662                                            base_dn,
663                                            base_dn_scope,
664                                            base_dn_filter,
665                                            base_dn_attrs,
666                                            NULL,
667                                            ac, extended_base_callback,
668                                            req);
669                 LDB_REQ_SET_LOCATION(down_req);
670                 if (ret != LDB_SUCCESS) {
671                         return ldb_operr(ldb_module_get_ctx(module));
672                 }
673
674                 dsdb_flags = DSDB_FLAG_AS_SYSTEM |
675                         DSDB_SEARCH_SHOW_RECYCLED |
676                         DSDB_SEARCH_SHOW_EXTENDED_DN;
677                 if (all_partitions) {
678                         dsdb_flags |= DSDB_SEARCH_SEARCH_ALL_PARTITIONS;
679                 }
680
681                 ret = dsdb_request_add_controls(down_req, dsdb_flags);
682                 if (ret != LDB_SUCCESS) {
683                         return ret;
684                 }
685
686                 /* perform the search */
687                 return ldb_next_request(module, down_req);
688         }
689 }
690
691 static int extended_dn_in_search(struct ldb_module *module, struct ldb_request *req)
692 {
693         return extended_dn_in_fix(module, req, req->op.search.base);
694 }
695
696 static int extended_dn_in_modify(struct ldb_module *module, struct ldb_request *req)
697 {
698         return extended_dn_in_fix(module, req, req->op.mod.message->dn);
699 }
700
701 static int extended_dn_in_del(struct ldb_module *module, struct ldb_request *req)
702 {
703         return extended_dn_in_fix(module, req, req->op.del.dn);
704 }
705
706 static int extended_dn_in_rename(struct ldb_module *module, struct ldb_request *req)
707 {
708         return extended_dn_in_fix(module, req, req->op.rename.olddn);
709 }
710
711 static const struct ldb_module_ops ldb_extended_dn_in_module_ops = {
712         .name              = "extended_dn_in",
713         .search            = extended_dn_in_search,
714         .modify            = extended_dn_in_modify,
715         .del               = extended_dn_in_del,
716         .rename            = extended_dn_in_rename,
717 };
718
719 static const struct ldb_module_ops ldb_extended_dn_in_openldap_module_ops = {
720         .name              = "extended_dn_in_openldap",
721         .search            = extended_dn_in_search,
722         .modify            = extended_dn_in_modify,
723         .del               = extended_dn_in_del,
724         .rename            = extended_dn_in_rename,
725 };
726
727 int ldb_extended_dn_in_module_init(const char *version)
728 {
729         int ret;
730         LDB_MODULE_CHECK_VERSION(version);
731         ret = ldb_register_module(&ldb_extended_dn_in_openldap_module_ops);
732         if (ret != LDB_SUCCESS) {
733                 return ret;
734         }
735         return ldb_register_module(&ldb_extended_dn_in_module_ops);
736 }