4 Copyright (C) Andrew Bartlett <abartlet@samba.org> 2007
5 Copyright (C) Simo Sorce <idra@samba.org> 2008
6 Copyright (C) Matthieu Patou <mat@matws.net> 2011
7 Copyright (C) Andrew Tridgell 2009
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 3 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program. If not, see <http://www.gnu.org/licenses/>.
26 * Component: ldb linked_attributes module
28 * Description: Module to ensure linked attribute pairs remain in sync
30 * Author: Andrew Bartlett
34 #include "ldb_module.h"
35 #include "util/dlinklist.h"
36 #include "dsdb/samdb/samdb.h"
37 #include "librpc/gen_ndr/ndr_misc.h"
38 #include "dsdb/samdb/ldb_modules/util.h"
41 struct la_context *la_list;
45 struct la_op_store *next;
46 struct la_op_store *prev;
47 enum la_op {LA_OP_ADD, LA_OP_DEL} op;
52 struct replace_context {
53 struct la_context *ac;
54 unsigned int num_elements;
55 struct ldb_message_element *el;
59 struct la_context *next, *prev;
60 const struct dsdb_schema *schema;
61 struct ldb_module *module;
62 struct ldb_request *req;
63 struct ldb_dn *mod_dn;
64 struct replace_context *rc;
65 struct la_op_store *ops;
66 struct ldb_extended *op_response;
67 struct ldb_control **op_controls;
70 * will tell which GC to use for resolving links
76 static int handle_verify_name_control(TALLOC_CTX *ctx, struct ldb_context *ldb,
77 struct ldb_control *control, struct la_context *ac)
80 * If we are a GC let's remove the control,
81 * if there is a specified GC check that is us.
83 struct ldb_verify_name_control *lvnc = (struct ldb_verify_name_control *)control->data;
84 if (samdb_is_gc(ldb)) {
85 /* Because we can't easily talloc a struct ldb_dn*/
86 struct ldb_dn **dn = talloc_array(ctx, struct ldb_dn *, 1);
87 int ret = samdb_server_reference_dn(ldb, ctx, dn);
90 if (ret != LDB_SUCCESS) {
91 return ldb_operr(ldb);
94 dns = samdb_dn_to_dnshostname(ldb, ctx, *dn);
96 return ldb_operr(ldb);
98 if (!lvnc->gc || strcasecmp(dns, lvnc->gc) == 0) {
99 if (!ldb_save_controls(control, ctx, NULL)) {
100 return ldb_operr(ldb);
103 control->critical = true;
107 /* For the moment we don't remove the control is this case in order
108 * to fail the request. It's better than having the client thinking
109 * that we honnor its control.
110 * Hopefully only a very small set of usecase should hit this problem.
113 ac->gc_dns_name = talloc_strdup(ac, lvnc->gc);
115 control->critical = true;
121 static struct la_context *linked_attributes_init(struct ldb_module *module,
122 struct ldb_request *req)
124 struct ldb_context *ldb;
125 struct la_context *ac;
127 ldb = ldb_module_get_ctx(module);
129 ac = talloc_zero(req, struct la_context);
135 ac->schema = dsdb_get_schema(ldb, ac);
143 turn a DN into a GUID
145 static int la_guid_from_dn(struct ldb_module *module,
146 struct ldb_request *parent,
147 struct ldb_dn *dn, struct GUID *guid)
152 status = dsdb_get_extended_dn_guid(dn, guid, "GUID");
153 if (NT_STATUS_IS_OK(status)) {
156 if (!NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
157 DEBUG(4,(__location__ ": Unable to parse GUID for dn %s\n",
158 ldb_dn_get_linearized(dn)));
159 return ldb_operr(ldb_module_get_ctx(module));
162 ret = dsdb_module_guid_by_dn(module, dn, guid, parent);
163 if (ret != LDB_SUCCESS) {
164 DEBUG(4,(__location__ ": Failed to find GUID for dn %s\n",
165 ldb_dn_get_linearized(dn)));
172 /* Common routine to handle reading the attributes and creating a
173 * series of modify requests */
174 static int la_store_op(struct la_context *ac,
176 const struct dsdb_attribute *schema_attr,
180 struct ldb_context *ldb;
181 struct la_op_store *os;
182 struct ldb_dn *op_dn;
183 struct dsdb_dn *dsdb_dn;
186 ldb = ldb_module_get_ctx(ac->module);
189 os = talloc_zero(ac, struct la_op_store);
194 dsdb_dn = dsdb_dn_parse(os, ldb, dn, schema_attr->syntax->ldap_oid);
197 ldb_asprintf_errstring(ldb,
198 "could not parse attribute as a DN");
200 return LDB_ERR_INVALID_DN_SYNTAX;
207 ret = la_guid_from_dn(ac->module, ac->req, op_dn, &os->guid);
209 if (ret == LDB_ERR_NO_SUCH_OBJECT && ac->req->operation == LDB_DELETE) {
210 /* we are deleting an object, and we've found it has a
211 * forward link to a target that no longer
212 * exists. This is not an error in the delete, and we
213 * should just not do the deferred delete of the
219 if (ret != LDB_SUCCESS) {
223 os->name = talloc_strdup(os, name);
228 /* Do deletes before adds */
229 if (op == LA_OP_ADD) {
230 DLIST_ADD_END(ac->ops, os);
232 /* By adding to the head of the list, we do deletes before
233 * adds when processing a replace */
234 DLIST_ADD(ac->ops, os);
240 static int la_queue_mod_request(struct la_context *ac);
241 static int la_down_req(struct la_context *ac);
246 static int linked_attributes_add(struct ldb_module *module, struct ldb_request *req)
248 struct ldb_context *ldb;
249 const struct dsdb_attribute *target_attr;
250 struct la_context *ac;
251 const char *attr_name;
252 struct ldb_control *ctrl;
254 struct ldb_control *control;
257 ldb = ldb_module_get_ctx(module);
259 if (ldb_dn_is_special(req->op.add.message->dn)) {
260 /* do not manipulate our control entries */
261 return ldb_next_request(module, req);
264 ac = linked_attributes_init(module, req);
266 return ldb_operr(ldb);
269 control = ldb_request_get_control(req, LDB_CONTROL_VERIFY_NAME_OID);
270 if (control != NULL && control->data != NULL) {
271 ret = handle_verify_name_control(req, ldb, control, ac);
272 if (ret != LDB_SUCCESS) {
273 return ldb_operr(ldb);
277 if (!(ctrl = ldb_request_get_control(req, DSDB_CONTROL_APPLY_LINKS))) {
278 /* don't do anything special for linked attributes, repl_meta_data has done it */
280 return ldb_next_request(module, req);
282 ctrl->critical = false;
285 /* without schema, this doesn't make any sense */
287 return ldb_next_request(module, req);
291 /* Need to ensure we only have forward links being specified */
292 for (i=0; i < req->op.add.message->num_elements; i++) {
293 const struct ldb_message_element *el = &req->op.add.message->elements[i];
294 const struct dsdb_attribute *schema_attr
295 = dsdb_attribute_by_lDAPDisplayName(ac->schema, el->name);
297 ldb_asprintf_errstring(ldb,
298 "%s: attribute %s is not a valid attribute in schema",
301 return LDB_ERR_OBJECT_CLASS_VIOLATION;
304 /* this could be a link with no partner, in which case
305 there is no special work to do */
306 if (schema_attr->linkID == 0) {
310 /* this part of the code should only be handling forward links */
311 SMB_ASSERT((schema_attr->linkID & 1) == 0);
313 /* Even link IDs are for the originating attribute */
314 target_attr = dsdb_attribute_by_linkID(ac->schema, schema_attr->linkID ^ 1);
317 * windows 2003 has a broken schema where
318 * the definition of msDS-IsDomainFor
319 * is missing (which is supposed to be
320 * the backlink of the msDS-HasDomainNCs
326 attr_name = target_attr->lDAPDisplayName;
328 for (j = 0; j < el->num_values; j++) {
329 ret = la_store_op(ac, LA_OP_ADD,
333 if (ret != LDB_SUCCESS) {
339 /* if no linked attributes are present continue */
340 if (ac->ops == NULL) {
341 /* nothing to do for this module, proceed */
343 return ldb_next_request(module, req);
346 /* start with the original request */
347 return la_down_req(ac);
350 /* For a delete or rename, we need to find out what linked attributes
351 * are currently on this DN, and then deal with them. This is the
352 * callback to the base search */
354 static int la_mod_search_callback(struct ldb_request *req, struct ldb_reply *ares)
356 struct ldb_context *ldb;
357 const struct dsdb_attribute *schema_attr;
358 const struct dsdb_attribute *target_attr;
359 struct ldb_message_element *search_el;
360 struct replace_context *rc;
361 struct la_context *ac;
362 const char *attr_name;
364 int ret = LDB_SUCCESS;
366 ac = talloc_get_type(req->context, struct la_context);
367 ldb = ldb_module_get_ctx(ac->module);
371 return ldb_module_done(ac->req, NULL, NULL,
372 LDB_ERR_OPERATIONS_ERROR);
374 if (ares->error != LDB_SUCCESS) {
375 return ldb_module_done(ac->req, ares->controls,
376 ares->response, ares->error);
379 /* Only entries are interesting, and we only want the olddn */
380 switch (ares->type) {
381 case LDB_REPLY_ENTRY:
383 if (ldb_dn_compare(ares->message->dn, ac->req->op.mod.message->dn) != 0) {
384 ldb_asprintf_errstring(ldb,
385 "linked_attributes: %s is not the DN we were looking for",
386 ldb_dn_get_linearized(ares->message->dn));
387 /* Guh? We only asked for this DN */
389 return ldb_module_done(ac->req, NULL, NULL,
390 LDB_ERR_OPERATIONS_ERROR);
393 ac->mod_dn = talloc_steal(ac, ares->message->dn);
395 /* We don't populate 'rc' for ADD - it can't be deleting elements anyway */
396 for (i = 0; rc && i < rc->num_elements; i++) {
398 schema_attr = dsdb_attribute_by_lDAPDisplayName(ac->schema, rc->el[i].name);
400 ldb_asprintf_errstring(ldb,
401 "%s: attribute %s is not a valid attribute in schema",
405 return ldb_module_done(ac->req, NULL, NULL,
406 LDB_ERR_OBJECT_CLASS_VIOLATION);
409 search_el = ldb_msg_find_element(ares->message,
412 /* See if this element already exists */
413 /* otherwise just ignore as
414 * the add has already been scheduled */
419 target_attr = dsdb_attribute_by_linkID(ac->schema, schema_attr->linkID ^ 1);
422 * windows 2003 has a broken schema where
423 * the definition of msDS-IsDomainFor
424 * is missing (which is supposed to be
425 * the backlink of the msDS-HasDomainNCs
430 attr_name = target_attr->lDAPDisplayName;
432 /* Now we know what was there, we can remove it for the re-add */
433 for (j = 0; j < search_el->num_values; j++) {
434 ret = la_store_op(ac, LA_OP_DEL,
436 &search_el->values[j],
438 if (ret != LDB_SUCCESS) {
440 return ldb_module_done(ac->req,
448 case LDB_REPLY_REFERRAL:
456 if (ac->req->operation == LDB_ADD) {
457 /* Start the modifies to the backlinks */
458 ret = la_queue_mod_request(ac);
460 if (ret != LDB_SUCCESS) {
461 return ldb_module_done(ac->req, NULL, NULL,
465 /* Start with the original request */
466 ret = la_down_req(ac);
467 if (ret != LDB_SUCCESS) {
468 return ldb_module_done(ac->req, NULL, NULL, ret);
480 static int linked_attributes_modify(struct ldb_module *module, struct ldb_request *req)
482 /* Look over list of modifications */
483 /* Find if any are for linked attributes */
484 /* Determine the effect of the modification */
485 /* Apply the modify to the linked entry */
487 struct ldb_control *control;
488 struct ldb_context *ldb;
490 struct la_context *ac;
491 struct ldb_request *search_req;
493 struct ldb_control *ctrl;
496 ldb = ldb_module_get_ctx(module);
498 if (ldb_dn_is_special(req->op.mod.message->dn)) {
499 /* do not manipulate our control entries */
500 return ldb_next_request(module, req);
503 ac = linked_attributes_init(module, req);
505 return ldb_operr(ldb);
508 control = ldb_request_get_control(req, LDB_CONTROL_VERIFY_NAME_OID);
509 if (control != NULL && control->data != NULL) {
510 ret = handle_verify_name_control(req, ldb, control, ac);
511 if (ret != LDB_SUCCESS) {
512 return ldb_operr(ldb);
516 if (!(ctrl = ldb_request_get_control(req, DSDB_CONTROL_APPLY_LINKS))) {
517 /* don't do anything special for linked attributes, repl_meta_data has done it */
519 return ldb_next_request(module, req);
521 ctrl->critical = false;
524 /* without schema, this doesn't make any sense */
525 return ldb_next_request(module, req);
528 ac->rc = talloc_zero(ac, struct replace_context);
533 for (i=0; i < req->op.mod.message->num_elements; i++) {
534 bool store_el = false;
535 const char *attr_name;
536 const struct dsdb_attribute *target_attr;
537 const struct ldb_message_element *el = &req->op.mod.message->elements[i];
538 const struct dsdb_attribute *schema_attr
539 = dsdb_attribute_by_lDAPDisplayName(ac->schema, el->name);
541 ldb_asprintf_errstring(ldb,
542 "%s: attribute %s is not a valid attribute in schema",
545 return LDB_ERR_OBJECT_CLASS_VIOLATION;
547 /* We have a valid attribute, now find out if it is a forward link
548 (Even link IDs are for the originating attribute) */
549 if (schema_attr->linkID == 0) {
553 /* this part of the code should only be handling forward links */
554 SMB_ASSERT((schema_attr->linkID & 1) == 0);
556 /* Now find the target attribute */
557 target_attr = dsdb_attribute_by_linkID(ac->schema, schema_attr->linkID ^ 1);
560 * windows 2003 has a broken schema where
561 * the definition of msDS-IsDomainFor
562 * is missing (which is supposed to be
563 * the backlink of the msDS-HasDomainNCs
569 attr_name = target_attr->lDAPDisplayName;
571 switch (el->flags & LDB_FLAG_MOD_MASK) {
572 case LDB_FLAG_MOD_REPLACE:
573 /* treat as just a normal add the delete part is handled by the callback */
577 case LDB_FLAG_MOD_ADD:
579 /* For each value being added, we need to setup the adds */
580 for (j = 0; j < el->num_values; j++) {
581 ret = la_store_op(ac, LA_OP_ADD,
585 if (ret != LDB_SUCCESS) {
591 case LDB_FLAG_MOD_DELETE:
593 if (el->num_values) {
594 /* For each value being deleted, we need to setup the delete */
595 for (j = 0; j < el->num_values; j++) {
596 ret = la_store_op(ac, LA_OP_DEL,
600 if (ret != LDB_SUCCESS) {
605 /* Flag that there was a DELETE
606 * without a value specified, so we
607 * need to look for the old value */
615 struct ldb_message_element *search_el;
617 search_el = talloc_realloc(ac->rc, ac->rc->el,
618 struct ldb_message_element,
619 ac->rc->num_elements +1);
623 ac->rc->el = search_el;
625 ac->rc->el[ac->rc->num_elements] = *el;
626 ac->rc->num_elements++;
630 if (ac->ops || ac->rc->el) {
631 /* both replace and delete without values are handled in the callback
632 * after the search on the entry to be modified is performed */
634 attrs = talloc_array(ac->rc, const char *, ac->rc->num_elements + 1);
638 for (i = 0; ac->rc && i < ac->rc->num_elements; i++) {
639 attrs[i] = ac->rc->el[i].name;
643 /* The callback does all the hard work here */
644 ret = ldb_build_search_req(&search_req, ldb, ac,
645 req->op.mod.message->dn,
647 "(objectClass=*)", attrs,
649 ac, la_mod_search_callback,
651 LDB_REQ_SET_LOCATION(search_req);
653 /* We need to figure out our own extended DN, to fill in as the backlink target */
654 if (ret == LDB_SUCCESS) {
655 ret = dsdb_request_add_controls(search_req,
656 DSDB_SEARCH_SHOW_RECYCLED |
657 DSDB_SEARCH_SHOW_EXTENDED_DN);
659 if (ret == LDB_SUCCESS) {
660 talloc_steal(search_req, attrs);
662 ret = ldb_next_request(module, search_req);
666 /* nothing to do for this module, proceed */
668 ret = ldb_next_request(module, req);
674 static int linked_attributes_fix_links(struct ldb_module *module,
675 struct GUID self_guid,
676 struct ldb_dn *old_dn, struct ldb_dn *new_dn,
677 struct ldb_message_element *el, struct dsdb_schema *schema,
678 const struct dsdb_attribute *schema_attr,
679 struct ldb_request *parent)
682 TALLOC_CTX *tmp_ctx = talloc_new(module);
683 struct ldb_context *ldb = ldb_module_get_ctx(module);
684 const struct dsdb_attribute *target;
685 const char *attrs[2];
688 target = dsdb_attribute_by_linkID(schema, schema_attr->linkID ^ 1);
689 if (target == NULL) {
690 /* there is no counterpart link to change */
694 attrs[0] = target->lDAPDisplayName;
697 for (i=0; i<el->num_values; i++) {
698 struct dsdb_dn *dsdb_dn;
699 struct ldb_result *res;
700 struct ldb_message *msg;
701 struct ldb_message_element *el2;
702 struct GUID link_guid;
704 dsdb_dn = dsdb_dn_parse(tmp_ctx, ldb, &el->values[i], schema_attr->syntax->ldap_oid);
705 if (dsdb_dn == NULL) {
706 talloc_free(tmp_ctx);
707 return LDB_ERR_INVALID_DN_SYNTAX;
710 ret = la_guid_from_dn(module, parent, dsdb_dn->dn, &link_guid);
711 if (ret != LDB_SUCCESS) {
712 ldb_asprintf_errstring(ldb, "Linked attribute %s->%s between %s and %s - GUID not found - %s",
713 el->name, target->lDAPDisplayName,
714 ldb_dn_get_linearized(old_dn),
715 ldb_dn_get_linearized(dsdb_dn->dn),
717 talloc_free(tmp_ctx);
722 * get the existing message from the db for the object with
723 * this GUID, returning attribute being modified. We will then
724 * use this msg as the basis for a modify call
726 ret = dsdb_module_search(module, tmp_ctx, &res, NULL, LDB_SCOPE_SUBTREE, attrs,
727 DSDB_FLAG_NEXT_MODULE |
728 DSDB_SEARCH_SEARCH_ALL_PARTITIONS |
729 DSDB_SEARCH_SHOW_RECYCLED |
730 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT |
731 DSDB_SEARCH_REVEAL_INTERNALS,
733 "objectGUID=%s", GUID_string(tmp_ctx, &link_guid));
734 if (ret != LDB_SUCCESS) {
735 ldb_asprintf_errstring(ldb, "Linked attribute %s->%s between %s and %s - target GUID %s not found - %s",
736 el->name, target->lDAPDisplayName,
737 ldb_dn_get_linearized(old_dn),
738 ldb_dn_get_linearized(dsdb_dn->dn),
739 GUID_string(tmp_ctx, &link_guid),
741 talloc_free(tmp_ctx);
744 if (res->count == 0) {
745 /* Forward link without backlink object remaining - nothing to do here */
748 if (res->count != 1) {
749 ldb_asprintf_errstring(ldb, "Linked attribute %s->%s between %s and %s - target GUID %s found more than once!",
750 el->name, target->lDAPDisplayName,
751 ldb_dn_get_linearized(old_dn),
752 ldb_dn_get_linearized(dsdb_dn->dn),
753 GUID_string(tmp_ctx, &link_guid));
754 talloc_free(tmp_ctx);
755 return LDB_ERR_OPERATIONS_ERROR;
760 if (msg->num_elements == 0) {
761 /* Forward link without backlink remaining - nothing to do here */
763 } else if (msg->num_elements != 1) {
764 ldb_asprintf_errstring(ldb, "Bad msg elements - got %u elements, expected one element to be returned in linked_attributes_fix_links for %s",
765 msg->num_elements, ldb_dn_get_linearized(msg->dn));
766 talloc_free(tmp_ctx);
767 return LDB_ERR_OPERATIONS_ERROR;
769 if (ldb_attr_cmp(msg->elements[0].name, target->lDAPDisplayName) != 0) {
770 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));
771 talloc_free(tmp_ctx);
772 return LDB_ERR_OPERATIONS_ERROR;
774 el2 = &msg->elements[0];
776 el2->flags = LDB_FLAG_MOD_REPLACE;
778 /* find our DN in the values */
779 for (j=0; j<el2->num_values; j++) {
780 struct dsdb_dn *dsdb_dn2;
781 struct GUID link_guid2;
783 dsdb_dn2 = dsdb_dn_parse(msg, ldb, &el2->values[j], target->syntax->ldap_oid);
784 if (dsdb_dn2 == NULL) {
785 talloc_free(tmp_ctx);
786 return LDB_ERR_INVALID_DN_SYNTAX;
789 ret = la_guid_from_dn(module, parent, dsdb_dn2->dn, &link_guid2);
790 if (ret != LDB_SUCCESS) {
791 talloc_free(tmp_ctx);
796 * By comparing using the GUID we ensure that
797 * even if somehow the name has got out of
798 * sync, this rename will fix it.
800 * If somehow we don't have a GUID on the DN
801 * in the DB, the la_guid_from_dn call will be
802 * more costly, but still give us a GUID.
803 * dbcheck will fix this if run.
805 if (!GUID_equal(&self_guid, &link_guid2)) {
809 ret = ldb_dn_update_components(dsdb_dn2->dn, new_dn);
810 if (ret != LDB_SUCCESS) {
811 talloc_free(tmp_ctx);
815 el2->values[j] = data_blob_string_const(
816 dsdb_dn_get_extended_linearized(el2->values, dsdb_dn2, 1));
819 ret = dsdb_check_single_valued_link(target, el2);
820 if (ret != LDB_SUCCESS) {
821 talloc_free(tmp_ctx);
825 /* we may be putting multiple values in an attribute -
826 disable checking for this attribute */
827 el2->flags |= LDB_FLAG_INTERNAL_DISABLE_SINGLE_VALUE_CHECK;
829 ret = dsdb_module_modify(module, msg, DSDB_FLAG_NEXT_MODULE, parent);
830 if (ret != LDB_SUCCESS) {
831 ldb_asprintf_errstring(ldb, "Linked attribute %s->%s between %s and %s - update failed - %s",
832 el->name, target->lDAPDisplayName,
833 ldb_dn_get_linearized(old_dn),
834 ldb_dn_get_linearized(dsdb_dn->dn),
836 talloc_free(tmp_ctx);
841 talloc_free(tmp_ctx);
847 static int linked_attributes_rename(struct ldb_module *module, struct ldb_request *req)
849 struct ldb_result *res;
850 struct ldb_message *msg;
852 struct ldb_context *ldb = ldb_module_get_ctx(module);
853 struct dsdb_schema *schema;
858 - load the current msg
859 - find any linked attributes
860 - if its a link then find the target object
861 - modify the target linked attributes with the new DN
863 ret = dsdb_module_search_dn(module, req, &res, req->op.rename.olddn,
865 DSDB_FLAG_NEXT_MODULE |
866 DSDB_SEARCH_SHOW_EXTENDED_DN |
867 DSDB_SEARCH_SHOW_RECYCLED, req);
868 if (ret != LDB_SUCCESS) {
872 schema = dsdb_get_schema(ldb, res);
879 ret = la_guid_from_dn(module, req, msg->dn, &guid);
880 if (ret != LDB_SUCCESS) {
884 for (i=0; i<msg->num_elements; i++) {
885 struct ldb_message_element *el = &msg->elements[i];
886 const struct dsdb_attribute *schema_attr
887 = dsdb_attribute_by_lDAPDisplayName(schema, el->name);
888 if (!schema_attr || schema_attr->linkID == 0) {
891 ret = linked_attributes_fix_links(module, guid, msg->dn, req->op.rename.newdn, el,
892 schema, schema_attr, req);
893 if (ret != LDB_SUCCESS) {
901 return ldb_next_request(module, req);
905 /* queue a linked attributes modify request in the la_private
907 static int la_queue_mod_request(struct la_context *ac)
909 struct la_private *la_private =
910 talloc_get_type(ldb_module_get_private(ac->module), struct la_private);
912 if (la_private == NULL) {
913 ldb_debug(ldb_module_get_ctx(ac->module), LDB_DEBUG_ERROR, __location__ ": No la_private transaction setup\n");
914 return ldb_operr(ldb_module_get_ctx(ac->module));
917 talloc_steal(la_private, ac);
918 DLIST_ADD(la_private->la_list, ac);
920 return ldb_module_done(ac->req, ac->op_controls,
921 ac->op_response, LDB_SUCCESS);
924 /* Having done the original operation, then try to fix up all the linked attributes for modify and delete */
925 static int la_mod_del_callback(struct ldb_request *req, struct ldb_reply *ares)
927 struct la_context *ac;
928 struct ldb_context *ldb;
931 ac = talloc_get_type(req->context, struct la_context);
932 ldb = ldb_module_get_ctx(ac->module);
935 return ldb_module_done(ac->req, NULL, NULL,
936 LDB_ERR_OPERATIONS_ERROR);
938 if (ares->error != LDB_SUCCESS) {
939 return ldb_module_done(ac->req, ares->controls,
940 ares->response, ares->error);
943 if (ares->type != LDB_REPLY_DONE) {
944 ldb_set_errstring(ldb,
945 "invalid ldb_reply_type in callback");
947 return ldb_module_done(ac->req, NULL, NULL,
948 LDB_ERR_OPERATIONS_ERROR);
951 ac->op_controls = talloc_steal(ac, ares->controls);
952 ac->op_response = talloc_steal(ac, ares->response);
954 /* If we have modfies to make, this is the time to do them for modify and delete */
955 ret = la_queue_mod_request(ac);
957 if (ret != LDB_SUCCESS) {
958 return ldb_module_done(ac->req, NULL, NULL, ret);
962 /* la_queue_mod_request has already sent the callbacks */
967 /* Having done the original add, then try to fix up all the linked attributes
969 This is done after the add so the links can get the extended DNs correctly.
971 static int la_add_callback(struct ldb_request *req, struct ldb_reply *ares)
973 struct la_context *ac;
974 struct ldb_context *ldb;
977 ac = talloc_get_type(req->context, struct la_context);
978 ldb = ldb_module_get_ctx(ac->module);
981 return ldb_module_done(ac->req, NULL, NULL,
982 LDB_ERR_OPERATIONS_ERROR);
984 if (ares->error != LDB_SUCCESS) {
985 return ldb_module_done(ac->req, ares->controls,
986 ares->response, ares->error);
989 if (ares->type != LDB_REPLY_DONE) {
990 ldb_set_errstring(ldb,
991 "invalid ldb_reply_type in callback");
993 return ldb_module_done(ac->req, NULL, NULL,
994 LDB_ERR_OPERATIONS_ERROR);
998 struct ldb_request *search_req;
999 static const char *attrs[] = { NULL };
1001 /* The callback does all the hard work here - we need
1002 * the objectGUID and SID of the added record */
1003 ret = ldb_build_search_req(&search_req, ldb, ac,
1004 ac->req->op.add.message->dn,
1006 "(objectClass=*)", attrs,
1008 ac, la_mod_search_callback,
1010 LDB_REQ_SET_LOCATION(search_req);
1012 if (ret == LDB_SUCCESS) {
1013 ret = dsdb_request_add_controls(search_req,
1014 DSDB_SEARCH_SHOW_RECYCLED |
1015 DSDB_SEARCH_SHOW_EXTENDED_DN);
1017 if (ret != LDB_SUCCESS) {
1018 return ldb_module_done(ac->req, NULL, NULL,
1022 ac->op_controls = talloc_steal(ac, ares->controls);
1023 ac->op_response = talloc_steal(ac, ares->response);
1025 return ldb_next_request(ac->module, search_req);
1028 return ldb_module_done(ac->req, ares->controls,
1029 ares->response, ares->error);
1033 /* Reconstruct the original request, but pointing at our local callback to finish things off */
1034 static int la_down_req(struct la_context *ac)
1036 struct ldb_request *down_req;
1037 struct ldb_context *ldb;
1040 ldb = ldb_module_get_ctx(ac->module);
1042 switch (ac->req->operation) {
1044 ret = ldb_build_add_req(&down_req, ldb, ac,
1045 ac->req->op.add.message,
1047 ac, la_add_callback,
1049 LDB_REQ_SET_LOCATION(down_req);
1052 ret = ldb_build_mod_req(&down_req, ldb, ac,
1053 ac->req->op.mod.message,
1055 ac, la_mod_del_callback,
1057 LDB_REQ_SET_LOCATION(down_req);
1060 ret = LDB_ERR_OPERATIONS_ERROR;
1062 if (ret != LDB_SUCCESS) {
1066 return ldb_next_request(ac->module, down_req);
1070 use the GUID part of an extended DN to find the target DN, in case
1073 static int la_find_dn_target(struct ldb_module *module, struct la_context *ac,
1074 struct GUID *guid, struct ldb_dn **dn)
1076 return dsdb_module_dn_by_guid(ac->module, ac, guid, dn, ac->req);
1079 /* apply one la_context op change */
1080 static int la_do_op_request(struct ldb_module *module, struct la_context *ac, struct la_op_store *op)
1082 struct ldb_message_element *ret_el;
1083 struct ldb_message *new_msg;
1084 struct ldb_context *ldb;
1087 if (ac->mod_dn == NULL) {
1088 /* we didn't find the DN that we searched for */
1092 ldb = ldb_module_get_ctx(ac->module);
1094 /* Create the modify request */
1095 new_msg = ldb_msg_new(ac);
1097 return ldb_oom(ldb);
1100 ret = la_find_dn_target(module, ac, &op->guid, &new_msg->dn);
1101 if (ret != LDB_SUCCESS) {
1105 if (op->op == LA_OP_ADD) {
1106 ret = ldb_msg_add_empty(new_msg, op->name,
1107 LDB_FLAG_MOD_ADD, &ret_el);
1109 ret = ldb_msg_add_empty(new_msg, op->name,
1110 LDB_FLAG_MOD_DELETE, &ret_el);
1112 if (ret != LDB_SUCCESS) {
1115 ret_el->values = talloc_array(new_msg, struct ldb_val, 1);
1116 if (!ret_el->values) {
1117 return ldb_oom(ldb);
1119 ret_el->num_values = 1;
1120 ret_el->values[0] = data_blob_string_const(ldb_dn_get_extended_linearized(new_msg, ac->mod_dn, 1));
1122 /* a backlink should never be single valued. Unfortunately the
1123 exchange schema has a attribute
1124 msExchBridgeheadedLocalConnectorsDNBL which is single
1125 valued and a backlink. We need to cope with that by
1126 ignoring the single value flag */
1127 ret_el->flags |= LDB_FLAG_INTERNAL_DISABLE_SINGLE_VALUE_CHECK;
1130 ldb_debug(ldb, LDB_DEBUG_WARNING,
1131 "link on %s %s: %s %s\n",
1132 ldb_dn_get_linearized(new_msg->dn), ret_el->name,
1133 ret_el->values[0].data, ac->ops->op == LA_OP_ADD ? "added" : "deleted");
1137 DEBUG(4,("Applying linked attribute change:\n%s\n",
1138 ldb_ldif_message_redacted_string(ldb, op,
1139 LDB_CHANGETYPE_MODIFY,
1143 ret = dsdb_module_modify(module, new_msg, DSDB_FLAG_NEXT_MODULE, ac->req);
1144 if (ret != LDB_SUCCESS) {
1145 ldb_debug(ldb, LDB_DEBUG_WARNING, __location__ ": failed to apply linked attribute change '%s'\n%s\n",
1147 ldb_ldif_message_redacted_string(ldb, op,
1148 LDB_CHANGETYPE_MODIFY,
1155 /* apply one set of la_context changes */
1156 static int la_do_mod_request(struct ldb_module *module, struct la_context *ac)
1158 struct la_op_store *op;
1160 for (op = ac->ops; op; op=op->next) {
1161 int ret = la_do_op_request(module, ac, op);
1162 if (ret != LDB_SUCCESS) {
1163 if (ret != LDB_ERR_NO_SUCH_OBJECT) {
1174 we hook into the transaction operations to allow us to
1175 perform the linked attribute updates at the end of the whole
1176 transaction. This allows a forward linked attribute to be created
1177 before the target is created, as long as the target is created
1178 in the same transaction
1180 static int linked_attributes_start_transaction(struct ldb_module *module)
1182 /* create our private structure for this transaction */
1183 struct la_private *la_private = talloc_get_type(ldb_module_get_private(module),
1185 talloc_free(la_private);
1186 la_private = talloc(module, struct la_private);
1187 if (la_private == NULL) {
1188 return ldb_oom(ldb_module_get_ctx(module));
1190 la_private->la_list = NULL;
1191 ldb_module_set_private(module, la_private);
1192 return ldb_next_start_trans(module);
1196 on prepare commit we loop over our queued la_context structures
1197 and apply each of them
1199 static int linked_attributes_prepare_commit(struct ldb_module *module)
1201 struct la_private *la_private =
1202 talloc_get_type(ldb_module_get_private(module), struct la_private);
1203 struct la_context *ac;
1206 /* prepare commit without begin_transaction - let someone else return the error, just don't segfault */
1207 return ldb_next_prepare_commit(module);
1209 /* walk the list backwards, to do the first entry first, as we
1210 * added the entries with DLIST_ADD() which puts them at the
1211 * start of the list */
1213 /* Start at the end of the list - so we can start
1214 * there, but ensure we don't create a loop by NULLing
1215 * it out in the first element */
1216 ac = DLIST_TAIL(la_private->la_list);
1218 for (; ac; ac=DLIST_PREV(ac)) {
1221 ret = la_do_mod_request(module, ac);
1222 if (ret != LDB_SUCCESS) {
1223 DEBUG(0,(__location__ ": Failed mod request ret=%d\n", ret));
1224 talloc_free(la_private);
1225 ldb_module_set_private(module, NULL);
1230 talloc_free(la_private);
1231 ldb_module_set_private(module, NULL);
1233 return ldb_next_prepare_commit(module);
1236 static int linked_attributes_del_transaction(struct ldb_module *module)
1238 struct la_private *la_private =
1239 talloc_get_type(ldb_module_get_private(module), struct la_private);
1240 talloc_free(la_private);
1241 ldb_module_set_private(module, NULL);
1242 return ldb_next_del_trans(module);
1245 static int linked_attributes_ldb_init(struct ldb_module *module)
1249 ret = ldb_mod_register_control(module, LDB_CONTROL_VERIFY_NAME_OID);
1250 if (ret != LDB_SUCCESS) {
1251 ldb_debug(ldb_module_get_ctx(module), LDB_DEBUG_ERROR,
1252 "verify_name: Unable to register control with rootdse!\n");
1253 return ldb_operr(ldb_module_get_ctx(module));
1256 return ldb_next_init(module);
1260 static const struct ldb_module_ops ldb_linked_attributes_module_ops = {
1261 .name = "linked_attributes",
1262 .add = linked_attributes_add,
1263 .modify = linked_attributes_modify,
1264 .rename = linked_attributes_rename,
1265 .init_context = linked_attributes_ldb_init,
1266 .start_transaction = linked_attributes_start_transaction,
1267 .prepare_commit = linked_attributes_prepare_commit,
1268 .del_transaction = linked_attributes_del_transaction,
1271 int ldb_linked_attributes_module_init(const char *version)
1273 LDB_MODULE_CHECK_VERSION(version);
1274 return ldb_register_module(&ldb_linked_attributes_module_ops);