4 Copyright (C) Andrew Bartlett <abartlet@samba.org> 2007
5 Copyright (C) Simo Sorce <idra@samba.org> 2008
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.
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.
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/>.
24 * Component: ldb linked_attributes module
26 * Description: Module to ensure linked attribute pairs remain in sync
28 * Author: Andrew Bartlett
32 #include "ldb_module.h"
33 #include "dlinklist.h"
34 #include "dsdb/samdb/samdb.h"
37 struct la_context *la_list;
41 struct la_op_store *next;
42 struct la_op_store *prev;
43 enum la_op {LA_OP_ADD, LA_OP_DEL} op;
49 struct replace_context {
50 struct la_context *ac;
51 unsigned int num_elements;
52 struct ldb_message_element *el;
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;
69 static struct la_context *linked_attributes_init(struct ldb_module *module,
70 struct ldb_request *req)
72 struct ldb_context *ldb;
73 struct la_context *ac;
74 const struct ldb_control *partition_ctrl;
76 ldb = ldb_module_get_ctx(module);
78 ac = talloc_zero(req, struct la_context);
84 ac->schema = dsdb_get_schema(ldb);
88 /* remember the partition DN that came in, if given */
89 partition_ctrl = ldb_request_get_control(req, DSDB_CONTROL_CURRENT_PARTITION_OID);
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);
96 ac->partition_dn = ldb_dn_copy(ac, partition->dn);
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,
108 struct ldb_context *ldb;
109 struct la_op_store *os;
110 struct ldb_dn *op_dn;
112 ldb = ldb_module_get_ctx(ac->module);
114 op_dn = ldb_dn_from_ldb_val(ac, ldb, dn);
116 ldb_asprintf_errstring(ldb,
117 "could not parse attribute as a DN");
118 return LDB_ERR_INVALID_DN_SYNTAX;
121 os = talloc_zero(ac, struct la_op_store);
124 return LDB_ERR_OPERATIONS_ERROR;
129 os->dn = talloc_steal(os, op_dn);
131 os->name = talloc_strdup(os, name);
134 return LDB_ERR_OPERATIONS_ERROR;
137 /* Do deletes before adds */
138 if (op == LA_OP_ADD) {
139 DLIST_ADD_END(ac->ops, os, struct la_op_store *);
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);
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);
157 static int linked_attributes_add(struct ldb_module *module, struct ldb_request *req)
159 struct ldb_context *ldb;
160 const struct dsdb_attribute *target_attr;
161 struct la_context *ac;
162 const char *attr_name;
166 ldb = ldb_module_get_ctx(module);
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);
173 ac = linked_attributes_init(module, req);
175 return LDB_ERR_OPERATIONS_ERROR;
179 /* without schema, this doesn't make any sense */
181 return ldb_next_request(module, req);
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);
190 ldb_asprintf_errstring(ldb,
191 "attribute %s is not a valid attribute in schema", el->name);
192 return LDB_ERR_OBJECT_CLASS_VIOLATION;
194 /* We have a valid attribute, now find out if it is linked */
195 if (schema_attr->linkID == 0) {
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;
206 /* Even link IDs are for the originating attribute */
207 target_attr = dsdb_attribute_by_linkID(ac->schema, schema_attr->linkID + 1);
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
219 attr_name = target_attr->lDAPDisplayName;
221 for (j = 0; j < el->num_values; j++) {
222 ret = la_store_op(ac, LA_OP_ADD,
225 if (ret != LDB_SUCCESS) {
231 /* if no linked attributes are present continue */
232 if (ac->ops == NULL) {
233 /* nothing to do for this module, proceed */
235 return ldb_next_request(module, req);
238 /* start with the original request */
239 return la_down_req(ac);
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 */
246 static int la_mod_search_callback(struct ldb_request *req, struct ldb_reply *ares)
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;
256 int ret = LDB_SUCCESS;
258 ac = talloc_get_type(req->context, struct la_context);
259 ldb = ldb_module_get_ctx(ac->module);
263 return ldb_module_done(ac->req, NULL, NULL,
264 LDB_ERR_OPERATIONS_ERROR);
266 if (ares->error != LDB_SUCCESS) {
267 return ldb_module_done(ac->req, ares->controls,
268 ares->response, ares->error);
271 /* Only entries are interesting, and we only want the olddn */
272 switch (ares->type) {
273 case LDB_REPLY_ENTRY:
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 */
280 return ldb_module_done(ac->req, NULL, NULL,
281 LDB_ERR_OPERATIONS_ERROR);
284 ac->add_dn = ac->del_dn = talloc_steal(ac, ares->message->dn);
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++) {
289 schema_attr = dsdb_attribute_by_lDAPDisplayName(ac->schema, rc->el[i].name);
291 ldb_asprintf_errstring(ldb,
292 "attribute %s is not a valid attribute in schema",
295 return ldb_module_done(ac->req, NULL, NULL,
296 LDB_ERR_OBJECT_CLASS_VIOLATION);
299 search_el = ldb_msg_find_element(ares->message,
302 /* See if this element already exists */
303 /* otherwise just ignore as
304 * the add has already been scheduled */
309 target_attr = dsdb_attribute_by_linkID(ac->schema, schema_attr->linkID + 1);
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
320 attr_name = target_attr->lDAPDisplayName;
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],
327 if (ret != LDB_SUCCESS) {
329 return ldb_module_done(ac->req,
337 case LDB_REPLY_REFERRAL:
345 if (ac->req->operation == LDB_ADD) {
346 /* Start the modifies to the backlinks */
347 ret = la_queue_mod_request(ac);
349 if (ret != LDB_SUCCESS) {
350 return ldb_module_done(ac->req, NULL, NULL,
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);
369 static int linked_attributes_modify(struct ldb_module *module, struct ldb_request *req)
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 */
376 struct ldb_context *ldb;
378 struct la_context *ac;
379 struct ldb_request *search_req;
384 ldb = ldb_module_get_ctx(module);
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);
391 ac = linked_attributes_init(module, req);
393 return LDB_ERR_OPERATIONS_ERROR;
397 /* without schema, this doesn't make any sense */
398 return ldb_next_request(module, req);
401 ac->rc = talloc_zero(ac, struct replace_context);
404 return LDB_ERR_OPERATIONS_ERROR;
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);
415 ldb_asprintf_errstring(ldb,
416 "attribute %s is not a valid attribute in schema", el->name);
417 return LDB_ERR_OBJECT_CLASS_VIOLATION;
419 /* We have a valid attribute, now find out if it is linked */
420 if (schema_attr->linkID == 0) {
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;
431 /* Even link IDs are for the originating attribute */
433 /* Now find the target attribute */
434 target_attr = dsdb_attribute_by_linkID(ac->schema, schema_attr->linkID + 1);
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
446 attr_name = target_attr->lDAPDisplayName;
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 */
453 /* break intentionally missing */
455 case LDB_FLAG_MOD_ADD:
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,
462 if (ret != LDB_SUCCESS) {
468 case LDB_FLAG_MOD_DELETE:
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,
476 if (ret != LDB_SUCCESS) {
481 /* Flag that there was a DELETE
482 * without a value specified, so we
483 * need to look for the old value */
491 struct ldb_message_element *search_el;
493 search_el = talloc_realloc(ac->rc, ac->rc->el,
494 struct ldb_message_element,
495 ac->rc->num_elements +1);
498 return LDB_ERR_OPERATIONS_ERROR;
500 ac->rc->el = search_el;
502 ac->rc->el[ac->rc->num_elements] = *el;
503 ac->rc->num_elements++;
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 */
511 attrs = talloc_array(ac->rc, const char *, ac->rc->num_elements + 1);
514 return LDB_ERR_OPERATIONS_ERROR;
516 for (i = 0; ac->rc && i < ac->rc->num_elements; i++) {
517 attrs[i] = ac->rc->el[i].name;
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,
525 "(objectClass=*)", attrs,
527 ac, la_mod_search_callback,
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,
536 if (ret == LDB_SUCCESS) {
537 talloc_steal(search_req, attrs);
539 ret = ldb_next_request(module, search_req);
543 /* nothing to do for this module, proceed */
545 ret = ldb_next_request(module, req);
552 static int linked_attributes_del(struct ldb_module *module, struct ldb_request *req)
554 struct ldb_context *ldb;
555 struct ldb_request *search_req;
556 struct la_context *ac;
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
570 ldb = ldb_module_get_ctx(module);
572 ac = linked_attributes_init(module, req);
574 return LDB_ERR_OPERATIONS_ERROR;
578 /* without schema, this doesn't make any sense */
579 return ldb_next_request(module, req);
582 werr = dsdb_linked_attribute_lDAPDisplayName_list(ac->schema, ac, &attrs);
583 if (!W_ERROR_IS_OK(werr)) {
584 return LDB_ERR_OPERATIONS_ERROR;
587 ret = ldb_build_search_req(&search_req, ldb, req,
588 req->op.del.dn, LDB_SCOPE_BASE,
589 "(objectClass=*)", attrs,
591 ac, la_op_search_callback,
594 if (ret != LDB_SUCCESS) {
598 talloc_steal(search_req, attrs);
600 return ldb_next_request(module, search_req);
604 static int linked_attributes_rename(struct ldb_module *module, struct ldb_request *req)
606 struct la_context *ac;
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
617 ac = linked_attributes_init(module, req);
619 return LDB_ERR_OPERATIONS_ERROR;
623 /* without schema, this doesn't make any sense */
624 return ldb_next_request(module, req);
627 /* start with the original request */
628 return la_down_req(ac);
632 static int la_op_search_callback(struct ldb_request *req,
633 struct ldb_reply *ares)
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;
644 ac = talloc_get_type(req->context, struct la_context);
645 ldb = ldb_module_get_ctx(ac->module);
648 return ldb_module_done(ac->req, NULL, NULL,
649 LDB_ERR_OPERATIONS_ERROR);
651 if (ares->error != LDB_SUCCESS) {
652 return ldb_module_done(ac->req, ares->controls,
653 ares->response, ares->error);
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);
661 /* Guh? We only asked for this DN */
663 return ldb_module_done(ac->req, NULL, NULL,
664 LDB_ERR_OPERATIONS_ERROR);
666 if (ares->message->num_elements == 0) {
667 /* only bother at all if there were some
668 * linked attributes found */
673 switch (ac->req->operation) {
675 ac->del_dn = talloc_steal(ac, ares->message->dn);
678 ac->add_dn = talloc_steal(ac, ares->message->dn);
679 ac->del_dn = talloc_steal(ac, ac->req->op.rename.olddn);
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);
689 for (i = 0; i < ares->message->num_elements; i++) {
690 el = &ares->message->elements[i];
692 schema_attr = dsdb_attribute_by_lDAPDisplayName(ac->schema, el->name);
694 ldb_asprintf_errstring(ldb,
695 "attribute %s is not a valid attribute"
696 " in schema", el->name);
698 return ldb_module_done(ac->req, NULL, NULL,
699 LDB_ERR_OBJECT_CLASS_VIOLATION);
702 /* Valid attribute, now find out if it is linked */
703 if (schema_attr->linkID == 0) {
704 /* Not a linked attribute, skip */
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);
714 attr_name = target_attr->lDAPDisplayName;
716 target_attr = dsdb_attribute_by_linkID(ac->schema, schema_attr->linkID - 1);
720 attr_name = target_attr->lDAPDisplayName;
722 for (j = 0; j < el->num_values; j++) {
723 ret = la_store_op(ac, LA_OP_DEL,
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,
734 if (ret != LDB_SUCCESS) {
736 return ldb_module_done(ac->req,
744 case LDB_REPLY_REFERRAL:
753 switch (ac->req->operation) {
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);
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,
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);
784 /* queue a linked attributes modify request in the la_private
786 static int la_queue_mod_request(struct la_context *ac)
788 struct la_private *la_private =
789 talloc_get_type(ldb_module_get_private(ac->module), struct la_private);
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;
796 talloc_steal(la_private, ac);
797 DLIST_ADD(la_private->la_list, ac);
799 return ldb_module_done(ac->req, ac->op_controls,
800 ac->op_response, LDB_SUCCESS);
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)
807 struct la_context *ac;
808 struct ldb_context *ldb;
810 ac = talloc_get_type(req->context, struct la_context);
811 ldb = ldb_module_get_ctx(ac->module);
814 return ldb_module_done(ac->req, NULL, NULL,
815 LDB_ERR_OPERATIONS_ERROR);
817 if (ares->error != LDB_SUCCESS) {
818 return ldb_module_done(ac->req, ares->controls,
819 ares->response, ares->error);
822 if (ares->type != LDB_REPLY_DONE) {
823 ldb_set_errstring(ldb,
824 "invalid ldb_reply_type in callback");
826 return ldb_module_done(ac->req, NULL, NULL,
827 LDB_ERR_OPERATIONS_ERROR);
830 ac->op_controls = talloc_steal(ac, ares->controls);
831 ac->op_response = talloc_steal(ac, ares->response);
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);
836 if (ret != LDB_SUCCESS) {
837 return ldb_module_done(ac->req, NULL, NULL, ret);
841 /* la_queue_mod_request has already sent the callbacks */
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)
850 struct la_context *ac;
851 struct ldb_request *search_req;
854 struct ldb_context *ldb;
856 ac = talloc_get_type(req->context, struct la_context);
857 ldb = ldb_module_get_ctx(ac->module);
860 return ldb_module_done(ac->req, NULL, NULL,
861 LDB_ERR_OPERATIONS_ERROR);
863 if (ares->error != LDB_SUCCESS) {
864 return ldb_module_done(ac->req, ares->controls,
865 ares->response, ares->error);
868 if (ares->type != LDB_REPLY_DONE) {
869 ldb_set_errstring(ldb,
870 "invalid ldb_reply_type in callback");
872 return ldb_module_done(ac->req, NULL, NULL,
873 LDB_ERR_OPERATIONS_ERROR);
876 werr = dsdb_linked_attribute_lDAPDisplayName_list(ac->schema, ac, &attrs);
877 if (!W_ERROR_IS_OK(werr)) {
878 return LDB_ERR_OPERATIONS_ERROR;
881 ret = ldb_build_search_req(&search_req, ldb, req,
882 ac->req->op.rename.newdn, LDB_SCOPE_BASE,
883 "(objectClass=*)", attrs,
885 ac, la_op_search_callback,
888 if (ret != LDB_SUCCESS) {
892 talloc_steal(search_req, attrs);
894 if (ret == LDB_SUCCESS) {
895 ret = ldb_request_add_control(search_req,
896 LDB_CONTROL_EXTENDED_DN_OID,
899 if (ret != LDB_SUCCESS) {
900 return ldb_module_done(ac->req, NULL, NULL,
904 ac->op_controls = talloc_steal(ac, ares->controls);
905 ac->op_response = talloc_steal(ac, ares->response);
907 return ldb_next_request(ac->module, search_req);
910 /* Having done the original add, then try to fix up all the linked attributes
912 This is done after the add so the links can get the extended DNs correctly.
914 static int la_add_callback(struct ldb_request *req, struct ldb_reply *ares)
917 struct la_context *ac;
918 struct ldb_context *ldb;
920 ac = talloc_get_type(req->context, struct la_context);
921 ldb = ldb_module_get_ctx(ac->module);
924 return ldb_module_done(ac->req, NULL, NULL,
925 LDB_ERR_OPERATIONS_ERROR);
927 if (ares->error != LDB_SUCCESS) {
928 return ldb_module_done(ac->req, ares->controls,
929 ares->response, ares->error);
932 if (ares->type != LDB_REPLY_DONE) {
933 ldb_set_errstring(ldb,
934 "invalid ldb_reply_type in callback");
936 return ldb_module_done(ac->req, NULL, NULL,
937 LDB_ERR_OPERATIONS_ERROR);
941 struct ldb_request *search_req;
942 static const char *attrs[] = { NULL };
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,
949 "(objectClass=*)", attrs,
951 ac, la_mod_search_callback,
954 if (ret == LDB_SUCCESS) {
955 ret = ldb_request_add_control(search_req,
956 LDB_CONTROL_EXTENDED_DN_OID,
959 if (ret != LDB_SUCCESS) {
960 return ldb_module_done(ac->req, NULL, NULL,
964 ac->op_controls = talloc_steal(ac, ares->controls);
965 ac->op_response = talloc_steal(ac, ares->response);
967 return ldb_next_request(ac->module, search_req);
970 return ldb_module_done(ac->req, ares->controls,
971 ares->response, ares->error);
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)
978 struct ldb_request *down_req;
980 struct ldb_context *ldb;
982 ldb = ldb_module_get_ctx(ac->module);
984 switch (ac->req->operation) {
986 ret = ldb_build_add_req(&down_req, ldb, ac,
987 ac->req->op.add.message,
993 ret = ldb_build_mod_req(&down_req, ldb, ac,
994 ac->req->op.mod.message,
996 ac, la_mod_del_callback,
1000 ret = ldb_build_del_req(&down_req, ldb, ac,
1003 ac, la_mod_del_callback,
1007 ret = ldb_build_rename_req(&down_req, ldb, ac,
1008 ac->req->op.rename.olddn,
1009 ac->req->op.rename.newdn,
1011 ac, la_rename_callback,
1015 ret = LDB_ERR_OPERATIONS_ERROR;
1017 if (ret != LDB_SUCCESS) {
1021 return ldb_next_request(ac->module, down_req);
1025 use the GUID part of an extended DN to find the target DN, in case
1028 static int la_find_dn_target(struct ldb_module *module, struct la_context *ac, struct ldb_dn **dn)
1030 const struct ldb_val *guid;
1031 struct ldb_context *ldb;
1033 struct ldb_result *res;
1034 const char *attrs[] = { NULL };
1035 struct ldb_request *search_req;
1037 struct ldb_search_options_control *options;
1039 ldb = ldb_module_get_ctx(ac->module);
1041 guid = ldb_dn_get_extended_component(*dn, "GUID");
1046 expression = talloc_asprintf(ac, "objectGUID=%s", ldb_binary_encode(ac, *guid));
1049 return LDB_ERR_OPERATIONS_ERROR;
1052 res = talloc_zero(ac, struct ldb_result);
1055 return LDB_ERR_OPERATIONS_ERROR;
1058 ret = ldb_build_search_req(&search_req, ldb, ac,
1059 ldb_get_default_basedn(ldb),
1063 res, ldb_search_default_callback,
1065 if (ret != LDB_SUCCESS) {
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) {
1074 return LDB_ERR_OPERATIONS_ERROR;
1076 options->search_options = LDB_SEARCH_OPTION_PHANTOM_ROOT;
1078 ret = ldb_request_add_control(search_req,
1079 LDB_CONTROL_SEARCH_OPTIONS_OID,
1081 if (ret != LDB_SUCCESS) {
1085 ret = ldb_next_request(module, search_req);
1086 if (ret != LDB_SUCCESS) {
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));
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;
1106 *dn = res->msgs[0]->dn;
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)
1114 struct ldb_message_element *ret_el;
1115 struct ldb_request *mod_req;
1116 struct ldb_message *new_msg;
1117 struct ldb_context *ldb;
1120 ldb = ldb_module_get_ctx(ac->module);
1122 /* Create the modify request */
1123 new_msg = ldb_msg_new(ac);
1126 return LDB_ERR_OPERATIONS_ERROR;
1129 new_msg->dn = op->dn;
1130 ret = la_find_dn_target(module, ac, &new_msg->dn);
1131 if (ret != LDB_SUCCESS) {
1135 if (op->op == LA_OP_ADD) {
1136 ret = ldb_msg_add_empty(new_msg, op->name,
1137 LDB_FLAG_MOD_ADD, &ret_el);
1139 ret = ldb_msg_add_empty(new_msg, op->name,
1140 LDB_FLAG_MOD_DELETE, &ret_el);
1142 if (ret != LDB_SUCCESS) {
1145 ret_el->values = talloc_array(new_msg, struct ldb_val, 1);
1146 if (!ret_el->values) {
1148 return LDB_ERR_OPERATIONS_ERROR;
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));
1154 ret_el->values[0] = data_blob_string_const(ldb_dn_get_extended_linearized(new_msg, ac->del_dn, 1));
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");
1164 ret = ldb_build_mod_req(&mod_req, ldb, op,
1168 ldb_op_default_callback,
1170 if (ret != LDB_SUCCESS) {
1173 talloc_steal(mod_req, new_msg);
1176 DEBUG(4,("Applying linked attribute change:\n%s\n",
1177 ldb_ldif_message_string(ldb, op, LDB_CHANGETYPE_MODIFY, new_msg)));
1180 /* Run the new request */
1181 ret = ldb_next_request(module, mod_req);
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);
1189 if (ret != LDB_SUCCESS) {
1190 ldb_debug(ldb, LDB_DEBUG_WARNING, "Failed to apply linked attribute change '%s' %s\n",
1192 ldb_ldif_message_string(ldb, op, LDB_CHANGETYPE_MODIFY, new_msg));
1198 /* apply one set of la_context changes */
1199 static int la_do_mod_request(struct ldb_module *module, struct la_context *ac)
1201 struct la_op_store *op;
1203 for (op = ac->ops; op; op=op->next) {
1204 int ret = la_do_op_request(module, ac, op);
1205 if (ret != LDB_SUCCESS) {
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
1221 static int linked_attributes_start_transaction(struct ldb_module *module)
1223 /* create our private structure for this transaction */
1224 struct la_private *la_private = talloc_get_type(ldb_module_get_private(module),
1226 talloc_free(la_private);
1227 la_private = talloc(module, struct la_private);
1228 if (la_private == NULL) {
1229 return LDB_ERR_OPERATIONS_ERROR;
1231 la_private->la_list = NULL;
1232 ldb_module_set_private(module, la_private);
1237 on end transaction we loop over our queued la_context structures and
1240 static int linked_attributes_end_transaction(struct ldb_module *module)
1242 struct la_private *la_private =
1243 talloc_get_type(ldb_module_get_private(module), struct la_private);
1244 struct la_context *ac;
1246 for (ac=la_private->la_list; ac; ac=ac->next) {
1249 ret = la_do_mod_request(module, ac);
1250 if (ret != LDB_SUCCESS) {
1251 ret = la_do_mod_request(module, ac);
1259 static int linked_attributes_del_transaction(struct ldb_module *module)
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);
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,