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
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 3 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program. If not, see <http://www.gnu.org/licenses/>.
25 * Component: ldb linked_attributes module
27 * Description: Module to ensure linked attribute pairs remain in sync
29 * Author: Andrew Bartlett
33 #include "ldb_module.h"
34 #include "util/dlinklist.h"
35 #include "dsdb/samdb/samdb.h"
36 #include "librpc/gen_ndr/ndr_misc.h"
37 #include "dsdb/samdb/ldb_modules/util.h"
40 struct la_context
*la_list
;
44 struct la_op_store
*next
;
45 struct la_op_store
*prev
;
46 enum la_op
{LA_OP_ADD
, LA_OP_DEL
} op
;
51 struct replace_context
{
52 struct la_context
*ac
;
53 unsigned int num_elements
;
54 struct ldb_message_element
*el
;
58 struct la_context
*next
, *prev
;
59 const struct dsdb_schema
*schema
;
60 struct ldb_module
*module
;
61 struct ldb_request
*req
;
62 struct ldb_dn
*mod_dn
;
63 struct replace_context
*rc
;
64 struct la_op_store
*ops
;
65 struct ldb_extended
*op_response
;
66 struct ldb_control
**op_controls
;
69 * will tell which GC to use for resolving links
75 static int handle_verify_name_control(TALLOC_CTX
*ctx
, struct ldb_context
*ldb
,
76 struct ldb_control
*control
, struct la_context
*ac
)
79 * If we are a GC let's remove the control,
80 * if there is a specified GC check that is us.
82 struct ldb_verify_name_control
*lvnc
= (struct ldb_verify_name_control
*)control
->data
;
83 if (samdb_is_gc(ldb
)) {
84 /* Because we can't easily talloc a struct ldb_dn*/
85 struct ldb_dn
**dn
= talloc_array(ctx
, struct ldb_dn
*, 1);
86 int ret
= samdb_server_reference_dn(ldb
, ctx
, dn
);
89 if (ret
!= LDB_SUCCESS
) {
90 return ldb_operr(ldb
);
93 dns
= samdb_dn_to_dnshostname(ldb
, ctx
, *dn
);
95 return ldb_operr(ldb
);
97 if (!lvnc
->gc
|| strcasecmp(dns
, lvnc
->gc
) == 0) {
98 if (!ldb_save_controls(control
, ctx
, NULL
)) {
99 return ldb_operr(ldb
);
102 control
->critical
= true;
106 /* For the moment we don't remove the control is this case in order
107 * to fail the request. It's better than having the client thinking
108 * that we honnor its control.
109 * Hopefully only a very small set of usecase should hit this problem.
112 ac
->gc_dns_name
= talloc_strdup(ac
, lvnc
->gc
);
114 control
->critical
= true;
120 static struct la_context
*linked_attributes_init(struct ldb_module
*module
,
121 struct ldb_request
*req
)
123 struct ldb_context
*ldb
;
124 struct la_context
*ac
;
126 ldb
= ldb_module_get_ctx(module
);
128 ac
= talloc_zero(req
, struct la_context
);
134 ac
->schema
= dsdb_get_schema(ldb
, ac
);
142 turn a DN into a GUID
144 static int la_guid_from_dn(struct la_context
*ac
, struct ldb_dn
*dn
, struct GUID
*guid
)
149 status
= dsdb_get_extended_dn_guid(dn
, guid
, "GUID");
150 if (NT_STATUS_IS_OK(status
)) {
153 if (!NT_STATUS_EQUAL(status
, NT_STATUS_OBJECT_NAME_NOT_FOUND
)) {
154 DEBUG(4,(__location__
": Unable to parse GUID for dn %s\n",
155 ldb_dn_get_linearized(dn
)));
156 return ldb_operr(ldb_module_get_ctx(ac
->module
));
159 ret
= dsdb_module_guid_by_dn(ac
->module
, dn
, guid
, ac
->req
);
160 if (ret
!= LDB_SUCCESS
) {
161 DEBUG(4,(__location__
": Failed to find GUID for dn %s\n",
162 ldb_dn_get_linearized(dn
)));
169 /* Common routine to handle reading the attributes and creating a
170 * series of modify requests */
171 static int la_store_op(struct la_context
*ac
,
172 enum la_op op
, struct ldb_val
*dn
,
175 struct ldb_context
*ldb
;
176 struct la_op_store
*os
;
177 struct ldb_dn
*op_dn
;
180 ldb
= ldb_module_get_ctx(ac
->module
);
182 op_dn
= ldb_dn_from_ldb_val(ac
, ldb
, dn
);
184 ldb_asprintf_errstring(ldb
,
185 "could not parse attribute as a DN");
186 return LDB_ERR_INVALID_DN_SYNTAX
;
189 os
= talloc_zero(ac
, struct la_op_store
);
196 ret
= la_guid_from_dn(ac
, op_dn
, &os
->guid
);
198 if (ret
== LDB_ERR_NO_SUCH_OBJECT
&& ac
->req
->operation
== LDB_DELETE
) {
199 /* we are deleting an object, and we've found it has a
200 * forward link to a target that no longer
201 * exists. This is not an error in the delete, and we
202 * should just not do the deferred delete of the
208 if (ret
!= LDB_SUCCESS
) {
212 os
->name
= talloc_strdup(os
, name
);
217 /* Do deletes before adds */
218 if (op
== LA_OP_ADD
) {
219 DLIST_ADD_END(ac
->ops
, os
, struct la_op_store
*);
221 /* By adding to the head of the list, we do deletes before
222 * adds when processing a replace */
223 DLIST_ADD(ac
->ops
, os
);
229 static int la_queue_mod_request(struct la_context
*ac
);
230 static int la_down_req(struct la_context
*ac
);
235 static int linked_attributes_add(struct ldb_module
*module
, struct ldb_request
*req
)
237 struct ldb_context
*ldb
;
238 const struct dsdb_attribute
*target_attr
;
239 struct la_context
*ac
;
240 const char *attr_name
;
241 struct ldb_control
*ctrl
;
243 struct ldb_control
*control
;
246 ldb
= ldb_module_get_ctx(module
);
248 if (ldb_dn_is_special(req
->op
.add
.message
->dn
)) {
249 /* do not manipulate our control entries */
250 return ldb_next_request(module
, req
);
253 ac
= linked_attributes_init(module
, req
);
255 return ldb_operr(ldb
);
258 control
= ldb_request_get_control(req
, LDB_CONTROL_VERIFY_NAME_OID
);
259 if (control
!= NULL
&& control
->data
!= NULL
) {
260 ret
= handle_verify_name_control(req
, ldb
, control
, ac
);
261 if (ret
!= LDB_SUCCESS
) {
262 return ldb_operr(ldb
);
266 if (!(ctrl
= ldb_request_get_control(req
, DSDB_CONTROL_APPLY_LINKS
))) {
267 /* don't do anything special for linked attributes, repl_meta_data has done it */
269 return ldb_next_request(module
, req
);
271 ctrl
->critical
= false;
274 /* without schema, this doesn't make any sense */
276 return ldb_next_request(module
, req
);
280 /* Need to ensure we only have forward links being specified */
281 for (i
=0; i
< req
->op
.add
.message
->num_elements
; i
++) {
282 const struct ldb_message_element
*el
= &req
->op
.add
.message
->elements
[i
];
283 const struct dsdb_attribute
*schema_attr
284 = dsdb_attribute_by_lDAPDisplayName(ac
->schema
, el
->name
);
286 ldb_asprintf_errstring(ldb
,
287 "%s: attribute %s is not a valid attribute in schema",
290 return LDB_ERR_OBJECT_CLASS_VIOLATION
;
293 /* this could be a link with no partner, in which case
294 there is no special work to do */
295 if (schema_attr
->linkID
== 0) {
299 /* this part of the code should only be handling forward links */
300 SMB_ASSERT((schema_attr
->linkID
& 1) == 0);
302 /* Even link IDs are for the originating attribute */
303 target_attr
= dsdb_attribute_by_linkID(ac
->schema
, schema_attr
->linkID
^ 1);
306 * windows 2003 has a broken schema where
307 * the definition of msDS-IsDomainFor
308 * is missing (which is supposed to be
309 * the backlink of the msDS-HasDomainNCs
315 attr_name
= target_attr
->lDAPDisplayName
;
317 for (j
= 0; j
< el
->num_values
; j
++) {
318 ret
= la_store_op(ac
, LA_OP_ADD
,
321 if (ret
!= LDB_SUCCESS
) {
327 /* if no linked attributes are present continue */
328 if (ac
->ops
== NULL
) {
329 /* nothing to do for this module, proceed */
331 return ldb_next_request(module
, req
);
334 /* start with the original request */
335 return la_down_req(ac
);
338 /* For a delete or rename, we need to find out what linked attributes
339 * are currently on this DN, and then deal with them. This is the
340 * callback to the base search */
342 static int la_mod_search_callback(struct ldb_request
*req
, struct ldb_reply
*ares
)
344 struct ldb_context
*ldb
;
345 const struct dsdb_attribute
*schema_attr
;
346 const struct dsdb_attribute
*target_attr
;
347 struct ldb_message_element
*search_el
;
348 struct replace_context
*rc
;
349 struct la_context
*ac
;
350 const char *attr_name
;
352 int ret
= LDB_SUCCESS
;
354 ac
= talloc_get_type(req
->context
, struct la_context
);
355 ldb
= ldb_module_get_ctx(ac
->module
);
359 return ldb_module_done(ac
->req
, NULL
, NULL
,
360 LDB_ERR_OPERATIONS_ERROR
);
362 if (ares
->error
!= LDB_SUCCESS
) {
363 return ldb_module_done(ac
->req
, ares
->controls
,
364 ares
->response
, ares
->error
);
367 /* Only entries are interesting, and we only want the olddn */
368 switch (ares
->type
) {
369 case LDB_REPLY_ENTRY
:
371 if (ldb_dn_compare(ares
->message
->dn
, ac
->req
->op
.mod
.message
->dn
) != 0) {
372 ldb_asprintf_errstring(ldb
,
373 "linked_attributes: %s is not the DN we were looking for",
374 ldb_dn_get_linearized(ares
->message
->dn
));
375 /* Guh? We only asked for this DN */
377 return ldb_module_done(ac
->req
, NULL
, NULL
,
378 LDB_ERR_OPERATIONS_ERROR
);
381 ac
->mod_dn
= talloc_steal(ac
, ares
->message
->dn
);
383 /* We don't populate 'rc' for ADD - it can't be deleting elements anyway */
384 for (i
= 0; rc
&& i
< rc
->num_elements
; i
++) {
386 schema_attr
= dsdb_attribute_by_lDAPDisplayName(ac
->schema
, rc
->el
[i
].name
);
388 ldb_asprintf_errstring(ldb
,
389 "%s: attribute %s is not a valid attribute in schema",
393 return ldb_module_done(ac
->req
, NULL
, NULL
,
394 LDB_ERR_OBJECT_CLASS_VIOLATION
);
397 search_el
= ldb_msg_find_element(ares
->message
,
400 /* See if this element already exists */
401 /* otherwise just ignore as
402 * the add has already been scheduled */
407 target_attr
= dsdb_attribute_by_linkID(ac
->schema
, schema_attr
->linkID
^ 1);
410 * windows 2003 has a broken schema where
411 * the definition of msDS-IsDomainFor
412 * is missing (which is supposed to be
413 * the backlink of the msDS-HasDomainNCs
418 attr_name
= target_attr
->lDAPDisplayName
;
420 /* Now we know what was there, we can remove it for the re-add */
421 for (j
= 0; j
< search_el
->num_values
; j
++) {
422 ret
= la_store_op(ac
, LA_OP_DEL
,
423 &search_el
->values
[j
],
425 if (ret
!= LDB_SUCCESS
) {
427 return ldb_module_done(ac
->req
,
435 case LDB_REPLY_REFERRAL
:
443 if (ac
->req
->operation
== LDB_ADD
) {
444 /* Start the modifies to the backlinks */
445 ret
= la_queue_mod_request(ac
);
447 if (ret
!= LDB_SUCCESS
) {
448 return ldb_module_done(ac
->req
, NULL
, NULL
,
452 /* Start with the original request */
453 ret
= la_down_req(ac
);
454 if (ret
!= LDB_SUCCESS
) {
455 return ldb_module_done(ac
->req
, NULL
, NULL
, ret
);
467 static int linked_attributes_modify(struct ldb_module
*module
, struct ldb_request
*req
)
469 /* Look over list of modifications */
470 /* Find if any are for linked attributes */
471 /* Determine the effect of the modification */
472 /* Apply the modify to the linked entry */
474 struct ldb_control
*control
;
475 struct ldb_context
*ldb
;
477 struct la_context
*ac
;
478 struct ldb_request
*search_req
;
480 struct ldb_control
*ctrl
;
483 ldb
= ldb_module_get_ctx(module
);
485 if (ldb_dn_is_special(req
->op
.mod
.message
->dn
)) {
486 /* do not manipulate our control entries */
487 return ldb_next_request(module
, req
);
490 ac
= linked_attributes_init(module
, req
);
492 return ldb_operr(ldb
);
495 control
= ldb_request_get_control(req
, LDB_CONTROL_VERIFY_NAME_OID
);
496 if (control
!= NULL
&& control
->data
!= NULL
) {
497 ret
= handle_verify_name_control(req
, ldb
, control
, ac
);
498 if (ret
!= LDB_SUCCESS
) {
499 return ldb_operr(ldb
);
503 if (!(ctrl
= ldb_request_get_control(req
, DSDB_CONTROL_APPLY_LINKS
))) {
504 /* don't do anything special for linked attributes, repl_meta_data has done it */
506 return ldb_next_request(module
, req
);
508 ctrl
->critical
= false;
511 /* without schema, this doesn't make any sense */
512 return ldb_next_request(module
, req
);
515 ac
->rc
= talloc_zero(ac
, struct replace_context
);
520 for (i
=0; i
< req
->op
.mod
.message
->num_elements
; i
++) {
521 bool store_el
= false;
522 const char *attr_name
;
523 const struct dsdb_attribute
*target_attr
;
524 const struct ldb_message_element
*el
= &req
->op
.mod
.message
->elements
[i
];
525 const struct dsdb_attribute
*schema_attr
526 = dsdb_attribute_by_lDAPDisplayName(ac
->schema
, el
->name
);
528 ldb_asprintf_errstring(ldb
,
529 "%s: attribute %s is not a valid attribute in schema",
532 return LDB_ERR_OBJECT_CLASS_VIOLATION
;
534 /* We have a valid attribute, now find out if it is a forward link
535 (Even link IDs are for the originating attribute) */
536 if (schema_attr
->linkID
== 0) {
540 /* this part of the code should only be handling forward links */
541 SMB_ASSERT((schema_attr
->linkID
& 1) == 0);
543 /* Now find the target attribute */
544 target_attr
= dsdb_attribute_by_linkID(ac
->schema
, schema_attr
->linkID
^ 1);
547 * windows 2003 has a broken schema where
548 * the definition of msDS-IsDomainFor
549 * is missing (which is supposed to be
550 * the backlink of the msDS-HasDomainNCs
556 attr_name
= target_attr
->lDAPDisplayName
;
558 switch (el
->flags
& LDB_FLAG_MOD_MASK
) {
559 case LDB_FLAG_MOD_REPLACE
:
560 /* treat as just a normal add the delete part is handled by the callback */
563 /* break intentionally missing */
565 case LDB_FLAG_MOD_ADD
:
567 /* For each value being added, we need to setup the adds */
568 for (j
= 0; j
< el
->num_values
; j
++) {
569 ret
= la_store_op(ac
, LA_OP_ADD
,
572 if (ret
!= LDB_SUCCESS
) {
578 case LDB_FLAG_MOD_DELETE
:
580 if (el
->num_values
) {
581 /* For each value being deleted, we need to setup the delete */
582 for (j
= 0; j
< el
->num_values
; j
++) {
583 ret
= la_store_op(ac
, LA_OP_DEL
,
586 if (ret
!= LDB_SUCCESS
) {
591 /* Flag that there was a DELETE
592 * without a value specified, so we
593 * need to look for the old value */
601 struct ldb_message_element
*search_el
;
603 search_el
= talloc_realloc(ac
->rc
, ac
->rc
->el
,
604 struct ldb_message_element
,
605 ac
->rc
->num_elements
+1);
609 ac
->rc
->el
= search_el
;
611 ac
->rc
->el
[ac
->rc
->num_elements
] = *el
;
612 ac
->rc
->num_elements
++;
616 if (ac
->ops
|| ac
->rc
->el
) {
617 /* both replace and delete without values are handled in the callback
618 * after the search on the entry to be modified is performed */
620 attrs
= talloc_array(ac
->rc
, const char *, ac
->rc
->num_elements
+ 1);
624 for (i
= 0; ac
->rc
&& i
< ac
->rc
->num_elements
; i
++) {
625 attrs
[i
] = ac
->rc
->el
[i
].name
;
629 /* The callback does all the hard work here */
630 ret
= ldb_build_search_req(&search_req
, ldb
, ac
,
631 req
->op
.mod
.message
->dn
,
633 "(objectClass=*)", attrs
,
635 ac
, la_mod_search_callback
,
637 LDB_REQ_SET_LOCATION(search_req
);
639 /* We need to figure out our own extended DN, to fill in as the backlink target */
640 if (ret
== LDB_SUCCESS
) {
641 ret
= dsdb_request_add_controls(search_req
,
642 DSDB_SEARCH_SHOW_DELETED
|
643 DSDB_SEARCH_SHOW_EXTENDED_DN
);
645 if (ret
== LDB_SUCCESS
) {
646 talloc_steal(search_req
, attrs
);
648 ret
= ldb_next_request(module
, search_req
);
652 /* nothing to do for this module, proceed */
654 ret
= ldb_next_request(module
, req
);
660 static int linked_attributes_fix_links(struct ldb_module
*module
,
661 struct ldb_dn
*old_dn
, struct ldb_dn
*new_dn
,
662 struct ldb_message_element
*el
, struct dsdb_schema
*schema
,
663 const struct dsdb_attribute
*schema_attr
,
664 struct ldb_request
*parent
)
667 TALLOC_CTX
*tmp_ctx
= talloc_new(module
);
668 struct ldb_context
*ldb
= ldb_module_get_ctx(module
);
669 const struct dsdb_attribute
*target
;
670 const char *attrs
[2];
673 target
= dsdb_attribute_by_linkID(schema
, schema_attr
->linkID
^ 1);
674 if (target
== NULL
) {
675 /* there is no counterpart link to change */
679 attrs
[0] = target
->lDAPDisplayName
;
682 for (i
=0; i
<el
->num_values
; i
++) {
683 struct dsdb_dn
*dsdb_dn
;
684 struct ldb_result
*res
;
685 struct ldb_message
*msg
;
686 struct ldb_message_element
*el2
;
688 dsdb_dn
= dsdb_dn_parse(tmp_ctx
, ldb
, &el
->values
[i
], schema_attr
->syntax
->ldap_oid
);
689 if (dsdb_dn
== NULL
) {
690 talloc_free(tmp_ctx
);
691 return LDB_ERR_INVALID_DN_SYNTAX
;
694 ret
= dsdb_module_search_dn(module
, tmp_ctx
, &res
, dsdb_dn
->dn
,
696 DSDB_FLAG_NEXT_MODULE
|
697 DSDB_SEARCH_SHOW_RECYCLED
|
698 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT
|
699 DSDB_SEARCH_REVEAL_INTERNALS
, parent
);
700 if (ret
!= LDB_SUCCESS
) {
701 ldb_asprintf_errstring(ldb
, "Linked attribute %s->%s between %s and %s - remote 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 if (msg
->num_elements
== 0) {
712 /* Forward link without backlink remaining - nothing to do here */
714 } else if (msg
->num_elements
!= 1) {
715 ldb_asprintf_errstring(ldb
, "Bad msg elements - got %u elements, expected one element to be returned in linked_attributes_fix_links for %s",
716 msg
->num_elements
, ldb_dn_get_linearized(msg
->dn
));
717 talloc_free(tmp_ctx
);
718 return LDB_ERR_OPERATIONS_ERROR
;
720 if (ldb_attr_cmp(msg
->elements
[0].name
, target
->lDAPDisplayName
) != 0) {
721 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
));
722 talloc_free(tmp_ctx
);
723 return LDB_ERR_OPERATIONS_ERROR
;
725 el2
= &msg
->elements
[0];
727 el2
->flags
= LDB_FLAG_MOD_REPLACE
;
729 /* find our DN in the values */
730 for (j
=0; j
<el2
->num_values
; j
++) {
731 struct dsdb_dn
*dsdb_dn2
;
732 dsdb_dn2
= dsdb_dn_parse(msg
, ldb
, &el2
->values
[j
], target
->syntax
->ldap_oid
);
733 if (dsdb_dn2
== NULL
) {
734 talloc_free(tmp_ctx
);
735 return LDB_ERR_INVALID_DN_SYNTAX
;
737 if (ldb_dn_compare(old_dn
, dsdb_dn2
->dn
) != 0) {
740 ret
= ldb_dn_update_components(dsdb_dn2
->dn
, new_dn
);
741 if (ret
!= LDB_SUCCESS
) {
742 talloc_free(tmp_ctx
);
746 el2
->values
[j
] = data_blob_string_const(
747 dsdb_dn_get_extended_linearized(el2
->values
, dsdb_dn2
, 1));
750 ret
= dsdb_check_single_valued_link(target
, el2
);
751 if (ret
!= LDB_SUCCESS
) {
752 talloc_free(tmp_ctx
);
756 /* we may be putting multiple values in an attribute -
757 disable checking for this attribute */
758 el2
->flags
|= LDB_FLAG_INTERNAL_DISABLE_SINGLE_VALUE_CHECK
;
760 ret
= dsdb_module_modify(module
, msg
, DSDB_FLAG_NEXT_MODULE
, parent
);
761 if (ret
!= LDB_SUCCESS
) {
762 ldb_asprintf_errstring(ldb
, "Linked attribute %s->%s between %s and %s - update failed - %s",
763 el
->name
, target
->lDAPDisplayName
,
764 ldb_dn_get_linearized(old_dn
),
765 ldb_dn_get_linearized(dsdb_dn
->dn
),
767 talloc_free(tmp_ctx
);
772 talloc_free(tmp_ctx
);
778 static int linked_attributes_rename(struct ldb_module
*module
, struct ldb_request
*req
)
780 struct ldb_result
*res
;
781 struct ldb_message
*msg
;
783 struct ldb_context
*ldb
= ldb_module_get_ctx(module
);
784 struct dsdb_schema
*schema
;
787 - load the current msg
788 - find any linked attributes
789 - if its a link then find the target object
790 - modify the target linked attributes with the new DN
792 ret
= dsdb_module_search_dn(module
, req
, &res
, req
->op
.rename
.olddn
,
794 DSDB_FLAG_NEXT_MODULE
|
795 DSDB_SEARCH_SHOW_RECYCLED
, req
);
796 if (ret
!= LDB_SUCCESS
) {
800 schema
= dsdb_get_schema(ldb
, res
);
807 for (i
=0; i
<msg
->num_elements
; i
++) {
808 struct ldb_message_element
*el
= &msg
->elements
[i
];
809 const struct dsdb_attribute
*schema_attr
810 = dsdb_attribute_by_lDAPDisplayName(schema
, el
->name
);
811 if (!schema_attr
|| schema_attr
->linkID
== 0) {
814 ret
= linked_attributes_fix_links(module
, msg
->dn
, req
->op
.rename
.newdn
, el
,
815 schema
, schema_attr
, req
);
816 if (ret
!= LDB_SUCCESS
) {
824 return ldb_next_request(module
, req
);
828 /* queue a linked attributes modify request in the la_private
830 static int la_queue_mod_request(struct la_context
*ac
)
832 struct la_private
*la_private
=
833 talloc_get_type(ldb_module_get_private(ac
->module
), struct la_private
);
835 if (la_private
== NULL
) {
836 ldb_debug(ldb_module_get_ctx(ac
->module
), LDB_DEBUG_ERROR
, __location__
": No la_private transaction setup\n");
837 return ldb_operr(ldb_module_get_ctx(ac
->module
));
840 talloc_steal(la_private
, ac
);
841 DLIST_ADD(la_private
->la_list
, ac
);
843 return ldb_module_done(ac
->req
, ac
->op_controls
,
844 ac
->op_response
, LDB_SUCCESS
);
847 /* Having done the original operation, then try to fix up all the linked attributes for modify and delete */
848 static int la_mod_del_callback(struct ldb_request
*req
, struct ldb_reply
*ares
)
850 struct la_context
*ac
;
851 struct ldb_context
*ldb
;
854 ac
= talloc_get_type(req
->context
, struct la_context
);
855 ldb
= ldb_module_get_ctx(ac
->module
);
858 return ldb_module_done(ac
->req
, NULL
, NULL
,
859 LDB_ERR_OPERATIONS_ERROR
);
861 if (ares
->error
!= LDB_SUCCESS
) {
862 return ldb_module_done(ac
->req
, ares
->controls
,
863 ares
->response
, ares
->error
);
866 if (ares
->type
!= LDB_REPLY_DONE
) {
867 ldb_set_errstring(ldb
,
868 "invalid ldb_reply_type in callback");
870 return ldb_module_done(ac
->req
, NULL
, NULL
,
871 LDB_ERR_OPERATIONS_ERROR
);
874 ac
->op_controls
= talloc_steal(ac
, ares
->controls
);
875 ac
->op_response
= talloc_steal(ac
, ares
->response
);
877 /* If we have modfies to make, this is the time to do them for modify and delete */
878 ret
= la_queue_mod_request(ac
);
880 if (ret
!= LDB_SUCCESS
) {
881 return ldb_module_done(ac
->req
, NULL
, NULL
, ret
);
885 /* la_queue_mod_request has already sent the callbacks */
890 /* Having done the original add, then try to fix up all the linked attributes
892 This is done after the add so the links can get the extended DNs correctly.
894 static int la_add_callback(struct ldb_request
*req
, struct ldb_reply
*ares
)
896 struct la_context
*ac
;
897 struct ldb_context
*ldb
;
900 ac
= talloc_get_type(req
->context
, struct la_context
);
901 ldb
= ldb_module_get_ctx(ac
->module
);
904 return ldb_module_done(ac
->req
, NULL
, NULL
,
905 LDB_ERR_OPERATIONS_ERROR
);
907 if (ares
->error
!= LDB_SUCCESS
) {
908 return ldb_module_done(ac
->req
, ares
->controls
,
909 ares
->response
, ares
->error
);
912 if (ares
->type
!= LDB_REPLY_DONE
) {
913 ldb_set_errstring(ldb
,
914 "invalid ldb_reply_type in callback");
916 return ldb_module_done(ac
->req
, NULL
, NULL
,
917 LDB_ERR_OPERATIONS_ERROR
);
921 struct ldb_request
*search_req
;
922 static const char *attrs
[] = { NULL
};
924 /* The callback does all the hard work here - we need
925 * the objectGUID and SID of the added record */
926 ret
= ldb_build_search_req(&search_req
, ldb
, ac
,
927 ac
->req
->op
.add
.message
->dn
,
929 "(objectClass=*)", attrs
,
931 ac
, la_mod_search_callback
,
933 LDB_REQ_SET_LOCATION(search_req
);
935 if (ret
== LDB_SUCCESS
) {
936 ret
= dsdb_request_add_controls(search_req
,
937 DSDB_SEARCH_SHOW_DELETED
|
938 DSDB_SEARCH_SHOW_EXTENDED_DN
);
940 if (ret
!= LDB_SUCCESS
) {
941 return ldb_module_done(ac
->req
, NULL
, NULL
,
945 ac
->op_controls
= talloc_steal(ac
, ares
->controls
);
946 ac
->op_response
= talloc_steal(ac
, ares
->response
);
948 return ldb_next_request(ac
->module
, search_req
);
951 return ldb_module_done(ac
->req
, ares
->controls
,
952 ares
->response
, ares
->error
);
956 /* Reconstruct the original request, but pointing at our local callback to finish things off */
957 static int la_down_req(struct la_context
*ac
)
959 struct ldb_request
*down_req
;
960 struct ldb_context
*ldb
;
963 ldb
= ldb_module_get_ctx(ac
->module
);
965 switch (ac
->req
->operation
) {
967 ret
= ldb_build_add_req(&down_req
, ldb
, ac
,
968 ac
->req
->op
.add
.message
,
972 LDB_REQ_SET_LOCATION(down_req
);
975 ret
= ldb_build_mod_req(&down_req
, ldb
, ac
,
976 ac
->req
->op
.mod
.message
,
978 ac
, la_mod_del_callback
,
980 LDB_REQ_SET_LOCATION(down_req
);
983 ret
= LDB_ERR_OPERATIONS_ERROR
;
985 if (ret
!= LDB_SUCCESS
) {
989 return ldb_next_request(ac
->module
, down_req
);
993 use the GUID part of an extended DN to find the target DN, in case
996 static int la_find_dn_target(struct ldb_module
*module
, struct la_context
*ac
,
997 struct GUID
*guid
, struct ldb_dn
**dn
)
999 return dsdb_module_dn_by_guid(ac
->module
, ac
, guid
, dn
, ac
->req
);
1002 /* apply one la_context op change */
1003 static int la_do_op_request(struct ldb_module
*module
, struct la_context
*ac
, struct la_op_store
*op
)
1005 struct ldb_message_element
*ret_el
;
1006 struct ldb_message
*new_msg
;
1007 struct ldb_context
*ldb
;
1010 if (ac
->mod_dn
== NULL
) {
1011 /* we didn't find the DN that we searched for */
1015 ldb
= ldb_module_get_ctx(ac
->module
);
1017 /* Create the modify request */
1018 new_msg
= ldb_msg_new(ac
);
1020 return ldb_oom(ldb
);
1023 ret
= la_find_dn_target(module
, ac
, &op
->guid
, &new_msg
->dn
);
1024 if (ret
!= LDB_SUCCESS
) {
1028 if (op
->op
== LA_OP_ADD
) {
1029 ret
= ldb_msg_add_empty(new_msg
, op
->name
,
1030 LDB_FLAG_MOD_ADD
, &ret_el
);
1032 ret
= ldb_msg_add_empty(new_msg
, op
->name
,
1033 LDB_FLAG_MOD_DELETE
, &ret_el
);
1035 if (ret
!= LDB_SUCCESS
) {
1038 ret_el
->values
= talloc_array(new_msg
, struct ldb_val
, 1);
1039 if (!ret_el
->values
) {
1040 return ldb_oom(ldb
);
1042 ret_el
->num_values
= 1;
1043 ret_el
->values
[0] = data_blob_string_const(ldb_dn_get_extended_linearized(new_msg
, ac
->mod_dn
, 1));
1045 /* a backlink should never be single valued. Unfortunately the
1046 exchange schema has a attribute
1047 msExchBridgeheadedLocalConnectorsDNBL which is single
1048 valued and a backlink. We need to cope with that by
1049 ignoring the single value flag */
1050 ret_el
->flags
|= LDB_FLAG_INTERNAL_DISABLE_SINGLE_VALUE_CHECK
;
1053 ldb_debug(ldb
, LDB_DEBUG_WARNING
,
1054 "link on %s %s: %s %s\n",
1055 ldb_dn_get_linearized(new_msg
->dn
), ret_el
->name
,
1056 ret_el
->values
[0].data
, ac
->ops
->op
== LA_OP_ADD
? "added" : "deleted");
1060 DEBUG(4,("Applying linked attribute change:\n%s\n",
1061 ldb_ldif_message_string(ldb
, op
, LDB_CHANGETYPE_MODIFY
, new_msg
)));
1064 ret
= dsdb_module_modify(module
, new_msg
, DSDB_FLAG_NEXT_MODULE
, ac
->req
);
1065 if (ret
!= LDB_SUCCESS
) {
1066 ldb_debug(ldb
, LDB_DEBUG_WARNING
, __location__
": failed to apply linked attribute change '%s'\n%s\n",
1068 ldb_ldif_message_string(ldb
, op
, LDB_CHANGETYPE_MODIFY
, new_msg
));
1074 /* apply one set of la_context changes */
1075 static int la_do_mod_request(struct ldb_module
*module
, struct la_context
*ac
)
1077 struct la_op_store
*op
;
1079 for (op
= ac
->ops
; op
; op
=op
->next
) {
1080 int ret
= la_do_op_request(module
, ac
, op
);
1081 if (ret
!= LDB_SUCCESS
) {
1082 if (ret
!= LDB_ERR_NO_SUCH_OBJECT
) {
1093 we hook into the transaction operations to allow us to
1094 perform the linked attribute updates at the end of the whole
1095 transaction. This allows a forward linked attribute to be created
1096 before the target is created, as long as the target is created
1097 in the same transaction
1099 static int linked_attributes_start_transaction(struct ldb_module
*module
)
1101 /* create our private structure for this transaction */
1102 struct la_private
*la_private
= talloc_get_type(ldb_module_get_private(module
),
1104 talloc_free(la_private
);
1105 la_private
= talloc(module
, struct la_private
);
1106 if (la_private
== NULL
) {
1107 return ldb_oom(ldb_module_get_ctx(module
));
1109 la_private
->la_list
= NULL
;
1110 ldb_module_set_private(module
, la_private
);
1111 return ldb_next_start_trans(module
);
1115 on prepare commit we loop over our queued la_context structures
1116 and apply each of them
1118 static int linked_attributes_prepare_commit(struct ldb_module
*module
)
1120 struct la_private
*la_private
=
1121 talloc_get_type(ldb_module_get_private(module
), struct la_private
);
1122 struct la_context
*ac
;
1125 /* prepare commit without begin_transaction - let someone else return the error, just don't segfault */
1126 return ldb_next_prepare_commit(module
);
1128 /* walk the list backwards, to do the first entry first, as we
1129 * added the entries with DLIST_ADD() which puts them at the
1130 * start of the list */
1132 /* Start at the end of the list - so we can start
1133 * there, but ensure we don't create a loop by NULLing
1134 * it out in the first element */
1135 ac
= DLIST_TAIL(la_private
->la_list
);
1137 for (; ac
; ac
=DLIST_PREV(ac
)) {
1140 ret
= la_do_mod_request(module
, ac
);
1141 if (ret
!= LDB_SUCCESS
) {
1142 DEBUG(0,(__location__
": Failed mod request ret=%d\n", ret
));
1143 talloc_free(la_private
);
1144 ldb_module_set_private(module
, NULL
);
1149 talloc_free(la_private
);
1150 ldb_module_set_private(module
, NULL
);
1152 return ldb_next_prepare_commit(module
);
1155 static int linked_attributes_del_transaction(struct ldb_module
*module
)
1157 struct la_private
*la_private
=
1158 talloc_get_type(ldb_module_get_private(module
), struct la_private
);
1159 talloc_free(la_private
);
1160 ldb_module_set_private(module
, NULL
);
1161 return ldb_next_del_trans(module
);
1164 static int linked_attributes_ldb_init(struct ldb_module
*module
)
1168 ret
= ldb_mod_register_control(module
, LDB_CONTROL_VERIFY_NAME_OID
);
1169 if (ret
!= LDB_SUCCESS
) {
1170 ldb_debug(ldb_module_get_ctx(module
), LDB_DEBUG_ERROR
,
1171 "verify_name: Unable to register control with rootdse!\n");
1172 return ldb_operr(ldb_module_get_ctx(module
));
1175 return ldb_next_init(module
);
1179 static const struct ldb_module_ops ldb_linked_attributes_module_ops
= {
1180 .name
= "linked_attributes",
1181 .add
= linked_attributes_add
,
1182 .modify
= linked_attributes_modify
,
1183 .rename
= linked_attributes_rename
,
1184 .init_context
= linked_attributes_ldb_init
,
1185 .start_transaction
= linked_attributes_start_transaction
,
1186 .prepare_commit
= linked_attributes_prepare_commit
,
1187 .del_transaction
= linked_attributes_del_transaction
,
1190 int ldb_linked_attributes_module_init(const char *version
)
1192 LDB_MODULE_CHECK_VERSION(version
);
1193 return ldb_register_module(&ldb_linked_attributes_module_ops
);