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