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