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