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