dsdb/linked_attributes: initialise more pointers to NULL
[gd/samba-autobuild/.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; ac->rc && 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 {
705         int ret;
706         unsigned int i;
707         struct GUID link_guid;
708         struct ldb_message_element *el = &msg->elements[0];
709         struct ldb_context *ldb = ldb_module_get_ctx(module);
710         TALLOC_CTX *tmp_ctx = talloc_new(module);
711         if (tmp_ctx == NULL) {
712                 return LDB_ERR_OPERATIONS_ERROR;
713         }
714         /*
715          * The msg has one element (el) containing links of one particular
716          * type from the remote object. We know that at least one of those
717          * links points to the object being renamed (identified by self_guid,
718          * renamed to new_dn). Usually only one of the links will point back
719          * to renamed object, but there can be more when the reverse link is a
720          * DN+Binary link.
721          *
722          * This is used for unsorted links, which is to say back links and
723          * forward links on old databases.
724          */
725         for (i = 0; i < el->num_values; i++) {
726                 struct dsdb_dn *dsdb_dn = dsdb_dn_parse(msg,
727                                                         ldb,
728                                                         &el->values[i],
729                                                         syntax_oid);
730                 if (dsdb_dn == NULL) {
731                         talloc_free(tmp_ctx);
732                         return LDB_ERR_INVALID_DN_SYNTAX;
733                 }
734
735                 ret = la_guid_from_dn(module, parent, dsdb_dn->dn, &link_guid);
736                 if (ret != LDB_SUCCESS) {
737                         talloc_free(tmp_ctx);
738                         return ret;
739                 }
740
741                 /*
742                  * By comparing using the GUID we ensure that even if somehow
743                  * the name has got out of sync, this rename will fix it.
744                  *
745                  * If somehow we don't have a GUID on the DN in the DB, the
746                  * la_guid_from_dn call will be more costly, but still give us
747                  * a GUID. dbcheck will fix this if run.
748                  */
749                 if (!GUID_equal(&self_guid, &link_guid)) {
750                         continue;
751                 }
752
753                 ret = ldb_dn_update_components(dsdb_dn->dn, new_dn);
754                 if (ret != LDB_SUCCESS) {
755                         talloc_free(tmp_ctx);
756                         return ret;
757                 }
758
759                 el->values[i] = data_blob_string_const(
760                         dsdb_dn_get_extended_linearized(el->values, dsdb_dn, 1));
761         }
762
763         talloc_free(tmp_ctx);
764         return LDB_SUCCESS;
765 }
766
767
768 static int linked_attributes_fix_forward_link(struct ldb_module *module,
769                                               struct ldb_message *msg,
770                                               struct ldb_dn *new_dn,
771                                               struct GUID self_guid,
772                                               const char *syntax_oid)
773 {
774         int ret;
775         struct ldb_context *ldb = ldb_module_get_ctx(module);
776         struct parsed_dn *pdn_list = NULL;
777         struct parsed_dn *exact = NULL;
778         struct parsed_dn *next = NULL;
779         bool is_plain_dn;
780         struct ldb_message_element *el = &msg->elements[0];
781         unsigned int num_parsed_dns = el->num_values;
782
783         TALLOC_CTX *tmp_ctx = talloc_new(module);
784         if (tmp_ctx == NULL) {
785                 return LDB_ERR_OPERATIONS_ERROR;
786         }
787
788         /*
789          * The msg has a single element (el) containing forward links which we
790          * trust are sorted in GUID order. We know that at least one of those
791          * links points to the object being renamed (identified by self_guid,
792          * renamed to new_dn), because that object has a backlink pointing
793          * here.
794          *
795          * In most cases we assume there will only be one forward link, which
796          * is found by parsed_dn_find(), but in the case of DN+Binary links
797          * (e.g. msDS-RevealedUsers) there may be many forward links that
798          * share the same DN/GUID but differ in the binary part. For those we
799          * need to look around the link found by parsed_dn_find() and convert
800          * them all -- there is no way to know which forward link belongs to
801          * which backlink.
802          */
803
804         ret = get_parsed_dns_trusted(tmp_ctx, el, &pdn_list);
805         if (ret != LDB_SUCCESS) {
806                 ldb_asprintf_errstring(ldb, "get_parsed_dn_trusted() "
807                                        "error fixing %s links for %s",
808                                        el->name,
809                                        ldb_dn_get_linearized(msg->dn));
810                 talloc_free(tmp_ctx);
811                 return ret;
812         }
813
814         /* find our DN in the values */
815         ret = parsed_dn_find(ldb, pdn_list, num_parsed_dns,
816                              &self_guid,
817                              NULL,
818                              data_blob_null, 0,
819                              &exact, &next,
820                              syntax_oid,
821                              false);
822
823         if (ret != LDB_SUCCESS) {
824                 ldb_asprintf_errstring(ldb, "parsed_dn_find() "
825                                        "error fixing %s links for %s",
826                                        el->name,
827                                        ldb_dn_get_linearized(msg->dn));
828                 talloc_free(tmp_ctx);
829                 return ret;
830         }
831
832         if (exact == NULL) {
833                 ldb_asprintf_errstring(
834                         ldb,
835                         "parsed_dn_find could not find %s link for %s",
836                         el->name,
837                         ldb_dn_get_linearized(msg->dn));
838                 talloc_free(tmp_ctx);
839                 return LDB_ERR_OPERATIONS_ERROR;
840         }
841
842         is_plain_dn = strcmp(syntax_oid, LDB_SYNTAX_DN) == 0;
843
844         if (is_plain_dn) {
845                 /*
846                  *  The common case -- we only have to update a single link
847                  */
848                 ret = ldb_dn_update_components(exact->dsdb_dn->dn, new_dn);
849                 if (ret != LDB_SUCCESS) {
850                         DBG_ERR("could not update components  %s  %s\n",
851                                 ldb_dn_get_linearized(exact->dsdb_dn->dn),
852                                 ldb_dn_get_linearized(new_dn)
853                                 );
854
855                         talloc_free(tmp_ctx);
856                         return ret;
857                 }
858                 *(exact->v) = data_blob_string_const(
859                                 dsdb_dn_get_extended_linearized(el->values,
860                                                                 exact->dsdb_dn,
861                                                                 1));
862         } else {
863                 /*
864                  * The forward link is a DN+Binary (or in some alternate
865                  * universes, DN+String), which means the parsed_dns are keyed
866                  * on GUID+Binary. We don't know the binary part, which means
867                  * from our point of view the list can have entries with
868                  * duplicate GUIDs that we can't tell apart. We don't know
869                  * which backlink belongs to which GUID+binary, and the binary
870                  * search will always find the same one. That means one link
871                  * link will get fixed n times, whil n-1 links get fixed
872                  * never.
873                  *
874                  * If we instead fixing all the possible links, we end up
875                  * fixing n links n times, which at least works and is
876                  * probably not too costly because n is probably small.
877                  */
878                 struct parsed_dn *first = exact;
879                 struct parsed_dn *last = exact;
880                 struct parsed_dn *p = NULL;
881                 int cmp;
882                 while (first > pdn_list) {
883                         p = first - 1;
884                         if (p->dsdb_dn == NULL) {
885                                 ret = really_parse_trusted_dn(tmp_ctx,
886                                                               ldb, p,
887                                                               syntax_oid);
888                                 if (ret != LDB_SUCCESS) {
889                                         talloc_free(tmp_ctx);
890                                         return ret;
891                                 }
892                         }
893                         cmp = ndr_guid_compare(&exact->guid, &p->guid);
894                         if (cmp != 0) {
895                                 break;
896                         }
897                         first = p;
898                 }
899
900                 while (last < pdn_list + num_parsed_dns - 1) {
901                         p = last + 1;
902                         if (p->dsdb_dn == NULL) {
903                                 ret = really_parse_trusted_dn(tmp_ctx,
904                                                               ldb, p,
905                                                               syntax_oid);
906                                 if (ret != LDB_SUCCESS) {
907                                         talloc_free(tmp_ctx);
908                                         return ret;
909                                 }
910                         }
911                         cmp = ndr_guid_compare(&exact->guid, &p->guid);
912                         if (cmp != 0) {
913                                 break;
914                         }
915                         last = p;
916                 }
917
918                 for (p = first; p <= last; p++) {
919                         ret = ldb_dn_update_components(p->dsdb_dn->dn, new_dn);
920                         if (ret != LDB_SUCCESS) {
921                                 DBG_ERR("could not update components  %s  %s\n",
922                                         ldb_dn_get_linearized(p->dsdb_dn->dn),
923                                         ldb_dn_get_linearized(new_dn)
924                                         );
925                                 talloc_free(tmp_ctx);
926                                 return ret;
927                         }
928                         *(p->v) = data_blob_string_const(
929                                    dsdb_dn_get_extended_linearized(el->values,
930                                                                    p->dsdb_dn,
931                                                                    1));
932                 }
933         }
934
935         talloc_free(tmp_ctx);
936         return LDB_SUCCESS;
937 }
938
939
940 static int linked_attributes_fix_links(struct ldb_module *module,
941                                        struct GUID self_guid,
942                                        struct ldb_dn *old_dn, struct ldb_dn *new_dn,
943                                        struct ldb_message_element *el, struct dsdb_schema *schema,
944                                        const struct dsdb_attribute *schema_attr,
945                                        struct ldb_request *parent)
946 {
947         unsigned int i;
948         TALLOC_CTX *tmp_ctx = NULL;
949         struct ldb_context *ldb = ldb_module_get_ctx(module);
950         const struct dsdb_attribute *target = NULL;
951         const char *attrs[2];
952         int ret;
953         struct la_private *la_private = NULL;
954
955         target = dsdb_attribute_by_linkID(schema, schema_attr->linkID ^ 1);
956         if (target == NULL) {
957                 /* there is no counterpart link to change */
958                 return LDB_SUCCESS;
959         }
960
961         tmp_ctx = talloc_new(module);
962         if (tmp_ctx == NULL) {
963                 return LDB_ERR_OPERATIONS_ERROR;
964         }
965
966         la_private = talloc_get_type(ldb_module_get_private(module),
967                                      struct la_private);
968         if (la_private == NULL) {
969                 talloc_free(tmp_ctx);
970                 return LDB_ERR_OPERATIONS_ERROR;
971         }
972
973         attrs[0] = target->lDAPDisplayName;
974         attrs[1] = NULL;
975
976         for (i=0; i<el->num_values; i++) {
977                 struct dsdb_dn *dsdb_dn = NULL;
978                 struct ldb_result *res = NULL;
979                 struct ldb_message *msg  = NULL;
980                 struct ldb_message_element *el2 = NULL;
981                 struct GUID link_guid;
982                 char *link_guid_str = NULL;
983
984                 dsdb_dn = dsdb_dn_parse(tmp_ctx, ldb, &el->values[i], schema_attr->syntax->ldap_oid);
985                 if (dsdb_dn == NULL) {
986                         talloc_free(tmp_ctx);
987                         return LDB_ERR_INVALID_DN_SYNTAX;
988                 }
989
990                 ret = la_guid_from_dn(module, parent, dsdb_dn->dn, &link_guid);
991                 if (ret != LDB_SUCCESS) {
992                         ldb_asprintf_errstring(ldb, "Linked attribute %s->%s between %s and %s - GUID not found - %s",
993                                                el->name, target->lDAPDisplayName,
994                                                ldb_dn_get_linearized(old_dn),
995                                                ldb_dn_get_linearized(dsdb_dn->dn),
996                                                ldb_errstring(ldb));
997                         talloc_free(tmp_ctx);
998                         return ret;
999                 }
1000
1001                 link_guid_str = GUID_string(tmp_ctx, &link_guid);
1002                 if (link_guid_str == NULL) {
1003                         talloc_free(tmp_ctx);
1004                         return LDB_ERR_OPERATIONS_ERROR;
1005                 }
1006
1007                 /*
1008                  * get the existing message from the db for the object with
1009                  * this GUID, returning attribute being modified. We will then
1010                  * use this msg as the basis for a modify call
1011                  */
1012
1013                 ret = dsdb_module_search(module, tmp_ctx, &res, NULL, LDB_SCOPE_SUBTREE, attrs,
1014                                          DSDB_FLAG_NEXT_MODULE |
1015                                          DSDB_SEARCH_SEARCH_ALL_PARTITIONS |
1016                                          DSDB_SEARCH_SHOW_RECYCLED |
1017                                          DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT |
1018                                          DSDB_SEARCH_REVEAL_INTERNALS,
1019                                          parent,
1020                                          "objectGUID=%s", link_guid_str);
1021                 if (ret != LDB_SUCCESS) {
1022                         ldb_asprintf_errstring(ldb, "Linked attribute %s->%s between %s and %s - target GUID %s not found - %s",
1023                                                el->name, target->lDAPDisplayName,
1024                                                ldb_dn_get_linearized(old_dn),
1025                                                ldb_dn_get_linearized(dsdb_dn->dn),
1026                                                link_guid_str,
1027                                                ldb_errstring(ldb));
1028                         talloc_free(tmp_ctx);
1029                         return ret;
1030                 }
1031                 if (res->count == 0) {
1032                         /* Forward link without backlink object remaining - nothing to do here */
1033                         continue;
1034                 }
1035                 if (res->count != 1) {
1036                         ldb_asprintf_errstring(ldb, "Linked attribute %s->%s between %s and %s - target GUID %s found more than once!",
1037                                                el->name, target->lDAPDisplayName,
1038                                                ldb_dn_get_linearized(old_dn),
1039                                                ldb_dn_get_linearized(dsdb_dn->dn),
1040                                                link_guid_str);
1041                         talloc_free(tmp_ctx);
1042                         return LDB_ERR_OPERATIONS_ERROR;
1043                 }
1044
1045                 msg = res->msgs[0];
1046
1047                 if (msg->num_elements == 0) {
1048                         /* Forward link without backlink remaining - nothing to do here */
1049                         continue;
1050                 } else if (msg->num_elements != 1) {
1051                         ldb_asprintf_errstring(ldb, "Bad msg elements - got %u elements, expected one element to be returned in linked_attributes_fix_links for %s",
1052                                                msg->num_elements, ldb_dn_get_linearized(msg->dn));
1053                         talloc_free(tmp_ctx);
1054                         return LDB_ERR_OPERATIONS_ERROR;
1055                 }
1056                 if (ldb_attr_cmp(msg->elements[0].name, target->lDAPDisplayName) != 0) {
1057                         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));
1058                         talloc_free(tmp_ctx);
1059                         return LDB_ERR_OPERATIONS_ERROR;
1060                 }
1061                 el2 = &msg->elements[0];
1062
1063                 el2->flags = LDB_FLAG_MOD_REPLACE;
1064
1065                 if (target->linkID & 1 ||
1066                         ! la_private->sorted_links) {
1067                         /* handle backlinks (which aren't sorted in the DB)
1068                            and forward links in old unsorted databases. */
1069                         ret = linked_attributes_fix_link_slow(
1070                                 module,
1071                                 parent,
1072                                 msg,
1073                                 new_dn,
1074                                 self_guid,
1075                                 target->syntax->ldap_oid);
1076                 } else {
1077                         /* we can binary search to find forward links */
1078                         ret = linked_attributes_fix_forward_link(
1079                                 module,
1080                                 msg,
1081                                 new_dn,
1082                                 self_guid,
1083                                 target->syntax->ldap_oid);
1084                 }
1085                 ret = dsdb_check_single_valued_link(target, el2);
1086                 if (ret != LDB_SUCCESS) {
1087                         talloc_free(tmp_ctx);
1088                         return ret;
1089                 }
1090
1091                 /* we may be putting multiple values in an attribute -
1092                    disable checking for this attribute */
1093                 el2->flags |= LDB_FLAG_INTERNAL_DISABLE_SINGLE_VALUE_CHECK;
1094
1095                 ret = dsdb_module_modify(module, msg, DSDB_FLAG_NEXT_MODULE, parent);
1096                 if (ret != LDB_SUCCESS) {
1097                         ldb_asprintf_errstring(ldb, "Linked attribute %s->%s between %s and %s - update failed - %s",
1098                                                el->name, target->lDAPDisplayName,
1099                                                ldb_dn_get_linearized(old_dn),
1100                                                ldb_dn_get_linearized(dsdb_dn->dn),
1101                                                ldb_errstring(ldb));
1102                         talloc_free(tmp_ctx);
1103                         return ret;
1104                 }
1105         }
1106
1107         talloc_free(tmp_ctx);
1108         return LDB_SUCCESS;
1109 }
1110
1111
1112 /* rename */
1113 static int linked_attributes_rename(struct ldb_module *module, struct ldb_request *req)
1114 {
1115         struct ldb_result *res;
1116         struct ldb_message *msg;
1117         unsigned int i;
1118         struct ldb_context *ldb = ldb_module_get_ctx(module);
1119         struct dsdb_schema *schema;
1120         int ret;
1121         struct GUID guid;
1122
1123         /*
1124            - load the current msg
1125            - find any linked attributes
1126            - if its a link then find the target object
1127            - modify the target linked attributes with the new DN
1128         */
1129         ret = dsdb_module_search_dn(module, req, &res, req->op.rename.olddn,
1130                                     NULL,
1131                                     DSDB_FLAG_NEXT_MODULE |
1132                                     DSDB_SEARCH_SHOW_EXTENDED_DN |
1133                                     DSDB_SEARCH_SHOW_RECYCLED, req);
1134         if (ret != LDB_SUCCESS) {
1135                 return ret;
1136         }
1137
1138         schema = dsdb_get_schema(ldb, res);
1139         if (!schema) {
1140                 return ldb_oom(ldb);
1141         }
1142
1143         msg = res->msgs[0];
1144
1145         ret = la_guid_from_dn(module, req, msg->dn, &guid);
1146         if (ret != LDB_SUCCESS) {
1147                 return ret;
1148         }
1149
1150         for (i=0; i<msg->num_elements; i++) {
1151                 struct ldb_message_element *el = &msg->elements[i];
1152                 const struct dsdb_attribute *schema_attr
1153                         = dsdb_attribute_by_lDAPDisplayName(schema, el->name);
1154                 if (!schema_attr || schema_attr->linkID == 0) {
1155                         continue;
1156                 }
1157                 ret = linked_attributes_fix_links(module, guid, msg->dn, req->op.rename.newdn, el,
1158                                                   schema, schema_attr, req);
1159                 if (ret != LDB_SUCCESS) {
1160                         talloc_free(res);
1161                         return ret;
1162                 }
1163         }
1164
1165         talloc_free(res);
1166
1167         return ldb_next_request(module, req);
1168 }
1169
1170
1171 /* queue a linked attributes modify request in the la_private
1172    structure */
1173 static int la_queue_mod_request(struct la_context *ac)
1174 {
1175         struct la_private *la_private =
1176                 talloc_get_type(ldb_module_get_private(ac->module),
1177                                 struct la_private);
1178
1179         if (la_private == NULL || la_private->transaction == NULL) {
1180                 ldb_debug(ldb_module_get_ctx(ac->module),
1181                           LDB_DEBUG_ERROR,
1182                           __location__ ": No la_private transaction setup\n");
1183                 return ldb_operr(ldb_module_get_ctx(ac->module));
1184         }
1185
1186         talloc_steal(la_private->transaction, ac);
1187         DLIST_ADD(la_private->transaction->la_list, ac);
1188
1189         return ldb_module_done(ac->req, ac->op_controls,
1190                                ac->op_response, LDB_SUCCESS);
1191 }
1192
1193 /* Having done the original operation, then try to fix up all the linked attributes for modify and delete */
1194 static int la_mod_del_callback(struct ldb_request *req, struct ldb_reply *ares)
1195 {
1196         struct la_context *ac;
1197         struct ldb_context *ldb;
1198         int ret;
1199
1200         ac = talloc_get_type(req->context, struct la_context);
1201         ldb = ldb_module_get_ctx(ac->module);
1202
1203         if (!ares) {
1204                 return ldb_module_done(ac->req, NULL, NULL,
1205                                         LDB_ERR_OPERATIONS_ERROR);
1206         }
1207         if (ares->error != LDB_SUCCESS) {
1208                 return ldb_module_done(ac->req, ares->controls,
1209                                         ares->response, ares->error);
1210         }
1211
1212         if (ares->type != LDB_REPLY_DONE) {
1213                 ldb_set_errstring(ldb,
1214                      "invalid reply type in linked attributes delete callback");
1215                 talloc_free(ares);
1216                 return ldb_module_done(ac->req, NULL, NULL,
1217                                         LDB_ERR_OPERATIONS_ERROR);
1218         }
1219
1220         ac->op_controls = talloc_steal(ac, ares->controls);
1221         ac->op_response = talloc_steal(ac, ares->response);
1222
1223         /* If we have modfies to make, this is the time to do them for modify and delete */
1224         ret = la_queue_mod_request(ac);
1225
1226         if (ret != LDB_SUCCESS) {
1227                 return ldb_module_done(ac->req, NULL, NULL, ret);
1228         }
1229         talloc_free(ares);
1230
1231         /* la_queue_mod_request has already sent the callbacks */
1232         return LDB_SUCCESS;
1233
1234 }
1235
1236 /* Having done the original add, then try to fix up all the linked attributes
1237
1238   This is done after the add so the links can get the extended DNs correctly.
1239  */
1240 static int la_add_callback(struct ldb_request *req, struct ldb_reply *ares)
1241 {
1242         struct la_context *ac;
1243         struct ldb_context *ldb;
1244         int ret;
1245
1246         ac = talloc_get_type(req->context, struct la_context);
1247         ldb = ldb_module_get_ctx(ac->module);
1248
1249         if (!ares) {
1250                 return ldb_module_done(ac->req, NULL, NULL,
1251                                         LDB_ERR_OPERATIONS_ERROR);
1252         }
1253         if (ares->error != LDB_SUCCESS) {
1254                 return ldb_module_done(ac->req, ares->controls,
1255                                         ares->response, ares->error);
1256         }
1257
1258         if (ares->type != LDB_REPLY_DONE) {
1259                 ldb_set_errstring(ldb,
1260                         "invalid reply type in linked attributes add callback");
1261                 talloc_free(ares);
1262                 return ldb_module_done(ac->req, NULL, NULL,
1263                                         LDB_ERR_OPERATIONS_ERROR);
1264         }
1265
1266         if (ac->ops) {
1267                 struct ldb_request *search_req;
1268                 static const char *attrs[] = { NULL };
1269
1270                 /* The callback does all the hard work here - we need
1271                  * the objectGUID and SID of the added record */
1272                 ret = ldb_build_search_req(&search_req, ldb, ac,
1273                                            ac->req->op.add.message->dn,
1274                                            LDB_SCOPE_BASE,
1275                                            "(objectClass=*)", attrs,
1276                                            NULL,
1277                                            ac, la_mod_search_callback,
1278                                            ac->req);
1279                 LDB_REQ_SET_LOCATION(search_req);
1280
1281                 if (ret == LDB_SUCCESS) {
1282                         ret = dsdb_request_add_controls(search_req,
1283                                                         DSDB_SEARCH_SHOW_RECYCLED |
1284                                                         DSDB_SEARCH_SHOW_EXTENDED_DN);
1285                 }
1286                 if (ret != LDB_SUCCESS) {
1287                         return ldb_module_done(ac->req, NULL, NULL,
1288                                                ret);
1289                 }
1290
1291                 ac->op_controls = talloc_steal(ac, ares->controls);
1292                 ac->op_response = talloc_steal(ac, ares->response);
1293
1294                 return ldb_next_request(ac->module, search_req);
1295
1296         } else {
1297                 return ldb_module_done(ac->req, ares->controls,
1298                                        ares->response, ares->error);
1299         }
1300 }
1301
1302 /* Reconstruct the original request, but pointing at our local callback to finish things off */
1303 static int la_down_req(struct la_context *ac)
1304 {
1305         struct ldb_request *down_req;
1306         struct ldb_context *ldb;
1307         int ret;
1308
1309         ldb = ldb_module_get_ctx(ac->module);
1310
1311         switch (ac->req->operation) {
1312         case LDB_ADD:
1313                 ret = ldb_build_add_req(&down_req, ldb, ac,
1314                                         ac->req->op.add.message,
1315                                         ac->req->controls,
1316                                         ac, la_add_callback,
1317                                         ac->req);
1318                 LDB_REQ_SET_LOCATION(down_req);
1319                 break;
1320         case LDB_MODIFY:
1321                 ret = ldb_build_mod_req(&down_req, ldb, ac,
1322                                         ac->req->op.mod.message,
1323                                         ac->req->controls,
1324                                         ac, la_mod_del_callback,
1325                                         ac->req);
1326                 LDB_REQ_SET_LOCATION(down_req);
1327                 break;
1328         default:
1329                 ret = LDB_ERR_OPERATIONS_ERROR;
1330         }
1331         if (ret != LDB_SUCCESS) {
1332                 return ret;
1333         }
1334
1335         return ldb_next_request(ac->module, down_req);
1336 }
1337
1338 /*
1339   use the GUID part of an extended DN to find the target DN, in case
1340   it has moved
1341  */
1342 static int la_find_dn_target(struct ldb_module *module, struct la_context *ac,
1343                              struct GUID *guid, struct ldb_dn **dn)
1344 {
1345         return dsdb_module_dn_by_guid(ac->module, ac, guid, dn, ac->req);
1346 }
1347
1348 /* apply one la_context op change */
1349 static int la_do_op_request(struct ldb_module *module, struct la_context *ac, struct la_op_store *op)
1350 {
1351         struct ldb_message_element *ret_el;
1352         struct ldb_message *new_msg;
1353         struct ldb_context *ldb;
1354         int ret;
1355
1356         if (ac->mod_dn == NULL) {
1357                 /* we didn't find the DN that we searched for */
1358                 return LDB_SUCCESS;
1359         }
1360
1361         ldb = ldb_module_get_ctx(ac->module);
1362
1363         /* Create the modify request */
1364         new_msg = ldb_msg_new(ac);
1365         if (!new_msg) {
1366                 return ldb_oom(ldb);
1367         }
1368
1369         ret = la_find_dn_target(module, ac, &op->guid, &new_msg->dn);
1370         if (ret != LDB_SUCCESS) {
1371                 return ret;
1372         }
1373
1374         if (op->op == LA_OP_ADD) {
1375                 ret = ldb_msg_add_empty(new_msg, op->name,
1376                                         LDB_FLAG_MOD_ADD, &ret_el);
1377         } else {
1378                 ret = ldb_msg_add_empty(new_msg, op->name,
1379                                         LDB_FLAG_MOD_DELETE, &ret_el);
1380         }
1381         if (ret != LDB_SUCCESS) {
1382                 return ret;
1383         }
1384         ret_el->values = talloc_array(new_msg, struct ldb_val, 1);
1385         if (!ret_el->values) {
1386                 return ldb_oom(ldb);
1387         }
1388         ret_el->num_values = 1;
1389         ret_el->values[0] = data_blob_string_const(ldb_dn_get_extended_linearized(new_msg, ac->mod_dn, 1));
1390
1391         /* a backlink should never be single valued. Unfortunately the
1392            exchange schema has a attribute
1393            msExchBridgeheadedLocalConnectorsDNBL which is single
1394            valued and a backlink. We need to cope with that by
1395            ignoring the single value flag */
1396         ret_el->flags |= LDB_FLAG_INTERNAL_DISABLE_SINGLE_VALUE_CHECK;
1397
1398 #if 0
1399         ldb_debug(ldb, LDB_DEBUG_WARNING,
1400                   "link on %s %s: %s %s\n",
1401                   ldb_dn_get_linearized(new_msg->dn), ret_el->name,
1402                   ret_el->values[0].data, ac->ops->op == LA_OP_ADD ? "added" : "deleted");
1403 #endif
1404
1405         if (DEBUGLVL(4)) {
1406                 DEBUG(4,("Applying linked attribute change:\n%s\n",
1407                          ldb_ldif_message_redacted_string(ldb, op,
1408                                                           LDB_CHANGETYPE_MODIFY,
1409                                                           new_msg)));
1410         }
1411
1412         ret = dsdb_module_modify(module, new_msg, DSDB_FLAG_NEXT_MODULE, ac->req);
1413         if (ret != LDB_SUCCESS) {
1414                 ldb_debug(ldb, LDB_DEBUG_WARNING, __location__ ": failed to apply linked attribute change '%s'\n%s\n",
1415                           ldb_errstring(ldb),
1416                           ldb_ldif_message_redacted_string(ldb, op,
1417                                                            LDB_CHANGETYPE_MODIFY,
1418                                                            new_msg));
1419         }
1420
1421         return ret;
1422 }
1423
1424 /* apply one set of la_context changes */
1425 static int la_do_mod_request(struct ldb_module *module, struct la_context *ac)
1426 {
1427         struct la_op_store *op;
1428
1429         for (op = ac->ops; op; op=op->next) {
1430                 int ret = la_do_op_request(module, ac, op);
1431                 if (ret != LDB_SUCCESS) {
1432                         if (ret != LDB_ERR_NO_SUCH_OBJECT) {
1433                                 return ret;
1434                         }
1435                 }
1436         }
1437
1438         return LDB_SUCCESS;
1439 }
1440
1441
1442 /*
1443   we hook into the transaction operations to allow us to
1444   perform the linked attribute updates at the end of the whole
1445   transaction. This allows a forward linked attribute to be created
1446   before the target is created, as long as the target is created
1447   in the same transaction
1448  */
1449 static int linked_attributes_start_transaction(struct ldb_module *module)
1450 {
1451         /* create our private structure for this transaction */
1452         struct la_private *la_private =
1453                 talloc_get_type(ldb_module_get_private(module),
1454                                 struct la_private);
1455
1456         if (la_private == NULL) {
1457                 return ldb_oom(ldb_module_get_ctx(module));
1458         }
1459         talloc_free(la_private->transaction);
1460         la_private->transaction = talloc(module, struct la_private_transaction);
1461         if (la_private->transaction == NULL) {
1462                 return ldb_oom(ldb_module_get_ctx(module));
1463         }
1464         la_private->transaction->la_list = NULL;
1465         return ldb_next_start_trans(module);
1466 }
1467
1468 /*
1469   on prepare commit we loop over our queued la_context structures
1470   and apply each of them
1471  */
1472 static int linked_attributes_prepare_commit(struct ldb_module *module)
1473 {
1474         struct la_context *ac;
1475         struct la_private *la_private =
1476                 talloc_get_type(ldb_module_get_private(module),
1477                                 struct la_private);
1478         if (la_private == NULL || la_private->transaction == NULL) {
1479                 DBG_ERR("prepare_commit without begin_transaction\n");
1480                 /* prepare commit without begin_transaction - let someone else
1481                  * return the error, just don't segfault */
1482                 return ldb_next_prepare_commit(module);
1483         }
1484         /* walk the list backwards, to do the first entry first, as we
1485          * added the entries with DLIST_ADD() which puts them at the
1486          * start of the list */
1487
1488         /* Start at the end of the list - so we can start
1489          * there, but ensure we don't create a loop by NULLing
1490          * it out in the first element */
1491         ac = DLIST_TAIL(la_private->transaction->la_list);
1492
1493         for (; ac; ac=DLIST_PREV(ac)) {
1494                 int ret;
1495                 ac->req = NULL;
1496                 ret = la_do_mod_request(module, ac);
1497                 if (ret != LDB_SUCCESS) {
1498                         DEBUG(0,(__location__ ": Failed mod request ret=%d\n", ret));
1499                         TALLOC_FREE(la_private->transaction);
1500                         return ret;
1501                 }
1502         }
1503
1504         TALLOC_FREE(la_private->transaction);
1505
1506         return ldb_next_prepare_commit(module);
1507 }
1508
1509 static int linked_attributes_del_transaction(struct ldb_module *module)
1510 {
1511         struct la_private *la_private =
1512                 talloc_get_type(ldb_module_get_private(module),
1513                                 struct la_private);
1514         TALLOC_FREE(la_private->transaction);
1515         return ldb_next_del_trans(module);
1516 }
1517
1518 static int linked_attributes_ldb_init(struct ldb_module *module)
1519 {
1520         int ret;
1521         struct la_private *la_private = NULL;
1522         struct ldb_context *ldb = ldb_module_get_ctx(module);
1523
1524         ret = ldb_mod_register_control(module, LDB_CONTROL_VERIFY_NAME_OID);
1525         if (ret != LDB_SUCCESS) {
1526                 ldb_debug(ldb_module_get_ctx(module), LDB_DEBUG_ERROR,
1527                         "verify_name: Unable to register control with rootdse!\n");
1528                 return ldb_operr(ldb_module_get_ctx(module));
1529         }
1530
1531         la_private = talloc_zero(module, struct la_private);
1532         if (la_private == NULL) {
1533                 ldb_oom(ldb);
1534                 return LDB_ERR_OPERATIONS_ERROR;
1535         }
1536
1537         ret = dsdb_check_samba_compatible_feature(module,
1538                                                   SAMBA_SORTED_LINKS_FEATURE,
1539                                                   &la_private->sorted_links);
1540         if (ret != LDB_SUCCESS) {
1541                 talloc_free(la_private);
1542                 return ret;
1543         }
1544
1545         ldb_module_set_private(module, la_private);
1546         return ldb_next_init(module);
1547 }
1548
1549
1550 static const struct ldb_module_ops ldb_linked_attributes_module_ops = {
1551         .name              = "linked_attributes",
1552         .add               = linked_attributes_add,
1553         .modify            = linked_attributes_modify,
1554         .rename            = linked_attributes_rename,
1555         .init_context      = linked_attributes_ldb_init,
1556         .start_transaction = linked_attributes_start_transaction,
1557         .prepare_commit    = linked_attributes_prepare_commit,
1558         .del_transaction   = linked_attributes_del_transaction,
1559 };
1560
1561 int ldb_linked_attributes_module_init(const char *version)
1562 {
1563         LDB_MODULE_CHECK_VERSION(version);
1564         return ldb_register_module(&ldb_linked_attributes_module_ops);
1565 }