s4-dsdb: use LDB_FLAG_INTERNAL_DISABLE_SINGLE_VALUE_CHECK in dsdb
[obnox/samba/samba-obnox.git] / source4 / dsdb / samdb / ldb_modules / linked_attributes.c
1 /*
2    ldb database library
3
4    Copyright (C) Andrew Bartlett <abartlet@samba.org> 2007
5    Copyright (C) Simo Sorce <idra@samba.org> 2008
6
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                 LDB_REQ_SET_LOCATION(search_req);
567
568                 /* We need to figure out our own extended DN, to fill in as the backlink target */
569                 if (ret == LDB_SUCCESS) {
570                         ret = ldb_request_add_control(search_req,
571                                                       LDB_CONTROL_EXTENDED_DN_OID,
572                                                       false, NULL);
573                 }
574                 if (ret == LDB_SUCCESS) {
575                         talloc_steal(search_req, attrs);
576
577                         ret = ldb_next_request(module, search_req);
578                 }
579
580         } else {
581                 /* nothing to do for this module, proceed */
582                 talloc_free(ac);
583                 ret = ldb_next_request(module, req);
584         }
585
586         return ret;
587 }
588
589 static int linked_attributes_fix_links(struct ldb_module *module,
590                                        struct ldb_dn *old_dn, struct ldb_dn *new_dn,
591                                        struct ldb_message_element *el, struct dsdb_schema *schema,
592                                        const struct dsdb_attribute *schema_attr)
593 {
594         unsigned int i, j;
595         TALLOC_CTX *tmp_ctx = talloc_new(module);
596         struct ldb_context *ldb = ldb_module_get_ctx(module);
597         const struct dsdb_attribute *target;
598         const char *attrs[2];
599         int ret;
600
601         target = dsdb_attribute_by_linkID(schema, schema_attr->linkID ^ 1);
602         if (target == NULL) {
603                 /* there is no counterpart link to change */
604                 return LDB_SUCCESS;
605         }
606
607         attrs[0] = target->lDAPDisplayName;
608         attrs[1] = NULL;
609
610         for (i=0; i<el->num_values; i++) {
611                 struct dsdb_dn *dsdb_dn;
612                 struct ldb_result *res;
613                 struct ldb_message *msg;
614                 struct ldb_message_element *el2;
615
616                 dsdb_dn = dsdb_dn_parse(tmp_ctx, ldb, &el->values[i], schema_attr->syntax->ldap_oid);
617                 if (dsdb_dn == NULL) {
618                         talloc_free(tmp_ctx);
619                         return LDB_ERR_INVALID_DN_SYNTAX;
620                 }
621
622                 ret = dsdb_module_search_dn(module, tmp_ctx, &res, dsdb_dn->dn,
623                                             attrs,
624                                             DSDB_FLAG_NEXT_MODULE |
625                                             DSDB_SEARCH_SHOW_RECYCLED |
626                                             DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT |
627                                             DSDB_SEARCH_REVEAL_INTERNALS);
628                 if (ret != LDB_SUCCESS) {
629                         ldb_asprintf_errstring(ldb, "Linked attribute %s->%s between %s and %s - remote not found - %s",
630                                                el->name, target->lDAPDisplayName,
631                                                ldb_dn_get_linearized(old_dn),
632                                                ldb_dn_get_linearized(dsdb_dn->dn),
633                                                ldb_errstring(ldb));
634                         talloc_free(tmp_ctx);
635                         return ret;
636                 }
637                 msg = res->msgs[0];
638
639                 if (msg->num_elements == 0) {
640                         /* Forward link without backlink remaining - nothing to do here */
641                         continue;
642                 } else if (msg->num_elements != 1) {
643                         ldb_asprintf_errstring(ldb, "Bad msg elements - got %u elements, expected one element to be returned in linked_attributes_fix_links for %s",
644                                                msg->num_elements, ldb_dn_get_linearized(msg->dn));
645                         talloc_free(tmp_ctx);
646                         return LDB_ERR_OPERATIONS_ERROR;
647                 }
648                 if (ldb_attr_cmp(msg->elements[0].name, target->lDAPDisplayName) != 0) {
649                         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));
650                         talloc_free(tmp_ctx);
651                         return LDB_ERR_OPERATIONS_ERROR;
652                 }
653                 el2 = &msg->elements[0];
654
655                 el2->flags = LDB_FLAG_MOD_REPLACE;
656
657                 /* find our DN in the values */
658                 for (j=0; j<el2->num_values; j++) {
659                         struct dsdb_dn *dsdb_dn2;
660                         dsdb_dn2 = dsdb_dn_parse(msg, ldb, &el2->values[j], target->syntax->ldap_oid);
661                         if (dsdb_dn2 == NULL) {
662                                 talloc_free(tmp_ctx);
663                                 return LDB_ERR_INVALID_DN_SYNTAX;
664                         }
665                         if (ldb_dn_compare(old_dn, dsdb_dn2->dn) != 0) {
666                                 continue;
667                         }
668                         ret = ldb_dn_update_components(dsdb_dn2->dn, new_dn);
669                         if (ret != LDB_SUCCESS) {
670                                 talloc_free(tmp_ctx);
671                                 return ret;
672                         }
673
674                         el2->values[j] = data_blob_string_const(
675                                 dsdb_dn_get_extended_linearized(el2->values, dsdb_dn2, 1));
676                 }
677
678                 ret = dsdb_check_single_valued_link(target, el2);
679                 if (ret != LDB_SUCCESS) {
680                         talloc_free(tmp_ctx);
681                         return ret;
682                 }
683
684                 /* we may be putting multiple values in an attribute -
685                    disable checking for this attribute */
686                 el2->flags |= LDB_FLAG_INTERNAL_DISABLE_SINGLE_VALUE_CHECK;
687
688                 ret = dsdb_module_modify(module, msg, DSDB_FLAG_NEXT_MODULE);
689                 if (ret != LDB_SUCCESS) {
690                         ldb_asprintf_errstring(ldb, "Linked attribute %s->%s between %s and %s - update failed - %s",
691                                                el->name, target->lDAPDisplayName,
692                                                ldb_dn_get_linearized(old_dn),
693                                                ldb_dn_get_linearized(dsdb_dn->dn),
694                                                ldb_errstring(ldb));
695                         talloc_free(tmp_ctx);
696                         return ret;
697                 }
698         }
699
700         talloc_free(tmp_ctx);
701         return LDB_SUCCESS;
702 }
703
704
705 /* rename */
706 static int linked_attributes_rename(struct ldb_module *module, struct ldb_request *req)
707 {
708         struct ldb_result *res;
709         struct ldb_message *msg;
710         unsigned int i;
711         struct ldb_context *ldb = ldb_module_get_ctx(module);
712         struct dsdb_schema *schema;
713         int ret;
714         /*
715            - load the current msg
716            - find any linked attributes
717            - if its a link then find the target object
718            - modify the target linked attributes with the new DN
719         */
720         ret = dsdb_module_search_dn(module, req, &res, req->op.rename.olddn,
721                                     NULL,
722                                     DSDB_FLAG_NEXT_MODULE |
723                                     DSDB_SEARCH_SHOW_RECYCLED);
724         if (ret != LDB_SUCCESS) {
725                 return ret;
726         }
727
728         schema = dsdb_get_schema(ldb, res);
729         if (!schema) {
730                 return ldb_oom(ldb);
731         }
732
733         msg = res->msgs[0];
734
735         for (i=0; i<msg->num_elements; i++) {
736                 struct ldb_message_element *el = &msg->elements[i];
737                 const struct dsdb_attribute *schema_attr
738                         = dsdb_attribute_by_lDAPDisplayName(schema, el->name);
739                 if (!schema_attr || schema_attr->linkID == 0) {
740                         continue;
741                 }
742                 ret = linked_attributes_fix_links(module, msg->dn, req->op.rename.newdn, el,
743                                                   schema, schema_attr);
744                 if (ret != LDB_SUCCESS) {
745                         talloc_free(res);
746                         return ret;
747                 }
748         }
749
750         talloc_free(res);
751
752         return ldb_next_request(module, req);
753 }
754
755
756 /* queue a linked attributes modify request in the la_private
757    structure */
758 static int la_queue_mod_request(struct la_context *ac)
759 {
760         struct la_private *la_private =
761                 talloc_get_type(ldb_module_get_private(ac->module), struct la_private);
762
763         if (la_private == NULL) {
764                 ldb_debug(ldb_module_get_ctx(ac->module), LDB_DEBUG_ERROR, __location__ ": No la_private transaction setup\n");
765                 return ldb_operr(ldb_module_get_ctx(ac->module));
766         }
767
768         talloc_steal(la_private, ac);
769         DLIST_ADD(la_private->la_list, ac);
770
771         return ldb_module_done(ac->req, ac->op_controls,
772                                ac->op_response, LDB_SUCCESS);
773 }
774
775 /* Having done the original operation, then try to fix up all the linked attributes for modify and delete */
776 static int la_mod_del_callback(struct ldb_request *req, struct ldb_reply *ares)
777 {
778         struct la_context *ac;
779         struct ldb_context *ldb;
780         int ret;
781
782         ac = talloc_get_type(req->context, struct la_context);
783         ldb = ldb_module_get_ctx(ac->module);
784
785         if (!ares) {
786                 return ldb_module_done(ac->req, NULL, NULL,
787                                         LDB_ERR_OPERATIONS_ERROR);
788         }
789         if (ares->error != LDB_SUCCESS) {
790                 return ldb_module_done(ac->req, ares->controls,
791                                         ares->response, ares->error);
792         }
793
794         if (ares->type != LDB_REPLY_DONE) {
795                 ldb_set_errstring(ldb,
796                                   "invalid ldb_reply_type in callback");
797                 talloc_free(ares);
798                 return ldb_module_done(ac->req, NULL, NULL,
799                                         LDB_ERR_OPERATIONS_ERROR);
800         }
801
802         ac->op_controls = talloc_steal(ac, ares->controls);
803         ac->op_response = talloc_steal(ac, ares->response);
804
805         /* If we have modfies to make, this is the time to do them for modify and delete */
806         ret = la_queue_mod_request(ac);
807
808         if (ret != LDB_SUCCESS) {
809                 return ldb_module_done(ac->req, NULL, NULL, ret);
810         }
811         talloc_free(ares);
812
813         /* la_queue_mod_request has already sent the callbacks */
814         return LDB_SUCCESS;
815
816 }
817
818 /* Having done the original add, then try to fix up all the linked attributes
819
820   This is done after the add so the links can get the extended DNs correctly.
821  */
822 static int la_add_callback(struct ldb_request *req, struct ldb_reply *ares)
823 {
824         struct la_context *ac;
825         struct ldb_context *ldb;
826         int ret;
827
828         ac = talloc_get_type(req->context, struct la_context);
829         ldb = ldb_module_get_ctx(ac->module);
830
831         if (!ares) {
832                 return ldb_module_done(ac->req, NULL, NULL,
833                                         LDB_ERR_OPERATIONS_ERROR);
834         }
835         if (ares->error != LDB_SUCCESS) {
836                 return ldb_module_done(ac->req, ares->controls,
837                                         ares->response, ares->error);
838         }
839
840         if (ares->type != LDB_REPLY_DONE) {
841                 ldb_set_errstring(ldb,
842                                   "invalid ldb_reply_type in callback");
843                 talloc_free(ares);
844                 return ldb_module_done(ac->req, NULL, NULL,
845                                         LDB_ERR_OPERATIONS_ERROR);
846         }
847
848         if (ac->ops) {
849                 struct ldb_request *search_req;
850                 static const char *attrs[] = { NULL };
851
852                 /* The callback does all the hard work here - we need
853                  * the objectGUID and SID of the added record */
854                 ret = ldb_build_search_req(&search_req, ldb, ac,
855                                            ac->req->op.add.message->dn,
856                                            LDB_SCOPE_BASE,
857                                            "(objectClass=*)", attrs,
858                                            NULL,
859                                            ac, la_mod_search_callback,
860                                            ac->req);
861                 LDB_REQ_SET_LOCATION(search_req);
862
863                 if (ret == LDB_SUCCESS) {
864                         ret = ldb_request_add_control(search_req,
865                                                       LDB_CONTROL_EXTENDED_DN_OID,
866                                                       false, NULL);
867                 }
868                 if (ret != LDB_SUCCESS) {
869                         return ldb_module_done(ac->req, NULL, NULL,
870                                                ret);
871                 }
872
873                 ac->op_controls = talloc_steal(ac, ares->controls);
874                 ac->op_response = talloc_steal(ac, ares->response);
875
876                 return ldb_next_request(ac->module, search_req);
877
878         } else {
879                 return ldb_module_done(ac->req, ares->controls,
880                                        ares->response, ares->error);
881         }
882 }
883
884 /* Reconstruct the original request, but pointing at our local callback to finish things off */
885 static int la_down_req(struct la_context *ac)
886 {
887         struct ldb_request *down_req;
888         struct ldb_context *ldb;
889         int ret;
890
891         ldb = ldb_module_get_ctx(ac->module);
892
893         switch (ac->req->operation) {
894         case LDB_ADD:
895                 ret = ldb_build_add_req(&down_req, ldb, ac,
896                                         ac->req->op.add.message,
897                                         ac->req->controls,
898                                         ac, la_add_callback,
899                                         ac->req);
900                 LDB_REQ_SET_LOCATION(down_req);
901                 break;
902         case LDB_MODIFY:
903                 ret = ldb_build_mod_req(&down_req, ldb, ac,
904                                         ac->req->op.mod.message,
905                                         ac->req->controls,
906                                         ac, la_mod_del_callback,
907                                         ac->req);
908                 LDB_REQ_SET_LOCATION(down_req);
909                 break;
910         default:
911                 ret = LDB_ERR_OPERATIONS_ERROR;
912         }
913         if (ret != LDB_SUCCESS) {
914                 return ret;
915         }
916
917         return ldb_next_request(ac->module, down_req);
918 }
919
920 /*
921   use the GUID part of an extended DN to find the target DN, in case
922   it has moved
923  */
924 static int la_find_dn_target(struct ldb_module *module, struct la_context *ac,
925                              struct GUID *guid, struct ldb_dn **dn)
926 {
927         return dsdb_find_dn_by_guid(ldb_module_get_ctx(ac->module), ac, guid, dn);
928 }
929
930 /* apply one la_context op change */
931 static int la_do_op_request(struct ldb_module *module, struct la_context *ac, struct la_op_store *op)
932 {
933         struct ldb_message_element *ret_el;
934         struct ldb_message *new_msg;
935         struct ldb_context *ldb;
936         int ret;
937
938         ldb = ldb_module_get_ctx(ac->module);
939
940         /* Create the modify request */
941         new_msg = ldb_msg_new(ac);
942         if (!new_msg) {
943                 return ldb_oom(ldb);
944         }
945
946         ret = la_find_dn_target(module, ac, &op->guid, &new_msg->dn);
947         if (ret != LDB_SUCCESS) {
948                 return ret;
949         }
950
951         if (op->op == LA_OP_ADD) {
952                 ret = ldb_msg_add_empty(new_msg, op->name,
953                                         LDB_FLAG_MOD_ADD, &ret_el);
954         } else {
955                 ret = ldb_msg_add_empty(new_msg, op->name,
956                                         LDB_FLAG_MOD_DELETE, &ret_el);
957         }
958         if (ret != LDB_SUCCESS) {
959                 return ret;
960         }
961         ret_el->values = talloc_array(new_msg, struct ldb_val, 1);
962         if (!ret_el->values) {
963                 return ldb_oom(ldb);
964         }
965         ret_el->num_values = 1;
966         if (op->op == LA_OP_ADD) {
967                 ret_el->values[0] = data_blob_string_const(ldb_dn_get_extended_linearized(new_msg, ac->add_dn, 1));
968         } else {
969                 ret_el->values[0] = data_blob_string_const(ldb_dn_get_extended_linearized(new_msg, ac->del_dn, 1));
970         }
971
972 #if 0
973         ldb_debug(ldb, LDB_DEBUG_WARNING,
974                   "link on %s %s: %s %s\n",
975                   ldb_dn_get_linearized(new_msg->dn), ret_el->name,
976                   ret_el->values[0].data, ac->ops->op == LA_OP_ADD ? "added" : "deleted");
977 #endif
978
979         if (DEBUGLVL(4)) {
980                 DEBUG(4,("Applying linked attribute change:\n%s\n",
981                          ldb_ldif_message_string(ldb, op, LDB_CHANGETYPE_MODIFY, new_msg)));
982         }
983
984         ret = dsdb_module_modify(module, new_msg, DSDB_FLAG_NEXT_MODULE);
985         if (ret != LDB_SUCCESS) {
986                 ldb_debug(ldb, LDB_DEBUG_WARNING, "Failed to apply linked attribute change '%s'\n%s\n",
987                           ldb_errstring(ldb),
988                           ldb_ldif_message_string(ldb, op, LDB_CHANGETYPE_MODIFY, new_msg));
989         }
990
991         return ret;
992 }
993
994 /* apply one set of la_context changes */
995 static int la_do_mod_request(struct ldb_module *module, struct la_context *ac)
996 {
997         struct la_op_store *op;
998
999         for (op = ac->ops; op; op=op->next) {
1000                 int ret = la_do_op_request(module, ac, op);
1001                 if (ret != LDB_SUCCESS) {
1002                         if (ret != LDB_ERR_NO_SUCH_OBJECT) {
1003                                 return ret;
1004                         }
1005                 }
1006         }
1007
1008         return LDB_SUCCESS;
1009 }
1010
1011
1012 /*
1013   we hook into the transaction operations to allow us to
1014   perform the linked attribute updates at the end of the whole
1015   transaction. This allows a forward linked attribute to be created
1016   before the target is created, as long as the target is created
1017   in the same transaction
1018  */
1019 static int linked_attributes_start_transaction(struct ldb_module *module)
1020 {
1021         /* create our private structure for this transaction */
1022         struct la_private *la_private = talloc_get_type(ldb_module_get_private(module),
1023                                                         struct la_private);
1024         talloc_free(la_private);
1025         la_private = talloc(module, struct la_private);
1026         if (la_private == NULL) {
1027                 return ldb_oom(ldb_module_get_ctx(module));
1028         }
1029         la_private->la_list = NULL;
1030         ldb_module_set_private(module, la_private);
1031         return ldb_next_start_trans(module);
1032 }
1033
1034 /*
1035   on prepare commit we loop over our queued la_context structures
1036   and apply each of them
1037  */
1038 static int linked_attributes_prepare_commit(struct ldb_module *module)
1039 {
1040         struct la_private *la_private =
1041                 talloc_get_type(ldb_module_get_private(module), struct la_private);
1042         struct la_context *ac;
1043
1044         if (!la_private) {
1045                 /* prepare commit without begin_transaction - let someone else return the error, just don't segfault */
1046                 return ldb_next_prepare_commit(module);
1047         }
1048         /* walk the list backwards, to do the first entry first, as we
1049          * added the entries with DLIST_ADD() which puts them at the
1050          * start of the list */
1051
1052         /* Start at the end of the list - so we can start
1053          * there, but ensure we don't create a loop by NULLing
1054          * it out in the first element */
1055         ac = DLIST_TAIL(la_private->la_list);
1056
1057         for (; ac; ac=DLIST_PREV(ac)) {
1058                 int ret;
1059                 ac->req = NULL;
1060                 ret = la_do_mod_request(module, ac);
1061                 if (ret != LDB_SUCCESS) {
1062                         DEBUG(0,(__location__ ": Failed mod request ret=%d\n", ret));
1063                         talloc_free(la_private);
1064                         ldb_module_set_private(module, NULL);
1065                         return ret;
1066                 }
1067         }
1068
1069         talloc_free(la_private);
1070         ldb_module_set_private(module, NULL);
1071
1072         return ldb_next_prepare_commit(module);
1073 }
1074
1075 static int linked_attributes_del_transaction(struct ldb_module *module)
1076 {
1077         struct la_private *la_private =
1078                 talloc_get_type(ldb_module_get_private(module), struct la_private);
1079         talloc_free(la_private);
1080         ldb_module_set_private(module, NULL);
1081         return ldb_next_del_trans(module);
1082 }
1083
1084
1085 static const struct ldb_module_ops ldb_linked_attributes_module_ops = {
1086         .name              = "linked_attributes",
1087         .add               = linked_attributes_add,
1088         .modify            = linked_attributes_modify,
1089         .rename            = linked_attributes_rename,
1090         .start_transaction = linked_attributes_start_transaction,
1091         .prepare_commit    = linked_attributes_prepare_commit,
1092         .del_transaction   = linked_attributes_del_transaction,
1093 };
1094
1095 int ldb_linked_attributes_module_init(const char *version)
1096 {
1097         LDB_MODULE_CHECK_VERSION(version);
1098         return ldb_register_module(&ldb_linked_attributes_module_ops);
1099 }