4 Copyright (C) Andrew Bartlett <abartlet@samba.org> 2007
5 Copyright (C) Simo Sorce <idra@samba.org> 2008
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program. If not, see <http://www.gnu.org/licenses/>.
24 * Component: ldb linked_attributes module
26 * Description: Module to ensure linked attribute pairs remain in sync
28 * Author: Andrew Bartlett
32 #include "ldb_module.h"
33 #include "dlinklist.h"
34 #include "dsdb/samdb/samdb.h"
37 struct la_op_store
*next
;
38 struct la_op_store
*prev
;
39 enum la_op
{LA_OP_ADD
, LA_OP_DEL
} op
;
45 struct replace_context
{
46 struct la_context
*ac
;
47 unsigned int num_elements
;
48 struct ldb_message_element
*el
;
52 const struct dsdb_schema
*schema
;
53 struct ldb_module
*module
;
54 struct ldb_request
*req
;
55 struct ldb_dn
*add_dn
;
56 struct ldb_dn
*del_dn
;
57 struct replace_context
*rc
;
58 struct la_op_store
*ops
;
59 struct ldb_extended
*op_response
;
60 struct ldb_control
**op_controls
;
63 static struct la_context
*linked_attributes_init(struct ldb_module
*module
,
64 struct ldb_request
*req
)
66 struct ldb_context
*ldb
;
67 struct la_context
*ac
;
69 ldb
= ldb_module_get_ctx(module
);
71 ac
= talloc_zero(req
, struct la_context
);
77 ac
->schema
= dsdb_get_schema(ldb
);
84 /* Common routine to handle reading the attributes and creating a
85 * series of modify requests */
86 static int la_store_op(struct la_context
*ac
,
87 enum la_op op
, struct ldb_val
*dn
,
90 struct ldb_context
*ldb
;
91 struct la_op_store
*os
;
94 ldb
= ldb_module_get_ctx(ac
->module
);
96 op_dn
= ldb_dn_from_ldb_val(ac
, ldb
, dn
);
98 ldb_asprintf_errstring(ldb
,
99 "could not parse attribute as a DN");
100 return LDB_ERR_INVALID_DN_SYNTAX
;
103 os
= talloc_zero(ac
, struct la_op_store
);
106 return LDB_ERR_OPERATIONS_ERROR
;
111 os
->dn
= talloc_steal(os
, op_dn
);
113 os
->name
= talloc_strdup(os
, name
);
116 return LDB_ERR_OPERATIONS_ERROR
;
119 /* Do deletes before adds */
120 if (op
== LA_OP_ADD
) {
121 DLIST_ADD_END(ac
->ops
, os
, struct la_op_store
*);
123 /* By adding to the head of the list, we do deletes before
124 * adds when processing a replace */
125 DLIST_ADD(ac
->ops
, os
);
131 static int la_op_search_callback(struct ldb_request
*req
,
132 struct ldb_reply
*ares
);
133 static int la_do_mod_request(struct la_context
*ac
);
134 static int la_mod_callback(struct ldb_request
*req
,
135 struct ldb_reply
*ares
);
136 static int la_down_req(struct la_context
*ac
);
141 static int linked_attributes_add(struct ldb_module
*module
, struct ldb_request
*req
)
143 struct ldb_context
*ldb
;
144 const struct dsdb_attribute
*target_attr
;
145 struct la_context
*ac
;
146 const char *attr_name
;
150 ldb
= ldb_module_get_ctx(module
);
152 if (ldb_dn_is_special(req
->op
.add
.message
->dn
)) {
153 /* do not manipulate our control entries */
154 return ldb_next_request(module
, req
);
157 ac
= linked_attributes_init(module
, req
);
159 return LDB_ERR_OPERATIONS_ERROR
;
163 /* without schema, this doesn't make any sense */
165 return ldb_next_request(module
, req
);
168 /* Need to ensure we only have forward links being specified */
169 for (i
=0; i
< req
->op
.add
.message
->num_elements
; i
++) {
170 const struct ldb_message_element
*el
= &req
->op
.add
.message
->elements
[i
];
171 const struct dsdb_attribute
*schema_attr
172 = dsdb_attribute_by_lDAPDisplayName(ac
->schema
, el
->name
);
174 ldb_asprintf_errstring(ldb
,
175 "attribute %s is not a valid attribute in schema", el
->name
);
176 return LDB_ERR_OBJECT_CLASS_VIOLATION
;
178 /* We have a valid attribute, now find out if it is linked */
179 if (schema_attr
->linkID
== 0) {
183 if ((schema_attr
->linkID
& 1) == 1) {
184 /* Odd is for the target. Illigal to modify */
185 ldb_asprintf_errstring(ldb
,
186 "attribute %s must not be modified directly, it is a linked attribute", el
->name
);
187 return LDB_ERR_UNWILLING_TO_PERFORM
;
190 /* Even link IDs are for the originating attribute */
191 target_attr
= dsdb_attribute_by_linkID(ac
->schema
, schema_attr
->linkID
+ 1);
194 * windows 2003 has a broken schema where
195 * the definition of msDS-IsDomainFor
196 * is missing (which is supposed to be
197 * the backlink of the msDS-HasDomainNCs
203 attr_name
= target_attr
->lDAPDisplayName
;
205 for (j
= 0; j
< el
->num_values
; j
++) {
206 ret
= la_store_op(ac
, LA_OP_ADD
,
209 if (ret
!= LDB_SUCCESS
) {
215 /* if no linked attributes are present continue */
216 if (ac
->ops
== NULL
) {
217 /* nothing to do for this module, proceed */
219 return ldb_next_request(module
, req
);
222 /* start with the original request */
223 return la_down_req(ac
);
226 /* For a delete or rename, we need to find out what linked attributes
227 * are currently on this DN, and then deal with them. This is the
228 * callback to the base search */
230 static int la_mod_search_callback(struct ldb_request
*req
, struct ldb_reply
*ares
)
232 struct ldb_context
*ldb
;
233 const struct dsdb_attribute
*schema_attr
;
234 const struct dsdb_attribute
*target_attr
;
235 struct ldb_message_element
*search_el
;
236 struct replace_context
*rc
;
237 struct la_context
*ac
;
238 const char *attr_name
;
240 int ret
= LDB_SUCCESS
;
242 ac
= talloc_get_type(req
->context
, struct la_context
);
243 ldb
= ldb_module_get_ctx(ac
->module
);
247 return ldb_module_done(ac
->req
, NULL
, NULL
,
248 LDB_ERR_OPERATIONS_ERROR
);
250 if (ares
->error
!= LDB_SUCCESS
) {
251 return ldb_module_done(ac
->req
, ares
->controls
,
252 ares
->response
, ares
->error
);
255 /* Only entries are interesting, and we only want the olddn */
256 switch (ares
->type
) {
257 case LDB_REPLY_ENTRY
:
259 if (ldb_dn_compare(ares
->message
->dn
, ac
->req
->op
.mod
.message
->dn
) != 0) {
260 ldb_asprintf_errstring(ldb
,
261 "linked_attributes: %s is not the DN we were looking for", ldb_dn_get_linearized(ares
->message
->dn
));
262 /* Guh? We only asked for this DN */
264 return ldb_module_done(ac
->req
, NULL
, NULL
,
265 LDB_ERR_OPERATIONS_ERROR
);
268 ac
->add_dn
= ac
->del_dn
= talloc_steal(ac
, ares
->message
->dn
);
270 /* We don't populate 'rc' for ADD - it can't be deleting elements anyway */
271 for (i
= 0; rc
&& i
< rc
->num_elements
; i
++) {
273 schema_attr
= dsdb_attribute_by_lDAPDisplayName(ac
->schema
, rc
->el
[i
].name
);
275 ldb_asprintf_errstring(ldb
,
276 "attribute %s is not a valid attribute in schema",
279 return ldb_module_done(ac
->req
, NULL
, NULL
,
280 LDB_ERR_OBJECT_CLASS_VIOLATION
);
283 search_el
= ldb_msg_find_element(ares
->message
,
286 /* See if this element already exists */
287 /* otherwise just ignore as
288 * the add has already been scheduled */
293 target_attr
= dsdb_attribute_by_linkID(ac
->schema
, schema_attr
->linkID
+ 1);
296 * windows 2003 has a broken schema where
297 * the definition of msDS-IsDomainFor
298 * is missing (which is supposed to be
299 * the backlink of the msDS-HasDomainNCs
304 attr_name
= target_attr
->lDAPDisplayName
;
306 /* Now we know what was there, we can remove it for the re-add */
307 for (j
= 0; j
< search_el
->num_values
; j
++) {
308 ret
= la_store_op(ac
, LA_OP_DEL
,
309 &search_el
->values
[j
],
311 if (ret
!= LDB_SUCCESS
) {
313 return ldb_module_done(ac
->req
,
321 case LDB_REPLY_REFERRAL
:
329 if (ac
->req
->operation
== LDB_ADD
) {
330 /* Start the modifies to the backlinks */
331 ret
= la_do_mod_request(ac
);
333 if (ret
!= LDB_SUCCESS
) {
334 return ldb_module_done(ac
->req
, NULL
, NULL
,
338 /* Start with the original request */
339 ret
= la_down_req(ac
);
340 if (ret
!= LDB_SUCCESS
) {
341 return ldb_module_done(ac
->req
, NULL
, NULL
, ret
);
353 static int linked_attributes_modify(struct ldb_module
*module
, struct ldb_request
*req
)
355 /* Look over list of modifications */
356 /* Find if any are for linked attributes */
357 /* Determine the effect of the modification */
358 /* Apply the modify to the linked entry */
360 struct ldb_context
*ldb
;
362 struct la_context
*ac
;
363 struct ldb_request
*search_req
;
368 ldb
= ldb_module_get_ctx(module
);
370 if (ldb_dn_is_special(req
->op
.mod
.message
->dn
)) {
371 /* do not manipulate our control entries */
372 return ldb_next_request(module
, req
);
375 ac
= linked_attributes_init(module
, req
);
377 return LDB_ERR_OPERATIONS_ERROR
;
381 /* without schema, this doesn't make any sense */
382 return ldb_next_request(module
, req
);
385 ac
->rc
= talloc_zero(ac
, struct replace_context
);
388 return LDB_ERR_OPERATIONS_ERROR
;
391 for (i
=0; i
< req
->op
.mod
.message
->num_elements
; i
++) {
392 bool store_el
= false;
393 const char *attr_name
;
394 const struct dsdb_attribute
*target_attr
;
395 const struct ldb_message_element
*el
= &req
->op
.mod
.message
->elements
[i
];
396 const struct dsdb_attribute
*schema_attr
397 = dsdb_attribute_by_lDAPDisplayName(ac
->schema
, el
->name
);
399 ldb_asprintf_errstring(ldb
,
400 "attribute %s is not a valid attribute in schema", el
->name
);
401 return LDB_ERR_OBJECT_CLASS_VIOLATION
;
403 /* We have a valid attribute, now find out if it is linked */
404 if (schema_attr
->linkID
== 0) {
408 if ((schema_attr
->linkID
& 1) == 1) {
409 /* Odd is for the target. Illegal to modify */
410 ldb_asprintf_errstring(ldb
,
411 "attribute %s must not be modified directly, it is a linked attribute", el
->name
);
412 return LDB_ERR_UNWILLING_TO_PERFORM
;
415 /* Even link IDs are for the originating attribute */
417 /* Now find the target attribute */
418 target_attr
= dsdb_attribute_by_linkID(ac
->schema
, schema_attr
->linkID
+ 1);
421 * windows 2003 has a broken schema where
422 * the definition of msDS-IsDomainFor
423 * is missing (which is supposed to be
424 * the backlink of the msDS-HasDomainNCs
430 attr_name
= target_attr
->lDAPDisplayName
;
432 switch (el
->flags
& LDB_FLAG_MOD_MASK
) {
433 case LDB_FLAG_MOD_REPLACE
:
434 /* treat as just a normal add the delete part is handled by the callback */
437 /* break intentionally missing */
439 case LDB_FLAG_MOD_ADD
:
441 /* For each value being added, we need to setup the adds */
442 for (j
= 0; j
< el
->num_values
; j
++) {
443 ret
= la_store_op(ac
, LA_OP_ADD
,
446 if (ret
!= LDB_SUCCESS
) {
452 case LDB_FLAG_MOD_DELETE
:
454 if (el
->num_values
) {
455 /* For each value being deleted, we need to setup the delete */
456 for (j
= 0; j
< el
->num_values
; j
++) {
457 ret
= la_store_op(ac
, LA_OP_DEL
,
460 if (ret
!= LDB_SUCCESS
) {
465 /* Flag that there was a DELETE
466 * without a value specified, so we
467 * need to look for the old value */
475 struct ldb_message_element
*search_el
;
477 search_el
= talloc_realloc(ac
->rc
, ac
->rc
->el
,
478 struct ldb_message_element
,
479 ac
->rc
->num_elements
+1);
482 return LDB_ERR_OPERATIONS_ERROR
;
484 ac
->rc
->el
= search_el
;
486 ac
->rc
->el
[ac
->rc
->num_elements
] = *el
;
487 ac
->rc
->num_elements
++;
491 if (ac
->ops
|| ac
->rc
->el
) {
492 /* both replace and delete without values are handled in the callback
493 * after the search on the entry to be modified is performed */
495 attrs
= talloc_array(ac
->rc
, const char *, ac
->rc
->num_elements
+ 1);
498 return LDB_ERR_OPERATIONS_ERROR
;
500 for (i
= 0; ac
->rc
&& i
< ac
->rc
->num_elements
; i
++) {
501 attrs
[i
] = ac
->rc
->el
[i
].name
;
505 /* The callback does all the hard work here */
506 ret
= ldb_build_search_req(&search_req
, ldb
, ac
,
507 req
->op
.mod
.message
->dn
,
509 "(objectClass=*)", attrs
,
511 ac
, la_mod_search_callback
,
514 /* We need to figure out our own extended DN, to fill in as the backlink target */
515 if (ret
== LDB_SUCCESS
) {
516 ret
= ldb_request_add_control(search_req
,
517 LDB_CONTROL_EXTENDED_DN_OID
,
520 if (ret
== LDB_SUCCESS
) {
521 talloc_steal(search_req
, attrs
);
523 ret
= ldb_next_request(module
, search_req
);
527 /* nothing to do for this module, proceed */
529 ret
= ldb_next_request(module
, req
);
536 static int linked_attributes_del(struct ldb_module
*module
, struct ldb_request
*req
)
538 struct ldb_context
*ldb
;
539 struct ldb_request
*search_req
;
540 struct la_context
*ac
;
545 /* This gets complex: We need to:
546 - Do a search for the entry
547 - Wait for these result to appear
548 - In the callback for the result, issue a modify
549 request based on the linked attributes found
550 - Wait for each modify result
554 ldb
= ldb_module_get_ctx(module
);
556 ac
= linked_attributes_init(module
, req
);
558 return LDB_ERR_OPERATIONS_ERROR
;
562 /* without schema, this doesn't make any sense */
563 return ldb_next_request(module
, req
);
566 werr
= dsdb_linked_attribute_lDAPDisplayName_list(ac
->schema
, ac
, &attrs
);
567 if (!W_ERROR_IS_OK(werr
)) {
568 return LDB_ERR_OPERATIONS_ERROR
;
571 ret
= ldb_build_search_req(&search_req
, ldb
, req
,
572 req
->op
.del
.dn
, LDB_SCOPE_BASE
,
573 "(objectClass=*)", attrs
,
575 ac
, la_op_search_callback
,
578 if (ret
!= LDB_SUCCESS
) {
582 talloc_steal(search_req
, attrs
);
584 return ldb_next_request(module
, search_req
);
588 static int linked_attributes_rename(struct ldb_module
*module
, struct ldb_request
*req
)
590 struct la_context
*ac
;
592 /* This gets complex: We need to:
593 - Do a search for the entry
594 - Wait for these result to appear
595 - In the callback for the result, issue a modify
596 request based on the linked attributes found
597 - Wait for each modify result
601 ac
= linked_attributes_init(module
, req
);
603 return LDB_ERR_OPERATIONS_ERROR
;
607 /* without schema, this doesn't make any sense */
608 return ldb_next_request(module
, req
);
611 /* start with the original request */
612 return la_down_req(ac
);
616 static int la_op_search_callback(struct ldb_request
*req
,
617 struct ldb_reply
*ares
)
619 struct ldb_context
*ldb
;
620 struct la_context
*ac
;
621 const struct dsdb_attribute
*schema_attr
;
622 const struct dsdb_attribute
*target_attr
;
623 const struct ldb_message_element
*el
;
624 const char *attr_name
;
628 ac
= talloc_get_type(req
->context
, struct la_context
);
629 ldb
= ldb_module_get_ctx(ac
->module
);
632 return ldb_module_done(ac
->req
, NULL
, NULL
,
633 LDB_ERR_OPERATIONS_ERROR
);
635 if (ares
->error
!= LDB_SUCCESS
) {
636 return ldb_module_done(ac
->req
, ares
->controls
,
637 ares
->response
, ares
->error
);
640 /* Only entries are interesting, and we only want the olddn */
641 switch (ares
->type
) {
642 case LDB_REPLY_ENTRY
:
643 ret
= ldb_dn_compare(ares
->message
->dn
, req
->op
.search
.base
);
645 /* Guh? We only asked for this DN */
647 return ldb_module_done(ac
->req
, NULL
, NULL
,
648 LDB_ERR_OPERATIONS_ERROR
);
650 if (ares
->message
->num_elements
== 0) {
651 /* only bother at all if there were some
652 * linked attributes found */
657 switch (ac
->req
->operation
) {
659 ac
->del_dn
= talloc_steal(ac
, ares
->message
->dn
);
662 ac
->add_dn
= talloc_steal(ac
, ares
->message
->dn
);
663 ac
->del_dn
= talloc_steal(ac
, ac
->req
->op
.rename
.olddn
);
667 ldb_set_errstring(ldb
,
668 "operations must be delete or rename");
669 return ldb_module_done(ac
->req
, NULL
, NULL
,
670 LDB_ERR_OPERATIONS_ERROR
);
673 for (i
= 0; i
< ares
->message
->num_elements
; i
++) {
674 el
= &ares
->message
->elements
[i
];
676 schema_attr
= dsdb_attribute_by_lDAPDisplayName(ac
->schema
, el
->name
);
678 ldb_asprintf_errstring(ldb
,
679 "attribute %s is not a valid attribute"
680 " in schema", el
->name
);
682 return ldb_module_done(ac
->req
, NULL
, NULL
,
683 LDB_ERR_OBJECT_CLASS_VIOLATION
);
686 /* Valid attribute, now find out if it is linked */
687 if (schema_attr
->linkID
== 0) {
688 /* Not a linked attribute, skip */
692 if ((schema_attr
->linkID
& 1) == 0) {
693 /* Odd is for the target. */
694 target_attr
= dsdb_attribute_by_linkID(ac
->schema
, schema_attr
->linkID
+ 1);
698 attr_name
= target_attr
->lDAPDisplayName
;
700 target_attr
= dsdb_attribute_by_linkID(ac
->schema
, schema_attr
->linkID
- 1);
704 attr_name
= target_attr
->lDAPDisplayName
;
706 for (j
= 0; j
< el
->num_values
; j
++) {
707 ret
= la_store_op(ac
, LA_OP_DEL
,
711 /* for renames, ensure we add it back */
712 if (ret
== LDB_SUCCESS
713 && ac
->req
->operation
== LDB_RENAME
) {
714 ret
= la_store_op(ac
, LA_OP_ADD
,
718 if (ret
!= LDB_SUCCESS
) {
720 return ldb_module_done(ac
->req
,
728 case LDB_REPLY_REFERRAL
:
737 switch (ac
->req
->operation
) {
739 /* start the mod requests chain */
740 ret
= la_down_req(ac
);
741 if (ret
!= LDB_SUCCESS
) {
742 return ldb_module_done(ac
->req
, NULL
, NULL
, ret
);
747 /* start the mod requests chain */
748 ret
= la_do_mod_request(ac
);
749 if (ret
!= LDB_SUCCESS
) {
750 return ldb_module_done(ac
->req
, NULL
, NULL
,
757 ldb_set_errstring(ldb
,
758 "operations must be delete or rename");
759 return ldb_module_done(ac
->req
, NULL
, NULL
,
760 LDB_ERR_OPERATIONS_ERROR
);
768 /* do a linked attributes modify request */
769 static int la_do_mod_request(struct la_context
*ac
)
771 struct ldb_message_element
*ret_el
;
772 struct ldb_request
*mod_req
;
773 struct ldb_message
*new_msg
;
774 struct ldb_context
*ldb
;
777 /* If we have no modifies in the queue, we are done! */
779 return ldb_module_done(ac
->req
, ac
->op_controls
,
780 ac
->op_response
, LDB_SUCCESS
);
783 ldb
= ldb_module_get_ctx(ac
->module
);
785 /* Create the modify request */
786 new_msg
= ldb_msg_new(ac
);
789 return LDB_ERR_OPERATIONS_ERROR
;
791 new_msg
->dn
= ac
->ops
->dn
;
793 if (ac
->ops
->op
== LA_OP_ADD
) {
794 ret
= ldb_msg_add_empty(new_msg
, ac
->ops
->name
,
795 LDB_FLAG_MOD_ADD
, &ret_el
);
797 ret
= ldb_msg_add_empty(new_msg
, ac
->ops
->name
,
798 LDB_FLAG_MOD_DELETE
, &ret_el
);
800 if (ret
!= LDB_SUCCESS
) {
803 ret_el
->values
= talloc_array(new_msg
, struct ldb_val
, 1);
804 if (!ret_el
->values
) {
806 return LDB_ERR_OPERATIONS_ERROR
;
808 ret_el
->num_values
= 1;
809 if (ac
->ops
->op
== LA_OP_ADD
) {
810 ret_el
->values
[0] = data_blob_string_const(ldb_dn_get_extended_linearized(new_msg
, ac
->add_dn
, 1));
812 ret_el
->values
[0] = data_blob_string_const(ldb_dn_get_extended_linearized(new_msg
, ac
->del_dn
, 1));
816 ldb_debug(ldb
, LDB_DEBUG_WARNING
,
817 "link on %s %s: %s %s\n",
818 ldb_dn_get_linearized(new_msg
->dn
), ret_el
->name
,
819 ret_el
->values
[0].data
, ac
->ops
->op
== LA_OP_ADD
? "added" : "deleted");
822 /* use ac->ops as the mem_ctx so that the request will be freed
823 * in the callback as soon as completed */
824 ret
= ldb_build_mod_req(&mod_req
, ldb
, ac
->ops
,
829 if (ret
!= LDB_SUCCESS
) {
832 talloc_steal(mod_req
, new_msg
);
834 /* Run the new request */
835 return ldb_next_request(ac
->module
, mod_req
);
838 static int la_mod_callback(struct ldb_request
*req
, struct ldb_reply
*ares
)
840 struct la_context
*ac
;
841 struct ldb_context
*ldb
;
842 struct la_op_store
*os
;
844 ac
= talloc_get_type(req
->context
, struct la_context
);
845 ldb
= ldb_module_get_ctx(ac
->module
);
848 return ldb_module_done(ac
->req
, NULL
, NULL
,
849 LDB_ERR_OPERATIONS_ERROR
);
851 if (ares
->error
!= LDB_SUCCESS
) {
852 return ldb_module_done(ac
->req
, ares
->controls
,
853 ares
->response
, ares
->error
);
856 if (ares
->type
!= LDB_REPLY_DONE
) {
857 ldb_set_errstring(ldb
,
858 "invalid ldb_reply_type in callback");
860 return ldb_module_done(ac
->req
, NULL
, NULL
,
861 LDB_ERR_OPERATIONS_ERROR
);
867 DLIST_REMOVE(ac
->ops
, os
);
869 /* this frees the request too
870 * DO NOT access 'req' after this point */
873 return la_do_mod_request(ac
);
876 /* Having done the original operation, then try to fix up all the linked attributes for modify and delete */
877 static int la_mod_del_callback(struct ldb_request
*req
, struct ldb_reply
*ares
)
880 struct la_context
*ac
;
881 struct ldb_context
*ldb
;
883 ac
= talloc_get_type(req
->context
, struct la_context
);
884 ldb
= ldb_module_get_ctx(ac
->module
);
887 return ldb_module_done(ac
->req
, NULL
, NULL
,
888 LDB_ERR_OPERATIONS_ERROR
);
890 if (ares
->error
!= LDB_SUCCESS
) {
891 return ldb_module_done(ac
->req
, ares
->controls
,
892 ares
->response
, ares
->error
);
895 if (ares
->type
!= LDB_REPLY_DONE
) {
896 ldb_set_errstring(ldb
,
897 "invalid ldb_reply_type in callback");
899 return ldb_module_done(ac
->req
, NULL
, NULL
,
900 LDB_ERR_OPERATIONS_ERROR
);
903 ac
->op_controls
= talloc_steal(ac
, ares
->controls
);
904 ac
->op_response
= talloc_steal(ac
, ares
->response
);
906 /* If we have modfies to make, this is the time to do them for modify and delete */
907 ret
= la_do_mod_request(ac
);
909 if (ret
!= LDB_SUCCESS
) {
910 return ldb_module_done(ac
->req
, NULL
, NULL
, ret
);
914 /* la_do_mod_request has already sent the callbacks */
919 /* Having done the original rename try to fix up all the linked attributes */
920 static int la_rename_callback(struct ldb_request
*req
, struct ldb_reply
*ares
)
923 struct la_context
*ac
;
924 struct ldb_request
*search_req
;
927 struct ldb_context
*ldb
;
929 ac
= talloc_get_type(req
->context
, struct la_context
);
930 ldb
= ldb_module_get_ctx(ac
->module
);
933 return ldb_module_done(ac
->req
, NULL
, NULL
,
934 LDB_ERR_OPERATIONS_ERROR
);
936 if (ares
->error
!= LDB_SUCCESS
) {
937 return ldb_module_done(ac
->req
, ares
->controls
,
938 ares
->response
, ares
->error
);
941 if (ares
->type
!= LDB_REPLY_DONE
) {
942 ldb_set_errstring(ldb
,
943 "invalid ldb_reply_type in callback");
945 return ldb_module_done(ac
->req
, NULL
, NULL
,
946 LDB_ERR_OPERATIONS_ERROR
);
949 werr
= dsdb_linked_attribute_lDAPDisplayName_list(ac
->schema
, ac
, &attrs
);
950 if (!W_ERROR_IS_OK(werr
)) {
951 return LDB_ERR_OPERATIONS_ERROR
;
954 ret
= ldb_build_search_req(&search_req
, ldb
, req
,
955 ac
->req
->op
.rename
.newdn
, LDB_SCOPE_BASE
,
956 "(objectClass=*)", attrs
,
958 ac
, la_op_search_callback
,
961 if (ret
!= LDB_SUCCESS
) {
965 talloc_steal(search_req
, attrs
);
967 if (ret
== LDB_SUCCESS
) {
968 ret
= ldb_request_add_control(search_req
,
969 LDB_CONTROL_EXTENDED_DN_OID
,
972 if (ret
!= LDB_SUCCESS
) {
973 return ldb_module_done(ac
->req
, NULL
, NULL
,
977 ac
->op_controls
= talloc_steal(ac
, ares
->controls
);
978 ac
->op_response
= talloc_steal(ac
, ares
->response
);
980 return ldb_next_request(ac
->module
, search_req
);
983 /* Having done the original add, then try to fix up all the linked attributes
985 This is done after the add so the links can get the extended DNs correctly.
987 static int la_add_callback(struct ldb_request
*req
, struct ldb_reply
*ares
)
990 struct la_context
*ac
;
991 struct ldb_context
*ldb
;
993 ac
= talloc_get_type(req
->context
, struct la_context
);
994 ldb
= ldb_module_get_ctx(ac
->module
);
997 return ldb_module_done(ac
->req
, NULL
, NULL
,
998 LDB_ERR_OPERATIONS_ERROR
);
1000 if (ares
->error
!= LDB_SUCCESS
) {
1001 return ldb_module_done(ac
->req
, ares
->controls
,
1002 ares
->response
, ares
->error
);
1005 if (ares
->type
!= LDB_REPLY_DONE
) {
1006 ldb_set_errstring(ldb
,
1007 "invalid ldb_reply_type in callback");
1009 return ldb_module_done(ac
->req
, NULL
, NULL
,
1010 LDB_ERR_OPERATIONS_ERROR
);
1014 struct ldb_request
*search_req
;
1015 static const char *attrs
[] = { NULL
};
1017 /* The callback does all the hard work here - we need
1018 * the objectGUID and SID of the added record */
1019 ret
= ldb_build_search_req(&search_req
, ldb
, ac
,
1020 ac
->req
->op
.add
.message
->dn
,
1022 "(objectClass=*)", attrs
,
1024 ac
, la_mod_search_callback
,
1027 if (ret
== LDB_SUCCESS
) {
1028 ret
= ldb_request_add_control(search_req
,
1029 LDB_CONTROL_EXTENDED_DN_OID
,
1032 if (ret
!= LDB_SUCCESS
) {
1033 return ldb_module_done(ac
->req
, NULL
, NULL
,
1037 ac
->op_controls
= talloc_steal(ac
, ares
->controls
);
1038 ac
->op_response
= talloc_steal(ac
, ares
->response
);
1040 return ldb_next_request(ac
->module
, search_req
);
1043 return ldb_module_done(ac
->req
, ares
->controls
,
1044 ares
->response
, ares
->error
);
1048 /* Reconstruct the original request, but pointing at our local callback to finish things off */
1049 static int la_down_req(struct la_context
*ac
)
1051 struct ldb_request
*down_req
;
1053 struct ldb_context
*ldb
;
1055 ldb
= ldb_module_get_ctx(ac
->module
);
1057 switch (ac
->req
->operation
) {
1059 ret
= ldb_build_add_req(&down_req
, ldb
, ac
,
1060 ac
->req
->op
.add
.message
,
1062 ac
, la_add_callback
,
1066 ret
= ldb_build_mod_req(&down_req
, ldb
, ac
,
1067 ac
->req
->op
.mod
.message
,
1069 ac
, la_mod_del_callback
,
1073 ret
= ldb_build_del_req(&down_req
, ldb
, ac
,
1076 ac
, la_mod_del_callback
,
1080 ret
= ldb_build_rename_req(&down_req
, ldb
, ac
,
1081 ac
->req
->op
.rename
.olddn
,
1082 ac
->req
->op
.rename
.newdn
,
1084 ac
, la_rename_callback
,
1088 ret
= LDB_ERR_OPERATIONS_ERROR
;
1090 if (ret
!= LDB_SUCCESS
) {
1094 return ldb_next_request(ac
->module
, down_req
);
1098 _PUBLIC_
const struct ldb_module_ops ldb_linked_attributes_module_ops
= {
1099 .name
= "linked_attributes",
1100 .add
= linked_attributes_add
,
1101 .modify
= linked_attributes_modify
,
1102 .del
= linked_attributes_del
,
1103 .rename
= linked_attributes_rename
,