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
,
175 enum la_op op
, struct ldb_val
*dn
,
178 struct ldb_context
*ldb
;
179 struct la_op_store
*os
;
180 struct ldb_dn
*op_dn
;
183 ldb
= ldb_module_get_ctx(ac
->module
);
185 op_dn
= ldb_dn_from_ldb_val(ac
, ldb
, 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
);
199 ret
= la_guid_from_dn(ac
->module
, ac
->req
, op_dn
, &os
->guid
);
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
211 if (ret
!= LDB_SUCCESS
) {
215 os
->name
= talloc_strdup(os
, name
);
220 /* Do deletes before adds */
221 if (op
== LA_OP_ADD
) {
222 DLIST_ADD_END(ac
->ops
, os
, struct la_op_store
*);
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
);
232 static int la_queue_mod_request(struct la_context
*ac
);
233 static int la_down_req(struct la_context
*ac
);
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
;
246 struct ldb_control
*control
;
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
);
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 */
272 return ldb_next_request(module
, req
);
274 ctrl
->critical
= false;
277 /* without schema, this doesn't make any sense */
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
);
289 ldb_asprintf_errstring(ldb
,
290 "%s: attribute %s is not a valid attribute in schema",
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) {
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);
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
318 attr_name
= target_attr
->lDAPDisplayName
;
320 for (j
= 0; j
< el
->num_values
; j
++) {
321 ret
= la_store_op(ac
, LA_OP_ADD
,
324 if (ret
!= LDB_SUCCESS
) {
330 /* if no linked attributes are present continue */
331 if (ac
->ops
== NULL
) {
332 /* nothing to do for this module, proceed */
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
;
355 int ret
= LDB_SUCCESS
;
357 ac
= talloc_get_type(req
->context
, struct la_context
);
358 ldb
= ldb_module_get_ctx(ac
->module
);
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 */
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
);
391 ldb_asprintf_errstring(ldb
,
392 "%s: attribute %s is not a valid attribute in schema",
396 return ldb_module_done(ac
->req
, NULL
, NULL
,
397 LDB_ERR_OBJECT_CLASS_VIOLATION
);
400 search_el
= ldb_msg_find_element(ares
->message
,
403 /* See if this element already exists */
404 /* otherwise just ignore as
405 * the add has already been scheduled */
410 target_attr
= dsdb_attribute_by_linkID(ac
->schema
, schema_attr
->linkID
^ 1);
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
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
],
428 if (ret
!= LDB_SUCCESS
) {
430 return ldb_module_done(ac
->req
,
438 case LDB_REPLY_REFERRAL
:
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
,
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
);
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
;
480 struct la_context
*ac
;
481 struct ldb_request
*search_req
;
483 struct ldb_control
*ctrl
;
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
);
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 */
509 return ldb_next_request(module
, req
);
511 ctrl
->critical
= false;
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
);
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
);
531 ldb_asprintf_errstring(ldb
,
532 "%s: attribute %s is not a valid attribute in schema",
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) {
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);
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
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 */
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
,
575 if (ret
!= LDB_SUCCESS
) {
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
,
589 if (ret
!= LDB_SUCCESS
) {
594 /* Flag that there was a DELETE
595 * without a value specified, so we
596 * need to look for the old value */
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);
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);
627 for (i
= 0; ac
->rc
&& i
< ac
->rc
->num_elements
; i
++) {
628 attrs
[i
] = ac
->rc
->el
[i
].name
;
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
,
636 "(objectClass=*)", attrs
,
638 ac
, la_mod_search_callback
,
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
);
655 /* nothing to do for this module, proceed */
657 ret
= ldb_next_request(module
, req
);
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
)
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];
677 target
= dsdb_attribute_by_linkID(schema
, schema_attr
->linkID
^ 1);
678 if (target
== NULL
) {
679 /* there is no counterpart link to change */
683 attrs
[0] = target
->lDAPDisplayName
;
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
),
706 talloc_free(tmp_ctx
);
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
,
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
),
730 talloc_free(tmp_ctx
);
733 if (res
->count
== 0) {
734 /* Forward link without backlink object remaining - nothing to do here */
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
;
749 if (msg
->num_elements
== 0) {
750 /* Forward link without backlink remaining - nothing to do here */
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
);
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
)) {
798 ret
= ldb_dn_update_components(dsdb_dn2
->dn
, new_dn
);
799 if (ret
!= LDB_SUCCESS
) {
800 talloc_free(tmp_ctx
);
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
);
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
),
825 talloc_free(tmp_ctx
);
830 talloc_free(tmp_ctx
);
836 static int linked_attributes_rename(struct ldb_module
*module
, struct ldb_request
*req
)
838 struct ldb_result
*res
;
839 struct ldb_message
*msg
;
841 struct ldb_context
*ldb
= ldb_module_get_ctx(module
);
842 struct dsdb_schema
*schema
;
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
,
854 DSDB_FLAG_NEXT_MODULE
|
855 DSDB_SEARCH_SHOW_EXTENDED_DN
|
856 DSDB_SEARCH_SHOW_RECYCLED
, req
);
857 if (ret
!= LDB_SUCCESS
) {
861 schema
= dsdb_get_schema(ldb
, res
);
868 ret
= la_guid_from_dn(module
, req
, msg
->dn
, &guid
);
869 if (ret
!= LDB_SUCCESS
) {
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) {
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
) {
890 return ldb_next_request(module
, req
);
894 /* queue a linked attributes modify request in the la_private
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
;
920 ac
= talloc_get_type(req
->context
, struct la_context
);
921 ldb
= ldb_module_get_ctx(ac
->module
);
924 return ldb_module_done(ac
->req
, NULL
, NULL
,
925 LDB_ERR_OPERATIONS_ERROR
);
927 if (ares
->error
!= LDB_SUCCESS
) {
928 return ldb_module_done(ac
->req
, ares
->controls
,
929 ares
->response
, ares
->error
);
932 if (ares
->type
!= LDB_REPLY_DONE
) {
933 ldb_set_errstring(ldb
,
934 "invalid ldb_reply_type in callback");
936 return ldb_module_done(ac
->req
, NULL
, NULL
,
937 LDB_ERR_OPERATIONS_ERROR
);
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
);
951 /* la_queue_mod_request has already sent the callbacks */
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
;
966 ac
= talloc_get_type(req
->context
, struct la_context
);
967 ldb
= ldb_module_get_ctx(ac
->module
);
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");
982 return ldb_module_done(ac
->req
, NULL
, NULL
,
983 LDB_ERR_OPERATIONS_ERROR
);
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
,
995 "(objectClass=*)", attrs
,
997 ac
, la_mod_search_callback
,
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
,
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
);
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
;
1029 ldb
= ldb_module_get_ctx(ac
->module
);
1031 switch (ac
->req
->operation
) {
1033 ret
= ldb_build_add_req(&down_req
, ldb
, ac
,
1034 ac
->req
->op
.add
.message
,
1036 ac
, la_add_callback
,
1038 LDB_REQ_SET_LOCATION(down_req
);
1041 ret
= ldb_build_mod_req(&down_req
, ldb
, ac
,
1042 ac
->req
->op
.mod
.message
,
1044 ac
, la_mod_del_callback
,
1046 LDB_REQ_SET_LOCATION(down_req
);
1049 ret
= LDB_ERR_OPERATIONS_ERROR
;
1051 if (ret
!= LDB_SUCCESS
) {
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
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
;
1076 if (ac
->mod_dn
== NULL
) {
1077 /* we didn't find the DN that we searched for */
1081 ldb
= ldb_module_get_ctx(ac
->module
);
1083 /* Create the modify request */
1084 new_msg
= ldb_msg_new(ac
);
1086 return ldb_oom(ldb
);
1089 ret
= la_find_dn_target(module
, ac
, &op
->guid
, &new_msg
->dn
);
1090 if (ret
!= LDB_SUCCESS
) {
1094 if (op
->op
== LA_OP_ADD
) {
1095 ret
= ldb_msg_add_empty(new_msg
, op
->name
,
1096 LDB_FLAG_MOD_ADD
, &ret_el
);
1098 ret
= ldb_msg_add_empty(new_msg
, op
->name
,
1099 LDB_FLAG_MOD_DELETE
, &ret_el
);
1101 if (ret
!= LDB_SUCCESS
) {
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
;
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");
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",
1134 ldb_ldif_message_string(ldb
, op
, LDB_CHANGETYPE_MODIFY
, new_msg
));
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
) {
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
),
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
;
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
)) {
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
);
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
)
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
);