librpc: Shorten dcerpc_binding_handle_call a bit
[Samba/gebeck_regimport.git] / source4 / dsdb / samdb / ldb_modules / linked_attributes.c
blobeb57f91e6d84a24f0f4428b3b93e507839681d33
1 /*
2 ldb database library
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/>.
24 * Name: ldb
26 * Component: ldb linked_attributes module
28 * Description: Module to ensure linked attribute pairs remain in sync
30 * Author: Andrew Bartlett
33 #include "includes.h"
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"
40 struct la_private {
41 struct la_context *la_list;
44 struct la_op_store {
45 struct la_op_store *next;
46 struct la_op_store *prev;
47 enum la_op {LA_OP_ADD, LA_OP_DEL} op;
48 struct GUID guid;
49 char *name;
52 struct replace_context {
53 struct la_context *ac;
54 unsigned int num_elements;
55 struct ldb_message_element *el;
58 struct la_context {
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;
69 * For futur use
70 * will tell which GC to use for resolving links
72 char *gc_dns_name;
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);
88 const char *dns;
90 if (ret != LDB_SUCCESS) {
91 return ldb_operr(ldb);
94 dns = samdb_dn_to_dnshostname(ldb, ctx, *dn);
95 if (!dns) {
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);
102 } else {
103 control->critical = true;
105 talloc_free(dn);
106 } else {
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.
112 if (lvnc->gc) {
113 ac->gc_dns_name = talloc_strdup(ac, lvnc->gc);
115 control->critical = true;
118 return LDB_SUCCESS;
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);
130 if (ac == NULL) {
131 ldb_oom(ldb);
132 return NULL;
135 ac->schema = dsdb_get_schema(ldb, ac);
136 ac->module = module;
137 ac->req = req;
139 return 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)
149 NTSTATUS status;
150 int ret;
152 status = dsdb_get_extended_dn_guid(dn, guid, "GUID");
153 if (NT_STATUS_IS_OK(status)) {
154 return LDB_SUCCESS;
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)));
166 return ret;
168 return LDB_SUCCESS;
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,
175 enum la_op op, struct ldb_val *dn,
176 const char *name)
178 struct ldb_context *ldb;
179 struct la_op_store *os;
180 struct ldb_dn *op_dn;
181 int ret;
183 ldb = ldb_module_get_ctx(ac->module);
185 op_dn = ldb_dn_from_ldb_val(ac, ldb, dn);
186 if (!op_dn) {
187 ldb_asprintf_errstring(ldb,
188 "could not parse attribute as a DN");
189 return LDB_ERR_INVALID_DN_SYNTAX;
192 os = talloc_zero(ac, struct la_op_store);
193 if (!os) {
194 return ldb_oom(ldb);
197 os->op = op;
199 ret = la_guid_from_dn(ac->module, ac->req, op_dn, &os->guid);
200 talloc_free(op_dn);
201 if (ret == LDB_ERR_NO_SUCH_OBJECT && ac->req->operation == LDB_DELETE) {
202 /* we are deleting an object, and we've found it has a
203 * forward link to a target that no longer
204 * exists. This is not an error in the delete, and we
205 * should just not do the deferred delete of the
206 * target attribute
208 talloc_free(os);
209 return LDB_SUCCESS;
211 if (ret != LDB_SUCCESS) {
212 return ret;
215 os->name = talloc_strdup(os, name);
216 if (!os->name) {
217 return ldb_oom(ldb);
220 /* Do deletes before adds */
221 if (op == LA_OP_ADD) {
222 DLIST_ADD_END(ac->ops, os, struct la_op_store *);
223 } else {
224 /* By adding to the head of the list, we do deletes before
225 * adds when processing a replace */
226 DLIST_ADD(ac->ops, os);
229 return LDB_SUCCESS;
232 static int la_queue_mod_request(struct la_context *ac);
233 static int la_down_req(struct la_context *ac);
237 /* add */
238 static int linked_attributes_add(struct ldb_module *module, struct ldb_request *req)
240 struct ldb_context *ldb;
241 const struct dsdb_attribute *target_attr;
242 struct la_context *ac;
243 const char *attr_name;
244 struct ldb_control *ctrl;
245 unsigned int i, j;
246 struct ldb_control *control;
247 int ret;
249 ldb = ldb_module_get_ctx(module);
251 if (ldb_dn_is_special(req->op.add.message->dn)) {
252 /* do not manipulate our control entries */
253 return ldb_next_request(module, req);
256 ac = linked_attributes_init(module, req);
257 if (!ac) {
258 return ldb_operr(ldb);
261 control = ldb_request_get_control(req, LDB_CONTROL_VERIFY_NAME_OID);
262 if (control != NULL && control->data != NULL) {
263 ret = handle_verify_name_control(req, ldb, control, ac);
264 if (ret != LDB_SUCCESS) {
265 return ldb_operr(ldb);
269 if (!(ctrl = ldb_request_get_control(req, DSDB_CONTROL_APPLY_LINKS))) {
270 /* don't do anything special for linked attributes, repl_meta_data has done it */
271 talloc_free(ac);
272 return ldb_next_request(module, req);
274 ctrl->critical = false;
276 if (!ac->schema) {
277 /* without schema, this doesn't make any sense */
278 talloc_free(ac);
279 return ldb_next_request(module, req);
283 /* Need to ensure we only have forward links being specified */
284 for (i=0; i < req->op.add.message->num_elements; i++) {
285 const struct ldb_message_element *el = &req->op.add.message->elements[i];
286 const struct dsdb_attribute *schema_attr
287 = dsdb_attribute_by_lDAPDisplayName(ac->schema, el->name);
288 if (!schema_attr) {
289 ldb_asprintf_errstring(ldb,
290 "%s: attribute %s is not a valid attribute in schema",
291 __FUNCTION__,
292 el->name);
293 return LDB_ERR_OBJECT_CLASS_VIOLATION;
296 /* this could be a link with no partner, in which case
297 there is no special work to do */
298 if (schema_attr->linkID == 0) {
299 continue;
302 /* this part of the code should only be handling forward links */
303 SMB_ASSERT((schema_attr->linkID & 1) == 0);
305 /* Even link IDs are for the originating attribute */
306 target_attr = dsdb_attribute_by_linkID(ac->schema, schema_attr->linkID ^ 1);
307 if (!target_attr) {
309 * windows 2003 has a broken schema where
310 * the definition of msDS-IsDomainFor
311 * is missing (which is supposed to be
312 * the backlink of the msDS-HasDomainNCs
313 * attribute
315 continue;
318 attr_name = target_attr->lDAPDisplayName;
320 for (j = 0; j < el->num_values; j++) {
321 ret = la_store_op(ac, LA_OP_ADD,
322 &el->values[j],
323 attr_name);
324 if (ret != LDB_SUCCESS) {
325 return ret;
330 /* if no linked attributes are present continue */
331 if (ac->ops == NULL) {
332 /* nothing to do for this module, proceed */
333 talloc_free(ac);
334 return ldb_next_request(module, req);
337 /* start with the original request */
338 return la_down_req(ac);
341 /* For a delete or rename, we need to find out what linked attributes
342 * are currently on this DN, and then deal with them. This is the
343 * callback to the base search */
345 static int la_mod_search_callback(struct ldb_request *req, struct ldb_reply *ares)
347 struct ldb_context *ldb;
348 const struct dsdb_attribute *schema_attr;
349 const struct dsdb_attribute *target_attr;
350 struct ldb_message_element *search_el;
351 struct replace_context *rc;
352 struct la_context *ac;
353 const char *attr_name;
354 unsigned int i, j;
355 int ret = LDB_SUCCESS;
357 ac = talloc_get_type(req->context, struct la_context);
358 ldb = ldb_module_get_ctx(ac->module);
359 rc = ac->rc;
361 if (!ares) {
362 return ldb_module_done(ac->req, NULL, NULL,
363 LDB_ERR_OPERATIONS_ERROR);
365 if (ares->error != LDB_SUCCESS) {
366 return ldb_module_done(ac->req, ares->controls,
367 ares->response, ares->error);
370 /* Only entries are interesting, and we only want the olddn */
371 switch (ares->type) {
372 case LDB_REPLY_ENTRY:
374 if (ldb_dn_compare(ares->message->dn, ac->req->op.mod.message->dn) != 0) {
375 ldb_asprintf_errstring(ldb,
376 "linked_attributes: %s is not the DN we were looking for",
377 ldb_dn_get_linearized(ares->message->dn));
378 /* Guh? We only asked for this DN */
379 talloc_free(ares);
380 return ldb_module_done(ac->req, NULL, NULL,
381 LDB_ERR_OPERATIONS_ERROR);
384 ac->mod_dn = talloc_steal(ac, ares->message->dn);
386 /* We don't populate 'rc' for ADD - it can't be deleting elements anyway */
387 for (i = 0; rc && i < rc->num_elements; i++) {
389 schema_attr = dsdb_attribute_by_lDAPDisplayName(ac->schema, rc->el[i].name);
390 if (!schema_attr) {
391 ldb_asprintf_errstring(ldb,
392 "%s: attribute %s is not a valid attribute in schema",
393 __FUNCTION__,
394 rc->el[i].name);
395 talloc_free(ares);
396 return ldb_module_done(ac->req, NULL, NULL,
397 LDB_ERR_OBJECT_CLASS_VIOLATION);
400 search_el = ldb_msg_find_element(ares->message,
401 rc->el[i].name);
403 /* See if this element already exists */
404 /* otherwise just ignore as
405 * the add has already been scheduled */
406 if ( ! search_el) {
407 continue;
410 target_attr = dsdb_attribute_by_linkID(ac->schema, schema_attr->linkID ^ 1);
411 if (!target_attr) {
413 * windows 2003 has a broken schema where
414 * the definition of msDS-IsDomainFor
415 * is missing (which is supposed to be
416 * the backlink of the msDS-HasDomainNCs
417 * attribute
419 continue;
421 attr_name = target_attr->lDAPDisplayName;
423 /* Now we know what was there, we can remove it for the re-add */
424 for (j = 0; j < search_el->num_values; j++) {
425 ret = la_store_op(ac, LA_OP_DEL,
426 &search_el->values[j],
427 attr_name);
428 if (ret != LDB_SUCCESS) {
429 talloc_free(ares);
430 return ldb_module_done(ac->req,
431 NULL, NULL, ret);
436 break;
438 case LDB_REPLY_REFERRAL:
439 /* ignore */
440 break;
442 case LDB_REPLY_DONE:
444 talloc_free(ares);
446 if (ac->req->operation == LDB_ADD) {
447 /* Start the modifies to the backlinks */
448 ret = la_queue_mod_request(ac);
450 if (ret != LDB_SUCCESS) {
451 return ldb_module_done(ac->req, NULL, NULL,
452 ret);
454 } else {
455 /* Start with the original request */
456 ret = la_down_req(ac);
457 if (ret != LDB_SUCCESS) {
458 return ldb_module_done(ac->req, NULL, NULL, ret);
461 return LDB_SUCCESS;
464 talloc_free(ares);
465 return ret;
469 /* modify */
470 static int linked_attributes_modify(struct ldb_module *module, struct ldb_request *req)
472 /* Look over list of modifications */
473 /* Find if any are for linked attributes */
474 /* Determine the effect of the modification */
475 /* Apply the modify to the linked entry */
477 struct ldb_control *control;
478 struct ldb_context *ldb;
479 unsigned int i, j;
480 struct la_context *ac;
481 struct ldb_request *search_req;
482 const char **attrs;
483 struct ldb_control *ctrl;
484 int ret;
486 ldb = ldb_module_get_ctx(module);
488 if (ldb_dn_is_special(req->op.mod.message->dn)) {
489 /* do not manipulate our control entries */
490 return ldb_next_request(module, req);
493 ac = linked_attributes_init(module, req);
494 if (!ac) {
495 return ldb_operr(ldb);
498 control = ldb_request_get_control(req, LDB_CONTROL_VERIFY_NAME_OID);
499 if (control != NULL && control->data != NULL) {
500 ret = handle_verify_name_control(req, ldb, control, ac);
501 if (ret != LDB_SUCCESS) {
502 return ldb_operr(ldb);
506 if (!(ctrl = ldb_request_get_control(req, DSDB_CONTROL_APPLY_LINKS))) {
507 /* don't do anything special for linked attributes, repl_meta_data has done it */
508 talloc_free(ac);
509 return ldb_next_request(module, req);
511 ctrl->critical = false;
513 if (!ac->schema) {
514 /* without schema, this doesn't make any sense */
515 return ldb_next_request(module, req);
518 ac->rc = talloc_zero(ac, struct replace_context);
519 if (!ac->rc) {
520 return ldb_oom(ldb);
523 for (i=0; i < req->op.mod.message->num_elements; i++) {
524 bool store_el = false;
525 const char *attr_name;
526 const struct dsdb_attribute *target_attr;
527 const struct ldb_message_element *el = &req->op.mod.message->elements[i];
528 const struct dsdb_attribute *schema_attr
529 = dsdb_attribute_by_lDAPDisplayName(ac->schema, el->name);
530 if (!schema_attr) {
531 ldb_asprintf_errstring(ldb,
532 "%s: attribute %s is not a valid attribute in schema",
533 __FUNCTION__,
534 el->name);
535 return LDB_ERR_OBJECT_CLASS_VIOLATION;
537 /* We have a valid attribute, now find out if it is a forward link
538 (Even link IDs are for the originating attribute) */
539 if (schema_attr->linkID == 0) {
540 continue;
543 /* this part of the code should only be handling forward links */
544 SMB_ASSERT((schema_attr->linkID & 1) == 0);
546 /* Now find the target attribute */
547 target_attr = dsdb_attribute_by_linkID(ac->schema, schema_attr->linkID ^ 1);
548 if (!target_attr) {
550 * windows 2003 has a broken schema where
551 * the definition of msDS-IsDomainFor
552 * is missing (which is supposed to be
553 * the backlink of the msDS-HasDomainNCs
554 * attribute
556 continue;
559 attr_name = target_attr->lDAPDisplayName;
561 switch (el->flags & LDB_FLAG_MOD_MASK) {
562 case LDB_FLAG_MOD_REPLACE:
563 /* treat as just a normal add the delete part is handled by the callback */
564 store_el = true;
566 /* break intentionally missing */
568 case LDB_FLAG_MOD_ADD:
570 /* For each value being added, we need to setup the adds */
571 for (j = 0; j < el->num_values; j++) {
572 ret = la_store_op(ac, LA_OP_ADD,
573 &el->values[j],
574 attr_name);
575 if (ret != LDB_SUCCESS) {
576 return ret;
579 break;
581 case LDB_FLAG_MOD_DELETE:
583 if (el->num_values) {
584 /* For each value being deleted, we need to setup the delete */
585 for (j = 0; j < el->num_values; j++) {
586 ret = la_store_op(ac, LA_OP_DEL,
587 &el->values[j],
588 attr_name);
589 if (ret != LDB_SUCCESS) {
590 return ret;
593 } else {
594 /* Flag that there was a DELETE
595 * without a value specified, so we
596 * need to look for the old value */
597 store_el = true;
600 break;
603 if (store_el) {
604 struct ldb_message_element *search_el;
606 search_el = talloc_realloc(ac->rc, ac->rc->el,
607 struct ldb_message_element,
608 ac->rc->num_elements +1);
609 if (!search_el) {
610 return ldb_oom(ldb);
612 ac->rc->el = search_el;
614 ac->rc->el[ac->rc->num_elements] = *el;
615 ac->rc->num_elements++;
619 if (ac->ops || ac->rc->el) {
620 /* both replace and delete without values are handled in the callback
621 * after the search on the entry to be modified is performed */
623 attrs = talloc_array(ac->rc, const char *, ac->rc->num_elements + 1);
624 if (!attrs) {
625 return ldb_oom(ldb);
627 for (i = 0; ac->rc && i < ac->rc->num_elements; i++) {
628 attrs[i] = ac->rc->el[i].name;
630 attrs[i] = NULL;
632 /* The callback does all the hard work here */
633 ret = ldb_build_search_req(&search_req, ldb, ac,
634 req->op.mod.message->dn,
635 LDB_SCOPE_BASE,
636 "(objectClass=*)", attrs,
637 NULL,
638 ac, la_mod_search_callback,
639 req);
640 LDB_REQ_SET_LOCATION(search_req);
642 /* We need to figure out our own extended DN, to fill in as the backlink target */
643 if (ret == LDB_SUCCESS) {
644 ret = dsdb_request_add_controls(search_req,
645 DSDB_SEARCH_SHOW_DELETED |
646 DSDB_SEARCH_SHOW_EXTENDED_DN);
648 if (ret == LDB_SUCCESS) {
649 talloc_steal(search_req, attrs);
651 ret = ldb_next_request(module, search_req);
654 } else {
655 /* nothing to do for this module, proceed */
656 talloc_free(ac);
657 ret = ldb_next_request(module, req);
660 return ret;
663 static int linked_attributes_fix_links(struct ldb_module *module,
664 struct GUID self_guid,
665 struct ldb_dn *old_dn, struct ldb_dn *new_dn,
666 struct ldb_message_element *el, struct dsdb_schema *schema,
667 const struct dsdb_attribute *schema_attr,
668 struct ldb_request *parent)
670 unsigned int i, j;
671 TALLOC_CTX *tmp_ctx = talloc_new(module);
672 struct ldb_context *ldb = ldb_module_get_ctx(module);
673 const struct dsdb_attribute *target;
674 const char *attrs[2];
675 int ret;
677 target = dsdb_attribute_by_linkID(schema, schema_attr->linkID ^ 1);
678 if (target == NULL) {
679 /* there is no counterpart link to change */
680 return LDB_SUCCESS;
683 attrs[0] = target->lDAPDisplayName;
684 attrs[1] = NULL;
686 for (i=0; i<el->num_values; i++) {
687 struct dsdb_dn *dsdb_dn;
688 struct ldb_result *res;
689 struct ldb_message *msg;
690 struct ldb_message_element *el2;
691 struct GUID link_guid;
693 dsdb_dn = dsdb_dn_parse(tmp_ctx, ldb, &el->values[i], schema_attr->syntax->ldap_oid);
694 if (dsdb_dn == NULL) {
695 talloc_free(tmp_ctx);
696 return LDB_ERR_INVALID_DN_SYNTAX;
699 ret = la_guid_from_dn(module, parent, dsdb_dn->dn, &link_guid);
700 if (ret != LDB_SUCCESS) {
701 ldb_asprintf_errstring(ldb, "Linked attribute %s->%s between %s and %s - GUID not found - %s",
702 el->name, target->lDAPDisplayName,
703 ldb_dn_get_linearized(old_dn),
704 ldb_dn_get_linearized(dsdb_dn->dn),
705 ldb_errstring(ldb));
706 talloc_free(tmp_ctx);
707 return ret;
711 * get the existing message from the db for the object with
712 * this GUID, returning attribute being modified. We will then
713 * use this msg as the basis for a modify call
715 ret = dsdb_module_search(module, tmp_ctx, &res, NULL, LDB_SCOPE_SUBTREE, attrs,
716 DSDB_FLAG_NEXT_MODULE |
717 DSDB_SEARCH_SEARCH_ALL_PARTITIONS |
718 DSDB_SEARCH_SHOW_RECYCLED |
719 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT |
720 DSDB_SEARCH_REVEAL_INTERNALS,
721 parent,
722 "objectGUID=%s", GUID_string(tmp_ctx, &link_guid));
723 if (ret != LDB_SUCCESS) {
724 ldb_asprintf_errstring(ldb, "Linked attribute %s->%s between %s and %s - target GUID %s not found - %s",
725 el->name, target->lDAPDisplayName,
726 ldb_dn_get_linearized(old_dn),
727 ldb_dn_get_linearized(dsdb_dn->dn),
728 GUID_string(tmp_ctx, &link_guid),
729 ldb_errstring(ldb));
730 talloc_free(tmp_ctx);
731 return ret;
733 if (res->count == 0) {
734 /* Forward link without backlink object remaining - nothing to do here */
735 continue;
737 if (res->count != 1) {
738 ldb_asprintf_errstring(ldb, "Linked attribute %s->%s between %s and %s - target GUID %s found more than once!",
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));
743 talloc_free(tmp_ctx);
744 return LDB_ERR_OPERATIONS_ERROR;
747 msg = res->msgs[0];
749 if (msg->num_elements == 0) {
750 /* Forward link without backlink remaining - nothing to do here */
751 continue;
752 } else if (msg->num_elements != 1) {
753 ldb_asprintf_errstring(ldb, "Bad msg elements - got %u elements, expected one element to be returned in linked_attributes_fix_links for %s",
754 msg->num_elements, ldb_dn_get_linearized(msg->dn));
755 talloc_free(tmp_ctx);
756 return LDB_ERR_OPERATIONS_ERROR;
758 if (ldb_attr_cmp(msg->elements[0].name, target->lDAPDisplayName) != 0) {
759 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));
760 talloc_free(tmp_ctx);
761 return LDB_ERR_OPERATIONS_ERROR;
763 el2 = &msg->elements[0];
765 el2->flags = LDB_FLAG_MOD_REPLACE;
767 /* find our DN in the values */
768 for (j=0; j<el2->num_values; j++) {
769 struct dsdb_dn *dsdb_dn2;
770 struct GUID link_guid2;
772 dsdb_dn2 = dsdb_dn_parse(msg, ldb, &el2->values[j], target->syntax->ldap_oid);
773 if (dsdb_dn2 == NULL) {
774 talloc_free(tmp_ctx);
775 return LDB_ERR_INVALID_DN_SYNTAX;
778 ret = la_guid_from_dn(module, parent, dsdb_dn2->dn, &link_guid2);
779 if (ret != LDB_SUCCESS) {
780 talloc_free(tmp_ctx);
781 return ret;
785 * By comparing using the GUID we ensure that
786 * even if somehow the name has got out of
787 * sync, this rename will fix it.
789 * If somehow we don't have a GUID on the DN
790 * in the DB, the la_guid_from_dn call will be
791 * more costly, but still give us a GUID.
792 * dbcheck will fix this if run.
794 if (!GUID_equal(&self_guid, &link_guid2)) {
795 continue;
798 ret = ldb_dn_update_components(dsdb_dn2->dn, new_dn);
799 if (ret != LDB_SUCCESS) {
800 talloc_free(tmp_ctx);
801 return ret;
804 el2->values[j] = data_blob_string_const(
805 dsdb_dn_get_extended_linearized(el2->values, dsdb_dn2, 1));
808 ret = dsdb_check_single_valued_link(target, el2);
809 if (ret != LDB_SUCCESS) {
810 talloc_free(tmp_ctx);
811 return ret;
814 /* we may be putting multiple values in an attribute -
815 disable checking for this attribute */
816 el2->flags |= LDB_FLAG_INTERNAL_DISABLE_SINGLE_VALUE_CHECK;
818 ret = dsdb_module_modify(module, msg, DSDB_FLAG_NEXT_MODULE, parent);
819 if (ret != LDB_SUCCESS) {
820 ldb_asprintf_errstring(ldb, "Linked attribute %s->%s between %s and %s - update failed - %s",
821 el->name, target->lDAPDisplayName,
822 ldb_dn_get_linearized(old_dn),
823 ldb_dn_get_linearized(dsdb_dn->dn),
824 ldb_errstring(ldb));
825 talloc_free(tmp_ctx);
826 return ret;
830 talloc_free(tmp_ctx);
831 return LDB_SUCCESS;
835 /* rename */
836 static int linked_attributes_rename(struct ldb_module *module, struct ldb_request *req)
838 struct ldb_result *res;
839 struct ldb_message *msg;
840 unsigned int i;
841 struct ldb_context *ldb = ldb_module_get_ctx(module);
842 struct dsdb_schema *schema;
843 int ret;
844 struct GUID guid;
847 - load the current msg
848 - find any linked attributes
849 - if its a link then find the target object
850 - modify the target linked attributes with the new DN
852 ret = dsdb_module_search_dn(module, req, &res, req->op.rename.olddn,
853 NULL,
854 DSDB_FLAG_NEXT_MODULE |
855 DSDB_SEARCH_SHOW_EXTENDED_DN |
856 DSDB_SEARCH_SHOW_RECYCLED, req);
857 if (ret != LDB_SUCCESS) {
858 return ret;
861 schema = dsdb_get_schema(ldb, res);
862 if (!schema) {
863 return ldb_oom(ldb);
866 msg = res->msgs[0];
868 ret = la_guid_from_dn(module, req, msg->dn, &guid);
869 if (ret != LDB_SUCCESS) {
870 return ret;
873 for (i=0; i<msg->num_elements; i++) {
874 struct ldb_message_element *el = &msg->elements[i];
875 const struct dsdb_attribute *schema_attr
876 = dsdb_attribute_by_lDAPDisplayName(schema, el->name);
877 if (!schema_attr || schema_attr->linkID == 0) {
878 continue;
880 ret = linked_attributes_fix_links(module, guid, msg->dn, req->op.rename.newdn, el,
881 schema, schema_attr, req);
882 if (ret != LDB_SUCCESS) {
883 talloc_free(res);
884 return ret;
888 talloc_free(res);
890 return ldb_next_request(module, req);
894 /* queue a linked attributes modify request in the la_private
895 structure */
896 static int la_queue_mod_request(struct la_context *ac)
898 struct la_private *la_private =
899 talloc_get_type(ldb_module_get_private(ac->module), struct la_private);
901 if (la_private == NULL) {
902 ldb_debug(ldb_module_get_ctx(ac->module), LDB_DEBUG_ERROR, __location__ ": No la_private transaction setup\n");
903 return ldb_operr(ldb_module_get_ctx(ac->module));
906 talloc_steal(la_private, ac);
907 DLIST_ADD(la_private->la_list, ac);
909 return ldb_module_done(ac->req, ac->op_controls,
910 ac->op_response, LDB_SUCCESS);
913 /* Having done the original operation, then try to fix up all the linked attributes for modify and delete */
914 static int la_mod_del_callback(struct ldb_request *req, struct ldb_reply *ares)
916 struct la_context *ac;
917 struct ldb_context *ldb;
918 int ret;
920 ac = talloc_get_type(req->context, struct la_context);
921 ldb = ldb_module_get_ctx(ac->module);
923 if (!ares) {
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");
935 talloc_free(ares);
936 return ldb_module_done(ac->req, NULL, NULL,
937 LDB_ERR_OPERATIONS_ERROR);
940 ac->op_controls = talloc_steal(ac, ares->controls);
941 ac->op_response = talloc_steal(ac, ares->response);
943 /* If we have modfies to make, this is the time to do them for modify and delete */
944 ret = la_queue_mod_request(ac);
946 if (ret != LDB_SUCCESS) {
947 return ldb_module_done(ac->req, NULL, NULL, ret);
949 talloc_free(ares);
951 /* la_queue_mod_request has already sent the callbacks */
952 return LDB_SUCCESS;
956 /* Having done the original add, then try to fix up all the linked attributes
958 This is done after the add so the links can get the extended DNs correctly.
960 static int la_add_callback(struct ldb_request *req, struct ldb_reply *ares)
962 struct la_context *ac;
963 struct ldb_context *ldb;
964 int ret;
966 ac = talloc_get_type(req->context, struct la_context);
967 ldb = ldb_module_get_ctx(ac->module);
969 if (!ares) {
970 return ldb_module_done(ac->req, NULL, NULL,
971 LDB_ERR_OPERATIONS_ERROR);
973 if (ares->error != LDB_SUCCESS) {
974 return ldb_module_done(ac->req, ares->controls,
975 ares->response, ares->error);
978 if (ares->type != LDB_REPLY_DONE) {
979 ldb_set_errstring(ldb,
980 "invalid ldb_reply_type in callback");
981 talloc_free(ares);
982 return ldb_module_done(ac->req, NULL, NULL,
983 LDB_ERR_OPERATIONS_ERROR);
986 if (ac->ops) {
987 struct ldb_request *search_req;
988 static const char *attrs[] = { NULL };
990 /* The callback does all the hard work here - we need
991 * the objectGUID and SID of the added record */
992 ret = ldb_build_search_req(&search_req, ldb, ac,
993 ac->req->op.add.message->dn,
994 LDB_SCOPE_BASE,
995 "(objectClass=*)", attrs,
996 NULL,
997 ac, la_mod_search_callback,
998 ac->req);
999 LDB_REQ_SET_LOCATION(search_req);
1001 if (ret == LDB_SUCCESS) {
1002 ret = dsdb_request_add_controls(search_req,
1003 DSDB_SEARCH_SHOW_DELETED |
1004 DSDB_SEARCH_SHOW_EXTENDED_DN);
1006 if (ret != LDB_SUCCESS) {
1007 return ldb_module_done(ac->req, NULL, NULL,
1008 ret);
1011 ac->op_controls = talloc_steal(ac, ares->controls);
1012 ac->op_response = talloc_steal(ac, ares->response);
1014 return ldb_next_request(ac->module, search_req);
1016 } else {
1017 return ldb_module_done(ac->req, ares->controls,
1018 ares->response, ares->error);
1022 /* Reconstruct the original request, but pointing at our local callback to finish things off */
1023 static int la_down_req(struct la_context *ac)
1025 struct ldb_request *down_req;
1026 struct ldb_context *ldb;
1027 int ret;
1029 ldb = ldb_module_get_ctx(ac->module);
1031 switch (ac->req->operation) {
1032 case LDB_ADD:
1033 ret = ldb_build_add_req(&down_req, ldb, ac,
1034 ac->req->op.add.message,
1035 ac->req->controls,
1036 ac, la_add_callback,
1037 ac->req);
1038 LDB_REQ_SET_LOCATION(down_req);
1039 break;
1040 case LDB_MODIFY:
1041 ret = ldb_build_mod_req(&down_req, ldb, ac,
1042 ac->req->op.mod.message,
1043 ac->req->controls,
1044 ac, la_mod_del_callback,
1045 ac->req);
1046 LDB_REQ_SET_LOCATION(down_req);
1047 break;
1048 default:
1049 ret = LDB_ERR_OPERATIONS_ERROR;
1051 if (ret != LDB_SUCCESS) {
1052 return ret;
1055 return ldb_next_request(ac->module, down_req);
1059 use the GUID part of an extended DN to find the target DN, in case
1060 it has moved
1062 static int la_find_dn_target(struct ldb_module *module, struct la_context *ac,
1063 struct GUID *guid, struct ldb_dn **dn)
1065 return dsdb_module_dn_by_guid(ac->module, ac, guid, dn, ac->req);
1068 /* apply one la_context op change */
1069 static int la_do_op_request(struct ldb_module *module, struct la_context *ac, struct la_op_store *op)
1071 struct ldb_message_element *ret_el;
1072 struct ldb_message *new_msg;
1073 struct ldb_context *ldb;
1074 int ret;
1076 if (ac->mod_dn == NULL) {
1077 /* we didn't find the DN that we searched for */
1078 return LDB_SUCCESS;
1081 ldb = ldb_module_get_ctx(ac->module);
1083 /* Create the modify request */
1084 new_msg = ldb_msg_new(ac);
1085 if (!new_msg) {
1086 return ldb_oom(ldb);
1089 ret = la_find_dn_target(module, ac, &op->guid, &new_msg->dn);
1090 if (ret != LDB_SUCCESS) {
1091 return ret;
1094 if (op->op == LA_OP_ADD) {
1095 ret = ldb_msg_add_empty(new_msg, op->name,
1096 LDB_FLAG_MOD_ADD, &ret_el);
1097 } else {
1098 ret = ldb_msg_add_empty(new_msg, op->name,
1099 LDB_FLAG_MOD_DELETE, &ret_el);
1101 if (ret != LDB_SUCCESS) {
1102 return ret;
1104 ret_el->values = talloc_array(new_msg, struct ldb_val, 1);
1105 if (!ret_el->values) {
1106 return ldb_oom(ldb);
1108 ret_el->num_values = 1;
1109 ret_el->values[0] = data_blob_string_const(ldb_dn_get_extended_linearized(new_msg, ac->mod_dn, 1));
1111 /* a backlink should never be single valued. Unfortunately the
1112 exchange schema has a attribute
1113 msExchBridgeheadedLocalConnectorsDNBL which is single
1114 valued and a backlink. We need to cope with that by
1115 ignoring the single value flag */
1116 ret_el->flags |= LDB_FLAG_INTERNAL_DISABLE_SINGLE_VALUE_CHECK;
1118 #if 0
1119 ldb_debug(ldb, LDB_DEBUG_WARNING,
1120 "link on %s %s: %s %s\n",
1121 ldb_dn_get_linearized(new_msg->dn), ret_el->name,
1122 ret_el->values[0].data, ac->ops->op == LA_OP_ADD ? "added" : "deleted");
1123 #endif
1125 if (DEBUGLVL(4)) {
1126 DEBUG(4,("Applying linked attribute change:\n%s\n",
1127 ldb_ldif_message_string(ldb, op, LDB_CHANGETYPE_MODIFY, new_msg)));
1130 ret = dsdb_module_modify(module, new_msg, DSDB_FLAG_NEXT_MODULE, ac->req);
1131 if (ret != LDB_SUCCESS) {
1132 ldb_debug(ldb, LDB_DEBUG_WARNING, __location__ ": failed to apply linked attribute change '%s'\n%s\n",
1133 ldb_errstring(ldb),
1134 ldb_ldif_message_string(ldb, op, LDB_CHANGETYPE_MODIFY, new_msg));
1137 return ret;
1140 /* apply one set of la_context changes */
1141 static int la_do_mod_request(struct ldb_module *module, struct la_context *ac)
1143 struct la_op_store *op;
1145 for (op = ac->ops; op; op=op->next) {
1146 int ret = la_do_op_request(module, ac, op);
1147 if (ret != LDB_SUCCESS) {
1148 if (ret != LDB_ERR_NO_SUCH_OBJECT) {
1149 return ret;
1154 return LDB_SUCCESS;
1159 we hook into the transaction operations to allow us to
1160 perform the linked attribute updates at the end of the whole
1161 transaction. This allows a forward linked attribute to be created
1162 before the target is created, as long as the target is created
1163 in the same transaction
1165 static int linked_attributes_start_transaction(struct ldb_module *module)
1167 /* create our private structure for this transaction */
1168 struct la_private *la_private = talloc_get_type(ldb_module_get_private(module),
1169 struct la_private);
1170 talloc_free(la_private);
1171 la_private = talloc(module, struct la_private);
1172 if (la_private == NULL) {
1173 return ldb_oom(ldb_module_get_ctx(module));
1175 la_private->la_list = NULL;
1176 ldb_module_set_private(module, la_private);
1177 return ldb_next_start_trans(module);
1181 on prepare commit we loop over our queued la_context structures
1182 and apply each of them
1184 static int linked_attributes_prepare_commit(struct ldb_module *module)
1186 struct la_private *la_private =
1187 talloc_get_type(ldb_module_get_private(module), struct la_private);
1188 struct la_context *ac;
1190 if (!la_private) {
1191 /* prepare commit without begin_transaction - let someone else return the error, just don't segfault */
1192 return ldb_next_prepare_commit(module);
1194 /* walk the list backwards, to do the first entry first, as we
1195 * added the entries with DLIST_ADD() which puts them at the
1196 * start of the list */
1198 /* Start at the end of the list - so we can start
1199 * there, but ensure we don't create a loop by NULLing
1200 * it out in the first element */
1201 ac = DLIST_TAIL(la_private->la_list);
1203 for (; ac; ac=DLIST_PREV(ac)) {
1204 int ret;
1205 ac->req = NULL;
1206 ret = la_do_mod_request(module, ac);
1207 if (ret != LDB_SUCCESS) {
1208 DEBUG(0,(__location__ ": Failed mod request ret=%d\n", ret));
1209 talloc_free(la_private);
1210 ldb_module_set_private(module, NULL);
1211 return ret;
1215 talloc_free(la_private);
1216 ldb_module_set_private(module, NULL);
1218 return ldb_next_prepare_commit(module);
1221 static int linked_attributes_del_transaction(struct ldb_module *module)
1223 struct la_private *la_private =
1224 talloc_get_type(ldb_module_get_private(module), struct la_private);
1225 talloc_free(la_private);
1226 ldb_module_set_private(module, NULL);
1227 return ldb_next_del_trans(module);
1230 static int linked_attributes_ldb_init(struct ldb_module *module)
1232 int ret;
1234 ret = ldb_mod_register_control(module, LDB_CONTROL_VERIFY_NAME_OID);
1235 if (ret != LDB_SUCCESS) {
1236 ldb_debug(ldb_module_get_ctx(module), LDB_DEBUG_ERROR,
1237 "verify_name: Unable to register control with rootdse!\n");
1238 return ldb_operr(ldb_module_get_ctx(module));
1241 return ldb_next_init(module);
1245 static const struct ldb_module_ops ldb_linked_attributes_module_ops = {
1246 .name = "linked_attributes",
1247 .add = linked_attributes_add,
1248 .modify = linked_attributes_modify,
1249 .rename = linked_attributes_rename,
1250 .init_context = linked_attributes_ldb_init,
1251 .start_transaction = linked_attributes_start_transaction,
1252 .prepare_commit = linked_attributes_prepare_commit,
1253 .del_transaction = linked_attributes_del_transaction,
1256 int ldb_linked_attributes_module_init(const char *version)
1258 LDB_MODULE_CHECK_VERSION(version);
1259 return ldb_register_module(&ldb_linked_attributes_module_ops);