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