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