4 Copyright (C) Simo Sorce 2004-2008
5 Copyright (C) Andrew Bartlett <abartlet@samba.org> 2005
6 Copyright (C) Andrew Tridgell 2005
7 Copyright (C) Stefan Metzmacher <metze@samba.org> 2007
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 repl_meta_data module
28 * Description: - add a unique objectGUID onto every new record,
29 * - handle whenCreated, whenChanged timestamps
30 * - handle uSNCreated, uSNChanged numbers
31 * - handle replPropertyMetaData attribute
34 * Author: Stefan Metzmacher
38 #include "ldb_module.h"
39 #include "dsdb/samdb/samdb.h"
40 #include "dsdb/common/proto.h"
41 #include "../libds/common/flags.h"
42 #include "librpc/gen_ndr/ndr_misc.h"
43 #include "librpc/gen_ndr/ndr_drsuapi.h"
44 #include "librpc/gen_ndr/ndr_drsblobs.h"
45 #include "param/param.h"
46 #include "libcli/security/dom_sid.h"
47 #include "lib/util/dlinklist.h"
49 struct replmd_private
{
51 struct la_entry
*la_list
;
61 struct la_entry
*next
, *prev
;
62 struct drsuapi_DsReplicaLinkedAttribute
*la
;
65 struct replmd_replicated_request
{
66 struct ldb_module
*module
;
67 struct ldb_request
*req
;
69 const struct dsdb_schema
*schema
;
71 struct dsdb_extended_replicated_objects
*objs
;
73 /* the controls we pass down */
74 struct ldb_control
**controls
;
76 uint32_t index_current
;
78 struct ldb_message
*search_msg
;
84 allocate the private structure and build the list
85 of partition DNs for use by replmd_notify()
87 static int replmd_init(struct ldb_module
*module
)
89 struct replmd_private
*replmd_private
;
90 struct ldb_context
*ldb
= ldb_module_get_ctx(module
);
92 replmd_private
= talloc_zero(module
, struct replmd_private
);
93 if (replmd_private
== NULL
) {
95 return LDB_ERR_OPERATIONS_ERROR
;
97 ldb_module_set_private(module
, replmd_private
);
99 return ldb_next_init(module
);
103 static int nc_compare(struct nc_entry
*n1
, struct nc_entry
*n2
)
105 return ldb_dn_compare(n1
->dn
, n2
->dn
);
109 build the list of partition DNs for use by replmd_notify()
111 static int replmd_load_NCs(struct ldb_module
*module
)
113 const char *attrs
[] = { "namingContexts", NULL
};
114 struct ldb_result
*res
= NULL
;
117 struct ldb_context
*ldb
;
118 struct ldb_message_element
*el
;
119 struct replmd_private
*replmd_private
=
120 talloc_get_type(ldb_module_get_private(module
), struct replmd_private
);
122 if (replmd_private
->ncs
!= NULL
) {
126 ldb
= ldb_module_get_ctx(module
);
127 tmp_ctx
= talloc_new(module
);
129 /* load the list of naming contexts */
130 ret
= ldb_search(ldb
, tmp_ctx
, &res
, ldb_dn_new(tmp_ctx
, ldb
, ""),
131 LDB_SCOPE_BASE
, attrs
, NULL
);
132 if (ret
!= LDB_SUCCESS
||
134 DEBUG(0,(__location__
": Failed to load rootDSE\n"));
135 return LDB_ERR_OPERATIONS_ERROR
;
138 el
= ldb_msg_find_element(res
->msgs
[0], "namingContexts");
140 DEBUG(0,(__location__
": Failed to load namingContexts\n"));
141 return LDB_ERR_OPERATIONS_ERROR
;
144 replmd_private
->num_ncs
= el
->num_values
;
145 replmd_private
->ncs
= talloc_array(replmd_private
, struct nc_entry
,
146 replmd_private
->num_ncs
);
147 if (replmd_private
->ncs
== NULL
) {
149 return LDB_ERR_OPERATIONS_ERROR
;
152 for (i
=0; i
<replmd_private
->num_ncs
; i
++) {
153 replmd_private
->ncs
[i
].dn
=
154 ldb_dn_from_ldb_val(replmd_private
->ncs
,
155 ldb
, &el
->values
[i
]);
156 replmd_private
->ncs
[i
].mod_usn
= 0;
161 /* now find the GUIDs of each of those DNs */
162 for (i
=0; i
<replmd_private
->num_ncs
; i
++) {
163 const char *attrs2
[] = { "objectGUID", NULL
};
164 ret
= ldb_search(ldb
, tmp_ctx
, &res
, replmd_private
->ncs
[i
].dn
,
165 LDB_SCOPE_BASE
, attrs2
, NULL
);
166 if (ret
!= LDB_SUCCESS
||
168 /* this happens when the schema is first being
170 talloc_free(replmd_private
->ncs
);
171 replmd_private
->ncs
= NULL
;
172 replmd_private
->num_ncs
= 0;
173 talloc_free(tmp_ctx
);
176 replmd_private
->ncs
[i
].guid
=
177 samdb_result_guid(res
->msgs
[0], "objectGUID");
181 /* sort the NCs into order, most to least specific */
182 qsort(replmd_private
->ncs
, replmd_private
->num_ncs
,
183 sizeof(replmd_private
->ncs
[0]), QSORT_CAST nc_compare
);
186 talloc_free(tmp_ctx
);
193 * notify the repl task that a object has changed. The notifies are
194 * gathered up in the replmd_private structure then written to the
195 * @REPLCHANGED object in each partition during the prepare_commit
197 static int replmd_notify(struct ldb_module
*module
, struct ldb_dn
*dn
, uint64_t uSN
)
200 struct replmd_private
*replmd_private
=
201 talloc_get_type(ldb_module_get_private(module
), struct replmd_private
);
203 ret
= replmd_load_NCs(module
);
204 if (ret
!= LDB_SUCCESS
) {
207 if (replmd_private
->num_ncs
== 0) {
211 for (i
=0; i
<replmd_private
->num_ncs
; i
++) {
212 if (ldb_dn_compare_base(replmd_private
->ncs
[i
].dn
, dn
) == 0) {
216 if (i
== replmd_private
->num_ncs
) {
217 DEBUG(0,(__location__
": DN not within known NCs '%s'\n",
218 ldb_dn_get_linearized(dn
)));
219 return LDB_ERR_OPERATIONS_ERROR
;
222 if (uSN
> replmd_private
->ncs
[i
].mod_usn
) {
223 replmd_private
->ncs
[i
].mod_usn
= uSN
;
231 * update a @REPLCHANGED record in each partition if there have been
232 * any writes of replicated data in the partition
234 static int replmd_notify_store(struct ldb_module
*module
)
237 struct replmd_private
*replmd_private
=
238 talloc_get_type(ldb_module_get_private(module
), struct replmd_private
);
239 struct ldb_context
*ldb
= ldb_module_get_ctx(module
);
241 for (i
=0; i
<replmd_private
->num_ncs
; i
++) {
244 if (replmd_private
->ncs
[i
].mod_usn
== 0) {
245 /* this partition has not changed in this
250 ret
= dsdb_save_partition_usn(ldb
, replmd_private
->ncs
[i
].dn
,
251 replmd_private
->ncs
[i
].mod_usn
);
252 if (ret
!= LDB_SUCCESS
) {
253 DEBUG(0,(__location__
": Failed to save partition uSN for %s\n",
254 ldb_dn_get_linearized(replmd_private
->ncs
[i
].dn
)));
264 created a replmd_replicated_request context
266 static struct replmd_replicated_request
*replmd_ctx_init(struct ldb_module
*module
,
267 struct ldb_request
*req
)
269 struct ldb_context
*ldb
;
270 struct replmd_replicated_request
*ac
;
272 ldb
= ldb_module_get_ctx(module
);
274 ac
= talloc_zero(req
, struct replmd_replicated_request
);
286 add a time element to a record
288 static int add_time_element(struct ldb_message
*msg
, const char *attr
, time_t t
)
290 struct ldb_message_element
*el
;
293 if (ldb_msg_find_element(msg
, attr
) != NULL
) {
297 s
= ldb_timestring(msg
, t
);
299 return LDB_ERR_OPERATIONS_ERROR
;
302 if (ldb_msg_add_string(msg
, attr
, s
) != LDB_SUCCESS
) {
303 return LDB_ERR_OPERATIONS_ERROR
;
306 el
= ldb_msg_find_element(msg
, attr
);
307 /* always set as replace. This works because on add ops, the flag
309 el
->flags
= LDB_FLAG_MOD_REPLACE
;
315 add a uint64_t element to a record
317 static int add_uint64_element(struct ldb_message
*msg
, const char *attr
, uint64_t v
)
319 struct ldb_message_element
*el
;
321 if (ldb_msg_find_element(msg
, attr
) != NULL
) {
325 if (ldb_msg_add_fmt(msg
, attr
, "%llu", (unsigned long long)v
) != LDB_SUCCESS
) {
326 return LDB_ERR_OPERATIONS_ERROR
;
329 el
= ldb_msg_find_element(msg
, attr
);
330 /* always set as replace. This works because on add ops, the flag
332 el
->flags
= LDB_FLAG_MOD_REPLACE
;
337 static int replmd_replPropertyMetaData1_attid_sort(const struct replPropertyMetaData1
*m1
,
338 const struct replPropertyMetaData1
*m2
,
339 const uint32_t *rdn_attid
)
341 if (m1
->attid
== m2
->attid
) {
346 * the rdn attribute should be at the end!
347 * so we need to return a value greater than zero
348 * which means m1 is greater than m2
350 if (m1
->attid
== *rdn_attid
) {
355 * the rdn attribute should be at the end!
356 * so we need to return a value less than zero
357 * which means m2 is greater than m1
359 if (m2
->attid
== *rdn_attid
) {
363 return m1
->attid
- m2
->attid
;
366 static void replmd_replPropertyMetaDataCtr1_sort(struct replPropertyMetaDataCtr1
*ctr1
,
367 const uint32_t *rdn_attid
)
369 ldb_qsort(ctr1
->array
, ctr1
->count
, sizeof(struct replPropertyMetaData1
),
370 discard_const_p(void, rdn_attid
), (ldb_qsort_cmp_fn_t
)replmd_replPropertyMetaData1_attid_sort
);
373 static int replmd_ldb_message_element_attid_sort(const struct ldb_message_element
*e1
,
374 const struct ldb_message_element
*e2
,
375 const struct dsdb_schema
*schema
)
377 const struct dsdb_attribute
*a1
;
378 const struct dsdb_attribute
*a2
;
381 * TODO: make this faster by caching the dsdb_attribute pointer
382 * on the ldb_messag_element
385 a1
= dsdb_attribute_by_lDAPDisplayName(schema
, e1
->name
);
386 a2
= dsdb_attribute_by_lDAPDisplayName(schema
, e2
->name
);
389 * TODO: remove this check, we should rely on e1 and e2 having valid attribute names
393 return strcasecmp(e1
->name
, e2
->name
);
396 return a1
->attributeID_id
- a2
->attributeID_id
;
399 static void replmd_ldb_message_sort(struct ldb_message
*msg
,
400 const struct dsdb_schema
*schema
)
402 ldb_qsort(msg
->elements
, msg
->num_elements
, sizeof(struct ldb_message_element
),
403 discard_const_p(void, schema
), (ldb_qsort_cmp_fn_t
)replmd_ldb_message_element_attid_sort
);
406 static int replmd_op_callback(struct ldb_request
*req
, struct ldb_reply
*ares
)
408 struct ldb_context
*ldb
;
409 struct replmd_replicated_request
*ac
;
411 ac
= talloc_get_type(req
->context
, struct replmd_replicated_request
);
412 ldb
= ldb_module_get_ctx(ac
->module
);
415 return ldb_module_done(ac
->req
, NULL
, NULL
,
416 LDB_ERR_OPERATIONS_ERROR
);
418 if (ares
->error
!= LDB_SUCCESS
) {
419 return ldb_module_done(ac
->req
, ares
->controls
,
420 ares
->response
, ares
->error
);
423 if (ares
->type
!= LDB_REPLY_DONE
) {
424 ldb_set_errstring(ldb
,
425 "invalid ldb_reply_type in callback");
427 return ldb_module_done(ac
->req
, NULL
, NULL
,
428 LDB_ERR_OPERATIONS_ERROR
);
431 return ldb_module_done(ac
->req
, ares
->controls
,
432 ares
->response
, LDB_SUCCESS
);
435 static int replmd_add(struct ldb_module
*module
, struct ldb_request
*req
)
437 struct ldb_context
*ldb
;
438 struct replmd_replicated_request
*ac
;
439 const struct dsdb_schema
*schema
;
440 enum ndr_err_code ndr_err
;
441 struct ldb_request
*down_req
;
442 struct ldb_message
*msg
;
443 const struct dsdb_attribute
*rdn_attr
= NULL
;
445 struct ldb_val guid_value
;
446 struct replPropertyMetaDataBlob nmd
;
447 struct ldb_val nmd_value
;
449 const struct GUID
*our_invocation_id
;
450 time_t t
= time(NULL
);
456 /* do not manipulate our control entries */
457 if (ldb_dn_is_special(req
->op
.add
.message
->dn
)) {
458 return ldb_next_request(module
, req
);
461 ldb
= ldb_module_get_ctx(module
);
463 ldb_debug(ldb
, LDB_DEBUG_TRACE
, "replmd_add\n");
465 schema
= dsdb_get_schema(ldb
);
467 ldb_debug_set(ldb
, LDB_DEBUG_FATAL
,
468 "replmd_add: no dsdb_schema loaded");
469 return LDB_ERR_CONSTRAINT_VIOLATION
;
472 ac
= replmd_ctx_init(module
, req
);
474 return LDB_ERR_OPERATIONS_ERROR
;
479 if (ldb_msg_find_element(req
->op
.add
.message
, "objectGUID") != NULL
) {
480 ldb_debug_set(ldb
, LDB_DEBUG_ERROR
,
481 "replmd_add: it's not allowed to add an object with objectGUID\n");
482 return LDB_ERR_UNWILLING_TO_PERFORM
;
485 /* Get a sequence number from the backend */
486 ret
= ldb_sequence_number(ldb
, LDB_SEQ_NEXT
, &seq_num
);
487 if (ret
!= LDB_SUCCESS
) {
492 guid
= GUID_random();
494 /* get our invocationId */
495 our_invocation_id
= samdb_ntds_invocation_id(ldb
);
496 if (!our_invocation_id
) {
497 ldb_debug_set(ldb
, LDB_DEBUG_ERROR
,
498 "replmd_add: unable to find invocationId\n");
499 return LDB_ERR_OPERATIONS_ERROR
;
502 /* we have to copy the message as the caller might have it as a const */
503 msg
= ldb_msg_copy_shallow(ac
, req
->op
.add
.message
);
506 return LDB_ERR_OPERATIONS_ERROR
;
509 /* generated times */
510 unix_to_nt_time(&now
, t
);
511 time_str
= ldb_timestring(msg
, t
);
513 return LDB_ERR_OPERATIONS_ERROR
;
517 * remove autogenerated attributes
519 ldb_msg_remove_attr(msg
, "whenCreated");
520 ldb_msg_remove_attr(msg
, "whenChanged");
521 ldb_msg_remove_attr(msg
, "uSNCreated");
522 ldb_msg_remove_attr(msg
, "uSNChanged");
523 ldb_msg_remove_attr(msg
, "replPropertyMetaData");
526 * readd replicated attributes
528 ret
= ldb_msg_add_string(msg
, "whenCreated", time_str
);
529 if (ret
!= LDB_SUCCESS
) {
531 return LDB_ERR_OPERATIONS_ERROR
;
534 /* build the replication meta_data */
537 nmd
.ctr
.ctr1
.count
= msg
->num_elements
;
538 nmd
.ctr
.ctr1
.array
= talloc_array(msg
,
539 struct replPropertyMetaData1
,
541 if (!nmd
.ctr
.ctr1
.array
) {
543 return LDB_ERR_OPERATIONS_ERROR
;
546 for (i
=0; i
< msg
->num_elements
; i
++) {
547 struct ldb_message_element
*e
= &msg
->elements
[i
];
548 struct replPropertyMetaData1
*m
= &nmd
.ctr
.ctr1
.array
[ni
];
549 const struct dsdb_attribute
*sa
;
551 if (e
->name
[0] == '@') continue;
553 sa
= dsdb_attribute_by_lDAPDisplayName(schema
, e
->name
);
555 ldb_debug_set(ldb
, LDB_DEBUG_ERROR
,
556 "replmd_add: attribute '%s' not defined in schema\n",
558 return LDB_ERR_NO_SUCH_ATTRIBUTE
;
561 if ((sa
->systemFlags
& 0x00000001) || (sa
->systemFlags
& 0x00000004)) {
562 /* if the attribute is not replicated (0x00000001)
563 * or constructed (0x00000004) it has no metadata
568 m
->attid
= sa
->attributeID_id
;
570 m
->originating_change_time
= now
;
571 m
->originating_invocation_id
= *our_invocation_id
;
572 m
->originating_usn
= seq_num
;
573 m
->local_usn
= seq_num
;
576 if (ldb_attr_cmp(e
->name
, ldb_dn_get_rdn_name(msg
->dn
))) {
581 /* fix meta data count */
582 nmd
.ctr
.ctr1
.count
= ni
;
585 * sort meta data array, and move the rdn attribute entry to the end
587 replmd_replPropertyMetaDataCtr1_sort(&nmd
.ctr
.ctr1
, &rdn_attr
->attributeID_id
);
589 /* generated NDR encoded values */
590 ndr_err
= ndr_push_struct_blob(&guid_value
, msg
,
593 (ndr_push_flags_fn_t
)ndr_push_GUID
);
594 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
596 return LDB_ERR_OPERATIONS_ERROR
;
598 ndr_err
= ndr_push_struct_blob(&nmd_value
, msg
,
599 lp_iconv_convenience(ldb_get_opaque(ldb
, "loadparm")),
601 (ndr_push_flags_fn_t
)ndr_push_replPropertyMetaDataBlob
);
602 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
604 return LDB_ERR_OPERATIONS_ERROR
;
608 * add the autogenerated values
610 ret
= ldb_msg_add_value(msg
, "objectGUID", &guid_value
, NULL
);
611 if (ret
!= LDB_SUCCESS
) {
613 return LDB_ERR_OPERATIONS_ERROR
;
615 ret
= ldb_msg_add_string(msg
, "whenChanged", time_str
);
616 if (ret
!= LDB_SUCCESS
) {
618 return LDB_ERR_OPERATIONS_ERROR
;
620 ret
= samdb_msg_add_uint64(ldb
, msg
, msg
, "uSNCreated", seq_num
);
621 if (ret
!= LDB_SUCCESS
) {
623 return LDB_ERR_OPERATIONS_ERROR
;
625 ret
= samdb_msg_add_uint64(ldb
, msg
, msg
, "uSNChanged", seq_num
);
626 if (ret
!= LDB_SUCCESS
) {
628 return LDB_ERR_OPERATIONS_ERROR
;
630 ret
= ldb_msg_add_value(msg
, "replPropertyMetaData", &nmd_value
, NULL
);
631 if (ret
!= LDB_SUCCESS
) {
633 return LDB_ERR_OPERATIONS_ERROR
;
637 * sort the attributes by attid before storing the object
639 replmd_ldb_message_sort(msg
, schema
);
641 ret
= ldb_build_add_req(&down_req
, ldb
, ac
,
644 ac
, replmd_op_callback
,
646 if (ret
!= LDB_SUCCESS
) {
650 ret
= replmd_notify(module
, msg
->dn
, seq_num
);
651 if (ret
!= LDB_SUCCESS
) {
655 /* go on with the call chain */
656 return ldb_next_request(module
, down_req
);
661 * update the replPropertyMetaData for one element
663 static int replmd_update_rpmd_element(struct ldb_context
*ldb
,
664 struct ldb_message
*msg
,
665 struct ldb_message_element
*el
,
666 struct replPropertyMetaDataBlob
*omd
,
667 struct dsdb_schema
*schema
,
669 const struct GUID
*our_invocation_id
,
673 const struct dsdb_attribute
*a
;
674 struct replPropertyMetaData1
*md1
;
676 a
= dsdb_attribute_by_lDAPDisplayName(schema
, el
->name
);
678 DEBUG(0,(__location__
": Unable to find attribute %s in schema\n",
680 return LDB_ERR_OPERATIONS_ERROR
;
683 if ((a
->systemFlags
& 0x00000001) || (a
->systemFlags
& 0x00000004)) {
684 /* if the attribute is not replicated (0x00000001)
685 * or constructed (0x00000004) it has no metadata
690 for (i
=0; i
<omd
->ctr
.ctr1
.count
; i
++) {
691 if (a
->attributeID_id
== omd
->ctr
.ctr1
.array
[i
].attid
) break;
693 if (i
== omd
->ctr
.ctr1
.count
) {
694 /* we need to add a new one */
695 omd
->ctr
.ctr1
.array
= talloc_realloc(msg
, omd
->ctr
.ctr1
.array
,
696 struct replPropertyMetaData1
, omd
->ctr
.ctr1
.count
+1);
697 if (omd
->ctr
.ctr1
.array
== NULL
) {
699 return LDB_ERR_OPERATIONS_ERROR
;
701 omd
->ctr
.ctr1
.count
++;
702 ZERO_STRUCT(omd
->ctr
.ctr1
.array
[i
]);
705 /* Get a new sequence number from the backend. We only do this
706 * if we have a change that requires a new
707 * replPropertyMetaData element
710 int ret
= ldb_sequence_number(ldb
, LDB_SEQ_NEXT
, seq_num
);
711 if (ret
!= LDB_SUCCESS
) {
712 return LDB_ERR_OPERATIONS_ERROR
;
716 md1
= &omd
->ctr
.ctr1
.array
[i
];
718 md1
->attid
= a
->attributeID_id
;
719 md1
->originating_change_time
= now
;
720 md1
->originating_invocation_id
= *our_invocation_id
;
721 md1
->originating_usn
= *seq_num
;
722 md1
->local_usn
= *seq_num
;
728 * update the replPropertyMetaData object each time we modify an
729 * object. This is needed for DRS replication, as the merge on the
730 * client is based on this object
732 static int replmd_update_rpmd(struct ldb_module
*module
,
733 struct ldb_message
*msg
, uint64_t *seq_num
)
735 const struct ldb_val
*omd_value
;
736 enum ndr_err_code ndr_err
;
737 struct replPropertyMetaDataBlob omd
;
739 struct dsdb_schema
*schema
;
740 time_t t
= time(NULL
);
742 const struct GUID
*our_invocation_id
;
744 const char *attrs
[] = { "replPropertyMetaData" , NULL
};
745 struct ldb_result
*res
;
746 struct ldb_context
*ldb
;
748 ldb
= ldb_module_get_ctx(module
);
750 our_invocation_id
= samdb_ntds_invocation_id(ldb
);
751 if (!our_invocation_id
) {
752 /* this happens during an initial vampire while
753 updating the schema */
754 DEBUG(5,("No invocationID - skipping replPropertyMetaData update\n"));
758 unix_to_nt_time(&now
, t
);
760 /* search for the existing replPropertyMetaDataBlob */
761 ret
= ldb_search(ldb
, msg
, &res
, msg
->dn
, LDB_SCOPE_BASE
, attrs
, NULL
);
762 if (ret
!= LDB_SUCCESS
|| res
->count
< 1) {
763 DEBUG(0,(__location__
": Object %s failed to find replPropertyMetaData\n",
764 ldb_dn_get_linearized(msg
->dn
)));
765 return LDB_ERR_OPERATIONS_ERROR
;
769 omd_value
= ldb_msg_find_ldb_val(res
->msgs
[0], "replPropertyMetaData");
771 DEBUG(0,(__location__
": Object %s does not have a replPropertyMetaData attribute\n",
772 ldb_dn_get_linearized(msg
->dn
)));
773 return LDB_ERR_OPERATIONS_ERROR
;
776 ndr_err
= ndr_pull_struct_blob(omd_value
, msg
,
777 lp_iconv_convenience(ldb_get_opaque(ldb
, "loadparm")), &omd
,
778 (ndr_pull_flags_fn_t
)ndr_pull_replPropertyMetaDataBlob
);
779 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
780 DEBUG(0,(__location__
": Failed to parse replPropertyMetaData for %s\n",
781 ldb_dn_get_linearized(msg
->dn
)));
782 return LDB_ERR_OPERATIONS_ERROR
;
785 if (omd
.version
!= 1) {
786 DEBUG(0,(__location__
": bad version %u in replPropertyMetaData for %s\n",
787 omd
.version
, ldb_dn_get_linearized(msg
->dn
)));
788 return LDB_ERR_OPERATIONS_ERROR
;
791 schema
= dsdb_get_schema(ldb
);
793 for (i
=0; i
<msg
->num_elements
; i
++) {
794 ret
= replmd_update_rpmd_element(ldb
, msg
, &msg
->elements
[i
], &omd
, schema
, seq_num
,
795 our_invocation_id
, now
);
796 if (ret
!= LDB_SUCCESS
) {
802 * replmd_update_rpmd_element has done an update if the
806 struct ldb_val
*md_value
;
807 struct ldb_message_element
*el
;
809 md_value
= talloc(msg
, struct ldb_val
);
810 if (md_value
== NULL
) {
812 return LDB_ERR_OPERATIONS_ERROR
;
815 ndr_err
= ndr_push_struct_blob(md_value
, msg
,
816 lp_iconv_convenience(ldb_get_opaque(ldb
, "loadparm")),
818 (ndr_push_flags_fn_t
)ndr_push_replPropertyMetaDataBlob
);
819 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
820 DEBUG(0,(__location__
": Failed to marshall replPropertyMetaData for %s\n",
821 ldb_dn_get_linearized(msg
->dn
)));
822 return LDB_ERR_OPERATIONS_ERROR
;
825 ret
= ldb_msg_add_empty(msg
, "replPropertyMetaData", LDB_FLAG_MOD_REPLACE
, &el
);
826 if (ret
!= LDB_SUCCESS
) {
827 DEBUG(0,(__location__
": Failed to add updated replPropertyMetaData %s\n",
828 ldb_dn_get_linearized(msg
->dn
)));
832 ret
= replmd_notify(module
, msg
->dn
, *seq_num
);
833 if (ret
!= LDB_SUCCESS
) {
838 el
->values
= md_value
;
845 static int replmd_modify(struct ldb_module
*module
, struct ldb_request
*req
)
847 struct ldb_context
*ldb
;
848 struct replmd_replicated_request
*ac
;
849 const struct dsdb_schema
*schema
;
850 struct ldb_request
*down_req
;
851 struct ldb_message
*msg
;
853 time_t t
= time(NULL
);
854 uint64_t seq_num
= 0;
856 /* do not manipulate our control entries */
857 if (ldb_dn_is_special(req
->op
.mod
.message
->dn
)) {
858 return ldb_next_request(module
, req
);
861 ldb
= ldb_module_get_ctx(module
);
863 ldb_debug(ldb
, LDB_DEBUG_TRACE
, "replmd_modify\n");
865 schema
= dsdb_get_schema(ldb
);
867 ldb_debug_set(ldb
, LDB_DEBUG_FATAL
,
868 "replmd_modify: no dsdb_schema loaded");
869 return LDB_ERR_CONSTRAINT_VIOLATION
;
872 ac
= replmd_ctx_init(module
, req
);
874 return LDB_ERR_OPERATIONS_ERROR
;
879 /* we have to copy the message as the caller might have it as a const */
880 msg
= ldb_msg_copy_shallow(ac
, req
->op
.mod
.message
);
883 return LDB_ERR_OPERATIONS_ERROR
;
887 * - get the whole old object
888 * - if the old object doesn't exist report an error
889 * - give an error when a readonly attribute should
891 * - merge the changed into the old object
892 * if the caller set values to the same value
893 * ignore the attribute, return success when no
894 * attribute was changed
897 ret
= replmd_update_rpmd(module
, msg
, &seq_num
);
898 if (ret
!= LDB_SUCCESS
) {
903 * - sort the attributes by attid with replmd_ldb_message_sort()
904 * - replace the old object with the newly constructed one
907 ret
= ldb_build_mod_req(&down_req
, ldb
, ac
,
910 ac
, replmd_op_callback
,
912 if (ret
!= LDB_SUCCESS
) {
915 talloc_steal(down_req
, msg
);
917 /* we only change whenChanged and uSNChanged if the seq_num
920 if (add_time_element(msg
, "whenChanged", t
) != LDB_SUCCESS
) {
922 return LDB_ERR_OPERATIONS_ERROR
;
925 if (add_uint64_element(msg
, "uSNChanged", seq_num
) != LDB_SUCCESS
) {
927 return LDB_ERR_OPERATIONS_ERROR
;
931 /* go on with the call chain */
932 return ldb_next_request(module
, down_req
);
937 handle a rename request
939 On a rename we need to do an extra ldb_modify which sets the
940 whenChanged and uSNChanged attributes
942 static int replmd_rename(struct ldb_module
*module
, struct ldb_request
*req
)
944 struct ldb_context
*ldb
;
946 time_t t
= time(NULL
);
947 uint64_t seq_num
= 0;
948 struct ldb_message
*msg
;
949 struct replmd_private
*replmd_private
=
950 talloc_get_type(ldb_module_get_private(module
), struct replmd_private
);
952 /* do not manipulate our control entries */
953 if (ldb_dn_is_special(req
->op
.mod
.message
->dn
)) {
954 return ldb_next_request(module
, req
);
957 ldb
= ldb_module_get_ctx(module
);
959 ldb_debug(ldb
, LDB_DEBUG_TRACE
, "replmd_rename\n");
961 /* Get a sequence number from the backend */
962 ret
= ldb_sequence_number(ldb
, LDB_SEQ_NEXT
, &seq_num
);
963 if (ret
!= LDB_SUCCESS
) {
967 msg
= ldb_msg_new(req
);
970 return LDB_ERR_OPERATIONS_ERROR
;
973 msg
->dn
= req
->op
.rename
.olddn
;
975 if (add_time_element(msg
, "whenChanged", t
) != LDB_SUCCESS
) {
977 return LDB_ERR_OPERATIONS_ERROR
;
979 msg
->elements
[0].flags
= LDB_FLAG_MOD_REPLACE
;
981 if (add_uint64_element(msg
, "uSNChanged", seq_num
) != LDB_SUCCESS
) {
983 return LDB_ERR_OPERATIONS_ERROR
;
985 msg
->elements
[1].flags
= LDB_FLAG_MOD_REPLACE
;
987 ret
= ldb_modify(ldb
, msg
);
989 if (ret
!= LDB_SUCCESS
) {
993 ret
= replmd_load_NCs(module
);
998 /* now update the highest uSNs of the partitions that are
999 affected. Note that two partitions could be changing */
1000 for (i
=0; i
<replmd_private
->num_ncs
; i
++) {
1001 if (ldb_dn_compare_base(replmd_private
->ncs
[i
].dn
,
1002 req
->op
.rename
.olddn
) == 0) {
1006 if (i
== replmd_private
->num_ncs
) {
1007 DEBUG(0,(__location__
": rename olddn outside tree? %s\n",
1008 ldb_dn_get_linearized(req
->op
.rename
.olddn
)));
1009 return LDB_ERR_OPERATIONS_ERROR
;
1011 replmd_private
->ncs
[i
].mod_usn
= seq_num
;
1013 for (i
=0; i
<replmd_private
->num_ncs
; i
++) {
1014 if (ldb_dn_compare_base(replmd_private
->ncs
[i
].dn
,
1015 req
->op
.rename
.newdn
) == 0) {
1019 if (i
== replmd_private
->num_ncs
) {
1020 DEBUG(0,(__location__
": rename newdn outside tree? %s\n",
1021 ldb_dn_get_linearized(req
->op
.rename
.newdn
)));
1022 return LDB_ERR_OPERATIONS_ERROR
;
1024 replmd_private
->ncs
[i
].mod_usn
= seq_num
;
1026 /* go on with the call chain */
1027 return ldb_next_request(module
, req
);
1031 static int replmd_replicated_request_error(struct replmd_replicated_request
*ar
, int ret
)
1036 static int replmd_replicated_request_werror(struct replmd_replicated_request
*ar
, WERROR status
)
1038 int ret
= LDB_ERR_OTHER
;
1039 /* TODO: do some error mapping */
1043 static int replmd_replicated_apply_next(struct replmd_replicated_request
*ar
);
1045 static int replmd_replicated_apply_add_callback(struct ldb_request
*req
,
1046 struct ldb_reply
*ares
)
1048 struct ldb_context
*ldb
;
1049 struct replmd_replicated_request
*ar
= talloc_get_type(req
->context
,
1050 struct replmd_replicated_request
);
1053 ldb
= ldb_module_get_ctx(ar
->module
);
1056 return ldb_module_done(ar
->req
, NULL
, NULL
,
1057 LDB_ERR_OPERATIONS_ERROR
);
1059 if (ares
->error
!= LDB_SUCCESS
) {
1060 return ldb_module_done(ar
->req
, ares
->controls
,
1061 ares
->response
, ares
->error
);
1064 if (ares
->type
!= LDB_REPLY_DONE
) {
1065 ldb_set_errstring(ldb
, "Invalid reply type\n!");
1066 return ldb_module_done(ar
->req
, NULL
, NULL
,
1067 LDB_ERR_OPERATIONS_ERROR
);
1071 ar
->index_current
++;
1073 ret
= replmd_replicated_apply_next(ar
);
1074 if (ret
!= LDB_SUCCESS
) {
1075 return ldb_module_done(ar
->req
, NULL
, NULL
, ret
);
1081 static int replmd_replicated_apply_add(struct replmd_replicated_request
*ar
)
1083 struct ldb_context
*ldb
;
1084 struct ldb_request
*change_req
;
1085 enum ndr_err_code ndr_err
;
1086 struct ldb_message
*msg
;
1087 struct replPropertyMetaDataBlob
*md
;
1088 struct ldb_val md_value
;
1094 * TODO: check if the parent object exist
1098 * TODO: handle the conflict case where an object with the
1102 ldb
= ldb_module_get_ctx(ar
->module
);
1103 msg
= ar
->objs
->objects
[ar
->index_current
].msg
;
1104 md
= ar
->objs
->objects
[ar
->index_current
].meta_data
;
1106 ret
= ldb_sequence_number(ldb
, LDB_SEQ_NEXT
, &seq_num
);
1107 if (ret
!= LDB_SUCCESS
) {
1108 return replmd_replicated_request_error(ar
, ret
);
1111 ret
= ldb_msg_add_value(msg
, "objectGUID", &ar
->objs
->objects
[ar
->index_current
].guid_value
, NULL
);
1112 if (ret
!= LDB_SUCCESS
) {
1113 return replmd_replicated_request_error(ar
, ret
);
1116 ret
= ldb_msg_add_string(msg
, "whenChanged", ar
->objs
->objects
[ar
->index_current
].when_changed
);
1117 if (ret
!= LDB_SUCCESS
) {
1118 return replmd_replicated_request_error(ar
, ret
);
1121 ret
= samdb_msg_add_uint64(ldb
, msg
, msg
, "uSNCreated", seq_num
);
1122 if (ret
!= LDB_SUCCESS
) {
1123 return replmd_replicated_request_error(ar
, ret
);
1126 ret
= samdb_msg_add_uint64(ldb
, msg
, msg
, "uSNChanged", seq_num
);
1127 if (ret
!= LDB_SUCCESS
) {
1128 return replmd_replicated_request_error(ar
, ret
);
1131 ret
= replmd_notify(ar
->module
, msg
->dn
, seq_num
);
1132 if (ret
!= LDB_SUCCESS
) {
1133 return replmd_replicated_request_error(ar
, ret
);
1137 * the meta data array is already sorted by the caller
1139 for (i
=0; i
< md
->ctr
.ctr1
.count
; i
++) {
1140 md
->ctr
.ctr1
.array
[i
].local_usn
= seq_num
;
1142 ndr_err
= ndr_push_struct_blob(&md_value
, msg
,
1143 lp_iconv_convenience(ldb_get_opaque(ldb
, "loadparm")),
1145 (ndr_push_flags_fn_t
)ndr_push_replPropertyMetaDataBlob
);
1146 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
1147 NTSTATUS nt_status
= ndr_map_error2ntstatus(ndr_err
);
1148 return replmd_replicated_request_werror(ar
, ntstatus_to_werror(nt_status
));
1150 ret
= ldb_msg_add_value(msg
, "replPropertyMetaData", &md_value
, NULL
);
1151 if (ret
!= LDB_SUCCESS
) {
1152 return replmd_replicated_request_error(ar
, ret
);
1155 replmd_ldb_message_sort(msg
, ar
->schema
);
1158 char *s
= ldb_ldif_message_string(ldb
, ar
, LDB_CHANGETYPE_ADD
, msg
);
1159 DEBUG(4, ("DRS replication add message:\n%s\n", s
));
1163 ret
= ldb_build_add_req(&change_req
,
1169 replmd_replicated_apply_add_callback
,
1171 if (ret
!= LDB_SUCCESS
) return replmd_replicated_request_error(ar
, ret
);
1173 return ldb_next_request(ar
->module
, change_req
);
1176 static int replmd_replPropertyMetaData1_conflict_compare(struct replPropertyMetaData1
*m1
,
1177 struct replPropertyMetaData1
*m2
)
1181 if (m1
->version
!= m2
->version
) {
1182 return m1
->version
- m2
->version
;
1185 if (m1
->originating_change_time
!= m2
->originating_change_time
) {
1186 return m1
->originating_change_time
- m2
->originating_change_time
;
1189 ret
= GUID_compare(&m1
->originating_invocation_id
, &m2
->originating_invocation_id
);
1194 return m1
->originating_usn
- m2
->originating_usn
;
1197 static int replmd_replicated_apply_merge_callback(struct ldb_request
*req
,
1198 struct ldb_reply
*ares
)
1200 struct ldb_context
*ldb
;
1201 struct replmd_replicated_request
*ar
= talloc_get_type(req
->context
,
1202 struct replmd_replicated_request
);
1205 ldb
= ldb_module_get_ctx(ar
->module
);
1208 return ldb_module_done(ar
->req
, NULL
, NULL
,
1209 LDB_ERR_OPERATIONS_ERROR
);
1211 if (ares
->error
!= LDB_SUCCESS
) {
1212 return ldb_module_done(ar
->req
, ares
->controls
,
1213 ares
->response
, ares
->error
);
1216 if (ares
->type
!= LDB_REPLY_DONE
) {
1217 ldb_set_errstring(ldb
, "Invalid reply type\n!");
1218 return ldb_module_done(ar
->req
, NULL
, NULL
,
1219 LDB_ERR_OPERATIONS_ERROR
);
1223 ar
->index_current
++;
1225 ret
= replmd_replicated_apply_next(ar
);
1226 if (ret
!= LDB_SUCCESS
) {
1227 return ldb_module_done(ar
->req
, NULL
, NULL
, ret
);
1233 static int replmd_replicated_apply_merge(struct replmd_replicated_request
*ar
)
1235 struct ldb_context
*ldb
;
1236 struct ldb_request
*change_req
;
1237 enum ndr_err_code ndr_err
;
1238 struct ldb_message
*msg
;
1239 struct replPropertyMetaDataBlob
*rmd
;
1240 struct replPropertyMetaDataBlob omd
;
1241 const struct ldb_val
*omd_value
;
1242 struct replPropertyMetaDataBlob nmd
;
1243 struct ldb_val nmd_value
;
1245 uint32_t removed_attrs
= 0;
1249 ldb
= ldb_module_get_ctx(ar
->module
);
1250 msg
= ar
->objs
->objects
[ar
->index_current
].msg
;
1251 rmd
= ar
->objs
->objects
[ar
->index_current
].meta_data
;
1256 * TODO: check repl data is correct after a rename
1258 if (ldb_dn_compare(msg
->dn
, ar
->search_msg
->dn
) != 0) {
1259 ldb_debug(ldb
, LDB_DEBUG_TRACE
, "replmd_replicated_request rename %s => %s\n",
1260 ldb_dn_get_linearized(ar
->search_msg
->dn
),
1261 ldb_dn_get_linearized(msg
->dn
));
1262 if (ldb_rename(ldb
, ar
->search_msg
->dn
, msg
->dn
) != LDB_SUCCESS
) {
1263 ldb_debug(ldb
, LDB_DEBUG_FATAL
, "replmd_replicated_request rename %s => %s failed - %s\n",
1264 ldb_dn_get_linearized(ar
->search_msg
->dn
),
1265 ldb_dn_get_linearized(msg
->dn
),
1266 ldb_errstring(ldb
));
1267 return replmd_replicated_request_werror(ar
, WERR_DS_DRA_DB_ERROR
);
1271 /* find existing meta data */
1272 omd_value
= ldb_msg_find_ldb_val(ar
->search_msg
, "replPropertyMetaData");
1274 ndr_err
= ndr_pull_struct_blob(omd_value
, ar
,
1275 lp_iconv_convenience(ldb_get_opaque(ldb
, "loadparm")), &omd
,
1276 (ndr_pull_flags_fn_t
)ndr_pull_replPropertyMetaDataBlob
);
1277 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
1278 NTSTATUS nt_status
= ndr_map_error2ntstatus(ndr_err
);
1279 return replmd_replicated_request_werror(ar
, ntstatus_to_werror(nt_status
));
1282 if (omd
.version
!= 1) {
1283 return replmd_replicated_request_werror(ar
, WERR_DS_DRA_INTERNAL_ERROR
);
1289 nmd
.ctr
.ctr1
.count
= omd
.ctr
.ctr1
.count
+ rmd
->ctr
.ctr1
.count
;
1290 nmd
.ctr
.ctr1
.array
= talloc_array(ar
,
1291 struct replPropertyMetaData1
,
1292 nmd
.ctr
.ctr1
.count
);
1293 if (!nmd
.ctr
.ctr1
.array
) return replmd_replicated_request_werror(ar
, WERR_NOMEM
);
1295 /* first copy the old meta data */
1296 for (i
=0; i
< omd
.ctr
.ctr1
.count
; i
++) {
1297 nmd
.ctr
.ctr1
.array
[ni
] = omd
.ctr
.ctr1
.array
[i
];
1301 /* now merge in the new meta data */
1302 for (i
=0; i
< rmd
->ctr
.ctr1
.count
; i
++) {
1305 for (j
=0; j
< ni
; j
++) {
1308 if (rmd
->ctr
.ctr1
.array
[i
].attid
!= nmd
.ctr
.ctr1
.array
[j
].attid
) {
1312 cmp
= replmd_replPropertyMetaData1_conflict_compare(&rmd
->ctr
.ctr1
.array
[i
],
1313 &nmd
.ctr
.ctr1
.array
[j
]);
1315 /* replace the entry */
1316 nmd
.ctr
.ctr1
.array
[j
] = rmd
->ctr
.ctr1
.array
[i
];
1321 /* we don't want to apply this change so remove the attribute */
1322 ldb_msg_remove_element(msg
, &msg
->elements
[i
-removed_attrs
]);
1329 if (found
) continue;
1331 nmd
.ctr
.ctr1
.array
[ni
] = rmd
->ctr
.ctr1
.array
[i
];
1336 * finally correct the size of the meta_data array
1338 nmd
.ctr
.ctr1
.count
= ni
;
1341 * the rdn attribute (the alias for the name attribute),
1342 * 'cn' for most objects is the last entry in the meta data array
1345 * sort the new meta data array
1348 struct replPropertyMetaData1
*rdn_p
;
1349 uint32_t rdn_idx
= omd
.ctr
.ctr1
.count
- 1;
1351 rdn_p
= &nmd
.ctr
.ctr1
.array
[rdn_idx
];
1352 replmd_replPropertyMetaDataCtr1_sort(&nmd
.ctr
.ctr1
, &rdn_p
->attid
);
1355 /* create the meta data value */
1356 ndr_err
= ndr_push_struct_blob(&nmd_value
, msg
,
1357 lp_iconv_convenience(ldb_get_opaque(ldb
, "loadparm")),
1359 (ndr_push_flags_fn_t
)ndr_push_replPropertyMetaDataBlob
);
1360 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
1361 NTSTATUS nt_status
= ndr_map_error2ntstatus(ndr_err
);
1362 return replmd_replicated_request_werror(ar
, ntstatus_to_werror(nt_status
));
1366 * check if some replicated attributes left, otherwise skip the ldb_modify() call
1368 if (msg
->num_elements
== 0) {
1369 ldb_debug(ldb
, LDB_DEBUG_TRACE
, "replmd_replicated_apply_merge[%u]: skip replace\n",
1372 ar
->index_current
++;
1373 return replmd_replicated_apply_next(ar
);
1376 ldb_debug(ldb
, LDB_DEBUG_TRACE
, "replmd_replicated_apply_merge[%u]: replace %u attributes\n",
1377 ar
->index_current
, msg
->num_elements
);
1379 ret
= ldb_sequence_number(ldb
, LDB_SEQ_NEXT
, &seq_num
);
1380 if (ret
!= LDB_SUCCESS
) {
1381 return replmd_replicated_request_error(ar
, ret
);
1384 for (i
=0; i
<ni
; i
++) {
1385 nmd
.ctr
.ctr1
.array
[i
].local_usn
= seq_num
;
1389 * when we know that we'll modify the record, add the whenChanged, uSNChanged
1390 * and replPopertyMetaData attributes
1392 ret
= ldb_msg_add_string(msg
, "whenChanged", ar
->objs
->objects
[ar
->index_current
].when_changed
);
1393 if (ret
!= LDB_SUCCESS
) {
1394 return replmd_replicated_request_error(ar
, ret
);
1396 ret
= samdb_msg_add_uint64(ldb
, msg
, msg
, "uSNChanged", seq_num
);
1397 if (ret
!= LDB_SUCCESS
) {
1398 return replmd_replicated_request_error(ar
, ret
);
1400 ret
= ldb_msg_add_value(msg
, "replPropertyMetaData", &nmd_value
, NULL
);
1401 if (ret
!= LDB_SUCCESS
) {
1402 return replmd_replicated_request_error(ar
, ret
);
1405 replmd_ldb_message_sort(msg
, ar
->schema
);
1407 /* we want to replace the old values */
1408 for (i
=0; i
< msg
->num_elements
; i
++) {
1409 msg
->elements
[i
].flags
= LDB_FLAG_MOD_REPLACE
;
1412 ret
= replmd_notify(ar
->module
, msg
->dn
, seq_num
);
1413 if (ret
!= LDB_SUCCESS
) {
1414 return replmd_replicated_request_error(ar
, ret
);
1418 char *s
= ldb_ldif_message_string(ldb
, ar
, LDB_CHANGETYPE_MODIFY
, msg
);
1419 DEBUG(4, ("DRS replication modify message:\n%s\n", s
));
1423 ret
= ldb_build_mod_req(&change_req
,
1429 replmd_replicated_apply_merge_callback
,
1431 if (ret
!= LDB_SUCCESS
) return replmd_replicated_request_error(ar
, ret
);
1433 return ldb_next_request(ar
->module
, change_req
);
1436 static int replmd_replicated_apply_search_callback(struct ldb_request
*req
,
1437 struct ldb_reply
*ares
)
1439 struct replmd_replicated_request
*ar
= talloc_get_type(req
->context
,
1440 struct replmd_replicated_request
);
1444 return ldb_module_done(ar
->req
, NULL
, NULL
,
1445 LDB_ERR_OPERATIONS_ERROR
);
1447 if (ares
->error
!= LDB_SUCCESS
&&
1448 ares
->error
!= LDB_ERR_NO_SUCH_OBJECT
) {
1449 return ldb_module_done(ar
->req
, ares
->controls
,
1450 ares
->response
, ares
->error
);
1453 switch (ares
->type
) {
1454 case LDB_REPLY_ENTRY
:
1455 ar
->search_msg
= talloc_steal(ar
, ares
->message
);
1458 case LDB_REPLY_REFERRAL
:
1459 /* we ignore referrals */
1462 case LDB_REPLY_DONE
:
1463 if (ar
->search_msg
!= NULL
) {
1464 ret
= replmd_replicated_apply_merge(ar
);
1466 ret
= replmd_replicated_apply_add(ar
);
1468 if (ret
!= LDB_SUCCESS
) {
1469 return ldb_module_done(ar
->req
, NULL
, NULL
, ret
);
1477 static int replmd_replicated_uptodate_vector(struct replmd_replicated_request
*ar
);
1479 static int replmd_replicated_apply_next(struct replmd_replicated_request
*ar
)
1481 struct ldb_context
*ldb
;
1485 struct ldb_request
*search_req
;
1487 if (ar
->index_current
>= ar
->objs
->num_objects
) {
1488 /* done with it, go to next stage */
1489 return replmd_replicated_uptodate_vector(ar
);
1492 ldb
= ldb_module_get_ctx(ar
->module
);
1493 ar
->search_msg
= NULL
;
1495 tmp_str
= ldb_binary_encode(ar
, ar
->objs
->objects
[ar
->index_current
].guid_value
);
1496 if (!tmp_str
) return replmd_replicated_request_werror(ar
, WERR_NOMEM
);
1498 filter
= talloc_asprintf(ar
, "(objectGUID=%s)", tmp_str
);
1499 if (!filter
) return replmd_replicated_request_werror(ar
, WERR_NOMEM
);
1500 talloc_free(tmp_str
);
1502 ret
= ldb_build_search_req(&search_req
,
1505 ar
->objs
->partition_dn
,
1511 replmd_replicated_apply_search_callback
,
1513 if (ret
!= LDB_SUCCESS
) return replmd_replicated_request_error(ar
, ret
);
1515 return ldb_next_request(ar
->module
, search_req
);
1518 static int replmd_replicated_uptodate_modify_callback(struct ldb_request
*req
,
1519 struct ldb_reply
*ares
)
1521 struct ldb_context
*ldb
;
1522 struct replmd_replicated_request
*ar
= talloc_get_type(req
->context
,
1523 struct replmd_replicated_request
);
1524 ldb
= ldb_module_get_ctx(ar
->module
);
1527 return ldb_module_done(ar
->req
, NULL
, NULL
,
1528 LDB_ERR_OPERATIONS_ERROR
);
1530 if (ares
->error
!= LDB_SUCCESS
) {
1531 return ldb_module_done(ar
->req
, ares
->controls
,
1532 ares
->response
, ares
->error
);
1535 if (ares
->type
!= LDB_REPLY_DONE
) {
1536 ldb_set_errstring(ldb
, "Invalid reply type\n!");
1537 return ldb_module_done(ar
->req
, NULL
, NULL
,
1538 LDB_ERR_OPERATIONS_ERROR
);
1543 return ldb_module_done(ar
->req
, NULL
, NULL
, LDB_SUCCESS
);
1546 static int replmd_drsuapi_DsReplicaCursor2_compare(const struct drsuapi_DsReplicaCursor2
*c1
,
1547 const struct drsuapi_DsReplicaCursor2
*c2
)
1549 return GUID_compare(&c1
->source_dsa_invocation_id
, &c2
->source_dsa_invocation_id
);
1552 static int replmd_replicated_uptodate_modify(struct replmd_replicated_request
*ar
)
1554 struct ldb_context
*ldb
;
1555 struct ldb_request
*change_req
;
1556 enum ndr_err_code ndr_err
;
1557 struct ldb_message
*msg
;
1558 struct replUpToDateVectorBlob ouv
;
1559 const struct ldb_val
*ouv_value
;
1560 const struct drsuapi_DsReplicaCursor2CtrEx
*ruv
;
1561 struct replUpToDateVectorBlob nuv
;
1562 struct ldb_val nuv_value
;
1563 struct ldb_message_element
*nuv_el
= NULL
;
1564 const struct GUID
*our_invocation_id
;
1565 struct ldb_message_element
*orf_el
= NULL
;
1566 struct repsFromToBlob nrf
;
1567 struct ldb_val
*nrf_value
= NULL
;
1568 struct ldb_message_element
*nrf_el
= NULL
;
1571 time_t t
= time(NULL
);
1575 ldb
= ldb_module_get_ctx(ar
->module
);
1576 ruv
= ar
->objs
->uptodateness_vector
;
1582 unix_to_nt_time(&now
, t
);
1585 * first create the new replUpToDateVector
1587 ouv_value
= ldb_msg_find_ldb_val(ar
->search_msg
, "replUpToDateVector");
1589 ndr_err
= ndr_pull_struct_blob(ouv_value
, ar
,
1590 lp_iconv_convenience(ldb_get_opaque(ldb
, "loadparm")), &ouv
,
1591 (ndr_pull_flags_fn_t
)ndr_pull_replUpToDateVectorBlob
);
1592 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
1593 NTSTATUS nt_status
= ndr_map_error2ntstatus(ndr_err
);
1594 return replmd_replicated_request_werror(ar
, ntstatus_to_werror(nt_status
));
1597 if (ouv
.version
!= 2) {
1598 return replmd_replicated_request_werror(ar
, WERR_DS_DRA_INTERNAL_ERROR
);
1603 * the new uptodateness vector will at least
1604 * contain 1 entry, one for the source_dsa
1606 * plus optional values from our old vector and the one from the source_dsa
1608 nuv
.ctr
.ctr2
.count
= 1 + ouv
.ctr
.ctr2
.count
;
1609 if (ruv
) nuv
.ctr
.ctr2
.count
+= ruv
->count
;
1610 nuv
.ctr
.ctr2
.cursors
= talloc_array(ar
,
1611 struct drsuapi_DsReplicaCursor2
,
1612 nuv
.ctr
.ctr2
.count
);
1613 if (!nuv
.ctr
.ctr2
.cursors
) return replmd_replicated_request_werror(ar
, WERR_NOMEM
);
1615 /* first copy the old vector */
1616 for (i
=0; i
< ouv
.ctr
.ctr2
.count
; i
++) {
1617 nuv
.ctr
.ctr2
.cursors
[ni
] = ouv
.ctr
.ctr2
.cursors
[i
];
1621 /* get our invocation_id if we have one already attached to the ldb */
1622 our_invocation_id
= samdb_ntds_invocation_id(ldb
);
1624 /* merge in the source_dsa vector is available */
1625 for (i
=0; (ruv
&& i
< ruv
->count
); i
++) {
1628 if (our_invocation_id
&&
1629 GUID_equal(&ruv
->cursors
[i
].source_dsa_invocation_id
,
1630 our_invocation_id
)) {
1634 for (j
=0; j
< ni
; j
++) {
1635 if (!GUID_equal(&ruv
->cursors
[i
].source_dsa_invocation_id
,
1636 &nuv
.ctr
.ctr2
.cursors
[j
].source_dsa_invocation_id
)) {
1643 * we update only the highest_usn and not the latest_sync_success time,
1644 * because the last success stands for direct replication
1646 if (ruv
->cursors
[i
].highest_usn
> nuv
.ctr
.ctr2
.cursors
[j
].highest_usn
) {
1647 nuv
.ctr
.ctr2
.cursors
[j
].highest_usn
= ruv
->cursors
[i
].highest_usn
;
1652 if (found
) continue;
1654 /* if it's not there yet, add it */
1655 nuv
.ctr
.ctr2
.cursors
[ni
] = ruv
->cursors
[i
];
1660 * merge in the current highwatermark for the source_dsa
1663 for (j
=0; j
< ni
; j
++) {
1664 if (!GUID_equal(&ar
->objs
->source_dsa
->source_dsa_invocation_id
,
1665 &nuv
.ctr
.ctr2
.cursors
[j
].source_dsa_invocation_id
)) {
1672 * here we update the highest_usn and last_sync_success time
1673 * because we're directly replicating from the source_dsa
1675 * and use the tmp_highest_usn because this is what we have just applied
1678 nuv
.ctr
.ctr2
.cursors
[j
].highest_usn
= ar
->objs
->source_dsa
->highwatermark
.tmp_highest_usn
;
1679 nuv
.ctr
.ctr2
.cursors
[j
].last_sync_success
= now
;
1684 * here we update the highest_usn and last_sync_success time
1685 * because we're directly replicating from the source_dsa
1687 * and use the tmp_highest_usn because this is what we have just applied
1690 nuv
.ctr
.ctr2
.cursors
[ni
].source_dsa_invocation_id
= ar
->objs
->source_dsa
->source_dsa_invocation_id
;
1691 nuv
.ctr
.ctr2
.cursors
[ni
].highest_usn
= ar
->objs
->source_dsa
->highwatermark
.tmp_highest_usn
;
1692 nuv
.ctr
.ctr2
.cursors
[ni
].last_sync_success
= now
;
1697 * finally correct the size of the cursors array
1699 nuv
.ctr
.ctr2
.count
= ni
;
1704 qsort(nuv
.ctr
.ctr2
.cursors
, nuv
.ctr
.ctr2
.count
,
1705 sizeof(struct drsuapi_DsReplicaCursor2
),
1706 (comparison_fn_t
)replmd_drsuapi_DsReplicaCursor2_compare
);
1709 * create the change ldb_message
1711 msg
= ldb_msg_new(ar
);
1712 if (!msg
) return replmd_replicated_request_werror(ar
, WERR_NOMEM
);
1713 msg
->dn
= ar
->search_msg
->dn
;
1715 ndr_err
= ndr_push_struct_blob(&nuv_value
, msg
,
1716 lp_iconv_convenience(ldb_get_opaque(ldb
, "loadparm")),
1718 (ndr_push_flags_fn_t
)ndr_push_replUpToDateVectorBlob
);
1719 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
1720 NTSTATUS nt_status
= ndr_map_error2ntstatus(ndr_err
);
1721 return replmd_replicated_request_werror(ar
, ntstatus_to_werror(nt_status
));
1723 ret
= ldb_msg_add_value(msg
, "replUpToDateVector", &nuv_value
, &nuv_el
);
1724 if (ret
!= LDB_SUCCESS
) {
1725 return replmd_replicated_request_error(ar
, ret
);
1727 nuv_el
->flags
= LDB_FLAG_MOD_REPLACE
;
1730 * now create the new repsFrom value from the given repsFromTo1 structure
1734 nrf
.ctr
.ctr1
= *ar
->objs
->source_dsa
;
1735 /* and fix some values... */
1736 nrf
.ctr
.ctr1
.consecutive_sync_failures
= 0;
1737 nrf
.ctr
.ctr1
.last_success
= now
;
1738 nrf
.ctr
.ctr1
.last_attempt
= now
;
1739 nrf
.ctr
.ctr1
.result_last_attempt
= WERR_OK
;
1740 nrf
.ctr
.ctr1
.highwatermark
.highest_usn
= nrf
.ctr
.ctr1
.highwatermark
.tmp_highest_usn
;
1743 * first see if we already have a repsFrom value for the current source dsa
1744 * if so we'll later replace this value
1746 orf_el
= ldb_msg_find_element(ar
->search_msg
, "repsFrom");
1748 for (i
=0; i
< orf_el
->num_values
; i
++) {
1749 struct repsFromToBlob
*trf
;
1751 trf
= talloc(ar
, struct repsFromToBlob
);
1752 if (!trf
) return replmd_replicated_request_werror(ar
, WERR_NOMEM
);
1754 ndr_err
= ndr_pull_struct_blob(&orf_el
->values
[i
], trf
, lp_iconv_convenience(ldb_get_opaque(ldb
, "loadparm")), trf
,
1755 (ndr_pull_flags_fn_t
)ndr_pull_repsFromToBlob
);
1756 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
1757 NTSTATUS nt_status
= ndr_map_error2ntstatus(ndr_err
);
1758 return replmd_replicated_request_werror(ar
, ntstatus_to_werror(nt_status
));
1761 if (trf
->version
!= 1) {
1762 return replmd_replicated_request_werror(ar
, WERR_DS_DRA_INTERNAL_ERROR
);
1766 * we compare the source dsa objectGUID not the invocation_id
1767 * because we want only one repsFrom value per source dsa
1768 * and when the invocation_id of the source dsa has changed we don't need
1769 * the old repsFrom with the old invocation_id
1771 if (!GUID_equal(&trf
->ctr
.ctr1
.source_dsa_obj_guid
,
1772 &ar
->objs
->source_dsa
->source_dsa_obj_guid
)) {
1778 nrf_value
= &orf_el
->values
[i
];
1783 * copy over all old values to the new ldb_message
1785 ret
= ldb_msg_add_empty(msg
, "repsFrom", 0, &nrf_el
);
1786 if (ret
!= LDB_SUCCESS
) return replmd_replicated_request_error(ar
, ret
);
1791 * if we haven't found an old repsFrom value for the current source dsa
1792 * we'll add a new value
1795 struct ldb_val zero_value
;
1796 ZERO_STRUCT(zero_value
);
1797 ret
= ldb_msg_add_value(msg
, "repsFrom", &zero_value
, &nrf_el
);
1798 if (ret
!= LDB_SUCCESS
) return replmd_replicated_request_error(ar
, ret
);
1800 nrf_value
= &nrf_el
->values
[nrf_el
->num_values
- 1];
1803 /* we now fill the value which is already attached to ldb_message */
1804 ndr_err
= ndr_push_struct_blob(nrf_value
, msg
,
1805 lp_iconv_convenience(ldb_get_opaque(ldb
, "loadparm")),
1807 (ndr_push_flags_fn_t
)ndr_push_repsFromToBlob
);
1808 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
1809 NTSTATUS nt_status
= ndr_map_error2ntstatus(ndr_err
);
1810 return replmd_replicated_request_werror(ar
, ntstatus_to_werror(nt_status
));
1814 * the ldb_message_element for the attribute, has all the old values and the new one
1815 * so we'll replace the whole attribute with all values
1817 nrf_el
->flags
= LDB_FLAG_MOD_REPLACE
;
1820 char *s
= ldb_ldif_message_string(ldb
, ar
, LDB_CHANGETYPE_MODIFY
, msg
);
1821 DEBUG(4, ("DRS replication uptodate modify message:\n%s\n", s
));
1825 /* prepare the ldb_modify() request */
1826 ret
= ldb_build_mod_req(&change_req
,
1832 replmd_replicated_uptodate_modify_callback
,
1834 if (ret
!= LDB_SUCCESS
) return replmd_replicated_request_error(ar
, ret
);
1836 return ldb_next_request(ar
->module
, change_req
);
1839 static int replmd_replicated_uptodate_search_callback(struct ldb_request
*req
,
1840 struct ldb_reply
*ares
)
1842 struct replmd_replicated_request
*ar
= talloc_get_type(req
->context
,
1843 struct replmd_replicated_request
);
1847 return ldb_module_done(ar
->req
, NULL
, NULL
,
1848 LDB_ERR_OPERATIONS_ERROR
);
1850 if (ares
->error
!= LDB_SUCCESS
&&
1851 ares
->error
!= LDB_ERR_NO_SUCH_OBJECT
) {
1852 return ldb_module_done(ar
->req
, ares
->controls
,
1853 ares
->response
, ares
->error
);
1856 switch (ares
->type
) {
1857 case LDB_REPLY_ENTRY
:
1858 ar
->search_msg
= talloc_steal(ar
, ares
->message
);
1861 case LDB_REPLY_REFERRAL
:
1862 /* we ignore referrals */
1865 case LDB_REPLY_DONE
:
1866 if (ar
->search_msg
== NULL
) {
1867 ret
= replmd_replicated_request_werror(ar
, WERR_DS_DRA_INTERNAL_ERROR
);
1869 ret
= replmd_replicated_uptodate_modify(ar
);
1871 if (ret
!= LDB_SUCCESS
) {
1872 return ldb_module_done(ar
->req
, NULL
, NULL
, ret
);
1881 static int replmd_replicated_uptodate_vector(struct replmd_replicated_request
*ar
)
1883 struct ldb_context
*ldb
;
1885 static const char *attrs
[] = {
1886 "replUpToDateVector",
1890 struct ldb_request
*search_req
;
1892 ldb
= ldb_module_get_ctx(ar
->module
);
1893 ar
->search_msg
= NULL
;
1895 ret
= ldb_build_search_req(&search_req
,
1898 ar
->objs
->partition_dn
,
1904 replmd_replicated_uptodate_search_callback
,
1906 if (ret
!= LDB_SUCCESS
) return replmd_replicated_request_error(ar
, ret
);
1908 return ldb_next_request(ar
->module
, search_req
);
1913 static int replmd_extended_replicated_objects(struct ldb_module
*module
, struct ldb_request
*req
)
1915 struct ldb_context
*ldb
;
1916 struct dsdb_extended_replicated_objects
*objs
;
1917 struct replmd_replicated_request
*ar
;
1918 struct ldb_control
**ctrls
;
1920 struct dsdb_control_current_partition
*partition_ctrl
;
1921 struct replmd_private
*replmd_private
=
1922 talloc_get_type(ldb_module_get_private(module
), struct replmd_private
);
1924 ldb
= ldb_module_get_ctx(module
);
1926 ldb_debug(ldb
, LDB_DEBUG_TRACE
, "replmd_extended_replicated_objects\n");
1928 objs
= talloc_get_type(req
->op
.extended
.data
, struct dsdb_extended_replicated_objects
);
1930 ldb_debug(ldb
, LDB_DEBUG_FATAL
, "replmd_extended_replicated_objects: invalid extended data\n");
1931 return LDB_ERR_PROTOCOL_ERROR
;
1934 if (objs
->version
!= DSDB_EXTENDED_REPLICATED_OBJECTS_VERSION
) {
1935 ldb_debug(ldb
, LDB_DEBUG_FATAL
, "replmd_extended_replicated_objects: extended data invalid version [%u != %u]\n",
1936 objs
->version
, DSDB_EXTENDED_REPLICATED_OBJECTS_VERSION
);
1937 return LDB_ERR_PROTOCOL_ERROR
;
1940 ar
= replmd_ctx_init(module
, req
);
1942 return LDB_ERR_OPERATIONS_ERROR
;
1945 ar
->schema
= dsdb_get_schema(ldb
);
1947 ldb_debug_set(ldb
, LDB_DEBUG_FATAL
, "replmd_ctx_init: no loaded schema found\n");
1949 return LDB_ERR_CONSTRAINT_VIOLATION
;
1952 ctrls
= req
->controls
;
1954 if (req
->controls
) {
1955 req
->controls
= talloc_memdup(ar
, req
->controls
,
1956 talloc_get_size(req
->controls
));
1957 if (!req
->controls
) return replmd_replicated_request_werror(ar
, WERR_NOMEM
);
1960 ret
= ldb_request_add_control(req
, DSDB_CONTROL_REPLICATED_UPDATE_OID
, false, NULL
);
1961 if (ret
!= LDB_SUCCESS
) {
1966 add the DSDB_CONTROL_CURRENT_PARTITION_OID control. This
1967 tells the partition module which partition this request is
1968 directed at. That is important as the partition roots appear
1969 twice in the directory, once as mount points in the top
1970 level store, and once as the roots of each partition. The
1971 replication code wants to operate on the root of the
1972 partitions, not the top level mount points
1974 partition_ctrl
= talloc(req
, struct dsdb_control_current_partition
);
1975 if (partition_ctrl
== NULL
) {
1976 if (!partition_ctrl
) return replmd_replicated_request_werror(ar
, WERR_NOMEM
);
1978 partition_ctrl
->version
= DSDB_CONTROL_CURRENT_PARTITION_VERSION
;
1979 partition_ctrl
->dn
= objs
->partition_dn
;
1981 ret
= ldb_request_add_control(req
, DSDB_CONTROL_CURRENT_PARTITION_OID
, false, partition_ctrl
);
1982 if (ret
!= LDB_SUCCESS
) {
1986 ar
->controls
= req
->controls
;
1987 req
->controls
= ctrls
;
1989 DEBUG(4,("linked_attributes_count=%u\n", objs
->linked_attributes_count
));
1991 /* save away the linked attributes for the end of the
1993 for (i
=0; i
<ar
->objs
->linked_attributes_count
; i
++) {
1994 struct la_entry
*la_entry
;
1996 if (replmd_private
->la_ctx
== NULL
) {
1997 replmd_private
->la_ctx
= talloc_new(replmd_private
);
1999 la_entry
= talloc(replmd_private
->la_ctx
, struct la_entry
);
2000 if (la_entry
== NULL
) {
2002 return LDB_ERR_OPERATIONS_ERROR
;
2004 la_entry
->la
= talloc(la_entry
, struct drsuapi_DsReplicaLinkedAttribute
);
2005 if (la_entry
->la
== NULL
) {
2006 talloc_free(la_entry
);
2008 return LDB_ERR_OPERATIONS_ERROR
;
2010 *la_entry
->la
= ar
->objs
->linked_attributes
[i
];
2012 /* we need to steal the non-scalars so they stay
2013 around until the end of the transaction */
2014 talloc_steal(la_entry
->la
, la_entry
->la
->identifier
);
2015 talloc_steal(la_entry
->la
, la_entry
->la
->value
.blob
);
2017 DLIST_ADD(replmd_private
->la_list
, la_entry
);
2020 return replmd_replicated_apply_next(ar
);
2024 process one linked attribute structure
2026 static int replmd_process_linked_attribute(struct ldb_module
*module
,
2027 struct la_entry
*la_entry
)
2029 struct drsuapi_DsReplicaLinkedAttribute
*la
= la_entry
->la
;
2030 struct ldb_context
*ldb
= ldb_module_get_ctx(module
);
2031 struct drsuapi_DsReplicaObjectIdentifier3 target
;
2032 struct ldb_message
*msg
;
2033 struct ldb_message_element
*ret_el
;
2034 TALLOC_CTX
*tmp_ctx
= talloc_new(la_entry
);
2035 enum ndr_err_code ndr_err
;
2037 struct ldb_request
*mod_req
;
2039 const struct dsdb_attribute
*attr
;
2042 linked_attributes[0]:
2043 &objs->linked_attributes[i]: struct drsuapi_DsReplicaLinkedAttribute
2045 identifier: struct drsuapi_DsReplicaObjectIdentifier
2046 __ndr_size : 0x0000003a (58)
2047 __ndr_size_sid : 0x00000000 (0)
2048 guid : 8e95b6a9-13dd-4158-89db-3220a5be5cc7
2050 __ndr_size_dn : 0x00000000 (0)
2052 attid : DRSUAPI_ATTRIBUTE_member (0x1F)
2053 value: struct drsuapi_DsAttributeValue
2054 __ndr_size : 0x0000007e (126)
2056 blob : DATA_BLOB length=126
2057 flags : 0x00000001 (1)
2058 1: DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE
2059 originating_add_time : Wed Sep 2 22:20:01 2009 EST
2060 meta_data: struct drsuapi_DsReplicaMetaData
2061 version : 0x00000015 (21)
2062 originating_change_time : Wed Sep 2 23:39:07 2009 EST
2063 originating_invocation_id: 794640f3-18cf-40ee-a211-a93992b67a64
2064 originating_usn : 0x000000000001e19c (123292)
2065 &target: struct drsuapi_DsReplicaObjectIdentifier3
2066 __ndr_size : 0x0000007e (126)
2067 __ndr_size_sid : 0x0000001c (28)
2068 guid : 7639e594-db75-4086-b0d4-67890ae46031
2069 sid : S-1-5-21-2848215498-2472035911-1947525656-19924
2070 __ndr_size_dn : 0x00000022 (34)
2071 dn : 'CN=UOne,OU=TestOU,DC=vsofs8,DC=com'
2074 NDR_PRINT_DEBUG(drsuapi_DsReplicaLinkedAttribute
, la
);
2077 /* decode the target of the link */
2078 ndr_err
= ndr_pull_struct_blob(la
->value
.blob
,
2079 tmp_ctx
, lp_iconv_convenience(ldb_get_opaque(ldb
, "loadparm")),
2081 (ndr_pull_flags_fn_t
)ndr_pull_drsuapi_DsReplicaObjectIdentifier3
);
2082 if (ndr_err
!= NDR_ERR_SUCCESS
) {
2083 DEBUG(0,("Unable to decode linked_attribute target\n"));
2084 dump_data(4, la
->value
.blob
->data
, la
->value
.blob
->length
);
2085 talloc_free(tmp_ctx
);
2086 return LDB_ERR_OPERATIONS_ERROR
;
2089 NDR_PRINT_DEBUG(drsuapi_DsReplicaObjectIdentifier3
, &target
);
2092 /* construct a modify request for this attribute change */
2093 msg
= ldb_msg_new(tmp_ctx
);
2096 talloc_free(tmp_ctx
);
2097 return LDB_ERR_OPERATIONS_ERROR
;
2100 ret
= dsdb_find_dn_by_guid(ldb
, tmp_ctx
,
2101 GUID_string(tmp_ctx
, &la
->identifier
->guid
), &msg
->dn
);
2102 if (ret
!= LDB_SUCCESS
) {
2103 talloc_free(tmp_ctx
);
2107 /* find the attribute being modified */
2108 attr
= dsdb_attribute_by_attributeID_id(dsdb_get_schema(ldb
), la
->attid
);
2110 DEBUG(0, (__location__
": Unable to find attributeID 0x%x\n", la
->attid
));
2111 talloc_free(tmp_ctx
);
2112 return LDB_ERR_OPERATIONS_ERROR
;
2115 if (la
->flags
& DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE
) {
2116 ret
= ldb_msg_add_empty(msg
, attr
->lDAPDisplayName
,
2117 LDB_FLAG_MOD_ADD
, &ret_el
);
2119 ret
= ldb_msg_add_empty(msg
, attr
->lDAPDisplayName
,
2120 LDB_FLAG_MOD_DELETE
, &ret_el
);
2122 if (ret
!= LDB_SUCCESS
) {
2123 talloc_free(tmp_ctx
);
2126 ret_el
->values
= talloc_array(msg
, struct ldb_val
, 1);
2127 if (!ret_el
->values
) {
2129 talloc_free(tmp_ctx
);
2130 return LDB_ERR_OPERATIONS_ERROR
;
2132 ret_el
->num_values
= 1;
2134 target_dn
= talloc_asprintf(tmp_ctx
, "<GUID=%s>;<SID=%s>;%s",
2135 GUID_string(tmp_ctx
, &target
.guid
),
2136 dom_sid_string(tmp_ctx
, &target
.sid
),
2138 if (target_dn
== NULL
) {
2140 talloc_free(tmp_ctx
);
2141 return LDB_ERR_OPERATIONS_ERROR
;
2143 ret_el
->values
[0] = data_blob_string_const(target_dn
);
2145 ret
= ldb_build_mod_req(&mod_req
, ldb
, tmp_ctx
,
2149 ldb_op_default_callback
,
2151 if (ret
!= LDB_SUCCESS
) {
2152 talloc_free(tmp_ctx
);
2155 talloc_steal(mod_req
, msg
);
2158 DEBUG(4,("Applying DRS linked attribute change:\n%s\n",
2159 ldb_ldif_message_string(ldb
, tmp_ctx
, LDB_CHANGETYPE_MODIFY
, msg
)));
2162 /* Run the new request */
2163 ret
= ldb_next_request(module
, mod_req
);
2165 /* we need to wait for this to finish, as we are being called
2166 from the synchronous end_transaction hook of this module */
2167 if (ret
== LDB_SUCCESS
) {
2168 ret
= ldb_wait(mod_req
->handle
, LDB_WAIT_ALL
);
2171 if (ret
!= LDB_SUCCESS
) {
2172 ldb_debug(ldb
, LDB_DEBUG_WARNING
, "Failed to apply linked attribute change '%s' %s\n",
2174 ldb_ldif_message_string(ldb
, tmp_ctx
, LDB_CHANGETYPE_MODIFY
, msg
));
2177 talloc_free(tmp_ctx
);
2182 static int replmd_extended(struct ldb_module
*module
, struct ldb_request
*req
)
2184 if (strcmp(req
->op
.extended
.oid
, DSDB_EXTENDED_REPLICATED_OBJECTS_OID
) == 0) {
2185 return replmd_extended_replicated_objects(module
, req
);
2188 return ldb_next_request(module
, req
);
2193 we hook into the transaction operations to allow us to
2194 perform the linked attribute updates at the end of the whole
2195 transaction. This allows a forward linked attribute to be created
2196 before the object is created. During a vampire, w2k8 sends us linked
2197 attributes before the objects they are part of.
2199 static int replmd_start_transaction(struct ldb_module
*module
)
2201 /* create our private structure for this transaction */
2203 struct replmd_private
*replmd_private
= talloc_get_type(ldb_module_get_private(module
),
2204 struct replmd_private
);
2205 talloc_free(replmd_private
->la_ctx
);
2206 replmd_private
->la_list
= NULL
;
2207 replmd_private
->la_ctx
= NULL
;
2209 for (i
=0; i
<replmd_private
->num_ncs
; i
++) {
2210 replmd_private
->ncs
[i
].mod_usn
= 0;
2213 return ldb_next_start_trans(module
);
2217 on prepare commit we loop over our queued la_context structures and
2220 static int replmd_prepare_commit(struct ldb_module
*module
)
2222 struct replmd_private
*replmd_private
=
2223 talloc_get_type(ldb_module_get_private(module
), struct replmd_private
);
2224 struct la_entry
*la
, *prev
;
2227 /* walk the list backwards, to do the first entry first, as we
2228 * added the entries with DLIST_ADD() which puts them at the
2229 * start of the list */
2230 for (la
= replmd_private
->la_list
; la
&& la
->next
; la
=la
->next
) ;
2232 for (; la
; la
=prev
) {
2234 DLIST_REMOVE(replmd_private
->la_list
, la
);
2235 ret
= replmd_process_linked_attribute(module
, la
);
2236 if (ret
!= LDB_SUCCESS
) {
2241 talloc_free(replmd_private
->la_ctx
);
2242 replmd_private
->la_list
= NULL
;
2243 replmd_private
->la_ctx
= NULL
;
2245 /* possibly change @REPLCHANGED */
2246 ret
= replmd_notify_store(module
);
2247 if (ret
!= LDB_SUCCESS
) {
2251 return ldb_next_prepare_commit(module
);
2254 static int replmd_del_transaction(struct ldb_module
*module
)
2256 struct replmd_private
*replmd_private
=
2257 talloc_get_type(ldb_module_get_private(module
), struct replmd_private
);
2258 talloc_free(replmd_private
->la_ctx
);
2259 replmd_private
->la_list
= NULL
;
2260 replmd_private
->la_ctx
= NULL
;
2261 return ldb_next_del_trans(module
);
2265 _PUBLIC_
const struct ldb_module_ops ldb_repl_meta_data_module_ops
= {
2266 .name
= "repl_meta_data",
2267 .init_context
= replmd_init
,
2269 .modify
= replmd_modify
,
2270 .rename
= replmd_rename
,
2271 .extended
= replmd_extended
,
2272 .start_transaction
= replmd_start_transaction
,
2273 .prepare_commit
= replmd_prepare_commit
,
2274 .del_transaction
= replmd_del_transaction
,