dsdb/modules/linked_attrs: remove pointless check (CID 240768)
[samba.git] / source4 / dsdb / samdb / ldb_modules / linked_attributes.c
1 /*
2    ldb database library
3
4    Copyright (C) Andrew Bartlett <abartlet@samba.org> 2007
5    Copyright (C) Simo Sorce <idra@samba.org> 2008
6    Copyright (C) Matthieu Patou <mat@matws.net> 2011
7    Copyright (C) Andrew Tridgell 2009
8
9    This program is free software; you can redistribute it and/or modify
10    it under the terms of the GNU General Public License as published by
11    the Free Software Foundation; either version 3 of the License, or
12    (at your option) any later version.
13
14    This program is distributed in the hope that it will be useful,
15    but WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17    GNU General Public License for more details.
18
19    You should have received a copy of the GNU General Public License
20    along with this program.  If not, see <http://www.gnu.org/licenses/>.
21 */
22
23 /*
24  *  Name: ldb
25  *
26  *  Component: ldb linked_attributes module
27  *
28  *  Description: Module to ensure linked attribute pairs (i.e. forward-links
29  *  and backlinks) remain in sync.
30  *
31  *  Backlinks are 'plain' links (without extra metadata). When the link target
32  *  object is modified (e.g. renamed), we use the backlinks to keep the link
33  *  source object updated. Note there are some cases where we can't do this:
34  *    - one-way links, which don't have a corresponding backlink
35  *    - two-way deactivated links, i.e. when a user is removed from a group,
36  *      the forward 'member' link still exists (but is inactive), however, the
37  *      'memberOf' backlink is deleted.
38  *  In these cases, we can end up with a dangling forward link which is
39  *  incorrect (i.e. the target has been renamed or deleted). We have dbcheck
40  *  rules to detect and fix this, and cope otherwise by filtering at runtime
41  *  (i.e. in the extended_dn module).
42  *
43  *  See also repl_meta_data.c, which handles updating links for deleted
44  *  objects, as well as link changes received from another DC.
45  *
46  *  Author: Andrew Bartlett
47  */
48
49 #include "includes.h"
50 #include "ldb_module.h"
51 #include "util/dlinklist.h"
52 #include "dsdb/samdb/samdb.h"
53 #include "librpc/gen_ndr/ndr_misc.h"
54 #include "dsdb/samdb/ldb_modules/util.h"
55
56
57 struct la_private_transaction {
58         struct la_context *la_list;
59 };
60
61
62 struct la_private {
63         struct la_private_transaction *transaction;
64         bool sorted_links;
65 };
66
67 struct la_op_store {
68         struct la_op_store *next;
69         struct la_op_store *prev;
70         enum la_op {LA_OP_ADD, LA_OP_DEL} op;
71         struct GUID guid;
72         char *name;
73 };
74
75 struct replace_context {
76         struct la_context *ac;
77         unsigned int num_elements;
78         struct ldb_message_element *el;
79 };
80
81 struct la_context {
82         struct la_context *next, *prev;
83         const struct dsdb_schema *schema;
84         struct ldb_module *module;
85         struct ldb_request *req;
86         struct ldb_dn *mod_dn;
87         struct replace_context *rc;
88         struct la_op_store *ops;
89         struct ldb_extended *op_response;
90         struct ldb_control **op_controls;
91         /*
92          * For futur use
93          * will tell which GC to use for resolving links
94          */
95         char *gc_dns_name;
96 };
97
98
99 static int handle_verify_name_control(TALLOC_CTX *ctx, struct ldb_context *ldb,
100                                         struct ldb_control *control, struct la_context *ac)
101 {
102         /*
103          * If we are a GC let's remove the control,
104          * if there is a specified GC check that is us.
105          */
106         struct ldb_verify_name_control *lvnc = (struct ldb_verify_name_control *)control->data;
107         if (samdb_is_gc(ldb)) {
108                 /* Because we can't easily talloc a struct ldb_dn*/
109                 struct ldb_dn **dn = talloc_array(ctx, struct ldb_dn *, 1);
110                 int ret = samdb_server_reference_dn(ldb, ctx, dn);
111                 const char *dns;
112
113                 if (ret != LDB_SUCCESS) {
114                         return ldb_operr(ldb);
115                 }
116
117                 dns = samdb_dn_to_dnshostname(ldb, ctx, *dn);
118                 if (!dns) {
119                         return ldb_operr(ldb);
120                 }
121                 if (!lvnc->gc || strcasecmp(dns, lvnc->gc) == 0) {
122                         if (!ldb_save_controls(control, ctx, NULL)) {
123                                 return ldb_operr(ldb);
124                         }
125                 } else {
126                         control->critical = true;
127                 }
128                 talloc_free(dn);
129         } else {
130                 /* For the moment we don't remove the control is this case in order
131                  * to fail the request. It's better than having the client thinking
132                  * that we honnor its control.
133                  * Hopefully only a very small set of usecase should hit this problem.
134                  */
135                 if (lvnc->gc) {
136                         ac->gc_dns_name = talloc_strdup(ac, lvnc->gc);
137                 }
138                 control->critical = true;
139         }
140
141         return LDB_SUCCESS;
142 }
143
144 static struct la_context *linked_attributes_init(struct ldb_module *module,
145                                                  struct ldb_request *req)
146 {
147         struct ldb_context *ldb;
148         struct la_context *ac;
149
150         ldb = ldb_module_get_ctx(module);
151
152         ac = talloc_zero(req, struct la_context);
153         if (ac == NULL) {
154                 ldb_oom(ldb);
155                 return NULL;
156         }
157
158         ac->schema = dsdb_get_schema(ldb, ac);
159         ac->module = module;
160         ac->req = req;
161
162         return ac;
163 }
164
165 /*
166   turn a DN into a GUID
167  */
168 static int la_guid_from_dn(struct ldb_module *module,
169                            struct ldb_request *parent,
170                            struct ldb_dn *dn, struct GUID *guid)
171 {
172         NTSTATUS status;
173         int ret;
174
175         status = dsdb_get_extended_dn_guid(dn, guid, "GUID");
176         if (NT_STATUS_IS_OK(status)) {
177                 return LDB_SUCCESS;
178         }
179         if (!NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
180                 DEBUG(4,(__location__ ": Unable to parse GUID for dn %s\n",
181                          ldb_dn_get_linearized(dn)));
182                 return ldb_operr(ldb_module_get_ctx(module));
183         }
184
185         ret = dsdb_module_guid_by_dn(module, dn, guid, parent);
186         if (ret != LDB_SUCCESS) {
187                 DEBUG(4,(__location__ ": Failed to find GUID for dn %s\n",
188                          ldb_dn_get_linearized(dn)));
189                 return ret;
190         }
191         return LDB_SUCCESS;
192 }
193
194
195 /* Common routine to handle reading the attributes and creating a
196  * series of modify requests */
197 static int la_store_op(struct la_context *ac,
198                        enum la_op op, 
199                        const struct dsdb_attribute *schema_attr,
200                        struct ldb_val *dn,
201                        const char *name)
202 {
203         struct ldb_context *ldb;
204         struct la_op_store *os;
205         struct ldb_dn *op_dn;
206         struct dsdb_dn *dsdb_dn;
207         int ret;
208
209         ldb = ldb_module_get_ctx(ac->module);
210
211
212         os = talloc_zero(ac, struct la_op_store);
213         if (!os) {
214                 return ldb_oom(ldb);
215         }
216
217         dsdb_dn = dsdb_dn_parse(os, ldb, dn, schema_attr->syntax->ldap_oid);
218
219         if (!dsdb_dn) {
220                 ldb_asprintf_errstring(ldb,
221                                        "could not parse attribute as a DN");
222                 TALLOC_FREE(os);
223                 return LDB_ERR_INVALID_DN_SYNTAX;
224         }
225
226         op_dn = dsdb_dn->dn;
227
228         os->op = op;
229
230         ret = la_guid_from_dn(ac->module, ac->req, op_dn, &os->guid);
231         talloc_free(op_dn);
232         if (ret == LDB_ERR_NO_SUCH_OBJECT && ac->req->operation == LDB_DELETE) {
233                 /* we are deleting an object, and we've found it has a
234                  * forward link to a target that no longer
235                  * exists. This is not an error in the delete, and we
236                  * should just not do the deferred delete of the
237                  * target attribute
238                  */
239                 talloc_free(os);
240                 return LDB_SUCCESS;
241         }
242         if (ret != LDB_SUCCESS) {
243                 return ret;
244         }
245
246         os->name = talloc_strdup(os, name);
247         if (!os->name) {
248                 return ldb_oom(ldb);
249         }
250
251         /* Do deletes before adds */
252         if (op == LA_OP_ADD) {
253                 DLIST_ADD_END(ac->ops, os);
254         } else {
255                 /* By adding to the head of the list, we do deletes before
256                  * adds when processing a replace */
257                 DLIST_ADD(ac->ops, os);
258         }
259
260         return LDB_SUCCESS;
261 }
262
263 static int la_queue_mod_request(struct la_context *ac);
264 static int la_down_req(struct la_context *ac);
265
266
267
268 /* add */
269 static int linked_attributes_add(struct ldb_module *module, struct ldb_request *req)
270 {
271         struct ldb_context *ldb;
272         const struct dsdb_attribute *target_attr;
273         struct la_context *ac;
274         const char *attr_name;
275         struct ldb_control *ctrl;
276         unsigned int i, j;
277         struct ldb_control *control;
278         int ret;
279
280         ldb = ldb_module_get_ctx(module);
281
282         if (ldb_dn_is_special(req->op.add.message->dn)) {
283                 /* do not manipulate our control entries */
284                 return ldb_next_request(module, req);
285         }
286
287         ac = linked_attributes_init(module, req);
288         if (!ac) {
289                 return ldb_operr(ldb);
290         }
291
292         control = ldb_request_get_control(req, LDB_CONTROL_VERIFY_NAME_OID);
293         if (control != NULL && control->data != NULL) {
294                 ret = handle_verify_name_control(req, ldb, control, ac);
295                 if (ret != LDB_SUCCESS) {
296                         return ldb_operr(ldb);
297                 }
298         }
299
300         if (!(ctrl = ldb_request_get_control(req, DSDB_CONTROL_APPLY_LINKS))) {
301                 /* don't do anything special for linked attributes, repl_meta_data has done it */
302                 talloc_free(ac);
303                 return ldb_next_request(module, req);
304         }
305         ctrl->critical = false;
306
307         if (!ac->schema) {
308                 /* without schema, this doesn't make any sense */
309                 talloc_free(ac);
310                 return ldb_next_request(module, req);
311         }
312
313
314         /* Need to ensure we only have forward links being specified */
315         for (i=0; i < req->op.add.message->num_elements; i++) {
316                 const struct ldb_message_element *el = &req->op.add.message->elements[i];
317                 const struct dsdb_attribute *schema_attr
318                         = dsdb_attribute_by_lDAPDisplayName(ac->schema, el->name);
319                 if (!schema_attr) {
320                         ldb_asprintf_errstring(ldb,
321                                                "%s: attribute %s is not a valid attribute in schema",
322                                                __FUNCTION__,
323                                                el->name);
324                         return LDB_ERR_OBJECT_CLASS_VIOLATION;
325                 }
326
327                 /* this could be a link with no partner, in which case
328                    there is no special work to do */
329                 if (schema_attr->linkID == 0) {
330                         continue;
331                 }
332
333                 /* this part of the code should only be handling forward links */
334                 SMB_ASSERT((schema_attr->linkID & 1) == 0);
335
336                 /* Even link IDs are for the originating attribute */
337                 target_attr = dsdb_attribute_by_linkID(ac->schema, schema_attr->linkID ^ 1);
338                 if (!target_attr) {
339                         /*
340                          * windows 2003 has a broken schema where
341                          * the definition of msDS-IsDomainFor
342                          * is missing (which is supposed to be
343                          * the backlink of the msDS-HasDomainNCs
344                          * attribute
345                          */
346                         continue;
347                 }
348
349                 attr_name = target_attr->lDAPDisplayName;
350
351                 for (j = 0; j < el->num_values; j++) {
352                         ret = la_store_op(ac, LA_OP_ADD,
353                                           schema_attr,
354                                           &el->values[j],
355                                           attr_name);
356                         if (ret != LDB_SUCCESS) {
357                                 return ret;
358                         }
359                 }
360         }
361
362         /* if no linked attributes are present continue */
363         if (ac->ops == NULL) {
364                 /* nothing to do for this module, proceed */
365                 talloc_free(ac);
366                 return ldb_next_request(module, req);
367         }
368
369         /* start with the original request */
370         return la_down_req(ac);
371 }
372
373 /* For a delete or rename, we need to find out what linked attributes
374  * are currently on this DN, and then deal with them.  This is the
375  * callback to the base search */
376
377 static int la_mod_search_callback(struct ldb_request *req, struct ldb_reply *ares)
378 {
379         struct ldb_context *ldb;
380         const struct dsdb_attribute *schema_attr;
381         const struct dsdb_attribute *target_attr;
382         struct ldb_message_element *search_el;
383         struct replace_context *rc;
384         struct la_context *ac;
385         const char *attr_name;
386         unsigned int i, j;
387         int ret = LDB_SUCCESS;
388
389         ac = talloc_get_type(req->context, struct la_context);
390         ldb = ldb_module_get_ctx(ac->module);
391         rc = ac->rc;
392
393         if (!ares) {
394                 return ldb_module_done(ac->req, NULL, NULL,
395                                         LDB_ERR_OPERATIONS_ERROR);
396         }
397         if (ares->error != LDB_SUCCESS) {
398                 return ldb_module_done(ac->req, ares->controls,
399                                         ares->response, ares->error);
400         }
401
402         /* Only entries are interesting, and we only want the olddn */
403         switch (ares->type) {
404         case LDB_REPLY_ENTRY:
405
406                 if (ldb_dn_compare(ares->message->dn, ac->req->op.mod.message->dn) != 0) {
407                         ldb_asprintf_errstring(ldb,
408                                                "linked_attributes: %s is not the DN we were looking for",
409                                                ldb_dn_get_linearized(ares->message->dn));
410                         /* Guh?  We only asked for this DN */
411                         talloc_free(ares);
412                         return ldb_module_done(ac->req, NULL, NULL,
413                                                 LDB_ERR_OPERATIONS_ERROR);
414                 }
415
416                 ac->mod_dn = talloc_steal(ac, ares->message->dn);
417
418                 /* We don't populate 'rc' for ADD - it can't be deleting elements anyway */
419                 for (i = 0; rc && i < rc->num_elements; i++) {
420
421                         schema_attr = dsdb_attribute_by_lDAPDisplayName(ac->schema, rc->el[i].name);
422                         if (!schema_attr) {
423                                 ldb_asprintf_errstring(ldb,
424                                         "%s: attribute %s is not a valid attribute in schema",
425                                         __FUNCTION__,
426                                         rc->el[i].name);
427                                 talloc_free(ares);
428                                 return ldb_module_done(ac->req, NULL, NULL,
429                                                 LDB_ERR_OBJECT_CLASS_VIOLATION);
430                         }
431
432                         search_el = ldb_msg_find_element(ares->message,
433                                                          rc->el[i].name);
434
435                         /* See if this element already exists */
436                         /* otherwise just ignore as
437                          * the add has already been scheduled */
438                         if ( ! search_el) {
439                                 continue;
440                         }
441
442                         target_attr = dsdb_attribute_by_linkID(ac->schema, schema_attr->linkID ^ 1);
443                         if (!target_attr) {
444                                 /*
445                                  * windows 2003 has a broken schema where
446                                  * the definition of msDS-IsDomainFor
447                                  * is missing (which is supposed to be
448                                  * the backlink of the msDS-HasDomainNCs
449                                  * attribute
450                                  */
451                                 continue;
452                         }
453                         attr_name = target_attr->lDAPDisplayName;
454
455                         /* Now we know what was there, we can remove it for the re-add */
456                         for (j = 0; j < search_el->num_values; j++) {
457                                 ret = la_store_op(ac, LA_OP_DEL,
458                                                   schema_attr, 
459                                                   &search_el->values[j],
460                                                   attr_name);
461                                 if (ret != LDB_SUCCESS) {
462                                         talloc_free(ares);
463                                         return ldb_module_done(ac->req,
464                                                                NULL, NULL, ret);
465                                 }
466                         }
467                 }
468
469                 break;
470
471         case LDB_REPLY_REFERRAL:
472                 /* ignore */
473                 break;
474
475         case LDB_REPLY_DONE:
476
477                 talloc_free(ares);
478
479                 if (ac->req->operation == LDB_ADD) {
480                         /* Start the modifies to the backlinks */
481                         ret = la_queue_mod_request(ac);
482
483                         if (ret != LDB_SUCCESS) {
484                                 return ldb_module_done(ac->req, NULL, NULL,
485                                                        ret);
486                         }
487                 } else {
488                         /* Start with the original request */
489                         ret = la_down_req(ac);
490                         if (ret != LDB_SUCCESS) {
491                                 return ldb_module_done(ac->req, NULL, NULL, ret);
492                         }
493                 }
494                 return LDB_SUCCESS;
495         }
496
497         talloc_free(ares);
498         return ret;
499 }
500
501
502 /* modify */
503 static int linked_attributes_modify(struct ldb_module *module, struct ldb_request *req)
504 {
505         /* Look over list of modifications */
506         /* Find if any are for linked attributes */
507         /* Determine the effect of the modification */
508         /* Apply the modify to the linked entry */
509
510         struct ldb_control *control;
511         struct ldb_context *ldb;
512         unsigned int i, j;
513         struct la_context *ac;
514         struct ldb_request *search_req;
515         const char **attrs;
516         struct ldb_control *ctrl;
517         int ret;
518
519         ldb = ldb_module_get_ctx(module);
520
521         if (ldb_dn_is_special(req->op.mod.message->dn)) {
522                 /* do not manipulate our control entries */
523                 return ldb_next_request(module, req);
524         }
525
526         ac = linked_attributes_init(module, req);
527         if (!ac) {
528                 return ldb_operr(ldb);
529         }
530
531         control = ldb_request_get_control(req, LDB_CONTROL_VERIFY_NAME_OID);
532         if (control != NULL && control->data != NULL) {
533                 ret = handle_verify_name_control(req, ldb, control, ac);
534                 if (ret != LDB_SUCCESS) {
535                         return ldb_operr(ldb);
536                 }
537         }
538
539         if (!(ctrl = ldb_request_get_control(req, DSDB_CONTROL_APPLY_LINKS))) {
540                 /* don't do anything special for linked attributes, repl_meta_data has done it */
541                 talloc_free(ac);
542                 return ldb_next_request(module, req);
543         }
544         ctrl->critical = false;
545
546         if (!ac->schema) {
547                 /* without schema, this doesn't make any sense */
548                 return ldb_next_request(module, req);
549         }
550
551         ac->rc = talloc_zero(ac, struct replace_context);
552         if (!ac->rc) {
553                 return ldb_oom(ldb);
554         }
555
556         for (i=0; i < req->op.mod.message->num_elements; i++) {
557                 bool store_el = false;
558                 const char *attr_name;
559                 const struct dsdb_attribute *target_attr;
560                 const struct ldb_message_element *el = &req->op.mod.message->elements[i];
561                 const struct dsdb_attribute *schema_attr
562                         = dsdb_attribute_by_lDAPDisplayName(ac->schema, el->name);
563                 if (!schema_attr) {
564                         ldb_asprintf_errstring(ldb,
565                                                "%s: attribute %s is not a valid attribute in schema",
566                                                __FUNCTION__,
567                                                el->name);
568                         return LDB_ERR_OBJECT_CLASS_VIOLATION;
569                 }
570                 /* We have a valid attribute, now find out if it is a forward link
571                    (Even link IDs are for the originating attribute) */
572                 if (schema_attr->linkID == 0) {
573                         continue;
574                 }
575
576                 /* this part of the code should only be handling forward links */
577                 SMB_ASSERT((schema_attr->linkID & 1) == 0);
578
579                 /* Now find the target attribute */
580                 target_attr = dsdb_attribute_by_linkID(ac->schema, schema_attr->linkID ^ 1);
581                 if (!target_attr) {
582                         /*
583                          * windows 2003 has a broken schema where
584                          * the definition of msDS-IsDomainFor
585                          * is missing (which is supposed to be
586                          * the backlink of the msDS-HasDomainNCs
587                          * attribute
588                          */
589                         continue;
590                 }
591
592                 attr_name = target_attr->lDAPDisplayName;
593
594                 switch (el->flags & LDB_FLAG_MOD_MASK) {
595                 case LDB_FLAG_MOD_REPLACE:
596                         /* treat as just a normal add the delete part is handled by the callback */
597                         store_el = true;
598
599                         FALL_THROUGH;
600                 case LDB_FLAG_MOD_ADD:
601
602                         /* For each value being added, we need to setup the adds */
603                         for (j = 0; j < el->num_values; j++) {
604                                 ret = la_store_op(ac, LA_OP_ADD,
605                                                   schema_attr,
606                                                   &el->values[j],
607                                                   attr_name);
608                                 if (ret != LDB_SUCCESS) {
609                                         return ret;
610                                 }
611                         }
612                         break;
613
614                 case LDB_FLAG_MOD_DELETE:
615
616                         if (el->num_values) {
617                                 /* For each value being deleted, we need to setup the delete */
618                                 for (j = 0; j < el->num_values; j++) {
619                                         ret = la_store_op(ac, LA_OP_DEL,
620                                                           schema_attr,
621                                                           &el->values[j],
622                                                           attr_name);
623                                         if (ret != LDB_SUCCESS) {
624                                                 return ret;
625                                         }
626                                 }
627                         } else {
628                                 /* Flag that there was a DELETE
629                                  * without a value specified, so we
630                                  * need to look for the old value */
631                                 store_el = true;
632                         }
633
634                         break;
635                 }
636
637                 if (store_el) {
638                         struct ldb_message_element *search_el;
639
640                         search_el = talloc_realloc(ac->rc, ac->rc->el,
641                                                    struct ldb_message_element,
642                                                    ac->rc->num_elements +1);
643                         if (!search_el) {
644                                 return ldb_oom(ldb);
645                         }
646                         ac->rc->el = search_el;
647
648                         ac->rc->el[ac->rc->num_elements] = *el;
649                         ac->rc->num_elements++;
650                 }
651         }
652
653         if (ac->ops || ac->rc->el) {
654                 /* both replace and delete without values are handled in the callback
655                  * after the search on the entry to be modified is performed */
656
657                 attrs = talloc_array(ac->rc, const char *, ac->rc->num_elements + 1);
658                 if (!attrs) {
659                         return ldb_oom(ldb);
660                 }
661                 for (i = 0; i < ac->rc->num_elements; i++) {
662                         attrs[i] = ac->rc->el[i].name;
663                 }
664                 attrs[i] = NULL;
665
666                 /* The callback does all the hard work here */
667                 ret = ldb_build_search_req(&search_req, ldb, ac,
668                                            req->op.mod.message->dn,
669                                            LDB_SCOPE_BASE,
670                                            "(objectClass=*)", attrs,
671                                            NULL,
672                                            ac, la_mod_search_callback,
673                                            req);
674                 LDB_REQ_SET_LOCATION(search_req);
675
676                 /* We need to figure out our own extended DN, to fill in as the backlink target */
677                 if (ret == LDB_SUCCESS) {
678                         ret = dsdb_request_add_controls(search_req,
679                                                         DSDB_SEARCH_SHOW_RECYCLED |
680                                                         DSDB_SEARCH_SHOW_EXTENDED_DN);
681                 }
682                 if (ret == LDB_SUCCESS) {
683                         talloc_steal(search_req, attrs);
684
685                         ret = ldb_next_request(module, search_req);
686                 }
687
688         } else {
689                 /* nothing to do for this module, proceed */
690                 talloc_free(ac);
691                 ret = ldb_next_request(module, req);
692         }
693
694         return ret;
695 }
696
697
698 static int linked_attributes_fix_link_slow(struct ldb_module *module,
699                                            struct ldb_request *parent,
700                                            struct ldb_message *msg,
701                                            struct ldb_dn *new_dn,
702                                            struct GUID self_guid,
703                                            const char *syntax_oid,
704                                            const char *reverse_syntax_oid)
705 {
706         int ret;
707         unsigned int i;
708         struct GUID link_guid;
709         struct ldb_message_element *el = &msg->elements[0];
710         struct ldb_context *ldb = ldb_module_get_ctx(module);
711         bool has_unique_value = strcmp(reverse_syntax_oid, LDB_SYNTAX_DN) == 0;
712         TALLOC_CTX *tmp_ctx = talloc_new(module);
713         if (tmp_ctx == NULL) {
714                 return LDB_ERR_OPERATIONS_ERROR;
715         }
716         /*
717          * The msg has one element (el) containing links of one particular
718          * type from the remote object. We know that at least one of those
719          * links points to the object being renamed (identified by self_guid,
720          * renamed to new_dn). Usually only one of the links will point back
721          * to renamed object, but there can be more when the reverse link is a
722          * DN+Binary link.
723          *
724          * This is used for unsorted links, which is to say back links and
725          * forward links on old databases. It necessarily involves a linear
726          * search, though when the link is a plain DN link, we can skip
727          * checking as soon as we find it.
728          *
729          * NOTE: if there are duplicate links, the extra ones will end up as
730          * dangling links to the old DN. This may or may not be better.
731          */
732         for (i = 0; i < el->num_values; i++) {
733                 struct dsdb_dn *dsdb_dn = dsdb_dn_parse(msg,
734                                                         ldb,
735                                                         &el->values[i],
736                                                         syntax_oid);
737                 if (dsdb_dn == NULL) {
738                         talloc_free(tmp_ctx);
739                         return LDB_ERR_INVALID_DN_SYNTAX;
740                 }
741
742                 ret = la_guid_from_dn(module, parent, dsdb_dn->dn, &link_guid);
743                 if (ret != LDB_SUCCESS) {
744                         talloc_free(tmp_ctx);
745                         return ret;
746                 }
747
748                 /*
749                  * By comparing using the GUID we ensure that even if somehow
750                  * the name has got out of sync, this rename will fix it.
751                  *
752                  * If somehow we don't have a GUID on the DN in the DB, the
753                  * la_guid_from_dn call will be more costly, but still give us
754                  * a GUID. dbcheck will fix this if run.
755                  */
756                 if (!GUID_equal(&self_guid, &link_guid)) {
757                         continue;
758                 }
759
760                 ret = ldb_dn_update_components(dsdb_dn->dn, new_dn);
761                 if (ret != LDB_SUCCESS) {
762                         talloc_free(tmp_ctx);
763                         return ret;
764                 }
765
766                 el->values[i] = data_blob_string_const(
767                         dsdb_dn_get_extended_linearized(el->values, dsdb_dn, 1));
768                 if (has_unique_value) {
769                         break;
770                 }
771         }
772
773         talloc_free(tmp_ctx);
774         return LDB_SUCCESS;
775 }
776
777
778 static int linked_attributes_fix_forward_link(struct ldb_module *module,
779                                               struct ldb_message *msg,
780                                               struct ldb_dn *new_dn,
781                                               struct GUID self_guid,
782                                               const char *syntax_oid)
783 {
784         int ret;
785         struct ldb_context *ldb = ldb_module_get_ctx(module);
786         struct parsed_dn *pdn_list = NULL;
787         struct parsed_dn *exact = NULL;
788         struct parsed_dn *next = NULL;
789         bool is_plain_dn;
790         struct ldb_message_element *el = &msg->elements[0];
791         unsigned int num_parsed_dns = el->num_values;
792
793         TALLOC_CTX *tmp_ctx = talloc_new(module);
794         if (tmp_ctx == NULL) {
795                 return LDB_ERR_OPERATIONS_ERROR;
796         }
797
798         /*
799          * The msg has a single element (el) containing forward links which we
800          * trust are sorted in GUID order. We know that at least one of those
801          * links points to the object being renamed (identified by self_guid,
802          * renamed to new_dn), because that object has a backlink pointing
803          * here.
804          *
805          * In most cases we assume there will only be one forward link, which
806          * is found by parsed_dn_find(), but in the case of DN+Binary links
807          * (e.g. msDS-RevealedUsers) there may be many forward links that
808          * share the same DN/GUID but differ in the binary part. For those we
809          * need to look around the link found by parsed_dn_find() and convert
810          * them all -- there is no way to know which forward link belongs to
811          * which backlink.
812          */
813
814         ret = get_parsed_dns_trusted(tmp_ctx, el, &pdn_list);
815         if (ret != LDB_SUCCESS) {
816                 ldb_asprintf_errstring(ldb, "get_parsed_dn_trusted() "
817                                        "error fixing %s links for %s",
818                                        el->name,
819                                        ldb_dn_get_linearized(msg->dn));
820                 talloc_free(tmp_ctx);
821                 return ret;
822         }
823
824         /* find our DN in the values */
825         ret = parsed_dn_find(ldb, pdn_list, num_parsed_dns,
826                              &self_guid,
827                              NULL,
828                              data_blob_null, 0,
829                              &exact, &next,
830                              syntax_oid,
831                              false);
832
833         if (ret != LDB_SUCCESS) {
834                 ldb_asprintf_errstring(ldb, "parsed_dn_find() "
835                                        "error fixing %s links for %s",
836                                        el->name,
837                                        ldb_dn_get_linearized(msg->dn));
838                 talloc_free(tmp_ctx);
839                 return ret;
840         }
841
842         if (exact == NULL) {
843                 ldb_asprintf_errstring(
844                         ldb,
845                         "parsed_dn_find could not find %s link for %s",
846                         el->name,
847                         ldb_dn_get_linearized(msg->dn));
848                 talloc_free(tmp_ctx);
849                 return LDB_ERR_OPERATIONS_ERROR;
850         }
851
852         is_plain_dn = strcmp(syntax_oid, LDB_SYNTAX_DN) == 0;
853
854         if (is_plain_dn) {
855                 /*
856                  *  The common case -- we only have to update a single link
857                  */
858                 ret = ldb_dn_update_components(exact->dsdb_dn->dn, new_dn);
859                 if (ret != LDB_SUCCESS) {
860                         DBG_ERR("could not update components  %s  %s\n",
861                                 ldb_dn_get_linearized(exact->dsdb_dn->dn),
862                                 ldb_dn_get_linearized(new_dn)
863                                 );
864
865                         talloc_free(tmp_ctx);
866                         return ret;
867                 }
868                 *(exact->v) = data_blob_string_const(
869                                 dsdb_dn_get_extended_linearized(el->values,
870                                                                 exact->dsdb_dn,
871                                                                 1));
872         } else {
873                 /*
874                  * The forward link is a DN+Binary (or in some alternate
875                  * universes, DN+String), which means the parsed_dns are keyed
876                  * on GUID+Binary. We don't know the binary part, which means
877                  * from our point of view the list can have entries with
878                  * duplicate GUIDs that we can't tell apart. We don't know
879                  * which backlink belongs to which GUID+binary, and the binary
880                  * search will always find the same one. That means one link
881                  * link will get fixed n times, whil n-1 links get fixed
882                  * never.
883                  *
884                  * If we instead fixing all the possible links, we end up
885                  * fixing n links n times, which at least works and is
886                  * probably not too costly because n is probably small.
887                  */
888                 struct parsed_dn *first = exact;
889                 struct parsed_dn *last = exact;
890                 struct parsed_dn *p = NULL;
891                 int cmp;
892                 while (first > pdn_list) {
893                         p = first - 1;
894                         if (p->dsdb_dn == NULL) {
895                                 ret = really_parse_trusted_dn(tmp_ctx,
896                                                               ldb, p,
897                                                               syntax_oid);
898                                 if (ret != LDB_SUCCESS) {
899                                         talloc_free(tmp_ctx);
900                                         return ret;
901                                 }
902                         }
903                         cmp = ndr_guid_compare(&exact->guid, &p->guid);
904                         if (cmp != 0) {
905                                 break;
906                         }
907                         first = p;
908                 }
909
910                 while (last < pdn_list + num_parsed_dns - 1) {
911                         p = last + 1;
912                         if (p->dsdb_dn == NULL) {
913                                 ret = really_parse_trusted_dn(tmp_ctx,
914                                                               ldb, p,
915                                                               syntax_oid);
916                                 if (ret != LDB_SUCCESS) {
917                                         talloc_free(tmp_ctx);
918                                         return ret;
919                                 }
920                         }
921                         cmp = ndr_guid_compare(&exact->guid, &p->guid);
922                         if (cmp != 0) {
923                                 break;
924                         }
925                         last = p;
926                 }
927
928                 for (p = first; p <= last; p++) {
929                         ret = ldb_dn_update_components(p->dsdb_dn->dn, new_dn);
930                         if (ret != LDB_SUCCESS) {
931                                 DBG_ERR("could not update components  %s  %s\n",
932                                         ldb_dn_get_linearized(p->dsdb_dn->dn),
933                                         ldb_dn_get_linearized(new_dn)
934                                         );
935                                 talloc_free(tmp_ctx);
936                                 return ret;
937                         }
938                         *(p->v) = data_blob_string_const(
939                                    dsdb_dn_get_extended_linearized(el->values,
940                                                                    p->dsdb_dn,
941                                                                    1));
942                 }
943         }
944
945         talloc_free(tmp_ctx);
946         return LDB_SUCCESS;
947 }
948
949
950 static int linked_attributes_fix_links(struct ldb_module *module,
951                                        struct GUID self_guid,
952                                        struct ldb_dn *old_dn,
953                                        struct ldb_dn *new_dn,
954                                        struct ldb_message_element *el,
955                                        struct dsdb_schema *schema,
956                                        const struct dsdb_attribute *schema_attr,
957                                        struct ldb_request *parent)
958 {
959         unsigned int i;
960         TALLOC_CTX *tmp_ctx = NULL;
961         struct ldb_context *ldb = ldb_module_get_ctx(module);
962         const struct dsdb_attribute *target = NULL;
963         const char *attrs[2];
964         int ret;
965         struct la_private *la_private = NULL;
966
967         target = dsdb_attribute_by_linkID(schema, schema_attr->linkID ^ 1);
968         if (target == NULL) {
969                 /* there is no counterpart link to change */
970                 return LDB_SUCCESS;
971         }
972
973         tmp_ctx = talloc_new(module);
974         if (tmp_ctx == NULL) {
975                 return LDB_ERR_OPERATIONS_ERROR;
976         }
977
978         la_private = talloc_get_type(ldb_module_get_private(module),
979                                      struct la_private);
980         if (la_private == NULL) {
981                 talloc_free(tmp_ctx);
982                 return LDB_ERR_OPERATIONS_ERROR;
983         }
984
985         attrs[0] = target->lDAPDisplayName;
986         attrs[1] = NULL;
987
988         for (i=0; i<el->num_values; i++) {
989                 struct dsdb_dn *dsdb_dn = NULL;
990                 struct ldb_result *res = NULL;
991                 struct ldb_message *msg  = NULL;
992                 struct ldb_message_element *el2 = NULL;
993                 struct GUID link_guid;
994                 char *link_guid_str = NULL;
995
996                 dsdb_dn = dsdb_dn_parse(tmp_ctx, ldb, &el->values[i],
997                                         schema_attr->syntax->ldap_oid);
998                 if (dsdb_dn == NULL) {
999                         talloc_free(tmp_ctx);
1000                         return LDB_ERR_INVALID_DN_SYNTAX;
1001                 }
1002
1003                 ret = la_guid_from_dn(module, parent, dsdb_dn->dn, &link_guid);
1004                 if (ret != LDB_SUCCESS) {
1005                         ldb_asprintf_errstring(ldb, "Linked attribute %s->%s between %s and %s - GUID not found - %s",
1006                                                el->name, target->lDAPDisplayName,
1007                                                ldb_dn_get_linearized(old_dn),
1008                                                ldb_dn_get_linearized(dsdb_dn->dn),
1009                                                ldb_errstring(ldb));
1010                         talloc_free(tmp_ctx);
1011                         return ret;
1012                 }
1013
1014                 link_guid_str = GUID_string(tmp_ctx, &link_guid);
1015                 if (link_guid_str == NULL) {
1016                         talloc_free(tmp_ctx);
1017                         return LDB_ERR_OPERATIONS_ERROR;
1018                 }
1019
1020                 /*
1021                  * get the existing message from the db for the object with
1022                  * this GUID, returning attribute being modified. We will then
1023                  * use this msg as the basis for a modify call
1024                  */
1025
1026                 ret = dsdb_module_search(module, tmp_ctx, &res, NULL, LDB_SCOPE_SUBTREE, attrs,
1027                                          DSDB_FLAG_NEXT_MODULE |
1028                                          DSDB_SEARCH_SEARCH_ALL_PARTITIONS |
1029                                          DSDB_SEARCH_SHOW_RECYCLED |
1030                                          DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT |
1031                                          DSDB_SEARCH_REVEAL_INTERNALS,
1032                                          parent,
1033                                          "objectGUID=%s", link_guid_str);
1034                 if (ret != LDB_SUCCESS) {
1035                         ldb_asprintf_errstring(ldb, "Linked attribute %s->%s between %s and %s - target GUID %s not found - %s",
1036                                                el->name, target->lDAPDisplayName,
1037                                                ldb_dn_get_linearized(old_dn),
1038                                                ldb_dn_get_linearized(dsdb_dn->dn),
1039                                                link_guid_str,
1040                                                ldb_errstring(ldb));
1041                         talloc_free(tmp_ctx);
1042                         return ret;
1043                 }
1044                 if (res->count == 0) {
1045                         /* Forward link without backlink object remaining - nothing to do here */
1046                         continue;
1047                 }
1048                 if (res->count != 1) {
1049                         ldb_asprintf_errstring(ldb, "Linked attribute %s->%s between %s and %s - target GUID %s found more than once!",
1050                                                el->name, target->lDAPDisplayName,
1051                                                ldb_dn_get_linearized(old_dn),
1052                                                ldb_dn_get_linearized(dsdb_dn->dn),
1053                                                link_guid_str);
1054                         talloc_free(tmp_ctx);
1055                         return LDB_ERR_OPERATIONS_ERROR;
1056                 }
1057
1058                 msg = res->msgs[0];
1059
1060                 if (msg->num_elements == 0) {
1061                         /* Forward link without backlink remaining - nothing to do here */
1062                         continue;
1063                 } else if (msg->num_elements != 1) {
1064                         ldb_asprintf_errstring(ldb, "Bad msg elements - got %u elements, expected one element to be returned in linked_attributes_fix_links for %s",
1065                                                msg->num_elements, ldb_dn_get_linearized(msg->dn));
1066                         talloc_free(tmp_ctx);
1067                         return LDB_ERR_OPERATIONS_ERROR;
1068                 }
1069                 if (ldb_attr_cmp(msg->elements[0].name, target->lDAPDisplayName) != 0) {
1070                         ldb_asprintf_errstring(ldb, "Bad returned attribute in linked_attributes_fix_links: got %s, expected %s for %s", msg->elements[0].name, target->lDAPDisplayName, ldb_dn_get_linearized(msg->dn));
1071                         talloc_free(tmp_ctx);
1072                         return LDB_ERR_OPERATIONS_ERROR;
1073                 }
1074                 el2 = &msg->elements[0];
1075
1076                 el2->flags = LDB_FLAG_MOD_REPLACE;
1077
1078                 if (target->linkID & 1 ||
1079                         ! la_private->sorted_links) {
1080                         /* handle backlinks (which aren't sorted in the DB)
1081                            and forward links in old unsorted databases. */
1082                         ret = linked_attributes_fix_link_slow(
1083                                 module,
1084                                 parent,
1085                                 msg,
1086                                 new_dn,
1087                                 self_guid,
1088                                 target->syntax->ldap_oid,
1089                                 schema_attr->syntax->ldap_oid);
1090                 } else {
1091                         /* we can binary search to find forward links */
1092                         ret = linked_attributes_fix_forward_link(
1093                                 module,
1094                                 msg,
1095                                 new_dn,
1096                                 self_guid,
1097                                 target->syntax->ldap_oid);
1098                 }
1099                 ret = dsdb_check_single_valued_link(target, el2);
1100                 if (ret != LDB_SUCCESS) {
1101                         talloc_free(tmp_ctx);
1102                         return ret;
1103                 }
1104
1105                 /* we may be putting multiple values in an attribute -
1106                    disable checking for this attribute */
1107                 el2->flags |= LDB_FLAG_INTERNAL_DISABLE_SINGLE_VALUE_CHECK;
1108
1109                 ret = dsdb_module_modify(module, msg, DSDB_FLAG_NEXT_MODULE, parent);
1110                 if (ret != LDB_SUCCESS) {
1111                         ldb_asprintf_errstring(ldb, "Linked attribute %s->%s between %s and %s - update failed - %s",
1112                                                el->name, target->lDAPDisplayName,
1113                                                ldb_dn_get_linearized(old_dn),
1114                                                ldb_dn_get_linearized(dsdb_dn->dn),
1115                                                ldb_errstring(ldb));
1116                         talloc_free(tmp_ctx);
1117                         return ret;
1118                 }
1119         }
1120
1121         talloc_free(tmp_ctx);
1122         return LDB_SUCCESS;
1123 }
1124
1125
1126 /* rename */
1127 static int linked_attributes_rename(struct ldb_module *module, struct ldb_request *req)
1128 {
1129         struct ldb_result *res;
1130         struct ldb_message *msg;
1131         unsigned int i;
1132         struct ldb_context *ldb = ldb_module_get_ctx(module);
1133         struct dsdb_schema *schema;
1134         int ret;
1135         struct GUID guid;
1136
1137         /*
1138            - load the current msg
1139            - find any linked attributes
1140            - if its a link then find the target object
1141            - modify the target linked attributes with the new DN
1142         */
1143         ret = dsdb_module_search_dn(module, req, &res, req->op.rename.olddn,
1144                                     NULL,
1145                                     DSDB_FLAG_NEXT_MODULE |
1146                                     DSDB_SEARCH_SHOW_EXTENDED_DN |
1147                                     DSDB_SEARCH_SHOW_RECYCLED, req);
1148         if (ret != LDB_SUCCESS) {
1149                 return ret;
1150         }
1151
1152         schema = dsdb_get_schema(ldb, res);
1153         if (!schema) {
1154                 return ldb_oom(ldb);
1155         }
1156
1157         msg = res->msgs[0];
1158
1159         ret = la_guid_from_dn(module, req, msg->dn, &guid);
1160         if (ret != LDB_SUCCESS) {
1161                 return ret;
1162         }
1163
1164         for (i=0; i<msg->num_elements; i++) {
1165                 struct ldb_message_element *el = &msg->elements[i];
1166                 const struct dsdb_attribute *schema_attr
1167                         = dsdb_attribute_by_lDAPDisplayName(schema, el->name);
1168                 if (!schema_attr || schema_attr->linkID == 0) {
1169                         continue;
1170                 }
1171                 ret = linked_attributes_fix_links(module, guid, msg->dn, req->op.rename.newdn, el,
1172                                                   schema, schema_attr, req);
1173                 if (ret != LDB_SUCCESS) {
1174                         talloc_free(res);
1175                         return ret;
1176                 }
1177         }
1178
1179         talloc_free(res);
1180
1181         return ldb_next_request(module, req);
1182 }
1183
1184
1185 /* queue a linked attributes modify request in the la_private
1186    structure */
1187 static int la_queue_mod_request(struct la_context *ac)
1188 {
1189         struct la_private *la_private =
1190                 talloc_get_type(ldb_module_get_private(ac->module),
1191                                 struct la_private);
1192
1193         if (la_private == NULL || la_private->transaction == NULL) {
1194                 ldb_debug(ldb_module_get_ctx(ac->module),
1195                           LDB_DEBUG_ERROR,
1196                           __location__ ": No la_private transaction setup\n");
1197                 return ldb_operr(ldb_module_get_ctx(ac->module));
1198         }
1199
1200         talloc_steal(la_private->transaction, ac);
1201         DLIST_ADD(la_private->transaction->la_list, ac);
1202
1203         return ldb_module_done(ac->req, ac->op_controls,
1204                                ac->op_response, LDB_SUCCESS);
1205 }
1206
1207 /* Having done the original operation, then try to fix up all the linked attributes for modify and delete */
1208 static int la_mod_del_callback(struct ldb_request *req, struct ldb_reply *ares)
1209 {
1210         struct la_context *ac;
1211         struct ldb_context *ldb;
1212         int ret;
1213
1214         ac = talloc_get_type(req->context, struct la_context);
1215         ldb = ldb_module_get_ctx(ac->module);
1216
1217         if (!ares) {
1218                 return ldb_module_done(ac->req, NULL, NULL,
1219                                         LDB_ERR_OPERATIONS_ERROR);
1220         }
1221         if (ares->error != LDB_SUCCESS) {
1222                 return ldb_module_done(ac->req, ares->controls,
1223                                         ares->response, ares->error);
1224         }
1225
1226         if (ares->type != LDB_REPLY_DONE) {
1227                 ldb_set_errstring(ldb,
1228                      "invalid reply type in linked attributes delete callback");
1229                 talloc_free(ares);
1230                 return ldb_module_done(ac->req, NULL, NULL,
1231                                         LDB_ERR_OPERATIONS_ERROR);
1232         }
1233
1234         ac->op_controls = talloc_steal(ac, ares->controls);
1235         ac->op_response = talloc_steal(ac, ares->response);
1236
1237         /* If we have modfies to make, this is the time to do them for modify and delete */
1238         ret = la_queue_mod_request(ac);
1239
1240         if (ret != LDB_SUCCESS) {
1241                 return ldb_module_done(ac->req, NULL, NULL, ret);
1242         }
1243         talloc_free(ares);
1244
1245         /* la_queue_mod_request has already sent the callbacks */
1246         return LDB_SUCCESS;
1247
1248 }
1249
1250 /* Having done the original add, then try to fix up all the linked attributes
1251
1252   This is done after the add so the links can get the extended DNs correctly.
1253  */
1254 static int la_add_callback(struct ldb_request *req, struct ldb_reply *ares)
1255 {
1256         struct la_context *ac;
1257         struct ldb_context *ldb;
1258         int ret;
1259
1260         ac = talloc_get_type(req->context, struct la_context);
1261         ldb = ldb_module_get_ctx(ac->module);
1262
1263         if (!ares) {
1264                 return ldb_module_done(ac->req, NULL, NULL,
1265                                         LDB_ERR_OPERATIONS_ERROR);
1266         }
1267         if (ares->error != LDB_SUCCESS) {
1268                 return ldb_module_done(ac->req, ares->controls,
1269                                         ares->response, ares->error);
1270         }
1271
1272         if (ares->type != LDB_REPLY_DONE) {
1273                 ldb_set_errstring(ldb,
1274                         "invalid reply type in linked attributes add callback");
1275                 talloc_free(ares);
1276                 return ldb_module_done(ac->req, NULL, NULL,
1277                                         LDB_ERR_OPERATIONS_ERROR);
1278         }
1279
1280         if (ac->ops) {
1281                 struct ldb_request *search_req;
1282                 static const char *attrs[] = { NULL };
1283
1284                 /* The callback does all the hard work here - we need
1285                  * the objectGUID and SID of the added record */
1286                 ret = ldb_build_search_req(&search_req, ldb, ac,
1287                                            ac->req->op.add.message->dn,
1288                                            LDB_SCOPE_BASE,
1289                                            "(objectClass=*)", attrs,
1290                                            NULL,
1291                                            ac, la_mod_search_callback,
1292                                            ac->req);
1293                 LDB_REQ_SET_LOCATION(search_req);
1294
1295                 if (ret == LDB_SUCCESS) {
1296                         ret = dsdb_request_add_controls(search_req,
1297                                                         DSDB_SEARCH_SHOW_RECYCLED |
1298                                                         DSDB_SEARCH_SHOW_EXTENDED_DN);
1299                 }
1300                 if (ret != LDB_SUCCESS) {
1301                         return ldb_module_done(ac->req, NULL, NULL,
1302                                                ret);
1303                 }
1304
1305                 ac->op_controls = talloc_steal(ac, ares->controls);
1306                 ac->op_response = talloc_steal(ac, ares->response);
1307
1308                 return ldb_next_request(ac->module, search_req);
1309
1310         } else {
1311                 return ldb_module_done(ac->req, ares->controls,
1312                                        ares->response, ares->error);
1313         }
1314 }
1315
1316 /* Reconstruct the original request, but pointing at our local callback to finish things off */
1317 static int la_down_req(struct la_context *ac)
1318 {
1319         struct ldb_request *down_req;
1320         struct ldb_context *ldb;
1321         int ret;
1322
1323         ldb = ldb_module_get_ctx(ac->module);
1324
1325         switch (ac->req->operation) {
1326         case LDB_ADD:
1327                 ret = ldb_build_add_req(&down_req, ldb, ac,
1328                                         ac->req->op.add.message,
1329                                         ac->req->controls,
1330                                         ac, la_add_callback,
1331                                         ac->req);
1332                 LDB_REQ_SET_LOCATION(down_req);
1333                 break;
1334         case LDB_MODIFY:
1335                 ret = ldb_build_mod_req(&down_req, ldb, ac,
1336                                         ac->req->op.mod.message,
1337                                         ac->req->controls,
1338                                         ac, la_mod_del_callback,
1339                                         ac->req);
1340                 LDB_REQ_SET_LOCATION(down_req);
1341                 break;
1342         default:
1343                 ret = LDB_ERR_OPERATIONS_ERROR;
1344         }
1345         if (ret != LDB_SUCCESS) {
1346                 return ret;
1347         }
1348
1349         return ldb_next_request(ac->module, down_req);
1350 }
1351
1352 /*
1353   use the GUID part of an extended DN to find the target DN, in case
1354   it has moved
1355  */
1356 static int la_find_dn_target(struct ldb_module *module, struct la_context *ac,
1357                              struct GUID *guid, struct ldb_dn **dn)
1358 {
1359         return dsdb_module_dn_by_guid(ac->module, ac, guid, dn, ac->req);
1360 }
1361
1362 /* apply one la_context op change */
1363 static int la_do_op_request(struct ldb_module *module, struct la_context *ac, struct la_op_store *op)
1364 {
1365         struct ldb_message_element *ret_el;
1366         struct ldb_message *new_msg;
1367         struct ldb_context *ldb;
1368         int ret;
1369
1370         if (ac->mod_dn == NULL) {
1371                 /* we didn't find the DN that we searched for */
1372                 return LDB_SUCCESS;
1373         }
1374
1375         ldb = ldb_module_get_ctx(ac->module);
1376
1377         /* Create the modify request */
1378         new_msg = ldb_msg_new(ac);
1379         if (!new_msg) {
1380                 return ldb_oom(ldb);
1381         }
1382
1383         ret = la_find_dn_target(module, ac, &op->guid, &new_msg->dn);
1384         if (ret != LDB_SUCCESS) {
1385                 return ret;
1386         }
1387
1388         if (op->op == LA_OP_ADD) {
1389                 ret = ldb_msg_add_empty(new_msg, op->name,
1390                                         LDB_FLAG_MOD_ADD, &ret_el);
1391         } else {
1392                 ret = ldb_msg_add_empty(new_msg, op->name,
1393                                         LDB_FLAG_MOD_DELETE, &ret_el);
1394         }
1395         if (ret != LDB_SUCCESS) {
1396                 return ret;
1397         }
1398         ret_el->values = talloc_array(new_msg, struct ldb_val, 1);
1399         if (!ret_el->values) {
1400                 return ldb_oom(ldb);
1401         }
1402         ret_el->num_values = 1;
1403         ret_el->values[0] = data_blob_string_const(ldb_dn_get_extended_linearized(new_msg, ac->mod_dn, 1));
1404
1405         /* a backlink should never be single valued. Unfortunately the
1406            exchange schema has a attribute
1407            msExchBridgeheadedLocalConnectorsDNBL which is single
1408            valued and a backlink. We need to cope with that by
1409            ignoring the single value flag */
1410         ret_el->flags |= LDB_FLAG_INTERNAL_DISABLE_SINGLE_VALUE_CHECK;
1411
1412 #if 0
1413         ldb_debug(ldb, LDB_DEBUG_WARNING,
1414                   "link on %s %s: %s %s\n",
1415                   ldb_dn_get_linearized(new_msg->dn), ret_el->name,
1416                   ret_el->values[0].data, ac->ops->op == LA_OP_ADD ? "added" : "deleted");
1417 #endif
1418
1419         if (DEBUGLVL(4)) {
1420                 DEBUG(4,("Applying linked attribute change:\n%s\n",
1421                          ldb_ldif_message_redacted_string(ldb, op,
1422                                                           LDB_CHANGETYPE_MODIFY,
1423                                                           new_msg)));
1424         }
1425
1426         ret = dsdb_module_modify(module, new_msg, DSDB_FLAG_NEXT_MODULE, ac->req);
1427         if (ret != LDB_SUCCESS) {
1428                 ldb_debug(ldb, LDB_DEBUG_WARNING, __location__ ": failed to apply linked attribute change '%s'\n%s\n",
1429                           ldb_errstring(ldb),
1430                           ldb_ldif_message_redacted_string(ldb, op,
1431                                                            LDB_CHANGETYPE_MODIFY,
1432                                                            new_msg));
1433         }
1434
1435         return ret;
1436 }
1437
1438 /* apply one set of la_context changes */
1439 static int la_do_mod_request(struct ldb_module *module, struct la_context *ac)
1440 {
1441         struct la_op_store *op;
1442
1443         for (op = ac->ops; op; op=op->next) {
1444                 int ret = la_do_op_request(module, ac, op);
1445                 if (ret != LDB_SUCCESS) {
1446                         if (ret != LDB_ERR_NO_SUCH_OBJECT) {
1447                                 return ret;
1448                         }
1449                 }
1450         }
1451
1452         return LDB_SUCCESS;
1453 }
1454
1455
1456 /*
1457   we hook into the transaction operations to allow us to
1458   perform the linked attribute updates at the end of the whole
1459   transaction. This allows a forward linked attribute to be created
1460   before the target is created, as long as the target is created
1461   in the same transaction
1462  */
1463 static int linked_attributes_start_transaction(struct ldb_module *module)
1464 {
1465         /* create our private structure for this transaction */
1466         struct la_private *la_private =
1467                 talloc_get_type(ldb_module_get_private(module),
1468                                 struct la_private);
1469
1470         if (la_private == NULL) {
1471                 return ldb_oom(ldb_module_get_ctx(module));
1472         }
1473         talloc_free(la_private->transaction);
1474         la_private->transaction = talloc(module, struct la_private_transaction);
1475         if (la_private->transaction == NULL) {
1476                 return ldb_oom(ldb_module_get_ctx(module));
1477         }
1478         la_private->transaction->la_list = NULL;
1479         return ldb_next_start_trans(module);
1480 }
1481
1482 /*
1483   on prepare commit we loop over our queued la_context structures
1484   and apply each of them
1485  */
1486 static int linked_attributes_prepare_commit(struct ldb_module *module)
1487 {
1488         struct la_context *ac;
1489         struct la_private *la_private =
1490                 talloc_get_type(ldb_module_get_private(module),
1491                                 struct la_private);
1492         if (la_private == NULL || la_private->transaction == NULL) {
1493                 DBG_ERR("prepare_commit without begin_transaction\n");
1494                 /* prepare commit without begin_transaction - let someone else
1495                  * return the error, just don't segfault */
1496                 return ldb_next_prepare_commit(module);
1497         }
1498         /* walk the list backwards, to do the first entry first, as we
1499          * added the entries with DLIST_ADD() which puts them at the
1500          * start of the list */
1501
1502         /* Start at the end of the list - so we can start
1503          * there, but ensure we don't create a loop by NULLing
1504          * it out in the first element */
1505         ac = DLIST_TAIL(la_private->transaction->la_list);
1506
1507         for (; ac; ac=DLIST_PREV(ac)) {
1508                 int ret;
1509                 ac->req = NULL;
1510                 ret = la_do_mod_request(module, ac);
1511                 if (ret != LDB_SUCCESS) {
1512                         DEBUG(0,(__location__ ": Failed mod request ret=%d\n", ret));
1513                         TALLOC_FREE(la_private->transaction);
1514                         return ret;
1515                 }
1516         }
1517
1518         TALLOC_FREE(la_private->transaction);
1519
1520         return ldb_next_prepare_commit(module);
1521 }
1522
1523 static int linked_attributes_del_transaction(struct ldb_module *module)
1524 {
1525         struct la_private *la_private =
1526                 talloc_get_type(ldb_module_get_private(module),
1527                                 struct la_private);
1528         TALLOC_FREE(la_private->transaction);
1529         return ldb_next_del_trans(module);
1530 }
1531
1532 static int linked_attributes_ldb_init(struct ldb_module *module)
1533 {
1534         int ret;
1535         struct la_private *la_private = NULL;
1536         struct ldb_context *ldb = ldb_module_get_ctx(module);
1537
1538         ret = ldb_mod_register_control(module, LDB_CONTROL_VERIFY_NAME_OID);
1539         if (ret != LDB_SUCCESS) {
1540                 ldb_debug(ldb_module_get_ctx(module), LDB_DEBUG_ERROR,
1541                         "verify_name: Unable to register control with rootdse!\n");
1542                 return ldb_operr(ldb_module_get_ctx(module));
1543         }
1544
1545         la_private = talloc_zero(module, struct la_private);
1546         if (la_private == NULL) {
1547                 ldb_oom(ldb);
1548                 return LDB_ERR_OPERATIONS_ERROR;
1549         }
1550
1551         ret = dsdb_check_samba_compatible_feature(module,
1552                                                   SAMBA_SORTED_LINKS_FEATURE,
1553                                                   &la_private->sorted_links);
1554         if (ret != LDB_SUCCESS) {
1555                 talloc_free(la_private);
1556                 return ret;
1557         }
1558
1559         ldb_module_set_private(module, la_private);
1560         return ldb_next_init(module);
1561 }
1562
1563
1564 static const struct ldb_module_ops ldb_linked_attributes_module_ops = {
1565         .name              = "linked_attributes",
1566         .add               = linked_attributes_add,
1567         .modify            = linked_attributes_modify,
1568         .rename            = linked_attributes_rename,
1569         .init_context      = linked_attributes_ldb_init,
1570         .start_transaction = linked_attributes_start_transaction,
1571         .prepare_commit    = linked_attributes_prepare_commit,
1572         .del_transaction   = linked_attributes_del_transaction,
1573 };
1574
1575 int ldb_linked_attributes_module_init(const char *version)
1576 {
1577         LDB_MODULE_CHECK_VERSION(version);
1578         return ldb_register_module(&ldb_linked_attributes_module_ops);
1579 }