dsdb: check NULL guid strings in la_fix_links
[kai/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 struct la_private {
57         struct la_context *la_list;
58 };
59
60 struct la_op_store {
61         struct la_op_store *next;
62         struct la_op_store *prev;
63         enum la_op {LA_OP_ADD, LA_OP_DEL} op;
64         struct GUID guid;
65         char *name;
66 };
67
68 struct replace_context {
69         struct la_context *ac;
70         unsigned int num_elements;
71         struct ldb_message_element *el;
72 };
73
74 struct la_context {
75         struct la_context *next, *prev;
76         const struct dsdb_schema *schema;
77         struct ldb_module *module;
78         struct ldb_request *req;
79         struct ldb_dn *mod_dn;
80         struct replace_context *rc;
81         struct la_op_store *ops;
82         struct ldb_extended *op_response;
83         struct ldb_control **op_controls;
84         /*
85          * For futur use
86          * will tell which GC to use for resolving links
87          */
88         char *gc_dns_name;
89 };
90
91
92 static int handle_verify_name_control(TALLOC_CTX *ctx, struct ldb_context *ldb,
93                                         struct ldb_control *control, struct la_context *ac)
94 {
95         /*
96          * If we are a GC let's remove the control,
97          * if there is a specified GC check that is us.
98          */
99         struct ldb_verify_name_control *lvnc = (struct ldb_verify_name_control *)control->data;
100         if (samdb_is_gc(ldb)) {
101                 /* Because we can't easily talloc a struct ldb_dn*/
102                 struct ldb_dn **dn = talloc_array(ctx, struct ldb_dn *, 1);
103                 int ret = samdb_server_reference_dn(ldb, ctx, dn);
104                 const char *dns;
105
106                 if (ret != LDB_SUCCESS) {
107                         return ldb_operr(ldb);
108                 }
109
110                 dns = samdb_dn_to_dnshostname(ldb, ctx, *dn);
111                 if (!dns) {
112                         return ldb_operr(ldb);
113                 }
114                 if (!lvnc->gc || strcasecmp(dns, lvnc->gc) == 0) {
115                         if (!ldb_save_controls(control, ctx, NULL)) {
116                                 return ldb_operr(ldb);
117                         }
118                 } else {
119                         control->critical = true;
120                 }
121                 talloc_free(dn);
122         } else {
123                 /* For the moment we don't remove the control is this case in order
124                  * to fail the request. It's better than having the client thinking
125                  * that we honnor its control.
126                  * Hopefully only a very small set of usecase should hit this problem.
127                  */
128                 if (lvnc->gc) {
129                         ac->gc_dns_name = talloc_strdup(ac, lvnc->gc);
130                 }
131                 control->critical = true;
132         }
133
134         return LDB_SUCCESS;
135 }
136
137 static struct la_context *linked_attributes_init(struct ldb_module *module,
138                                                  struct ldb_request *req)
139 {
140         struct ldb_context *ldb;
141         struct la_context *ac;
142
143         ldb = ldb_module_get_ctx(module);
144
145         ac = talloc_zero(req, struct la_context);
146         if (ac == NULL) {
147                 ldb_oom(ldb);
148                 return NULL;
149         }
150
151         ac->schema = dsdb_get_schema(ldb, ac);
152         ac->module = module;
153         ac->req = req;
154
155         return ac;
156 }
157
158 /*
159   turn a DN into a GUID
160  */
161 static int la_guid_from_dn(struct ldb_module *module,
162                            struct ldb_request *parent,
163                            struct ldb_dn *dn, struct GUID *guid)
164 {
165         NTSTATUS status;
166         int ret;
167
168         status = dsdb_get_extended_dn_guid(dn, guid, "GUID");
169         if (NT_STATUS_IS_OK(status)) {
170                 return LDB_SUCCESS;
171         }
172         if (!NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
173                 DEBUG(4,(__location__ ": Unable to parse GUID for dn %s\n",
174                          ldb_dn_get_linearized(dn)));
175                 return ldb_operr(ldb_module_get_ctx(module));
176         }
177
178         ret = dsdb_module_guid_by_dn(module, dn, guid, parent);
179         if (ret != LDB_SUCCESS) {
180                 DEBUG(4,(__location__ ": Failed to find GUID for dn %s\n",
181                          ldb_dn_get_linearized(dn)));
182                 return ret;
183         }
184         return LDB_SUCCESS;
185 }
186
187
188 /* Common routine to handle reading the attributes and creating a
189  * series of modify requests */
190 static int la_store_op(struct la_context *ac,
191                        enum la_op op, 
192                        const struct dsdb_attribute *schema_attr,
193                        struct ldb_val *dn,
194                        const char *name)
195 {
196         struct ldb_context *ldb;
197         struct la_op_store *os;
198         struct ldb_dn *op_dn;
199         struct dsdb_dn *dsdb_dn;
200         int ret;
201
202         ldb = ldb_module_get_ctx(ac->module);
203
204
205         os = talloc_zero(ac, struct la_op_store);
206         if (!os) {
207                 return ldb_oom(ldb);
208         }
209
210         dsdb_dn = dsdb_dn_parse(os, ldb, dn, schema_attr->syntax->ldap_oid);
211
212         if (!dsdb_dn) {
213                 ldb_asprintf_errstring(ldb,
214                                        "could not parse attribute as a DN");
215                 TALLOC_FREE(os);
216                 return LDB_ERR_INVALID_DN_SYNTAX;
217         }
218
219         op_dn = dsdb_dn->dn;
220
221         os->op = op;
222
223         ret = la_guid_from_dn(ac->module, ac->req, op_dn, &os->guid);
224         talloc_free(op_dn);
225         if (ret == LDB_ERR_NO_SUCH_OBJECT && ac->req->operation == LDB_DELETE) {
226                 /* we are deleting an object, and we've found it has a
227                  * forward link to a target that no longer
228                  * exists. This is not an error in the delete, and we
229                  * should just not do the deferred delete of the
230                  * target attribute
231                  */
232                 talloc_free(os);
233                 return LDB_SUCCESS;
234         }
235         if (ret != LDB_SUCCESS) {
236                 return ret;
237         }
238
239         os->name = talloc_strdup(os, name);
240         if (!os->name) {
241                 return ldb_oom(ldb);
242         }
243
244         /* Do deletes before adds */
245         if (op == LA_OP_ADD) {
246                 DLIST_ADD_END(ac->ops, os);
247         } else {
248                 /* By adding to the head of the list, we do deletes before
249                  * adds when processing a replace */
250                 DLIST_ADD(ac->ops, os);
251         }
252
253         return LDB_SUCCESS;
254 }
255
256 static int la_queue_mod_request(struct la_context *ac);
257 static int la_down_req(struct la_context *ac);
258
259
260
261 /* add */
262 static int linked_attributes_add(struct ldb_module *module, struct ldb_request *req)
263 {
264         struct ldb_context *ldb;
265         const struct dsdb_attribute *target_attr;
266         struct la_context *ac;
267         const char *attr_name;
268         struct ldb_control *ctrl;
269         unsigned int i, j;
270         struct ldb_control *control;
271         int ret;
272
273         ldb = ldb_module_get_ctx(module);
274
275         if (ldb_dn_is_special(req->op.add.message->dn)) {
276                 /* do not manipulate our control entries */
277                 return ldb_next_request(module, req);
278         }
279
280         ac = linked_attributes_init(module, req);
281         if (!ac) {
282                 return ldb_operr(ldb);
283         }
284
285         control = ldb_request_get_control(req, LDB_CONTROL_VERIFY_NAME_OID);
286         if (control != NULL && control->data != NULL) {
287                 ret = handle_verify_name_control(req, ldb, control, ac);
288                 if (ret != LDB_SUCCESS) {
289                         return ldb_operr(ldb);
290                 }
291         }
292
293         if (!(ctrl = ldb_request_get_control(req, DSDB_CONTROL_APPLY_LINKS))) {
294                 /* don't do anything special for linked attributes, repl_meta_data has done it */
295                 talloc_free(ac);
296                 return ldb_next_request(module, req);
297         }
298         ctrl->critical = false;
299
300         if (!ac->schema) {
301                 /* without schema, this doesn't make any sense */
302                 talloc_free(ac);
303                 return ldb_next_request(module, req);
304         }
305
306
307         /* Need to ensure we only have forward links being specified */
308         for (i=0; i < req->op.add.message->num_elements; i++) {
309                 const struct ldb_message_element *el = &req->op.add.message->elements[i];
310                 const struct dsdb_attribute *schema_attr
311                         = dsdb_attribute_by_lDAPDisplayName(ac->schema, el->name);
312                 if (!schema_attr) {
313                         ldb_asprintf_errstring(ldb,
314                                                "%s: attribute %s is not a valid attribute in schema",
315                                                __FUNCTION__,
316                                                el->name);
317                         return LDB_ERR_OBJECT_CLASS_VIOLATION;
318                 }
319
320                 /* this could be a link with no partner, in which case
321                    there is no special work to do */
322                 if (schema_attr->linkID == 0) {
323                         continue;
324                 }
325
326                 /* this part of the code should only be handling forward links */
327                 SMB_ASSERT((schema_attr->linkID & 1) == 0);
328
329                 /* Even link IDs are for the originating attribute */
330                 target_attr = dsdb_attribute_by_linkID(ac->schema, schema_attr->linkID ^ 1);
331                 if (!target_attr) {
332                         /*
333                          * windows 2003 has a broken schema where
334                          * the definition of msDS-IsDomainFor
335                          * is missing (which is supposed to be
336                          * the backlink of the msDS-HasDomainNCs
337                          * attribute
338                          */
339                         continue;
340                 }
341
342                 attr_name = target_attr->lDAPDisplayName;
343
344                 for (j = 0; j < el->num_values; j++) {
345                         ret = la_store_op(ac, LA_OP_ADD,
346                                           schema_attr,
347                                           &el->values[j],
348                                           attr_name);
349                         if (ret != LDB_SUCCESS) {
350                                 return ret;
351                         }
352                 }
353         }
354
355         /* if no linked attributes are present continue */
356         if (ac->ops == NULL) {
357                 /* nothing to do for this module, proceed */
358                 talloc_free(ac);
359                 return ldb_next_request(module, req);
360         }
361
362         /* start with the original request */
363         return la_down_req(ac);
364 }
365
366 /* For a delete or rename, we need to find out what linked attributes
367  * are currently on this DN, and then deal with them.  This is the
368  * callback to the base search */
369
370 static int la_mod_search_callback(struct ldb_request *req, struct ldb_reply *ares)
371 {
372         struct ldb_context *ldb;
373         const struct dsdb_attribute *schema_attr;
374         const struct dsdb_attribute *target_attr;
375         struct ldb_message_element *search_el;
376         struct replace_context *rc;
377         struct la_context *ac;
378         const char *attr_name;
379         unsigned int i, j;
380         int ret = LDB_SUCCESS;
381
382         ac = talloc_get_type(req->context, struct la_context);
383         ldb = ldb_module_get_ctx(ac->module);
384         rc = ac->rc;
385
386         if (!ares) {
387                 return ldb_module_done(ac->req, NULL, NULL,
388                                         LDB_ERR_OPERATIONS_ERROR);
389         }
390         if (ares->error != LDB_SUCCESS) {
391                 return ldb_module_done(ac->req, ares->controls,
392                                         ares->response, ares->error);
393         }
394
395         /* Only entries are interesting, and we only want the olddn */
396         switch (ares->type) {
397         case LDB_REPLY_ENTRY:
398
399                 if (ldb_dn_compare(ares->message->dn, ac->req->op.mod.message->dn) != 0) {
400                         ldb_asprintf_errstring(ldb,
401                                                "linked_attributes: %s is not the DN we were looking for",
402                                                ldb_dn_get_linearized(ares->message->dn));
403                         /* Guh?  We only asked for this DN */
404                         talloc_free(ares);
405                         return ldb_module_done(ac->req, NULL, NULL,
406                                                 LDB_ERR_OPERATIONS_ERROR);
407                 }
408
409                 ac->mod_dn = talloc_steal(ac, ares->message->dn);
410
411                 /* We don't populate 'rc' for ADD - it can't be deleting elements anyway */
412                 for (i = 0; rc && i < rc->num_elements; i++) {
413
414                         schema_attr = dsdb_attribute_by_lDAPDisplayName(ac->schema, rc->el[i].name);
415                         if (!schema_attr) {
416                                 ldb_asprintf_errstring(ldb,
417                                         "%s: attribute %s is not a valid attribute in schema",
418                                         __FUNCTION__,
419                                         rc->el[i].name);
420                                 talloc_free(ares);
421                                 return ldb_module_done(ac->req, NULL, NULL,
422                                                 LDB_ERR_OBJECT_CLASS_VIOLATION);
423                         }
424
425                         search_el = ldb_msg_find_element(ares->message,
426                                                          rc->el[i].name);
427
428                         /* See if this element already exists */
429                         /* otherwise just ignore as
430                          * the add has already been scheduled */
431                         if ( ! search_el) {
432                                 continue;
433                         }
434
435                         target_attr = dsdb_attribute_by_linkID(ac->schema, schema_attr->linkID ^ 1);
436                         if (!target_attr) {
437                                 /*
438                                  * windows 2003 has a broken schema where
439                                  * the definition of msDS-IsDomainFor
440                                  * is missing (which is supposed to be
441                                  * the backlink of the msDS-HasDomainNCs
442                                  * attribute
443                                  */
444                                 continue;
445                         }
446                         attr_name = target_attr->lDAPDisplayName;
447
448                         /* Now we know what was there, we can remove it for the re-add */
449                         for (j = 0; j < search_el->num_values; j++) {
450                                 ret = la_store_op(ac, LA_OP_DEL,
451                                                   schema_attr, 
452                                                   &search_el->values[j],
453                                                   attr_name);
454                                 if (ret != LDB_SUCCESS) {
455                                         talloc_free(ares);
456                                         return ldb_module_done(ac->req,
457                                                                NULL, NULL, ret);
458                                 }
459                         }
460                 }
461
462                 break;
463
464         case LDB_REPLY_REFERRAL:
465                 /* ignore */
466                 break;
467
468         case LDB_REPLY_DONE:
469
470                 talloc_free(ares);
471
472                 if (ac->req->operation == LDB_ADD) {
473                         /* Start the modifies to the backlinks */
474                         ret = la_queue_mod_request(ac);
475
476                         if (ret != LDB_SUCCESS) {
477                                 return ldb_module_done(ac->req, NULL, NULL,
478                                                        ret);
479                         }
480                 } else {
481                         /* Start with the original request */
482                         ret = la_down_req(ac);
483                         if (ret != LDB_SUCCESS) {
484                                 return ldb_module_done(ac->req, NULL, NULL, ret);
485                         }
486                 }
487                 return LDB_SUCCESS;
488         }
489
490         talloc_free(ares);
491         return ret;
492 }
493
494
495 /* modify */
496 static int linked_attributes_modify(struct ldb_module *module, struct ldb_request *req)
497 {
498         /* Look over list of modifications */
499         /* Find if any are for linked attributes */
500         /* Determine the effect of the modification */
501         /* Apply the modify to the linked entry */
502
503         struct ldb_control *control;
504         struct ldb_context *ldb;
505         unsigned int i, j;
506         struct la_context *ac;
507         struct ldb_request *search_req;
508         const char **attrs;
509         struct ldb_control *ctrl;
510         int ret;
511
512         ldb = ldb_module_get_ctx(module);
513
514         if (ldb_dn_is_special(req->op.mod.message->dn)) {
515                 /* do not manipulate our control entries */
516                 return ldb_next_request(module, req);
517         }
518
519         ac = linked_attributes_init(module, req);
520         if (!ac) {
521                 return ldb_operr(ldb);
522         }
523
524         control = ldb_request_get_control(req, LDB_CONTROL_VERIFY_NAME_OID);
525         if (control != NULL && control->data != NULL) {
526                 ret = handle_verify_name_control(req, ldb, control, ac);
527                 if (ret != LDB_SUCCESS) {
528                         return ldb_operr(ldb);
529                 }
530         }
531
532         if (!(ctrl = ldb_request_get_control(req, DSDB_CONTROL_APPLY_LINKS))) {
533                 /* don't do anything special for linked attributes, repl_meta_data has done it */
534                 talloc_free(ac);
535                 return ldb_next_request(module, req);
536         }
537         ctrl->critical = false;
538
539         if (!ac->schema) {
540                 /* without schema, this doesn't make any sense */
541                 return ldb_next_request(module, req);
542         }
543
544         ac->rc = talloc_zero(ac, struct replace_context);
545         if (!ac->rc) {
546                 return ldb_oom(ldb);
547         }
548
549         for (i=0; i < req->op.mod.message->num_elements; i++) {
550                 bool store_el = false;
551                 const char *attr_name;
552                 const struct dsdb_attribute *target_attr;
553                 const struct ldb_message_element *el = &req->op.mod.message->elements[i];
554                 const struct dsdb_attribute *schema_attr
555                         = dsdb_attribute_by_lDAPDisplayName(ac->schema, el->name);
556                 if (!schema_attr) {
557                         ldb_asprintf_errstring(ldb,
558                                                "%s: attribute %s is not a valid attribute in schema",
559                                                __FUNCTION__,
560                                                el->name);
561                         return LDB_ERR_OBJECT_CLASS_VIOLATION;
562                 }
563                 /* We have a valid attribute, now find out if it is a forward link
564                    (Even link IDs are for the originating attribute) */
565                 if (schema_attr->linkID == 0) {
566                         continue;
567                 }
568
569                 /* this part of the code should only be handling forward links */
570                 SMB_ASSERT((schema_attr->linkID & 1) == 0);
571
572                 /* Now find the target attribute */
573                 target_attr = dsdb_attribute_by_linkID(ac->schema, schema_attr->linkID ^ 1);
574                 if (!target_attr) {
575                         /*
576                          * windows 2003 has a broken schema where
577                          * the definition of msDS-IsDomainFor
578                          * is missing (which is supposed to be
579                          * the backlink of the msDS-HasDomainNCs
580                          * attribute
581                          */
582                         continue;
583                 }
584
585                 attr_name = target_attr->lDAPDisplayName;
586
587                 switch (el->flags & LDB_FLAG_MOD_MASK) {
588                 case LDB_FLAG_MOD_REPLACE:
589                         /* treat as just a normal add the delete part is handled by the callback */
590                         store_el = true;
591
592                         FALL_THROUGH;
593                 case LDB_FLAG_MOD_ADD:
594
595                         /* For each value being added, we need to setup the adds */
596                         for (j = 0; j < el->num_values; j++) {
597                                 ret = la_store_op(ac, LA_OP_ADD,
598                                                   schema_attr,
599                                                   &el->values[j],
600                                                   attr_name);
601                                 if (ret != LDB_SUCCESS) {
602                                         return ret;
603                                 }
604                         }
605                         break;
606
607                 case LDB_FLAG_MOD_DELETE:
608
609                         if (el->num_values) {
610                                 /* For each value being deleted, we need to setup the delete */
611                                 for (j = 0; j < el->num_values; j++) {
612                                         ret = la_store_op(ac, LA_OP_DEL,
613                                                           schema_attr,
614                                                           &el->values[j],
615                                                           attr_name);
616                                         if (ret != LDB_SUCCESS) {
617                                                 return ret;
618                                         }
619                                 }
620                         } else {
621                                 /* Flag that there was a DELETE
622                                  * without a value specified, so we
623                                  * need to look for the old value */
624                                 store_el = true;
625                         }
626
627                         break;
628                 }
629
630                 if (store_el) {
631                         struct ldb_message_element *search_el;
632
633                         search_el = talloc_realloc(ac->rc, ac->rc->el,
634                                                    struct ldb_message_element,
635                                                    ac->rc->num_elements +1);
636                         if (!search_el) {
637                                 return ldb_oom(ldb);
638                         }
639                         ac->rc->el = search_el;
640
641                         ac->rc->el[ac->rc->num_elements] = *el;
642                         ac->rc->num_elements++;
643                 }
644         }
645
646         if (ac->ops || ac->rc->el) {
647                 /* both replace and delete without values are handled in the callback
648                  * after the search on the entry to be modified is performed */
649
650                 attrs = talloc_array(ac->rc, const char *, ac->rc->num_elements + 1);
651                 if (!attrs) {
652                         return ldb_oom(ldb);
653                 }
654                 for (i = 0; ac->rc && i < ac->rc->num_elements; i++) {
655                         attrs[i] = ac->rc->el[i].name;
656                 }
657                 attrs[i] = NULL;
658
659                 /* The callback does all the hard work here */
660                 ret = ldb_build_search_req(&search_req, ldb, ac,
661                                            req->op.mod.message->dn,
662                                            LDB_SCOPE_BASE,
663                                            "(objectClass=*)", attrs,
664                                            NULL,
665                                            ac, la_mod_search_callback,
666                                            req);
667                 LDB_REQ_SET_LOCATION(search_req);
668
669                 /* We need to figure out our own extended DN, to fill in as the backlink target */
670                 if (ret == LDB_SUCCESS) {
671                         ret = dsdb_request_add_controls(search_req,
672                                                         DSDB_SEARCH_SHOW_RECYCLED |
673                                                         DSDB_SEARCH_SHOW_EXTENDED_DN);
674                 }
675                 if (ret == LDB_SUCCESS) {
676                         talloc_steal(search_req, attrs);
677
678                         ret = ldb_next_request(module, search_req);
679                 }
680
681         } else {
682                 /* nothing to do for this module, proceed */
683                 talloc_free(ac);
684                 ret = ldb_next_request(module, req);
685         }
686
687         return ret;
688 }
689
690 static int linked_attributes_fix_links(struct ldb_module *module,
691                                        struct GUID self_guid,
692                                        struct ldb_dn *old_dn, struct ldb_dn *new_dn,
693                                        struct ldb_message_element *el, struct dsdb_schema *schema,
694                                        const struct dsdb_attribute *schema_attr,
695                                        struct ldb_request *parent)
696 {
697         unsigned int i, j;
698         TALLOC_CTX *tmp_ctx = NULL;
699         struct ldb_context *ldb = ldb_module_get_ctx(module);
700         const struct dsdb_attribute *target;
701         const char *attrs[2];
702         int ret;
703
704         target = dsdb_attribute_by_linkID(schema, schema_attr->linkID ^ 1);
705         if (target == NULL) {
706                 /* there is no counterpart link to change */
707                 return LDB_SUCCESS;
708         }
709
710         tmp_ctx = talloc_new(module);
711         if (tmp_ctx == NULL) {
712                 return LDB_ERR_OPERATIONS_ERROR;
713         }
714
715         attrs[0] = target->lDAPDisplayName;
716         attrs[1] = NULL;
717
718         for (i=0; i<el->num_values; i++) {
719                 struct dsdb_dn *dsdb_dn;
720                 struct ldb_result *res;
721                 struct ldb_message *msg;
722                 struct ldb_message_element *el2;
723                 struct GUID link_guid;
724                 char *link_guid_str = NULL;
725
726                 dsdb_dn = dsdb_dn_parse(tmp_ctx, ldb, &el->values[i], schema_attr->syntax->ldap_oid);
727                 if (dsdb_dn == NULL) {
728                         talloc_free(tmp_ctx);
729                         return LDB_ERR_INVALID_DN_SYNTAX;
730                 }
731
732                 ret = la_guid_from_dn(module, parent, dsdb_dn->dn, &link_guid);
733                 if (ret != LDB_SUCCESS) {
734                         ldb_asprintf_errstring(ldb, "Linked attribute %s->%s between %s and %s - GUID not found - %s",
735                                                el->name, target->lDAPDisplayName,
736                                                ldb_dn_get_linearized(old_dn),
737                                                ldb_dn_get_linearized(dsdb_dn->dn),
738                                                ldb_errstring(ldb));
739                         talloc_free(tmp_ctx);
740                         return ret;
741                 }
742
743                 link_guid_str = GUID_string(tmp_ctx, &link_guid);
744                 if (link_guid_str == NULL) {
745                         talloc_free(tmp_ctx);
746                         return LDB_ERR_OPERATIONS_ERROR;
747                 }
748
749                 /*
750                  * get the existing message from the db for the object with
751                  * this GUID, returning attribute being modified. We will then
752                  * use this msg as the basis for a modify call
753                  */
754
755                 ret = dsdb_module_search(module, tmp_ctx, &res, NULL, LDB_SCOPE_SUBTREE, attrs,
756                                          DSDB_FLAG_NEXT_MODULE |
757                                          DSDB_SEARCH_SEARCH_ALL_PARTITIONS |
758                                          DSDB_SEARCH_SHOW_RECYCLED |
759                                          DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT |
760                                          DSDB_SEARCH_REVEAL_INTERNALS,
761                                          parent,
762                                          "objectGUID=%s", link_guid_str);
763                 if (ret != LDB_SUCCESS) {
764                         ldb_asprintf_errstring(ldb, "Linked attribute %s->%s between %s and %s - target GUID %s not found - %s",
765                                                el->name, target->lDAPDisplayName,
766                                                ldb_dn_get_linearized(old_dn),
767                                                ldb_dn_get_linearized(dsdb_dn->dn),
768                                                link_guid_str,
769                                                ldb_errstring(ldb));
770                         talloc_free(tmp_ctx);
771                         return ret;
772                 }
773                 if (res->count == 0) {
774                         /* Forward link without backlink object remaining - nothing to do here */
775                         continue;
776                 }
777                 if (res->count != 1) {
778                         ldb_asprintf_errstring(ldb, "Linked attribute %s->%s between %s and %s - target GUID %s found more than once!",
779                                                el->name, target->lDAPDisplayName,
780                                                ldb_dn_get_linearized(old_dn),
781                                                ldb_dn_get_linearized(dsdb_dn->dn),
782                                                link_guid_str);
783                         talloc_free(tmp_ctx);
784                         return LDB_ERR_OPERATIONS_ERROR;
785                 }
786
787                 msg = res->msgs[0];
788
789                 if (msg->num_elements == 0) {
790                         /* Forward link without backlink remaining - nothing to do here */
791                         continue;
792                 } else if (msg->num_elements != 1) {
793                         ldb_asprintf_errstring(ldb, "Bad msg elements - got %u elements, expected one element to be returned in linked_attributes_fix_links for %s",
794                                                msg->num_elements, ldb_dn_get_linearized(msg->dn));
795                         talloc_free(tmp_ctx);
796                         return LDB_ERR_OPERATIONS_ERROR;
797                 }
798                 if (ldb_attr_cmp(msg->elements[0].name, target->lDAPDisplayName) != 0) {
799                         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));
800                         talloc_free(tmp_ctx);
801                         return LDB_ERR_OPERATIONS_ERROR;
802                 }
803                 el2 = &msg->elements[0];
804
805                 el2->flags = LDB_FLAG_MOD_REPLACE;
806
807                 /* find our DN in the values */
808                 for (j=0; j<el2->num_values; j++) {
809                         struct dsdb_dn *dsdb_dn2;
810                         struct GUID link_guid2;
811
812                         dsdb_dn2 = dsdb_dn_parse(msg, ldb, &el2->values[j], target->syntax->ldap_oid);
813                         if (dsdb_dn2 == NULL) {
814                                 talloc_free(tmp_ctx);
815                                 return LDB_ERR_INVALID_DN_SYNTAX;
816                         }
817
818                         ret = la_guid_from_dn(module, parent, dsdb_dn2->dn, &link_guid2);
819                         if (ret != LDB_SUCCESS) {
820                                 talloc_free(tmp_ctx);
821                                 return ret;
822                         }
823
824                         /*
825                          * By comparing using the GUID we ensure that
826                          * even if somehow the name has got out of
827                          * sync, this rename will fix it.
828                          *
829                          * If somehow we don't have a GUID on the DN
830                          * in the DB, the la_guid_from_dn call will be
831                          * more costly, but still give us a GUID.
832                          * dbcheck will fix this if run.
833                          */
834                         if (!GUID_equal(&self_guid, &link_guid2)) {
835                                 continue;
836                         }
837
838                         ret = ldb_dn_update_components(dsdb_dn2->dn, new_dn);
839                         if (ret != LDB_SUCCESS) {
840                                 talloc_free(tmp_ctx);
841                                 return ret;
842                         }
843
844                         el2->values[j] = data_blob_string_const(
845                                 dsdb_dn_get_extended_linearized(el2->values, dsdb_dn2, 1));
846                 }
847
848                 ret = dsdb_check_single_valued_link(target, el2);
849                 if (ret != LDB_SUCCESS) {
850                         talloc_free(tmp_ctx);
851                         return ret;
852                 }
853
854                 /* we may be putting multiple values in an attribute -
855                    disable checking for this attribute */
856                 el2->flags |= LDB_FLAG_INTERNAL_DISABLE_SINGLE_VALUE_CHECK;
857
858                 ret = dsdb_module_modify(module, msg, DSDB_FLAG_NEXT_MODULE, parent);
859                 if (ret != LDB_SUCCESS) {
860                         ldb_asprintf_errstring(ldb, "Linked attribute %s->%s between %s and %s - update failed - %s",
861                                                el->name, target->lDAPDisplayName,
862                                                ldb_dn_get_linearized(old_dn),
863                                                ldb_dn_get_linearized(dsdb_dn->dn),
864                                                ldb_errstring(ldb));
865                         talloc_free(tmp_ctx);
866                         return ret;
867                 }
868         }
869
870         talloc_free(tmp_ctx);
871         return LDB_SUCCESS;
872 }
873
874
875 /* rename */
876 static int linked_attributes_rename(struct ldb_module *module, struct ldb_request *req)
877 {
878         struct ldb_result *res;
879         struct ldb_message *msg;
880         unsigned int i;
881         struct ldb_context *ldb = ldb_module_get_ctx(module);
882         struct dsdb_schema *schema;
883         int ret;
884         struct GUID guid;
885
886         /*
887            - load the current msg
888            - find any linked attributes
889            - if its a link then find the target object
890            - modify the target linked attributes with the new DN
891         */
892         ret = dsdb_module_search_dn(module, req, &res, req->op.rename.olddn,
893                                     NULL,
894                                     DSDB_FLAG_NEXT_MODULE |
895                                     DSDB_SEARCH_SHOW_EXTENDED_DN |
896                                     DSDB_SEARCH_SHOW_RECYCLED, req);
897         if (ret != LDB_SUCCESS) {
898                 return ret;
899         }
900
901         schema = dsdb_get_schema(ldb, res);
902         if (!schema) {
903                 return ldb_oom(ldb);
904         }
905
906         msg = res->msgs[0];
907
908         ret = la_guid_from_dn(module, req, msg->dn, &guid);
909         if (ret != LDB_SUCCESS) {
910                 return ret;
911         }
912
913         for (i=0; i<msg->num_elements; i++) {
914                 struct ldb_message_element *el = &msg->elements[i];
915                 const struct dsdb_attribute *schema_attr
916                         = dsdb_attribute_by_lDAPDisplayName(schema, el->name);
917                 if (!schema_attr || schema_attr->linkID == 0) {
918                         continue;
919                 }
920                 ret = linked_attributes_fix_links(module, guid, msg->dn, req->op.rename.newdn, el,
921                                                   schema, schema_attr, req);
922                 if (ret != LDB_SUCCESS) {
923                         talloc_free(res);
924                         return ret;
925                 }
926         }
927
928         talloc_free(res);
929
930         return ldb_next_request(module, req);
931 }
932
933
934 /* queue a linked attributes modify request in the la_private
935    structure */
936 static int la_queue_mod_request(struct la_context *ac)
937 {
938         struct la_private *la_private =
939                 talloc_get_type(ldb_module_get_private(ac->module), struct la_private);
940
941         if (la_private == NULL) {
942                 ldb_debug(ldb_module_get_ctx(ac->module), LDB_DEBUG_ERROR, __location__ ": No la_private transaction setup\n");
943                 return ldb_operr(ldb_module_get_ctx(ac->module));
944         }
945
946         talloc_steal(la_private, ac);
947         DLIST_ADD(la_private->la_list, ac);
948
949         return ldb_module_done(ac->req, ac->op_controls,
950                                ac->op_response, LDB_SUCCESS);
951 }
952
953 /* Having done the original operation, then try to fix up all the linked attributes for modify and delete */
954 static int la_mod_del_callback(struct ldb_request *req, struct ldb_reply *ares)
955 {
956         struct la_context *ac;
957         struct ldb_context *ldb;
958         int ret;
959
960         ac = talloc_get_type(req->context, struct la_context);
961         ldb = ldb_module_get_ctx(ac->module);
962
963         if (!ares) {
964                 return ldb_module_done(ac->req, NULL, NULL,
965                                         LDB_ERR_OPERATIONS_ERROR);
966         }
967         if (ares->error != LDB_SUCCESS) {
968                 return ldb_module_done(ac->req, ares->controls,
969                                         ares->response, ares->error);
970         }
971
972         if (ares->type != LDB_REPLY_DONE) {
973                 ldb_set_errstring(ldb,
974                                   "invalid ldb_reply_type in callback");
975                 talloc_free(ares);
976                 return ldb_module_done(ac->req, NULL, NULL,
977                                         LDB_ERR_OPERATIONS_ERROR);
978         }
979
980         ac->op_controls = talloc_steal(ac, ares->controls);
981         ac->op_response = talloc_steal(ac, ares->response);
982
983         /* If we have modfies to make, this is the time to do them for modify and delete */
984         ret = la_queue_mod_request(ac);
985
986         if (ret != LDB_SUCCESS) {
987                 return ldb_module_done(ac->req, NULL, NULL, ret);
988         }
989         talloc_free(ares);
990
991         /* la_queue_mod_request has already sent the callbacks */
992         return LDB_SUCCESS;
993
994 }
995
996 /* Having done the original add, then try to fix up all the linked attributes
997
998   This is done after the add so the links can get the extended DNs correctly.
999  */
1000 static int la_add_callback(struct ldb_request *req, struct ldb_reply *ares)
1001 {
1002         struct la_context *ac;
1003         struct ldb_context *ldb;
1004         int ret;
1005
1006         ac = talloc_get_type(req->context, struct la_context);
1007         ldb = ldb_module_get_ctx(ac->module);
1008
1009         if (!ares) {
1010                 return ldb_module_done(ac->req, NULL, NULL,
1011                                         LDB_ERR_OPERATIONS_ERROR);
1012         }
1013         if (ares->error != LDB_SUCCESS) {
1014                 return ldb_module_done(ac->req, ares->controls,
1015                                         ares->response, ares->error);
1016         }
1017
1018         if (ares->type != LDB_REPLY_DONE) {
1019                 ldb_set_errstring(ldb,
1020                                   "invalid ldb_reply_type in callback");
1021                 talloc_free(ares);
1022                 return ldb_module_done(ac->req, NULL, NULL,
1023                                         LDB_ERR_OPERATIONS_ERROR);
1024         }
1025
1026         if (ac->ops) {
1027                 struct ldb_request *search_req;
1028                 static const char *attrs[] = { NULL };
1029
1030                 /* The callback does all the hard work here - we need
1031                  * the objectGUID and SID of the added record */
1032                 ret = ldb_build_search_req(&search_req, ldb, ac,
1033                                            ac->req->op.add.message->dn,
1034                                            LDB_SCOPE_BASE,
1035                                            "(objectClass=*)", attrs,
1036                                            NULL,
1037                                            ac, la_mod_search_callback,
1038                                            ac->req);
1039                 LDB_REQ_SET_LOCATION(search_req);
1040
1041                 if (ret == LDB_SUCCESS) {
1042                         ret = dsdb_request_add_controls(search_req,
1043                                                         DSDB_SEARCH_SHOW_RECYCLED |
1044                                                         DSDB_SEARCH_SHOW_EXTENDED_DN);
1045                 }
1046                 if (ret != LDB_SUCCESS) {
1047                         return ldb_module_done(ac->req, NULL, NULL,
1048                                                ret);
1049                 }
1050
1051                 ac->op_controls = talloc_steal(ac, ares->controls);
1052                 ac->op_response = talloc_steal(ac, ares->response);
1053
1054                 return ldb_next_request(ac->module, search_req);
1055
1056         } else {
1057                 return ldb_module_done(ac->req, ares->controls,
1058                                        ares->response, ares->error);
1059         }
1060 }
1061
1062 /* Reconstruct the original request, but pointing at our local callback to finish things off */
1063 static int la_down_req(struct la_context *ac)
1064 {
1065         struct ldb_request *down_req;
1066         struct ldb_context *ldb;
1067         int ret;
1068
1069         ldb = ldb_module_get_ctx(ac->module);
1070
1071         switch (ac->req->operation) {
1072         case LDB_ADD:
1073                 ret = ldb_build_add_req(&down_req, ldb, ac,
1074                                         ac->req->op.add.message,
1075                                         ac->req->controls,
1076                                         ac, la_add_callback,
1077                                         ac->req);
1078                 LDB_REQ_SET_LOCATION(down_req);
1079                 break;
1080         case LDB_MODIFY:
1081                 ret = ldb_build_mod_req(&down_req, ldb, ac,
1082                                         ac->req->op.mod.message,
1083                                         ac->req->controls,
1084                                         ac, la_mod_del_callback,
1085                                         ac->req);
1086                 LDB_REQ_SET_LOCATION(down_req);
1087                 break;
1088         default:
1089                 ret = LDB_ERR_OPERATIONS_ERROR;
1090         }
1091         if (ret != LDB_SUCCESS) {
1092                 return ret;
1093         }
1094
1095         return ldb_next_request(ac->module, down_req);
1096 }
1097
1098 /*
1099   use the GUID part of an extended DN to find the target DN, in case
1100   it has moved
1101  */
1102 static int la_find_dn_target(struct ldb_module *module, struct la_context *ac,
1103                              struct GUID *guid, struct ldb_dn **dn)
1104 {
1105         return dsdb_module_dn_by_guid(ac->module, ac, guid, dn, ac->req);
1106 }
1107
1108 /* apply one la_context op change */
1109 static int la_do_op_request(struct ldb_module *module, struct la_context *ac, struct la_op_store *op)
1110 {
1111         struct ldb_message_element *ret_el;
1112         struct ldb_message *new_msg;
1113         struct ldb_context *ldb;
1114         int ret;
1115
1116         if (ac->mod_dn == NULL) {
1117                 /* we didn't find the DN that we searched for */
1118                 return LDB_SUCCESS;
1119         }
1120
1121         ldb = ldb_module_get_ctx(ac->module);
1122
1123         /* Create the modify request */
1124         new_msg = ldb_msg_new(ac);
1125         if (!new_msg) {
1126                 return ldb_oom(ldb);
1127         }
1128
1129         ret = la_find_dn_target(module, ac, &op->guid, &new_msg->dn);
1130         if (ret != LDB_SUCCESS) {
1131                 return ret;
1132         }
1133
1134         if (op->op == LA_OP_ADD) {
1135                 ret = ldb_msg_add_empty(new_msg, op->name,
1136                                         LDB_FLAG_MOD_ADD, &ret_el);
1137         } else {
1138                 ret = ldb_msg_add_empty(new_msg, op->name,
1139                                         LDB_FLAG_MOD_DELETE, &ret_el);
1140         }
1141         if (ret != LDB_SUCCESS) {
1142                 return ret;
1143         }
1144         ret_el->values = talloc_array(new_msg, struct ldb_val, 1);
1145         if (!ret_el->values) {
1146                 return ldb_oom(ldb);
1147         }
1148         ret_el->num_values = 1;
1149         ret_el->values[0] = data_blob_string_const(ldb_dn_get_extended_linearized(new_msg, ac->mod_dn, 1));
1150
1151         /* a backlink should never be single valued. Unfortunately the
1152            exchange schema has a attribute
1153            msExchBridgeheadedLocalConnectorsDNBL which is single
1154            valued and a backlink. We need to cope with that by
1155            ignoring the single value flag */
1156         ret_el->flags |= LDB_FLAG_INTERNAL_DISABLE_SINGLE_VALUE_CHECK;
1157
1158 #if 0
1159         ldb_debug(ldb, LDB_DEBUG_WARNING,
1160                   "link on %s %s: %s %s\n",
1161                   ldb_dn_get_linearized(new_msg->dn), ret_el->name,
1162                   ret_el->values[0].data, ac->ops->op == LA_OP_ADD ? "added" : "deleted");
1163 #endif
1164
1165         if (DEBUGLVL(4)) {
1166                 DEBUG(4,("Applying linked attribute change:\n%s\n",
1167                          ldb_ldif_message_redacted_string(ldb, op,
1168                                                           LDB_CHANGETYPE_MODIFY,
1169                                                           new_msg)));
1170         }
1171
1172         ret = dsdb_module_modify(module, new_msg, DSDB_FLAG_NEXT_MODULE, ac->req);
1173         if (ret != LDB_SUCCESS) {
1174                 ldb_debug(ldb, LDB_DEBUG_WARNING, __location__ ": failed to apply linked attribute change '%s'\n%s\n",
1175                           ldb_errstring(ldb),
1176                           ldb_ldif_message_redacted_string(ldb, op,
1177                                                            LDB_CHANGETYPE_MODIFY,
1178                                                            new_msg));
1179         }
1180
1181         return ret;
1182 }
1183
1184 /* apply one set of la_context changes */
1185 static int la_do_mod_request(struct ldb_module *module, struct la_context *ac)
1186 {
1187         struct la_op_store *op;
1188
1189         for (op = ac->ops; op; op=op->next) {
1190                 int ret = la_do_op_request(module, ac, op);
1191                 if (ret != LDB_SUCCESS) {
1192                         if (ret != LDB_ERR_NO_SUCH_OBJECT) {
1193                                 return ret;
1194                         }
1195                 }
1196         }
1197
1198         return LDB_SUCCESS;
1199 }
1200
1201
1202 /*
1203   we hook into the transaction operations to allow us to
1204   perform the linked attribute updates at the end of the whole
1205   transaction. This allows a forward linked attribute to be created
1206   before the target is created, as long as the target is created
1207   in the same transaction
1208  */
1209 static int linked_attributes_start_transaction(struct ldb_module *module)
1210 {
1211         /* create our private structure for this transaction */
1212         struct la_private *la_private = talloc_get_type(ldb_module_get_private(module),
1213                                                         struct la_private);
1214         talloc_free(la_private);
1215         la_private = talloc(module, struct la_private);
1216         if (la_private == NULL) {
1217                 return ldb_oom(ldb_module_get_ctx(module));
1218         }
1219         la_private->la_list = NULL;
1220         ldb_module_set_private(module, la_private);
1221         return ldb_next_start_trans(module);
1222 }
1223
1224 /*
1225   on prepare commit we loop over our queued la_context structures
1226   and apply each of them
1227  */
1228 static int linked_attributes_prepare_commit(struct ldb_module *module)
1229 {
1230         struct la_private *la_private =
1231                 talloc_get_type(ldb_module_get_private(module), struct la_private);
1232         struct la_context *ac;
1233
1234         if (!la_private) {
1235                 /* prepare commit without begin_transaction - let someone else return the error, just don't segfault */
1236                 return ldb_next_prepare_commit(module);
1237         }
1238         /* walk the list backwards, to do the first entry first, as we
1239          * added the entries with DLIST_ADD() which puts them at the
1240          * start of the list */
1241
1242         /* Start at the end of the list - so we can start
1243          * there, but ensure we don't create a loop by NULLing
1244          * it out in the first element */
1245         ac = DLIST_TAIL(la_private->la_list);
1246
1247         for (; ac; ac=DLIST_PREV(ac)) {
1248                 int ret;
1249                 ac->req = NULL;
1250                 ret = la_do_mod_request(module, ac);
1251                 if (ret != LDB_SUCCESS) {
1252                         DEBUG(0,(__location__ ": Failed mod request ret=%d\n", ret));
1253                         talloc_free(la_private);
1254                         ldb_module_set_private(module, NULL);
1255                         return ret;
1256                 }
1257         }
1258
1259         talloc_free(la_private);
1260         ldb_module_set_private(module, NULL);
1261
1262         return ldb_next_prepare_commit(module);
1263 }
1264
1265 static int linked_attributes_del_transaction(struct ldb_module *module)
1266 {
1267         struct la_private *la_private =
1268                 talloc_get_type(ldb_module_get_private(module), struct la_private);
1269         talloc_free(la_private);
1270         ldb_module_set_private(module, NULL);
1271         return ldb_next_del_trans(module);
1272 }
1273
1274 static int linked_attributes_ldb_init(struct ldb_module *module)
1275 {
1276         int ret;
1277
1278         ret = ldb_mod_register_control(module, LDB_CONTROL_VERIFY_NAME_OID);
1279         if (ret != LDB_SUCCESS) {
1280                 ldb_debug(ldb_module_get_ctx(module), LDB_DEBUG_ERROR,
1281                         "verify_name: Unable to register control with rootdse!\n");
1282                 return ldb_operr(ldb_module_get_ctx(module));
1283         }
1284
1285         return ldb_next_init(module);
1286 }
1287
1288
1289 static const struct ldb_module_ops ldb_linked_attributes_module_ops = {
1290         .name              = "linked_attributes",
1291         .add               = linked_attributes_add,
1292         .modify            = linked_attributes_modify,
1293         .rename            = linked_attributes_rename,
1294         .init_context      = linked_attributes_ldb_init,
1295         .start_transaction = linked_attributes_start_transaction,
1296         .prepare_commit    = linked_attributes_prepare_commit,
1297         .del_transaction   = linked_attributes_del_transaction,
1298 };
1299
1300 int ldb_linked_attributes_module_init(const char *version)
1301 {
1302         LDB_MODULE_CHECK_VERSION(version);
1303         return ldb_register_module(&ldb_linked_attributes_module_ops);
1304 }