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