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"
42 struct la_context *la_list;
46 struct la_op_store *next;
47 struct la_op_store *prev;
48 enum la_op {LA_OP_ADD, LA_OP_DEL} op;
53 struct replace_context {
54 struct la_context *ac;
55 unsigned int num_elements;
56 struct ldb_message_element *el;
60 struct la_context *next, *prev;
61 const struct dsdb_schema *schema;
62 struct ldb_module *module;
63 struct ldb_request *req;
64 struct ldb_dn *mod_dn;
65 struct replace_context *rc;
66 struct la_op_store *ops;
67 struct ldb_extended *op_response;
68 struct ldb_control **op_controls;
71 * will tell which GC to use for resolving links
77 static int handle_verify_name_control(TALLOC_CTX *ctx, struct ldb_context *ldb,
78 struct ldb_control *control, struct la_context *ac)
81 * If we are a GC let's remove the control,
82 * if there is a specified GC check that is us.
84 struct ldb_verify_name_control *lvnc = (struct ldb_verify_name_control *)control->data;
85 if (samdb_is_gc(ldb)) {
86 /* Because we can't easily talloc a struct ldb_dn*/
87 struct ldb_dn **dn = talloc_array(ctx, struct ldb_dn *, 1);
88 int ret = samdb_server_reference_dn(ldb, ctx, dn);
91 if (ret != LDB_SUCCESS) {
92 return ldb_operr(ldb);
95 dns = samdb_dn_to_dnshostname(ldb, ctx, *dn);
97 return ldb_operr(ldb);
99 if (!lvnc->gc || strcasecmp(dns, lvnc->gc) == 0) {
100 if (!ldb_save_controls(control, ctx, NULL)) {
101 return ldb_operr(ldb);
104 control->critical = true;
108 /* For the moment we don't remove the control is this case in order
109 * to fail the request. It's better than having the client thinking
110 * that we honnor its control.
111 * Hopefully only a very small set of usecase should hit this problem.
114 ac->gc_dns_name = talloc_strdup(ac, lvnc->gc);
116 control->critical = true;
122 static struct la_context *linked_attributes_init(struct ldb_module *module,
123 struct ldb_request *req)
125 struct ldb_context *ldb;
126 struct la_context *ac;
128 ldb = ldb_module_get_ctx(module);
130 ac = talloc_zero(req, struct la_context);
136 ac->schema = dsdb_get_schema(ldb, ac);
144 turn a DN into a GUID
146 static int la_guid_from_dn(struct ldb_module *module,
147 struct ldb_request *parent,
148 struct ldb_dn *dn, struct GUID *guid)
153 status = dsdb_get_extended_dn_guid(dn, guid, "GUID");
154 if (NT_STATUS_IS_OK(status)) {
157 if (!NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
158 DEBUG(4,(__location__ ": Unable to parse GUID for dn %s\n",
159 ldb_dn_get_linearized(dn)));
160 return ldb_operr(ldb_module_get_ctx(module));
163 ret = dsdb_module_guid_by_dn(module, dn, guid, parent);
164 if (ret != LDB_SUCCESS) {
165 pid_t ppid = getpid();
169 snprintf(buf, 1024, "%s %d",
170 "/tmp/samba-4.0.6/selftest/gdb_backtrace",
172 fprintf(stderr, "%s",buf);
178 DEBUG(4,(__location__ ": Failed to find GUID for dn %s\n",
179 ldb_dn_get_linearized(dn)));
186 /* Common routine to handle reading the attributes and creating a
187 * series of modify requests */
188 static int la_store_op(struct la_context *ac,
189 enum la_op op, struct ldb_val *dn,
192 struct ldb_context *ldb;
193 struct la_op_store *os;
194 struct ldb_dn *op_dn;
197 ldb = ldb_module_get_ctx(ac->module);
199 op_dn = ldb_dn_from_ldb_val(ac, ldb, dn);
201 ldb_asprintf_errstring(ldb,
202 "could not parse attribute as a DN");
203 return LDB_ERR_INVALID_DN_SYNTAX;
206 os = talloc_zero(ac, struct la_op_store);
213 ret = la_guid_from_dn(ac->module, ac->req, op_dn, &os->guid);
215 if (ret == LDB_ERR_NO_SUCH_OBJECT && ac->req->operation == LDB_DELETE) {
216 /* we are deleting an object, and we've found it has a
217 * forward link to a target that no longer
218 * exists. This is not an error in the delete, and we
219 * should just not do the deferred delete of the
225 if (ret != LDB_SUCCESS) {
229 os->name = talloc_strdup(os, name);
234 /* Do deletes before adds */
235 if (op == LA_OP_ADD) {
236 DLIST_ADD_END(ac->ops, os, struct la_op_store *);
238 /* By adding to the head of the list, we do deletes before
239 * adds when processing a replace */
240 DLIST_ADD(ac->ops, os);
246 static int la_queue_mod_request(struct la_context *ac);
247 static int la_down_req(struct la_context *ac);
252 static int linked_attributes_add(struct ldb_module *module, struct ldb_request *req)
254 struct ldb_context *ldb;
255 const struct dsdb_attribute *target_attr;
256 struct la_context *ac;
257 const char *attr_name;
258 struct ldb_control *ctrl;
260 struct ldb_control *control;
263 ldb = ldb_module_get_ctx(module);
265 if (ldb_dn_is_special(req->op.add.message->dn)) {
266 /* do not manipulate our control entries */
267 return ldb_next_request(module, req);
270 ac = linked_attributes_init(module, req);
272 return ldb_operr(ldb);
275 control = ldb_request_get_control(req, LDB_CONTROL_VERIFY_NAME_OID);
276 if (control != NULL && control->data != NULL) {
277 ret = handle_verify_name_control(req, ldb, control, ac);
278 if (ret != LDB_SUCCESS) {
279 return ldb_operr(ldb);
283 if (!(ctrl = ldb_request_get_control(req, DSDB_CONTROL_APPLY_LINKS))) {
284 /* don't do anything special for linked attributes, repl_meta_data has done it */
286 return ldb_next_request(module, req);
288 ctrl->critical = false;
291 /* without schema, this doesn't make any sense */
293 return ldb_next_request(module, req);
297 /* Need to ensure we only have forward links being specified */
298 for (i=0; i < req->op.add.message->num_elements; i++) {
299 const struct ldb_message_element *el = &req->op.add.message->elements[i];
300 const struct dsdb_attribute *schema_attr
301 = dsdb_attribute_by_lDAPDisplayName(ac->schema, el->name);
303 ldb_asprintf_errstring(ldb,
304 "%s: attribute %s is not a valid attribute in schema",
307 return LDB_ERR_OBJECT_CLASS_VIOLATION;
310 /* this could be a link with no partner, in which case
311 there is no special work to do */
312 if (schema_attr->linkID == 0) {
316 /* this part of the code should only be handling forward links */
317 SMB_ASSERT((schema_attr->linkID & 1) == 0);
319 /* Even link IDs are for the originating attribute */
320 target_attr = dsdb_attribute_by_linkID(ac->schema, schema_attr->linkID ^ 1);
323 * windows 2003 has a broken schema where
324 * the definition of msDS-IsDomainFor
325 * is missing (which is supposed to be
326 * the backlink of the msDS-HasDomainNCs
332 attr_name = target_attr->lDAPDisplayName;
334 for (j = 0; j < el->num_values; j++) {
335 ret = la_store_op(ac, LA_OP_ADD,
338 if (ret != LDB_SUCCESS) {
344 /* if no linked attributes are present continue */
345 if (ac->ops == NULL) {
346 /* nothing to do for this module, proceed */
348 return ldb_next_request(module, req);
351 /* start with the original request */
352 return la_down_req(ac);
355 /* For a delete or rename, we need to find out what linked attributes
356 * are currently on this DN, and then deal with them. This is the
357 * callback to the base search */
359 static int la_mod_search_callback(struct ldb_request *req, struct ldb_reply *ares)
361 struct ldb_context *ldb;
362 const struct dsdb_attribute *schema_attr;
363 const struct dsdb_attribute *target_attr;
364 struct ldb_message_element *search_el;
365 struct replace_context *rc;
366 struct la_context *ac;
367 const char *attr_name;
369 int ret = LDB_SUCCESS;
371 ac = talloc_get_type(req->context, struct la_context);
372 ldb = ldb_module_get_ctx(ac->module);
376 return ldb_module_done(ac->req, NULL, NULL,
377 LDB_ERR_OPERATIONS_ERROR);
379 if (ares->error != LDB_SUCCESS) {
380 return ldb_module_done(ac->req, ares->controls,
381 ares->response, ares->error);
384 /* Only entries are interesting, and we only want the olddn */
385 switch (ares->type) {
386 case LDB_REPLY_ENTRY:
388 if (ldb_dn_compare(ares->message->dn, ac->req->op.mod.message->dn) != 0) {
389 ldb_asprintf_errstring(ldb,
390 "linked_attributes: %s is not the DN we were looking for",
391 ldb_dn_get_linearized(ares->message->dn));
392 /* Guh? We only asked for this DN */
394 return ldb_module_done(ac->req, NULL, NULL,
395 LDB_ERR_OPERATIONS_ERROR);
398 ac->mod_dn = talloc_steal(ac, ares->message->dn);
400 /* We don't populate 'rc' for ADD - it can't be deleting elements anyway */
401 for (i = 0; rc && i < rc->num_elements; i++) {
403 schema_attr = dsdb_attribute_by_lDAPDisplayName(ac->schema, rc->el[i].name);
405 ldb_asprintf_errstring(ldb,
406 "%s: attribute %s is not a valid attribute in schema",
410 return ldb_module_done(ac->req, NULL, NULL,
411 LDB_ERR_OBJECT_CLASS_VIOLATION);
414 search_el = ldb_msg_find_element(ares->message,
417 /* See if this element already exists */
418 /* otherwise just ignore as
419 * the add has already been scheduled */
424 target_attr = dsdb_attribute_by_linkID(ac->schema, schema_attr->linkID ^ 1);
427 * windows 2003 has a broken schema where
428 * the definition of msDS-IsDomainFor
429 * is missing (which is supposed to be
430 * the backlink of the msDS-HasDomainNCs
435 attr_name = target_attr->lDAPDisplayName;
437 /* Now we know what was there, we can remove it for the re-add */
438 for (j = 0; j < search_el->num_values; j++) {
439 ret = la_store_op(ac, LA_OP_DEL,
440 &search_el->values[j],
442 if (ret != LDB_SUCCESS) {
444 return ldb_module_done(ac->req,
452 case LDB_REPLY_REFERRAL:
460 if (ac->req->operation == LDB_ADD) {
461 /* Start the modifies to the backlinks */
462 ret = la_queue_mod_request(ac);
464 if (ret != LDB_SUCCESS) {
465 return ldb_module_done(ac->req, NULL, NULL,
469 /* Start with the original request */
470 ret = la_down_req(ac);
471 if (ret != LDB_SUCCESS) {
472 return ldb_module_done(ac->req, NULL, NULL, ret);
484 static int linked_attributes_modify(struct ldb_module *module, struct ldb_request *req)
486 /* Look over list of modifications */
487 /* Find if any are for linked attributes */
488 /* Determine the effect of the modification */
489 /* Apply the modify to the linked entry */
491 struct ldb_control *control;
492 struct ldb_context *ldb;
494 struct la_context *ac;
495 struct ldb_request *search_req;
497 struct ldb_control *ctrl;
500 ldb = ldb_module_get_ctx(module);
502 if (ldb_dn_is_special(req->op.mod.message->dn)) {
503 /* do not manipulate our control entries */
504 return ldb_next_request(module, req);
507 ac = linked_attributes_init(module, req);
509 return ldb_operr(ldb);
512 control = ldb_request_get_control(req, LDB_CONTROL_VERIFY_NAME_OID);
513 if (control != NULL && control->data != NULL) {
514 ret = handle_verify_name_control(req, ldb, control, ac);
515 if (ret != LDB_SUCCESS) {
516 return ldb_operr(ldb);
520 if (!(ctrl = ldb_request_get_control(req, DSDB_CONTROL_APPLY_LINKS))) {
521 /* don't do anything special for linked attributes, repl_meta_data has done it */
523 return ldb_next_request(module, req);
525 ctrl->critical = false;
528 /* without schema, this doesn't make any sense */
529 return ldb_next_request(module, req);
532 ac->rc = talloc_zero(ac, struct replace_context);
537 for (i=0; i < req->op.mod.message->num_elements; i++) {
538 bool store_el = false;
539 const char *attr_name;
540 const struct dsdb_attribute *target_attr;
541 const struct ldb_message_element *el = &req->op.mod.message->elements[i];
542 const struct dsdb_attribute *schema_attr
543 = dsdb_attribute_by_lDAPDisplayName(ac->schema, el->name);
545 ldb_asprintf_errstring(ldb,
546 "%s: attribute %s is not a valid attribute in schema",
549 return LDB_ERR_OBJECT_CLASS_VIOLATION;
551 /* We have a valid attribute, now find out if it is a forward link
552 (Even link IDs are for the originating attribute) */
553 if (schema_attr->linkID == 0) {
557 /* this part of the code should only be handling forward links */
558 SMB_ASSERT((schema_attr->linkID & 1) == 0);
560 /* Now find the target attribute */
561 target_attr = dsdb_attribute_by_linkID(ac->schema, schema_attr->linkID ^ 1);
564 * windows 2003 has a broken schema where
565 * the definition of msDS-IsDomainFor
566 * is missing (which is supposed to be
567 * the backlink of the msDS-HasDomainNCs
573 attr_name = target_attr->lDAPDisplayName;
575 switch (el->flags & LDB_FLAG_MOD_MASK) {
576 case LDB_FLAG_MOD_REPLACE:
577 /* treat as just a normal add the delete part is handled by the callback */
580 /* break intentionally missing */
582 case LDB_FLAG_MOD_ADD:
584 /* For each value being added, we need to setup the adds */
585 for (j = 0; j < el->num_values; j++) {
586 ret = la_store_op(ac, LA_OP_ADD,
589 if (ret != LDB_SUCCESS) {
595 case LDB_FLAG_MOD_DELETE:
597 if (el->num_values) {
598 /* For each value being deleted, we need to setup the delete */
599 for (j = 0; j < el->num_values; j++) {
600 ret = la_store_op(ac, LA_OP_DEL,
603 if (ret != LDB_SUCCESS) {
608 /* Flag that there was a DELETE
609 * without a value specified, so we
610 * need to look for the old value */
618 struct ldb_message_element *search_el;
620 search_el = talloc_realloc(ac->rc, ac->rc->el,
621 struct ldb_message_element,
622 ac->rc->num_elements +1);
626 ac->rc->el = search_el;
628 ac->rc->el[ac->rc->num_elements] = *el;
629 ac->rc->num_elements++;
633 if (ac->ops || ac->rc->el) {
634 /* both replace and delete without values are handled in the callback
635 * after the search on the entry to be modified is performed */
637 attrs = talloc_array(ac->rc, const char *, ac->rc->num_elements + 1);
641 for (i = 0; ac->rc && i < ac->rc->num_elements; i++) {
642 attrs[i] = ac->rc->el[i].name;
646 /* The callback does all the hard work here */
647 ret = ldb_build_search_req(&search_req, ldb, ac,
648 req->op.mod.message->dn,
650 "(objectClass=*)", attrs,
652 ac, la_mod_search_callback,
654 LDB_REQ_SET_LOCATION(search_req);
656 /* We need to figure out our own extended DN, to fill in as the backlink target */
657 if (ret == LDB_SUCCESS) {
658 ret = dsdb_request_add_controls(search_req,
659 DSDB_SEARCH_SHOW_RECYCLED |
660 DSDB_SEARCH_SHOW_EXTENDED_DN);
662 if (ret == LDB_SUCCESS) {
663 talloc_steal(search_req, attrs);
665 ret = ldb_next_request(module, search_req);
669 /* nothing to do for this module, proceed */
671 ret = ldb_next_request(module, req);
677 static int linked_attributes_fix_links(struct ldb_module *module,
678 struct GUID self_guid,
679 struct ldb_dn *old_dn, struct ldb_dn *new_dn,
680 struct ldb_message_element *el, struct dsdb_schema *schema,
681 const struct dsdb_attribute *schema_attr,
682 struct ldb_request *parent)
685 TALLOC_CTX *tmp_ctx = talloc_new(module);
686 struct ldb_context *ldb = ldb_module_get_ctx(module);
687 const struct dsdb_attribute *target;
688 const char *attrs[2];
691 target = dsdb_attribute_by_linkID(schema, schema_attr->linkID ^ 1);
692 if (target == NULL) {
693 /* there is no counterpart link to change */
697 attrs[0] = target->lDAPDisplayName;
700 for (i=0; i<el->num_values; i++) {
701 struct dsdb_dn *dsdb_dn;
702 struct ldb_result *res;
703 struct ldb_message *msg;
704 struct ldb_message_element *el2;
705 struct GUID link_guid;
707 dsdb_dn = dsdb_dn_parse(tmp_ctx, ldb, &el->values[i], schema_attr->syntax->ldap_oid);
708 if (dsdb_dn == NULL) {
709 talloc_free(tmp_ctx);
710 return LDB_ERR_INVALID_DN_SYNTAX;
713 ret = la_guid_from_dn(module, parent, dsdb_dn->dn, &link_guid);
714 if (ret != LDB_SUCCESS) {
715 ldb_asprintf_errstring(ldb, "Linked attribute %s->%s between %s and %s - GUID not found - %s",
716 el->name, target->lDAPDisplayName,
717 ldb_dn_get_linearized(old_dn),
718 ldb_dn_get_linearized(dsdb_dn->dn),
720 talloc_free(tmp_ctx);
725 * get the existing message from the db for the object with
726 * this GUID, returning attribute being modified. We will then
727 * use this msg as the basis for a modify call
729 ret = dsdb_module_search(module, tmp_ctx, &res, NULL, LDB_SCOPE_SUBTREE, attrs,
730 DSDB_FLAG_NEXT_MODULE |
731 DSDB_SEARCH_SEARCH_ALL_PARTITIONS |
732 DSDB_SEARCH_SHOW_RECYCLED |
733 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT |
734 DSDB_SEARCH_REVEAL_INTERNALS,
736 "objectGUID=%s", GUID_string(tmp_ctx, &link_guid));
737 if (ret != LDB_SUCCESS) {
738 ldb_asprintf_errstring(ldb, "Linked attribute %s->%s between %s and %s - target GUID %s not found - %s",
739 el->name, target->lDAPDisplayName,
740 ldb_dn_get_linearized(old_dn),
741 ldb_dn_get_linearized(dsdb_dn->dn),
742 GUID_string(tmp_ctx, &link_guid),
744 talloc_free(tmp_ctx);
747 if (res->count == 0) {
748 /* Forward link without backlink object remaining - nothing to do here */
751 if (res->count != 1) {
752 ldb_asprintf_errstring(ldb, "Linked attribute %s->%s between %s and %s - target GUID %s found more than once!",
753 el->name, target->lDAPDisplayName,
754 ldb_dn_get_linearized(old_dn),
755 ldb_dn_get_linearized(dsdb_dn->dn),
756 GUID_string(tmp_ctx, &link_guid));
757 talloc_free(tmp_ctx);
758 return LDB_ERR_OPERATIONS_ERROR;
763 if (msg->num_elements == 0) {
764 /* Forward link without backlink remaining - nothing to do here */
766 } else if (msg->num_elements != 1) {
767 ldb_asprintf_errstring(ldb, "Bad msg elements - got %u elements, expected one element to be returned in linked_attributes_fix_links for %s",
768 msg->num_elements, ldb_dn_get_linearized(msg->dn));
769 talloc_free(tmp_ctx);
770 return LDB_ERR_OPERATIONS_ERROR;
772 if (ldb_attr_cmp(msg->elements[0].name, target->lDAPDisplayName) != 0) {
773 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));
774 talloc_free(tmp_ctx);
775 return LDB_ERR_OPERATIONS_ERROR;
777 el2 = &msg->elements[0];
779 el2->flags = LDB_FLAG_MOD_REPLACE;
781 /* find our DN in the values */
782 for (j=0; j<el2->num_values; j++) {
783 struct dsdb_dn *dsdb_dn2;
784 struct GUID link_guid2;
786 dsdb_dn2 = dsdb_dn_parse(msg, ldb, &el2->values[j], target->syntax->ldap_oid);
787 if (dsdb_dn2 == NULL) {
788 talloc_free(tmp_ctx);
789 return LDB_ERR_INVALID_DN_SYNTAX;
792 ret = la_guid_from_dn(module, parent, dsdb_dn2->dn, &link_guid2);
793 if (ret != LDB_SUCCESS) {
794 talloc_free(tmp_ctx);
799 * By comparing using the GUID we ensure that
800 * even if somehow the name has got out of
801 * sync, this rename will fix it.
803 * If somehow we don't have a GUID on the DN
804 * in the DB, the la_guid_from_dn call will be
805 * more costly, but still give us a GUID.
806 * dbcheck will fix this if run.
808 if (!GUID_equal(&self_guid, &link_guid2)) {
812 ret = ldb_dn_update_components(dsdb_dn2->dn, new_dn);
813 if (ret != LDB_SUCCESS) {
814 talloc_free(tmp_ctx);
818 el2->values[j] = data_blob_string_const(
819 dsdb_dn_get_extended_linearized(el2->values, dsdb_dn2, 1));
822 ret = dsdb_check_single_valued_link(target, el2);
823 if (ret != LDB_SUCCESS) {
824 talloc_free(tmp_ctx);
828 /* we may be putting multiple values in an attribute -
829 disable checking for this attribute */
830 el2->flags |= LDB_FLAG_INTERNAL_DISABLE_SINGLE_VALUE_CHECK;
832 ret = dsdb_module_modify(module, msg, DSDB_FLAG_NEXT_MODULE, parent);
833 if (ret != LDB_SUCCESS) {
834 ldb_asprintf_errstring(ldb, "Linked attribute %s->%s between %s and %s - update failed - %s",
835 el->name, target->lDAPDisplayName,
836 ldb_dn_get_linearized(old_dn),
837 ldb_dn_get_linearized(dsdb_dn->dn),
839 talloc_free(tmp_ctx);
844 talloc_free(tmp_ctx);
850 static int linked_attributes_rename(struct ldb_module *module, struct ldb_request *req)
852 struct ldb_result *res;
853 struct ldb_message *msg;
855 struct ldb_context *ldb = ldb_module_get_ctx(module);
856 struct dsdb_schema *schema;
861 - load the current msg
862 - find any linked attributes
863 - if its a link then find the target object
864 - modify the target linked attributes with the new DN
866 ret = dsdb_module_search_dn(module, req, &res, req->op.rename.olddn,
868 DSDB_FLAG_NEXT_MODULE |
869 DSDB_SEARCH_SHOW_EXTENDED_DN |
870 DSDB_SEARCH_SHOW_RECYCLED, req);
871 if (ret != LDB_SUCCESS) {
875 schema = dsdb_get_schema(ldb, res);
882 ret = la_guid_from_dn(module, req, msg->dn, &guid);
883 if (ret != LDB_SUCCESS) {
887 for (i=0; i<msg->num_elements; i++) {
888 struct ldb_message_element *el = &msg->elements[i];
889 const struct dsdb_attribute *schema_attr
890 = dsdb_attribute_by_lDAPDisplayName(schema, el->name);
891 if (!schema_attr || schema_attr->linkID == 0) {
894 ret = linked_attributes_fix_links(module, guid, msg->dn, req->op.rename.newdn, el,
895 schema, schema_attr, req);
896 if (ret != LDB_SUCCESS) {
904 return ldb_next_request(module, req);
908 /* queue a linked attributes modify request in the la_private
910 static int la_queue_mod_request(struct la_context *ac)
912 struct la_private *la_private =
913 talloc_get_type(ldb_module_get_private(ac->module), struct la_private);
915 if (la_private == NULL) {
916 ldb_debug(ldb_module_get_ctx(ac->module), LDB_DEBUG_ERROR, __location__ ": No la_private transaction setup\n");
917 return ldb_operr(ldb_module_get_ctx(ac->module));
920 talloc_steal(la_private, ac);
921 DLIST_ADD(la_private->la_list, ac);
923 return ldb_module_done(ac->req, ac->op_controls,
924 ac->op_response, LDB_SUCCESS);
927 /* Having done the original operation, then try to fix up all the linked attributes for modify and delete */
928 static int la_mod_del_callback(struct ldb_request *req, struct ldb_reply *ares)
930 struct la_context *ac;
931 struct ldb_context *ldb;
934 ac = talloc_get_type(req->context, struct la_context);
935 ldb = ldb_module_get_ctx(ac->module);
938 return ldb_module_done(ac->req, NULL, NULL,
939 LDB_ERR_OPERATIONS_ERROR);
941 if (ares->error != LDB_SUCCESS) {
942 return ldb_module_done(ac->req, ares->controls,
943 ares->response, ares->error);
946 if (ares->type != LDB_REPLY_DONE) {
947 ldb_set_errstring(ldb,
948 "invalid ldb_reply_type in callback");
950 return ldb_module_done(ac->req, NULL, NULL,
951 LDB_ERR_OPERATIONS_ERROR);
954 ac->op_controls = talloc_steal(ac, ares->controls);
955 ac->op_response = talloc_steal(ac, ares->response);
957 /* If we have modfies to make, this is the time to do them for modify and delete */
958 ret = la_queue_mod_request(ac);
960 if (ret != LDB_SUCCESS) {
961 return ldb_module_done(ac->req, NULL, NULL, ret);
965 /* la_queue_mod_request has already sent the callbacks */
970 /* Having done the original add, then try to fix up all the linked attributes
972 This is done after the add so the links can get the extended DNs correctly.
974 static int la_add_callback(struct ldb_request *req, struct ldb_reply *ares)
976 struct la_context *ac;
977 struct ldb_context *ldb;
980 ac = talloc_get_type(req->context, struct la_context);
981 ldb = ldb_module_get_ctx(ac->module);
984 return ldb_module_done(ac->req, NULL, NULL,
985 LDB_ERR_OPERATIONS_ERROR);
987 if (ares->error != LDB_SUCCESS) {
988 return ldb_module_done(ac->req, ares->controls,
989 ares->response, ares->error);
992 if (ares->type != LDB_REPLY_DONE) {
993 ldb_set_errstring(ldb,
994 "invalid ldb_reply_type in callback");
996 return ldb_module_done(ac->req, NULL, NULL,
997 LDB_ERR_OPERATIONS_ERROR);
1001 struct ldb_request *search_req;
1002 static const char *attrs[] = { NULL };
1004 /* The callback does all the hard work here - we need
1005 * the objectGUID and SID of the added record */
1006 ret = ldb_build_search_req(&search_req, ldb, ac,
1007 ac->req->op.add.message->dn,
1009 "(objectClass=*)", attrs,
1011 ac, la_mod_search_callback,
1013 LDB_REQ_SET_LOCATION(search_req);
1015 if (ret == LDB_SUCCESS) {
1016 ret = dsdb_request_add_controls(search_req,
1017 DSDB_SEARCH_SHOW_RECYCLED |
1018 DSDB_SEARCH_SHOW_EXTENDED_DN);
1020 if (ret != LDB_SUCCESS) {
1021 return ldb_module_done(ac->req, NULL, NULL,
1025 ac->op_controls = talloc_steal(ac, ares->controls);
1026 ac->op_response = talloc_steal(ac, ares->response);
1028 return ldb_next_request(ac->module, search_req);
1031 return ldb_module_done(ac->req, ares->controls,
1032 ares->response, ares->error);
1036 /* Reconstruct the original request, but pointing at our local callback to finish things off */
1037 static int la_down_req(struct la_context *ac)
1039 struct ldb_request *down_req;
1040 struct ldb_context *ldb;
1043 ldb = ldb_module_get_ctx(ac->module);
1045 switch (ac->req->operation) {
1047 ret = ldb_build_add_req(&down_req, ldb, ac,
1048 ac->req->op.add.message,
1050 ac, la_add_callback,
1052 LDB_REQ_SET_LOCATION(down_req);
1055 ret = ldb_build_mod_req(&down_req, ldb, ac,
1056 ac->req->op.mod.message,
1058 ac, la_mod_del_callback,
1060 LDB_REQ_SET_LOCATION(down_req);
1063 ret = LDB_ERR_OPERATIONS_ERROR;
1065 if (ret != LDB_SUCCESS) {
1069 return ldb_next_request(ac->module, down_req);
1073 use the GUID part of an extended DN to find the target DN, in case
1076 static int la_find_dn_target(struct ldb_module *module, struct la_context *ac,
1077 struct GUID *guid, struct ldb_dn **dn)
1079 return dsdb_module_dn_by_guid(ac->module, ac, guid, dn, ac->req);
1082 /* apply one la_context op change */
1083 static int la_do_op_request(struct ldb_module *module, struct la_context *ac, struct la_op_store *op)
1085 struct ldb_message_element *ret_el;
1086 struct ldb_message *new_msg;
1087 struct ldb_context *ldb;
1090 if (ac->mod_dn == NULL) {
1091 /* we didn't find the DN that we searched for */
1095 ldb = ldb_module_get_ctx(ac->module);
1097 /* Create the modify request */
1098 new_msg = ldb_msg_new(ac);
1100 return ldb_oom(ldb);
1103 ret = la_find_dn_target(module, ac, &op->guid, &new_msg->dn);
1104 if (ret != LDB_SUCCESS) {
1108 if (op->op == LA_OP_ADD) {
1109 ret = ldb_msg_add_empty(new_msg, op->name,
1110 LDB_FLAG_MOD_ADD, &ret_el);
1112 ret = ldb_msg_add_empty(new_msg, op->name,
1113 LDB_FLAG_MOD_DELETE, &ret_el);
1115 if (ret != LDB_SUCCESS) {
1118 ret_el->values = talloc_array(new_msg, struct ldb_val, 1);
1119 if (!ret_el->values) {
1120 return ldb_oom(ldb);
1122 ret_el->num_values = 1;
1123 ret_el->values[0] = data_blob_string_const(ldb_dn_get_extended_linearized(new_msg, ac->mod_dn, 1));
1125 /* a backlink should never be single valued. Unfortunately the
1126 exchange schema has a attribute
1127 msExchBridgeheadedLocalConnectorsDNBL which is single
1128 valued and a backlink. We need to cope with that by
1129 ignoring the single value flag */
1130 ret_el->flags |= LDB_FLAG_INTERNAL_DISABLE_SINGLE_VALUE_CHECK;
1133 ldb_debug(ldb, LDB_DEBUG_WARNING,
1134 "link on %s %s: %s %s\n",
1135 ldb_dn_get_linearized(new_msg->dn), ret_el->name,
1136 ret_el->values[0].data, ac->ops->op == LA_OP_ADD ? "added" : "deleted");
1140 DEBUG(4,("Applying linked attribute change:\n%s\n",
1141 ldb_ldif_message_string(ldb, op, LDB_CHANGETYPE_MODIFY, new_msg)));
1144 ret = dsdb_module_modify(module, new_msg, DSDB_FLAG_NEXT_MODULE, ac->req);
1145 if (ret != LDB_SUCCESS) {
1146 ldb_debug(ldb, LDB_DEBUG_WARNING, __location__ ": failed to apply linked attribute change '%s'\n%s\n",
1148 ldb_ldif_message_string(ldb, op, LDB_CHANGETYPE_MODIFY, new_msg));
1154 /* apply one set of la_context changes */
1155 static int la_do_mod_request(struct ldb_module *module, struct la_context *ac)
1157 struct la_op_store *op;
1159 for (op = ac->ops; op; op=op->next) {
1160 int ret = la_do_op_request(module, ac, op);
1161 if (ret != LDB_SUCCESS) {
1162 if (ret != LDB_ERR_NO_SUCH_OBJECT) {
1173 we hook into the transaction operations to allow us to
1174 perform the linked attribute updates at the end of the whole
1175 transaction. This allows a forward linked attribute to be created
1176 before the target is created, as long as the target is created
1177 in the same transaction
1179 static int linked_attributes_start_transaction(struct ldb_module *module)
1181 /* create our private structure for this transaction */
1182 struct la_private *la_private = talloc_get_type(ldb_module_get_private(module),
1184 talloc_free(la_private);
1185 la_private = talloc(module, struct la_private);
1186 if (la_private == NULL) {
1187 return ldb_oom(ldb_module_get_ctx(module));
1189 la_private->la_list = NULL;
1190 ldb_module_set_private(module, la_private);
1191 return ldb_next_start_trans(module);
1195 on prepare commit we loop over our queued la_context structures
1196 and apply each of them
1198 static int linked_attributes_prepare_commit(struct ldb_module *module)
1200 struct la_private *la_private =
1201 talloc_get_type(ldb_module_get_private(module), struct la_private);
1202 struct la_context *ac;
1205 /* prepare commit without begin_transaction - let someone else return the error, just don't segfault */
1206 return ldb_next_prepare_commit(module);
1208 /* walk the list backwards, to do the first entry first, as we
1209 * added the entries with DLIST_ADD() which puts them at the
1210 * start of the list */
1212 /* Start at the end of the list - so we can start
1213 * there, but ensure we don't create a loop by NULLing
1214 * it out in the first element */
1215 ac = DLIST_TAIL(la_private->la_list);
1217 for (; ac; ac=DLIST_PREV(ac)) {
1220 ret = la_do_mod_request(module, ac);
1221 if (ret != LDB_SUCCESS) {
1222 DEBUG(0,(__location__ ": Failed mod request ret=%d\n", ret));
1223 talloc_free(la_private);
1224 ldb_module_set_private(module, NULL);
1229 talloc_free(la_private);
1230 ldb_module_set_private(module, NULL);
1232 return ldb_next_prepare_commit(module);
1235 static int linked_attributes_del_transaction(struct ldb_module *module)
1237 struct la_private *la_private =
1238 talloc_get_type(ldb_module_get_private(module), struct la_private);
1239 talloc_free(la_private);
1240 ldb_module_set_private(module, NULL);
1241 return ldb_next_del_trans(module);
1244 static int linked_attributes_ldb_init(struct ldb_module *module)
1248 ret = ldb_mod_register_control(module, LDB_CONTROL_VERIFY_NAME_OID);
1249 if (ret != LDB_SUCCESS) {
1250 ldb_debug(ldb_module_get_ctx(module), LDB_DEBUG_ERROR,
1251 "verify_name: Unable to register control with rootdse!\n");
1252 return ldb_operr(ldb_module_get_ctx(module));
1255 return ldb_next_init(module);
1259 static const struct ldb_module_ops ldb_linked_attributes_module_ops = {
1260 .name = "linked_attributes",
1261 .add = linked_attributes_add,
1262 .modify = linked_attributes_modify,
1263 .rename = linked_attributes_rename,
1264 .init_context = linked_attributes_ldb_init,
1265 .start_transaction = linked_attributes_start_transaction,
1266 .prepare_commit = linked_attributes_prepare_commit,
1267 .del_transaction = linked_attributes_del_transaction,
1270 int ldb_linked_attributes_module_init(const char *version)
1272 LDB_MODULE_CHECK_VERSION(version);
1273 return ldb_register_module(&ldb_linked_attributes_module_ops);