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