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
);
1356 * check if some replicated attributes left, otherwise skip the ldb_modify() call
1358 if (msg
->num_elements
== 0) {
1359 ldb_debug(ldb
, LDB_DEBUG_TRACE
, "replmd_replicated_apply_merge[%u]: skip replace\n",
1362 ar
->index_current
++;
1363 return replmd_replicated_apply_next(ar
);
1366 ldb_debug(ldb
, LDB_DEBUG_TRACE
, "replmd_replicated_apply_merge[%u]: replace %u attributes\n",
1367 ar
->index_current
, msg
->num_elements
);
1369 ret
= ldb_sequence_number(ldb
, LDB_SEQ_NEXT
, &seq_num
);
1370 if (ret
!= LDB_SUCCESS
) {
1371 return replmd_replicated_request_error(ar
, ret
);
1374 for (i
=0; i
<ni
; i
++) {
1375 nmd
.ctr
.ctr1
.array
[i
].local_usn
= seq_num
;
1378 /* create the meta data value */
1379 ndr_err
= ndr_push_struct_blob(&nmd_value
, msg
,
1380 lp_iconv_convenience(ldb_get_opaque(ldb
, "loadparm")),
1382 (ndr_push_flags_fn_t
)ndr_push_replPropertyMetaDataBlob
);
1383 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
1384 NTSTATUS nt_status
= ndr_map_error2ntstatus(ndr_err
);
1385 return replmd_replicated_request_werror(ar
, ntstatus_to_werror(nt_status
));
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_replicated_uptodate_modify(struct replmd_replicated_request
*ar
)
1548 struct ldb_context
*ldb
;
1549 struct ldb_request
*change_req
;
1550 enum ndr_err_code ndr_err
;
1551 struct ldb_message
*msg
;
1552 struct replUpToDateVectorBlob ouv
;
1553 const struct ldb_val
*ouv_value
;
1554 const struct drsuapi_DsReplicaCursor2CtrEx
*ruv
;
1555 struct replUpToDateVectorBlob nuv
;
1556 struct ldb_val nuv_value
;
1557 struct ldb_message_element
*nuv_el
= NULL
;
1558 const struct GUID
*our_invocation_id
;
1559 struct ldb_message_element
*orf_el
= NULL
;
1560 struct repsFromToBlob nrf
;
1561 struct ldb_val
*nrf_value
= NULL
;
1562 struct ldb_message_element
*nrf_el
= NULL
;
1565 time_t t
= time(NULL
);
1569 ldb
= ldb_module_get_ctx(ar
->module
);
1570 ruv
= ar
->objs
->uptodateness_vector
;
1576 unix_to_nt_time(&now
, t
);
1579 * first create the new replUpToDateVector
1581 ouv_value
= ldb_msg_find_ldb_val(ar
->search_msg
, "replUpToDateVector");
1583 ndr_err
= ndr_pull_struct_blob(ouv_value
, ar
,
1584 lp_iconv_convenience(ldb_get_opaque(ldb
, "loadparm")), &ouv
,
1585 (ndr_pull_flags_fn_t
)ndr_pull_replUpToDateVectorBlob
);
1586 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
1587 NTSTATUS nt_status
= ndr_map_error2ntstatus(ndr_err
);
1588 return replmd_replicated_request_werror(ar
, ntstatus_to_werror(nt_status
));
1591 if (ouv
.version
!= 2) {
1592 return replmd_replicated_request_werror(ar
, WERR_DS_DRA_INTERNAL_ERROR
);
1597 * the new uptodateness vector will at least
1598 * contain 1 entry, one for the source_dsa
1600 * plus optional values from our old vector and the one from the source_dsa
1602 nuv
.ctr
.ctr2
.count
= 1 + ouv
.ctr
.ctr2
.count
;
1603 if (ruv
) nuv
.ctr
.ctr2
.count
+= ruv
->count
;
1604 nuv
.ctr
.ctr2
.cursors
= talloc_array(ar
,
1605 struct drsuapi_DsReplicaCursor2
,
1606 nuv
.ctr
.ctr2
.count
);
1607 if (!nuv
.ctr
.ctr2
.cursors
) return replmd_replicated_request_werror(ar
, WERR_NOMEM
);
1609 /* first copy the old vector */
1610 for (i
=0; i
< ouv
.ctr
.ctr2
.count
; i
++) {
1611 nuv
.ctr
.ctr2
.cursors
[ni
] = ouv
.ctr
.ctr2
.cursors
[i
];
1615 /* get our invocation_id if we have one already attached to the ldb */
1616 our_invocation_id
= samdb_ntds_invocation_id(ldb
);
1618 /* merge in the source_dsa vector is available */
1619 for (i
=0; (ruv
&& i
< ruv
->count
); i
++) {
1622 if (our_invocation_id
&&
1623 GUID_equal(&ruv
->cursors
[i
].source_dsa_invocation_id
,
1624 our_invocation_id
)) {
1628 for (j
=0; j
< ni
; j
++) {
1629 if (!GUID_equal(&ruv
->cursors
[i
].source_dsa_invocation_id
,
1630 &nuv
.ctr
.ctr2
.cursors
[j
].source_dsa_invocation_id
)) {
1637 * we update only the highest_usn and not the latest_sync_success time,
1638 * because the last success stands for direct replication
1640 if (ruv
->cursors
[i
].highest_usn
> nuv
.ctr
.ctr2
.cursors
[j
].highest_usn
) {
1641 nuv
.ctr
.ctr2
.cursors
[j
].highest_usn
= ruv
->cursors
[i
].highest_usn
;
1646 if (found
) continue;
1648 /* if it's not there yet, add it */
1649 nuv
.ctr
.ctr2
.cursors
[ni
] = ruv
->cursors
[i
];
1654 * merge in the current highwatermark for the source_dsa
1657 for (j
=0; j
< ni
; j
++) {
1658 if (!GUID_equal(&ar
->objs
->source_dsa
->source_dsa_invocation_id
,
1659 &nuv
.ctr
.ctr2
.cursors
[j
].source_dsa_invocation_id
)) {
1666 * here we update the highest_usn and last_sync_success time
1667 * because we're directly replicating from the source_dsa
1669 * and use the tmp_highest_usn because this is what we have just applied
1672 nuv
.ctr
.ctr2
.cursors
[j
].highest_usn
= ar
->objs
->source_dsa
->highwatermark
.tmp_highest_usn
;
1673 nuv
.ctr
.ctr2
.cursors
[j
].last_sync_success
= now
;
1678 * here we update the highest_usn and last_sync_success time
1679 * because we're directly replicating from the source_dsa
1681 * and use the tmp_highest_usn because this is what we have just applied
1684 nuv
.ctr
.ctr2
.cursors
[ni
].source_dsa_invocation_id
= ar
->objs
->source_dsa
->source_dsa_invocation_id
;
1685 nuv
.ctr
.ctr2
.cursors
[ni
].highest_usn
= ar
->objs
->source_dsa
->highwatermark
.tmp_highest_usn
;
1686 nuv
.ctr
.ctr2
.cursors
[ni
].last_sync_success
= now
;
1691 * finally correct the size of the cursors array
1693 nuv
.ctr
.ctr2
.count
= ni
;
1698 qsort(nuv
.ctr
.ctr2
.cursors
, nuv
.ctr
.ctr2
.count
,
1699 sizeof(struct drsuapi_DsReplicaCursor2
),
1700 (comparison_fn_t
)drsuapi_DsReplicaCursor2_compare
);
1703 * create the change ldb_message
1705 msg
= ldb_msg_new(ar
);
1706 if (!msg
) return replmd_replicated_request_werror(ar
, WERR_NOMEM
);
1707 msg
->dn
= ar
->search_msg
->dn
;
1709 ndr_err
= ndr_push_struct_blob(&nuv_value
, msg
,
1710 lp_iconv_convenience(ldb_get_opaque(ldb
, "loadparm")),
1712 (ndr_push_flags_fn_t
)ndr_push_replUpToDateVectorBlob
);
1713 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
1714 NTSTATUS nt_status
= ndr_map_error2ntstatus(ndr_err
);
1715 return replmd_replicated_request_werror(ar
, ntstatus_to_werror(nt_status
));
1717 ret
= ldb_msg_add_value(msg
, "replUpToDateVector", &nuv_value
, &nuv_el
);
1718 if (ret
!= LDB_SUCCESS
) {
1719 return replmd_replicated_request_error(ar
, ret
);
1721 nuv_el
->flags
= LDB_FLAG_MOD_REPLACE
;
1724 * now create the new repsFrom value from the given repsFromTo1 structure
1728 nrf
.ctr
.ctr1
= *ar
->objs
->source_dsa
;
1729 /* and fix some values... */
1730 nrf
.ctr
.ctr1
.consecutive_sync_failures
= 0;
1731 nrf
.ctr
.ctr1
.last_success
= now
;
1732 nrf
.ctr
.ctr1
.last_attempt
= now
;
1733 nrf
.ctr
.ctr1
.result_last_attempt
= WERR_OK
;
1734 nrf
.ctr
.ctr1
.highwatermark
.highest_usn
= nrf
.ctr
.ctr1
.highwatermark
.tmp_highest_usn
;
1737 * first see if we already have a repsFrom value for the current source dsa
1738 * if so we'll later replace this value
1740 orf_el
= ldb_msg_find_element(ar
->search_msg
, "repsFrom");
1742 for (i
=0; i
< orf_el
->num_values
; i
++) {
1743 struct repsFromToBlob
*trf
;
1745 trf
= talloc(ar
, struct repsFromToBlob
);
1746 if (!trf
) return replmd_replicated_request_werror(ar
, WERR_NOMEM
);
1748 ndr_err
= ndr_pull_struct_blob(&orf_el
->values
[i
], trf
, lp_iconv_convenience(ldb_get_opaque(ldb
, "loadparm")), trf
,
1749 (ndr_pull_flags_fn_t
)ndr_pull_repsFromToBlob
);
1750 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
1751 NTSTATUS nt_status
= ndr_map_error2ntstatus(ndr_err
);
1752 return replmd_replicated_request_werror(ar
, ntstatus_to_werror(nt_status
));
1755 if (trf
->version
!= 1) {
1756 return replmd_replicated_request_werror(ar
, WERR_DS_DRA_INTERNAL_ERROR
);
1760 * we compare the source dsa objectGUID not the invocation_id
1761 * because we want only one repsFrom value per source dsa
1762 * and when the invocation_id of the source dsa has changed we don't need
1763 * the old repsFrom with the old invocation_id
1765 if (!GUID_equal(&trf
->ctr
.ctr1
.source_dsa_obj_guid
,
1766 &ar
->objs
->source_dsa
->source_dsa_obj_guid
)) {
1772 nrf_value
= &orf_el
->values
[i
];
1777 * copy over all old values to the new ldb_message
1779 ret
= ldb_msg_add_empty(msg
, "repsFrom", 0, &nrf_el
);
1780 if (ret
!= LDB_SUCCESS
) return replmd_replicated_request_error(ar
, ret
);
1785 * if we haven't found an old repsFrom value for the current source dsa
1786 * we'll add a new value
1789 struct ldb_val zero_value
;
1790 ZERO_STRUCT(zero_value
);
1791 ret
= ldb_msg_add_value(msg
, "repsFrom", &zero_value
, &nrf_el
);
1792 if (ret
!= LDB_SUCCESS
) return replmd_replicated_request_error(ar
, ret
);
1794 nrf_value
= &nrf_el
->values
[nrf_el
->num_values
- 1];
1797 /* we now fill the value which is already attached to ldb_message */
1798 ndr_err
= ndr_push_struct_blob(nrf_value
, msg
,
1799 lp_iconv_convenience(ldb_get_opaque(ldb
, "loadparm")),
1801 (ndr_push_flags_fn_t
)ndr_push_repsFromToBlob
);
1802 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
1803 NTSTATUS nt_status
= ndr_map_error2ntstatus(ndr_err
);
1804 return replmd_replicated_request_werror(ar
, ntstatus_to_werror(nt_status
));
1808 * the ldb_message_element for the attribute, has all the old values and the new one
1809 * so we'll replace the whole attribute with all values
1811 nrf_el
->flags
= LDB_FLAG_MOD_REPLACE
;
1814 char *s
= ldb_ldif_message_string(ldb
, ar
, LDB_CHANGETYPE_MODIFY
, msg
);
1815 DEBUG(4, ("DRS replication uptodate modify message:\n%s\n", s
));
1819 /* prepare the ldb_modify() request */
1820 ret
= ldb_build_mod_req(&change_req
,
1826 replmd_replicated_uptodate_modify_callback
,
1828 if (ret
!= LDB_SUCCESS
) return replmd_replicated_request_error(ar
, ret
);
1830 return ldb_next_request(ar
->module
, change_req
);
1833 static int replmd_replicated_uptodate_search_callback(struct ldb_request
*req
,
1834 struct ldb_reply
*ares
)
1836 struct replmd_replicated_request
*ar
= talloc_get_type(req
->context
,
1837 struct replmd_replicated_request
);
1841 return ldb_module_done(ar
->req
, NULL
, NULL
,
1842 LDB_ERR_OPERATIONS_ERROR
);
1844 if (ares
->error
!= LDB_SUCCESS
&&
1845 ares
->error
!= LDB_ERR_NO_SUCH_OBJECT
) {
1846 return ldb_module_done(ar
->req
, ares
->controls
,
1847 ares
->response
, ares
->error
);
1850 switch (ares
->type
) {
1851 case LDB_REPLY_ENTRY
:
1852 ar
->search_msg
= talloc_steal(ar
, ares
->message
);
1855 case LDB_REPLY_REFERRAL
:
1856 /* we ignore referrals */
1859 case LDB_REPLY_DONE
:
1860 if (ar
->search_msg
== NULL
) {
1861 ret
= replmd_replicated_request_werror(ar
, WERR_DS_DRA_INTERNAL_ERROR
);
1863 ret
= replmd_replicated_uptodate_modify(ar
);
1865 if (ret
!= LDB_SUCCESS
) {
1866 return ldb_module_done(ar
->req
, NULL
, NULL
, ret
);
1875 static int replmd_replicated_uptodate_vector(struct replmd_replicated_request
*ar
)
1877 struct ldb_context
*ldb
;
1879 static const char *attrs
[] = {
1880 "replUpToDateVector",
1884 struct ldb_request
*search_req
;
1886 ldb
= ldb_module_get_ctx(ar
->module
);
1887 ar
->search_msg
= NULL
;
1889 ret
= ldb_build_search_req(&search_req
,
1892 ar
->objs
->partition_dn
,
1898 replmd_replicated_uptodate_search_callback
,
1900 if (ret
!= LDB_SUCCESS
) return replmd_replicated_request_error(ar
, ret
);
1902 return ldb_next_request(ar
->module
, search_req
);
1907 static int replmd_extended_replicated_objects(struct ldb_module
*module
, struct ldb_request
*req
)
1909 struct ldb_context
*ldb
;
1910 struct dsdb_extended_replicated_objects
*objs
;
1911 struct replmd_replicated_request
*ar
;
1912 struct ldb_control
**ctrls
;
1914 struct dsdb_control_current_partition
*partition_ctrl
;
1915 struct replmd_private
*replmd_private
=
1916 talloc_get_type(ldb_module_get_private(module
), struct replmd_private
);
1918 ldb
= ldb_module_get_ctx(module
);
1920 ldb_debug(ldb
, LDB_DEBUG_TRACE
, "replmd_extended_replicated_objects\n");
1922 objs
= talloc_get_type(req
->op
.extended
.data
, struct dsdb_extended_replicated_objects
);
1924 ldb_debug(ldb
, LDB_DEBUG_FATAL
, "replmd_extended_replicated_objects: invalid extended data\n");
1925 return LDB_ERR_PROTOCOL_ERROR
;
1928 if (objs
->version
!= DSDB_EXTENDED_REPLICATED_OBJECTS_VERSION
) {
1929 ldb_debug(ldb
, LDB_DEBUG_FATAL
, "replmd_extended_replicated_objects: extended data invalid version [%u != %u]\n",
1930 objs
->version
, DSDB_EXTENDED_REPLICATED_OBJECTS_VERSION
);
1931 return LDB_ERR_PROTOCOL_ERROR
;
1934 ar
= replmd_ctx_init(module
, req
);
1936 return LDB_ERR_OPERATIONS_ERROR
;
1939 ar
->schema
= dsdb_get_schema(ldb
);
1941 ldb_debug_set(ldb
, LDB_DEBUG_FATAL
, "replmd_ctx_init: no loaded schema found\n");
1943 return LDB_ERR_CONSTRAINT_VIOLATION
;
1946 ctrls
= req
->controls
;
1948 if (req
->controls
) {
1949 req
->controls
= talloc_memdup(ar
, req
->controls
,
1950 talloc_get_size(req
->controls
));
1951 if (!req
->controls
) return replmd_replicated_request_werror(ar
, WERR_NOMEM
);
1954 ret
= ldb_request_add_control(req
, DSDB_CONTROL_REPLICATED_UPDATE_OID
, false, NULL
);
1955 if (ret
!= LDB_SUCCESS
) {
1960 add the DSDB_CONTROL_CURRENT_PARTITION_OID control. This
1961 tells the partition module which partition this request is
1962 directed at. That is important as the partition roots appear
1963 twice in the directory, once as mount points in the top
1964 level store, and once as the roots of each partition. The
1965 replication code wants to operate on the root of the
1966 partitions, not the top level mount points
1968 partition_ctrl
= talloc(req
, struct dsdb_control_current_partition
);
1969 if (partition_ctrl
== NULL
) {
1970 if (!partition_ctrl
) return replmd_replicated_request_werror(ar
, WERR_NOMEM
);
1972 partition_ctrl
->version
= DSDB_CONTROL_CURRENT_PARTITION_VERSION
;
1973 partition_ctrl
->dn
= objs
->partition_dn
;
1975 ret
= ldb_request_add_control(req
, DSDB_CONTROL_CURRENT_PARTITION_OID
, false, partition_ctrl
);
1976 if (ret
!= LDB_SUCCESS
) {
1980 ar
->controls
= req
->controls
;
1981 req
->controls
= ctrls
;
1983 DEBUG(4,("linked_attributes_count=%u\n", objs
->linked_attributes_count
));
1985 /* save away the linked attributes for the end of the
1987 for (i
=0; i
<ar
->objs
->linked_attributes_count
; i
++) {
1988 struct la_entry
*la_entry
;
1990 if (replmd_private
->la_ctx
== NULL
) {
1991 replmd_private
->la_ctx
= talloc_new(replmd_private
);
1993 la_entry
= talloc(replmd_private
->la_ctx
, struct la_entry
);
1994 if (la_entry
== NULL
) {
1996 return LDB_ERR_OPERATIONS_ERROR
;
1998 la_entry
->la
= talloc(la_entry
, struct drsuapi_DsReplicaLinkedAttribute
);
1999 if (la_entry
->la
== NULL
) {
2000 talloc_free(la_entry
);
2002 return LDB_ERR_OPERATIONS_ERROR
;
2004 *la_entry
->la
= ar
->objs
->linked_attributes
[i
];
2006 /* we need to steal the non-scalars so they stay
2007 around until the end of the transaction */
2008 talloc_steal(la_entry
->la
, la_entry
->la
->identifier
);
2009 talloc_steal(la_entry
->la
, la_entry
->la
->value
.blob
);
2011 DLIST_ADD(replmd_private
->la_list
, la_entry
);
2014 return replmd_replicated_apply_next(ar
);
2018 process one linked attribute structure
2020 static int replmd_process_linked_attribute(struct ldb_module
*module
,
2021 struct la_entry
*la_entry
)
2023 struct drsuapi_DsReplicaLinkedAttribute
*la
= la_entry
->la
;
2024 struct ldb_context
*ldb
= ldb_module_get_ctx(module
);
2025 struct drsuapi_DsReplicaObjectIdentifier3 target
;
2026 struct ldb_message
*msg
;
2027 struct ldb_message_element
*ret_el
;
2028 TALLOC_CTX
*tmp_ctx
= talloc_new(la_entry
);
2029 enum ndr_err_code ndr_err
;
2031 struct ldb_request
*mod_req
;
2033 const struct dsdb_attribute
*attr
;
2036 linked_attributes[0]:
2037 &objs->linked_attributes[i]: struct drsuapi_DsReplicaLinkedAttribute
2039 identifier: struct drsuapi_DsReplicaObjectIdentifier
2040 __ndr_size : 0x0000003a (58)
2041 __ndr_size_sid : 0x00000000 (0)
2042 guid : 8e95b6a9-13dd-4158-89db-3220a5be5cc7
2044 __ndr_size_dn : 0x00000000 (0)
2046 attid : DRSUAPI_ATTRIBUTE_member (0x1F)
2047 value: struct drsuapi_DsAttributeValue
2048 __ndr_size : 0x0000007e (126)
2050 blob : DATA_BLOB length=126
2051 flags : 0x00000001 (1)
2052 1: DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE
2053 originating_add_time : Wed Sep 2 22:20:01 2009 EST
2054 meta_data: struct drsuapi_DsReplicaMetaData
2055 version : 0x00000015 (21)
2056 originating_change_time : Wed Sep 2 23:39:07 2009 EST
2057 originating_invocation_id: 794640f3-18cf-40ee-a211-a93992b67a64
2058 originating_usn : 0x000000000001e19c (123292)
2059 &target: struct drsuapi_DsReplicaObjectIdentifier3
2060 __ndr_size : 0x0000007e (126)
2061 __ndr_size_sid : 0x0000001c (28)
2062 guid : 7639e594-db75-4086-b0d4-67890ae46031
2063 sid : S-1-5-21-2848215498-2472035911-1947525656-19924
2064 __ndr_size_dn : 0x00000022 (34)
2065 dn : 'CN=UOne,OU=TestOU,DC=vsofs8,DC=com'
2068 NDR_PRINT_DEBUG(drsuapi_DsReplicaLinkedAttribute
, la
);
2071 /* decode the target of the link */
2072 ndr_err
= ndr_pull_struct_blob(la
->value
.blob
,
2073 tmp_ctx
, lp_iconv_convenience(ldb_get_opaque(ldb
, "loadparm")),
2075 (ndr_pull_flags_fn_t
)ndr_pull_drsuapi_DsReplicaObjectIdentifier3
);
2076 if (ndr_err
!= NDR_ERR_SUCCESS
) {
2077 DEBUG(0,("Unable to decode linked_attribute target\n"));
2078 dump_data(4, la
->value
.blob
->data
, la
->value
.blob
->length
);
2079 talloc_free(tmp_ctx
);
2080 return LDB_ERR_OPERATIONS_ERROR
;
2083 NDR_PRINT_DEBUG(drsuapi_DsReplicaObjectIdentifier3
, &target
);
2086 /* construct a modify request for this attribute change */
2087 msg
= ldb_msg_new(tmp_ctx
);
2090 talloc_free(tmp_ctx
);
2091 return LDB_ERR_OPERATIONS_ERROR
;
2094 ret
= dsdb_find_dn_by_guid(ldb
, tmp_ctx
,
2095 GUID_string(tmp_ctx
, &la
->identifier
->guid
), &msg
->dn
);
2096 if (ret
!= LDB_SUCCESS
) {
2097 talloc_free(tmp_ctx
);
2101 /* find the attribute being modified */
2102 attr
= dsdb_attribute_by_attributeID_id(dsdb_get_schema(ldb
), la
->attid
);
2104 DEBUG(0, (__location__
": Unable to find attributeID 0x%x\n", la
->attid
));
2105 talloc_free(tmp_ctx
);
2106 return LDB_ERR_OPERATIONS_ERROR
;
2109 if (la
->flags
& DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE
) {
2110 ret
= ldb_msg_add_empty(msg
, attr
->lDAPDisplayName
,
2111 LDB_FLAG_MOD_ADD
, &ret_el
);
2113 ret
= ldb_msg_add_empty(msg
, attr
->lDAPDisplayName
,
2114 LDB_FLAG_MOD_DELETE
, &ret_el
);
2116 if (ret
!= LDB_SUCCESS
) {
2117 talloc_free(tmp_ctx
);
2120 /* we allocate two entries here, in case we need a remove/add
2122 ret_el
->values
= talloc_array(msg
, struct ldb_val
, 2);
2123 if (!ret_el
->values
) {
2125 talloc_free(tmp_ctx
);
2126 return LDB_ERR_OPERATIONS_ERROR
;
2128 ret_el
->num_values
= 1;
2130 target_dn
= talloc_asprintf(tmp_ctx
, "<GUID=%s>;<SID=%s>;%s",
2131 GUID_string(tmp_ctx
, &target
.guid
),
2132 dom_sid_string(tmp_ctx
, &target
.sid
),
2134 if (target_dn
== NULL
) {
2136 talloc_free(tmp_ctx
);
2137 return LDB_ERR_OPERATIONS_ERROR
;
2139 ret_el
->values
[0] = data_blob_string_const(target_dn
);
2141 ret
= ldb_build_mod_req(&mod_req
, ldb
, tmp_ctx
,
2145 ldb_op_default_callback
,
2147 if (ret
!= LDB_SUCCESS
) {
2148 talloc_free(tmp_ctx
);
2151 talloc_steal(mod_req
, msg
);
2154 DEBUG(4,("Applying DRS linked attribute change:\n%s\n",
2155 ldb_ldif_message_string(ldb
, tmp_ctx
, LDB_CHANGETYPE_MODIFY
, msg
)));
2158 /* Run the new request */
2159 ret
= ldb_next_request(module
, mod_req
);
2161 /* we need to wait for this to finish, as we are being called
2162 from the synchronous end_transaction hook of this module */
2163 if (ret
== LDB_SUCCESS
) {
2164 ret
= ldb_wait(mod_req
->handle
, LDB_WAIT_ALL
);
2167 if (ret
== LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS
) {
2168 /* the link destination exists, we need to update it
2169 * by deleting the old one for the same DN then adding
2171 msg
->elements
= talloc_realloc(msg
, msg
->elements
,
2172 struct ldb_message_element
,
2173 msg
->num_elements
+1);
2174 if (msg
->elements
== NULL
) {
2176 talloc_free(tmp_ctx
);
2177 return LDB_ERR_OPERATIONS_ERROR
;
2179 /* this relies on the backend matching the old entry
2180 only by the DN portion of the extended DN */
2181 msg
->elements
[1] = msg
->elements
[0];
2182 msg
->elements
[0].flags
= LDB_FLAG_MOD_DELETE
;
2183 msg
->num_elements
++;
2185 ret
= ldb_build_mod_req(&mod_req
, ldb
, tmp_ctx
,
2189 ldb_op_default_callback
,
2191 if (ret
!= LDB_SUCCESS
) {
2192 talloc_free(tmp_ctx
);
2196 /* Run the new request */
2197 ret
= ldb_next_request(module
, mod_req
);
2199 if (ret
== LDB_SUCCESS
) {
2200 ret
= ldb_wait(mod_req
->handle
, LDB_WAIT_ALL
);
2204 if (ret
!= LDB_SUCCESS
) {
2205 ldb_debug(ldb
, LDB_DEBUG_WARNING
, "Failed to apply linked attribute change '%s' %s\n",
2207 ldb_ldif_message_string(ldb
, tmp_ctx
, LDB_CHANGETYPE_MODIFY
, msg
));
2211 talloc_free(tmp_ctx
);
2216 static int replmd_extended(struct ldb_module
*module
, struct ldb_request
*req
)
2218 if (strcmp(req
->op
.extended
.oid
, DSDB_EXTENDED_REPLICATED_OBJECTS_OID
) == 0) {
2219 return replmd_extended_replicated_objects(module
, req
);
2222 return ldb_next_request(module
, req
);
2227 we hook into the transaction operations to allow us to
2228 perform the linked attribute updates at the end of the whole
2229 transaction. This allows a forward linked attribute to be created
2230 before the object is created. During a vampire, w2k8 sends us linked
2231 attributes before the objects they are part of.
2233 static int replmd_start_transaction(struct ldb_module
*module
)
2235 /* create our private structure for this transaction */
2237 struct replmd_private
*replmd_private
= talloc_get_type(ldb_module_get_private(module
),
2238 struct replmd_private
);
2239 talloc_free(replmd_private
->la_ctx
);
2240 replmd_private
->la_list
= NULL
;
2241 replmd_private
->la_ctx
= NULL
;
2243 for (i
=0; i
<replmd_private
->num_ncs
; i
++) {
2244 replmd_private
->ncs
[i
].mod_usn
= 0;
2247 return ldb_next_start_trans(module
);
2251 on prepare commit we loop over our queued la_context structures and
2254 static int replmd_prepare_commit(struct ldb_module
*module
)
2256 struct replmd_private
*replmd_private
=
2257 talloc_get_type(ldb_module_get_private(module
), struct replmd_private
);
2258 struct la_entry
*la
, *prev
;
2261 /* walk the list backwards, to do the first entry first, as we
2262 * added the entries with DLIST_ADD() which puts them at the
2263 * start of the list */
2264 for (la
= replmd_private
->la_list
; la
&& la
->next
; la
=la
->next
) ;
2266 for (; la
; la
=prev
) {
2268 DLIST_REMOVE(replmd_private
->la_list
, la
);
2269 ret
= replmd_process_linked_attribute(module
, la
);
2270 if (ret
!= LDB_SUCCESS
) {
2275 talloc_free(replmd_private
->la_ctx
);
2276 replmd_private
->la_list
= NULL
;
2277 replmd_private
->la_ctx
= NULL
;
2279 /* possibly change @REPLCHANGED */
2280 ret
= replmd_notify_store(module
);
2281 if (ret
!= LDB_SUCCESS
) {
2285 return ldb_next_prepare_commit(module
);
2288 static int replmd_del_transaction(struct ldb_module
*module
)
2290 struct replmd_private
*replmd_private
=
2291 talloc_get_type(ldb_module_get_private(module
), struct replmd_private
);
2292 talloc_free(replmd_private
->la_ctx
);
2293 replmd_private
->la_list
= NULL
;
2294 replmd_private
->la_ctx
= NULL
;
2295 return ldb_next_del_trans(module
);
2299 _PUBLIC_
const struct ldb_module_ops ldb_repl_meta_data_module_ops
= {
2300 .name
= "repl_meta_data",
2301 .init_context
= replmd_init
,
2303 .modify
= replmd_modify
,
2304 .rename
= replmd_rename
,
2305 .extended
= replmd_extended
,
2306 .start_transaction
= replmd_start_transaction
,
2307 .prepare_commit
= replmd_prepare_commit
,
2308 .del_transaction
= replmd_del_transaction
,