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 int replmd_replPropertyMetaDataCtr1_sort(struct replPropertyMetaDataCtr1
*ctr1
,
367 const struct dsdb_schema
*schema
,
370 const char *rdn_name
;
371 const struct dsdb_attribute
*rdn_sa
;
373 rdn_name
= ldb_dn_get_rdn_name(dn
);
375 DEBUG(0,(__location__
": No rDN for %s?\n", ldb_dn_get_linearized(dn
)));
376 return LDB_ERR_OPERATIONS_ERROR
;
379 rdn_sa
= dsdb_attribute_by_lDAPDisplayName(schema
, rdn_name
);
380 if (rdn_sa
== NULL
) {
381 DEBUG(0,(__location__
": No sa found for rDN %s for %s\n", rdn_name
, ldb_dn_get_linearized(dn
)));
382 return LDB_ERR_OPERATIONS_ERROR
;
385 DEBUG(6,("Sorting rpmd with attid exception %u rDN=%s DN=%s\n",
386 rdn_sa
->attributeID_id
, rdn_name
, ldb_dn_get_linearized(dn
)));
388 ldb_qsort(ctr1
->array
, ctr1
->count
, sizeof(struct replPropertyMetaData1
),
389 discard_const_p(void, &rdn_sa
->attributeID_id
),
390 (ldb_qsort_cmp_fn_t
)replmd_replPropertyMetaData1_attid_sort
);
395 static int replmd_ldb_message_element_attid_sort(const struct ldb_message_element
*e1
,
396 const struct ldb_message_element
*e2
,
397 const struct dsdb_schema
*schema
)
399 const struct dsdb_attribute
*a1
;
400 const struct dsdb_attribute
*a2
;
403 * TODO: make this faster by caching the dsdb_attribute pointer
404 * on the ldb_messag_element
407 a1
= dsdb_attribute_by_lDAPDisplayName(schema
, e1
->name
);
408 a2
= dsdb_attribute_by_lDAPDisplayName(schema
, e2
->name
);
411 * TODO: remove this check, we should rely on e1 and e2 having valid attribute names
415 return strcasecmp(e1
->name
, e2
->name
);
418 return a1
->attributeID_id
- a2
->attributeID_id
;
421 static void replmd_ldb_message_sort(struct ldb_message
*msg
,
422 const struct dsdb_schema
*schema
)
424 ldb_qsort(msg
->elements
, msg
->num_elements
, sizeof(struct ldb_message_element
),
425 discard_const_p(void, schema
), (ldb_qsort_cmp_fn_t
)replmd_ldb_message_element_attid_sort
);
428 static int replmd_op_callback(struct ldb_request
*req
, struct ldb_reply
*ares
)
430 struct ldb_context
*ldb
;
431 struct replmd_replicated_request
*ac
;
433 ac
= talloc_get_type(req
->context
, struct replmd_replicated_request
);
434 ldb
= ldb_module_get_ctx(ac
->module
);
437 return ldb_module_done(ac
->req
, NULL
, NULL
,
438 LDB_ERR_OPERATIONS_ERROR
);
440 if (ares
->error
!= LDB_SUCCESS
) {
441 return ldb_module_done(ac
->req
, ares
->controls
,
442 ares
->response
, ares
->error
);
445 if (ares
->type
!= LDB_REPLY_DONE
) {
446 ldb_set_errstring(ldb
,
447 "invalid ldb_reply_type in callback");
449 return ldb_module_done(ac
->req
, NULL
, NULL
,
450 LDB_ERR_OPERATIONS_ERROR
);
453 return ldb_module_done(ac
->req
, ares
->controls
,
454 ares
->response
, LDB_SUCCESS
);
457 static int replmd_add(struct ldb_module
*module
, struct ldb_request
*req
)
459 struct ldb_context
*ldb
;
460 struct ldb_control
*control
;
461 struct ldb_control
**saved_controls
;
462 struct replmd_replicated_request
*ac
;
463 const struct dsdb_schema
*schema
;
464 enum ndr_err_code ndr_err
;
465 struct ldb_request
*down_req
;
466 struct ldb_message
*msg
;
467 const DATA_BLOB
*guid_blob
;
469 struct ldb_val guid_value
;
470 struct replPropertyMetaDataBlob nmd
;
471 struct ldb_val nmd_value
;
473 const struct GUID
*our_invocation_id
;
474 time_t t
= time(NULL
);
479 bool allow_add_guid
= false;
480 bool remove_current_guid
= false;
482 /* check if there's a show relax control (used by provision to say 'I know what I'm doing') */
483 control
= ldb_request_get_control(req
, LDB_CONTROL_RELAX_OID
);
488 /* do not manipulate our control entries */
489 if (ldb_dn_is_special(req
->op
.add
.message
->dn
)) {
490 return ldb_next_request(module
, req
);
493 ldb
= ldb_module_get_ctx(module
);
495 ldb_debug(ldb
, LDB_DEBUG_TRACE
, "replmd_add\n");
497 schema
= dsdb_get_schema(ldb
);
499 ldb_debug_set(ldb
, LDB_DEBUG_FATAL
,
500 "replmd_add: no dsdb_schema loaded");
501 DEBUG(0,(__location__
": %s\n", ldb_errstring(ldb
)));
502 return LDB_ERR_CONSTRAINT_VIOLATION
;
505 ac
= replmd_ctx_init(module
, req
);
507 return LDB_ERR_OPERATIONS_ERROR
;
512 guid_blob
= ldb_msg_find_ldb_val(req
->op
.add
.message
, "objectGUID");
513 if ( guid_blob
!= NULL
) {
514 if( !allow_add_guid
) {
515 ldb_debug_set(ldb
, LDB_DEBUG_ERROR
,
516 "replmd_add: it's not allowed to add an object with objectGUID\n");
518 return LDB_ERR_UNWILLING_TO_PERFORM
;
520 NTSTATUS status
= GUID_from_data_blob(guid_blob
,&guid
);
521 if ( !NT_STATUS_IS_OK(status
)) {
522 ldb_debug_set(ldb
, LDB_DEBUG_ERROR
,
523 "replmd_add: Unable to parse as a GUID the attribute objectGUID\n");
525 return LDB_ERR_UNWILLING_TO_PERFORM
;
527 /* we remove this attribute as it can be a string and will not be treated
528 correctly and then we will readd it latter on in the good format*/
529 remove_current_guid
= true;
533 guid
= GUID_random();
536 /* Get a sequence number from the backend */
537 ret
= ldb_sequence_number(ldb
, LDB_SEQ_NEXT
, &seq_num
);
538 if (ret
!= LDB_SUCCESS
) {
543 /* get our invocationId */
544 our_invocation_id
= samdb_ntds_invocation_id(ldb
);
545 if (!our_invocation_id
) {
546 ldb_debug_set(ldb
, LDB_DEBUG_ERROR
,
547 "replmd_add: unable to find invocationId\n");
549 return LDB_ERR_OPERATIONS_ERROR
;
552 /* we have to copy the message as the caller might have it as a const */
553 msg
= ldb_msg_copy_shallow(ac
, req
->op
.add
.message
);
557 return LDB_ERR_OPERATIONS_ERROR
;
560 /* generated times */
561 unix_to_nt_time(&now
, t
);
562 time_str
= ldb_timestring(msg
, t
);
566 return LDB_ERR_OPERATIONS_ERROR
;
568 if (remove_current_guid
) {
569 ldb_msg_remove_attr(msg
,"objectGUID");
573 * remove autogenerated attributes
575 ldb_msg_remove_attr(msg
, "whenCreated");
576 ldb_msg_remove_attr(msg
, "whenChanged");
577 ldb_msg_remove_attr(msg
, "uSNCreated");
578 ldb_msg_remove_attr(msg
, "uSNChanged");
579 ldb_msg_remove_attr(msg
, "replPropertyMetaData");
581 if (!ldb_msg_find_element(req
->op
.add
.message
, "instanceType")) {
582 ret
= ldb_msg_add_fmt(msg
, "instanceType", "%u", INSTANCE_TYPE_WRITE
);
583 if (ret
!= LDB_SUCCESS
) {
591 * readd replicated attributes
593 ret
= ldb_msg_add_string(msg
, "whenCreated", time_str
);
594 if (ret
!= LDB_SUCCESS
) {
600 /* build the replication meta_data */
603 nmd
.ctr
.ctr1
.count
= msg
->num_elements
;
604 nmd
.ctr
.ctr1
.array
= talloc_array(msg
,
605 struct replPropertyMetaData1
,
607 if (!nmd
.ctr
.ctr1
.array
) {
610 return LDB_ERR_OPERATIONS_ERROR
;
613 for (i
=0; i
< msg
->num_elements
; i
++) {
614 struct ldb_message_element
*e
= &msg
->elements
[i
];
615 struct replPropertyMetaData1
*m
= &nmd
.ctr
.ctr1
.array
[ni
];
616 const struct dsdb_attribute
*sa
;
618 if (e
->name
[0] == '@') continue;
620 sa
= dsdb_attribute_by_lDAPDisplayName(schema
, e
->name
);
622 ldb_debug_set(ldb
, LDB_DEBUG_ERROR
,
623 "replmd_add: attribute '%s' not defined in schema\n",
626 return LDB_ERR_NO_SUCH_ATTRIBUTE
;
629 if ((sa
->systemFlags
& DS_FLAG_ATTR_NOT_REPLICATED
) || (sa
->systemFlags
& DS_FLAG_ATTR_IS_CONSTRUCTED
)) {
630 /* if the attribute is not replicated (0x00000001)
631 * or constructed (0x00000004) it has no metadata
636 m
->attid
= sa
->attributeID_id
;
638 m
->originating_change_time
= now
;
639 m
->originating_invocation_id
= *our_invocation_id
;
640 m
->originating_usn
= seq_num
;
641 m
->local_usn
= seq_num
;
645 /* fix meta data count */
646 nmd
.ctr
.ctr1
.count
= ni
;
649 * sort meta data array, and move the rdn attribute entry to the end
651 ret
= replmd_replPropertyMetaDataCtr1_sort(&nmd
.ctr
.ctr1
, schema
, msg
->dn
);
652 if (ret
!= LDB_SUCCESS
) {
657 /* generated NDR encoded values */
658 ndr_err
= ndr_push_struct_blob(&guid_value
, msg
,
661 (ndr_push_flags_fn_t
)ndr_push_GUID
);
662 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
665 return LDB_ERR_OPERATIONS_ERROR
;
667 ndr_err
= ndr_push_struct_blob(&nmd_value
, msg
,
668 lp_iconv_convenience(ldb_get_opaque(ldb
, "loadparm")),
670 (ndr_push_flags_fn_t
)ndr_push_replPropertyMetaDataBlob
);
671 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
674 return LDB_ERR_OPERATIONS_ERROR
;
678 * add the autogenerated values
680 ret
= ldb_msg_add_value(msg
, "objectGUID", &guid_value
, NULL
);
681 if (ret
!= LDB_SUCCESS
) {
686 ret
= ldb_msg_add_string(msg
, "whenChanged", time_str
);
687 if (ret
!= LDB_SUCCESS
) {
692 ret
= samdb_msg_add_uint64(ldb
, msg
, msg
, "uSNCreated", seq_num
);
693 if (ret
!= LDB_SUCCESS
) {
698 ret
= samdb_msg_add_uint64(ldb
, msg
, msg
, "uSNChanged", seq_num
);
699 if (ret
!= LDB_SUCCESS
) {
704 ret
= ldb_msg_add_value(msg
, "replPropertyMetaData", &nmd_value
, NULL
);
705 if (ret
!= LDB_SUCCESS
) {
712 * sort the attributes by attid before storing the object
714 replmd_ldb_message_sort(msg
, schema
);
716 ret
= ldb_build_add_req(&down_req
, ldb
, ac
,
719 ac
, replmd_op_callback
,
721 if (ret
!= LDB_SUCCESS
) {
726 ret
= replmd_notify(module
, msg
->dn
, seq_num
);
727 if (ret
!= LDB_SUCCESS
) {
732 /* if a control is there remove if from the modified request */
733 if (control
&& !save_controls(control
, down_req
, &saved_controls
)) {
735 return LDB_ERR_OPERATIONS_ERROR
;
738 /* go on with the call chain */
739 return ldb_next_request(module
, down_req
);
744 * update the replPropertyMetaData for one element
746 static int replmd_update_rpmd_element(struct ldb_context
*ldb
,
747 struct ldb_message
*msg
,
748 struct ldb_message_element
*el
,
749 struct replPropertyMetaDataBlob
*omd
,
750 struct dsdb_schema
*schema
,
752 const struct GUID
*our_invocation_id
,
756 const struct dsdb_attribute
*a
;
757 struct replPropertyMetaData1
*md1
;
759 a
= dsdb_attribute_by_lDAPDisplayName(schema
, el
->name
);
761 DEBUG(0,(__location__
": Unable to find attribute %s in schema\n",
763 return LDB_ERR_OPERATIONS_ERROR
;
766 if ((a
->systemFlags
& DS_FLAG_ATTR_NOT_REPLICATED
) || (a
->systemFlags
& DS_FLAG_ATTR_IS_CONSTRUCTED
)) {
770 for (i
=0; i
<omd
->ctr
.ctr1
.count
; i
++) {
771 if (a
->attributeID_id
== omd
->ctr
.ctr1
.array
[i
].attid
) break;
773 if (i
== omd
->ctr
.ctr1
.count
) {
774 /* we need to add a new one */
775 omd
->ctr
.ctr1
.array
= talloc_realloc(msg
, omd
->ctr
.ctr1
.array
,
776 struct replPropertyMetaData1
, omd
->ctr
.ctr1
.count
+1);
777 if (omd
->ctr
.ctr1
.array
== NULL
) {
779 return LDB_ERR_OPERATIONS_ERROR
;
781 omd
->ctr
.ctr1
.count
++;
782 ZERO_STRUCT(omd
->ctr
.ctr1
.array
[i
]);
785 /* Get a new sequence number from the backend. We only do this
786 * if we have a change that requires a new
787 * replPropertyMetaData element
790 int ret
= ldb_sequence_number(ldb
, LDB_SEQ_NEXT
, seq_num
);
791 if (ret
!= LDB_SUCCESS
) {
792 return LDB_ERR_OPERATIONS_ERROR
;
796 md1
= &omd
->ctr
.ctr1
.array
[i
];
798 md1
->attid
= a
->attributeID_id
;
799 md1
->originating_change_time
= now
;
800 md1
->originating_invocation_id
= *our_invocation_id
;
801 md1
->originating_usn
= *seq_num
;
802 md1
->local_usn
= *seq_num
;
808 * update the replPropertyMetaData object each time we modify an
809 * object. This is needed for DRS replication, as the merge on the
810 * client is based on this object
812 static int replmd_update_rpmd(struct ldb_module
*module
,
813 struct ldb_message
*msg
, uint64_t *seq_num
)
815 const struct ldb_val
*omd_value
;
816 enum ndr_err_code ndr_err
;
817 struct replPropertyMetaDataBlob omd
;
819 struct dsdb_schema
*schema
;
820 time_t t
= time(NULL
);
822 const struct GUID
*our_invocation_id
;
824 const char *attrs
[] = { "replPropertyMetaData" , NULL
};
825 struct ldb_result
*res
;
826 struct ldb_context
*ldb
;
828 ldb
= ldb_module_get_ctx(module
);
830 our_invocation_id
= samdb_ntds_invocation_id(ldb
);
831 if (!our_invocation_id
) {
832 /* this happens during an initial vampire while
833 updating the schema */
834 DEBUG(5,("No invocationID - skipping replPropertyMetaData update\n"));
838 unix_to_nt_time(&now
, t
);
840 /* search for the existing replPropertyMetaDataBlob */
841 ret
= dsdb_search_dn_with_deleted(ldb
, msg
, &res
, msg
->dn
, attrs
);
842 if (ret
!= LDB_SUCCESS
|| res
->count
!= 1) {
843 DEBUG(0,(__location__
": Object %s failed to find replPropertyMetaData\n",
844 ldb_dn_get_linearized(msg
->dn
)));
845 return LDB_ERR_OPERATIONS_ERROR
;
849 omd_value
= ldb_msg_find_ldb_val(res
->msgs
[0], "replPropertyMetaData");
851 DEBUG(0,(__location__
": Object %s does not have a replPropertyMetaData attribute\n",
852 ldb_dn_get_linearized(msg
->dn
)));
853 return LDB_ERR_OPERATIONS_ERROR
;
856 ndr_err
= ndr_pull_struct_blob(omd_value
, msg
,
857 lp_iconv_convenience(ldb_get_opaque(ldb
, "loadparm")), &omd
,
858 (ndr_pull_flags_fn_t
)ndr_pull_replPropertyMetaDataBlob
);
859 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
860 DEBUG(0,(__location__
": Failed to parse replPropertyMetaData for %s\n",
861 ldb_dn_get_linearized(msg
->dn
)));
862 return LDB_ERR_OPERATIONS_ERROR
;
865 if (omd
.version
!= 1) {
866 DEBUG(0,(__location__
": bad version %u in replPropertyMetaData for %s\n",
867 omd
.version
, ldb_dn_get_linearized(msg
->dn
)));
868 return LDB_ERR_OPERATIONS_ERROR
;
871 schema
= dsdb_get_schema(ldb
);
873 for (i
=0; i
<msg
->num_elements
; i
++) {
874 ret
= replmd_update_rpmd_element(ldb
, msg
, &msg
->elements
[i
], &omd
, schema
, seq_num
,
875 our_invocation_id
, now
);
876 if (ret
!= LDB_SUCCESS
) {
882 * replmd_update_rpmd_element has done an update if the
886 struct ldb_val
*md_value
;
887 struct ldb_message_element
*el
;
889 md_value
= talloc(msg
, struct ldb_val
);
890 if (md_value
== NULL
) {
892 return LDB_ERR_OPERATIONS_ERROR
;
895 ret
= replmd_replPropertyMetaDataCtr1_sort(&omd
.ctr
.ctr1
, schema
, msg
->dn
);
896 if (ret
!= LDB_SUCCESS
) {
900 ndr_err
= ndr_push_struct_blob(md_value
, msg
,
901 lp_iconv_convenience(ldb_get_opaque(ldb
, "loadparm")),
903 (ndr_push_flags_fn_t
)ndr_push_replPropertyMetaDataBlob
);
904 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
905 DEBUG(0,(__location__
": Failed to marshall replPropertyMetaData for %s\n",
906 ldb_dn_get_linearized(msg
->dn
)));
907 return LDB_ERR_OPERATIONS_ERROR
;
910 ret
= ldb_msg_add_empty(msg
, "replPropertyMetaData", LDB_FLAG_MOD_REPLACE
, &el
);
911 if (ret
!= LDB_SUCCESS
) {
912 DEBUG(0,(__location__
": Failed to add updated replPropertyMetaData %s\n",
913 ldb_dn_get_linearized(msg
->dn
)));
917 ret
= replmd_notify(module
, msg
->dn
, *seq_num
);
918 if (ret
!= LDB_SUCCESS
) {
923 el
->values
= md_value
;
930 static int replmd_modify(struct ldb_module
*module
, struct ldb_request
*req
)
932 struct ldb_context
*ldb
;
933 struct replmd_replicated_request
*ac
;
934 const struct dsdb_schema
*schema
;
935 struct ldb_request
*down_req
;
936 struct ldb_message
*msg
;
937 struct ldb_result
*res
;
938 time_t t
= time(NULL
);
939 uint64_t seq_num
= 0;
942 /* do not manipulate our control entries */
943 if (ldb_dn_is_special(req
->op
.mod
.message
->dn
)) {
944 return ldb_next_request(module
, req
);
947 ldb
= ldb_module_get_ctx(module
);
949 ldb_debug(ldb
, LDB_DEBUG_TRACE
, "replmd_modify\n");
951 schema
= dsdb_get_schema(ldb
);
953 ldb_debug_set(ldb
, LDB_DEBUG_FATAL
,
954 "replmd_modify: no dsdb_schema loaded");
955 DEBUG(0,(__location__
": %s\n", ldb_errstring(ldb
)));
956 return LDB_ERR_CONSTRAINT_VIOLATION
;
959 ac
= replmd_ctx_init(module
, req
);
961 return LDB_ERR_OPERATIONS_ERROR
;
966 /* we have to copy the message as the caller might have it as a const */
967 msg
= ldb_msg_copy_shallow(ac
, req
->op
.mod
.message
);
971 return LDB_ERR_OPERATIONS_ERROR
;
975 * - give an error when a readonly attribute should
977 * - merge the changed into the old object
978 * if the caller set values to the same value
979 * ignore the attribute, return success when no
980 * attribute was changed
983 ret
= dsdb_search_dn_with_deleted(ldb
, msg
, &res
, msg
->dn
, NULL
);
984 if (ret
!= LDB_SUCCESS
) {
989 ret
= replmd_update_rpmd(module
, msg
, &seq_num
);
990 if (ret
!= LDB_SUCCESS
) {
996 * - replace the old object with the newly constructed one
999 ret
= ldb_build_mod_req(&down_req
, ldb
, ac
,
1002 ac
, replmd_op_callback
,
1004 if (ret
!= LDB_SUCCESS
) {
1008 talloc_steal(down_req
, msg
);
1010 /* we only change whenChanged and uSNChanged if the seq_num
1013 if (add_time_element(msg
, "whenChanged", t
) != LDB_SUCCESS
) {
1018 if (add_uint64_element(msg
, "uSNChanged", seq_num
) != LDB_SUCCESS
) {
1024 /* go on with the call chain */
1025 return ldb_next_request(module
, down_req
);
1030 handle a rename request
1032 On a rename we need to do an extra ldb_modify which sets the
1033 whenChanged and uSNChanged attributes
1035 static int replmd_rename(struct ldb_module
*module
, struct ldb_request
*req
)
1037 struct ldb_context
*ldb
;
1039 time_t t
= time(NULL
);
1040 uint64_t seq_num
= 0;
1041 struct ldb_message
*msg
;
1042 struct replmd_private
*replmd_private
=
1043 talloc_get_type(ldb_module_get_private(module
), struct replmd_private
);
1045 /* do not manipulate our control entries */
1046 if (ldb_dn_is_special(req
->op
.mod
.message
->dn
)) {
1047 return ldb_next_request(module
, req
);
1050 ldb
= ldb_module_get_ctx(module
);
1052 ldb_debug(ldb
, LDB_DEBUG_TRACE
, "replmd_rename\n");
1054 /* Get a sequence number from the backend */
1055 ret
= ldb_sequence_number(ldb
, LDB_SEQ_NEXT
, &seq_num
);
1056 if (ret
!= LDB_SUCCESS
) {
1060 msg
= ldb_msg_new(req
);
1063 return LDB_ERR_OPERATIONS_ERROR
;
1066 msg
->dn
= req
->op
.rename
.olddn
;
1068 if (add_time_element(msg
, "whenChanged", t
) != LDB_SUCCESS
) {
1070 return LDB_ERR_OPERATIONS_ERROR
;
1072 msg
->elements
[0].flags
= LDB_FLAG_MOD_REPLACE
;
1074 if (add_uint64_element(msg
, "uSNChanged", seq_num
) != LDB_SUCCESS
) {
1076 return LDB_ERR_OPERATIONS_ERROR
;
1078 msg
->elements
[1].flags
= LDB_FLAG_MOD_REPLACE
;
1080 ret
= ldb_modify(ldb
, msg
);
1082 if (ret
!= LDB_SUCCESS
) {
1086 ret
= replmd_load_NCs(module
);
1091 /* now update the highest uSNs of the partitions that are
1092 affected. Note that two partitions could be changing */
1093 for (i
=0; i
<replmd_private
->num_ncs
; i
++) {
1094 if (ldb_dn_compare_base(replmd_private
->ncs
[i
].dn
,
1095 req
->op
.rename
.olddn
) == 0) {
1099 if (i
== replmd_private
->num_ncs
) {
1100 DEBUG(0,(__location__
": rename olddn outside tree? %s\n",
1101 ldb_dn_get_linearized(req
->op
.rename
.olddn
)));
1102 return LDB_ERR_OPERATIONS_ERROR
;
1104 replmd_private
->ncs
[i
].mod_usn
= seq_num
;
1106 for (i
=0; i
<replmd_private
->num_ncs
; i
++) {
1107 if (ldb_dn_compare_base(replmd_private
->ncs
[i
].dn
,
1108 req
->op
.rename
.newdn
) == 0) {
1112 if (i
== replmd_private
->num_ncs
) {
1113 DEBUG(0,(__location__
": rename newdn outside tree? %s\n",
1114 ldb_dn_get_linearized(req
->op
.rename
.newdn
)));
1115 return LDB_ERR_OPERATIONS_ERROR
;
1117 replmd_private
->ncs
[i
].mod_usn
= seq_num
;
1119 /* go on with the call chain */
1120 return ldb_next_request(module
, req
);
1124 static int replmd_replicated_request_error(struct replmd_replicated_request
*ar
, int ret
)
1129 static int replmd_replicated_request_werror(struct replmd_replicated_request
*ar
, WERROR status
)
1131 int ret
= LDB_ERR_OTHER
;
1132 /* TODO: do some error mapping */
1136 static int replmd_replicated_apply_next(struct replmd_replicated_request
*ar
);
1138 static int replmd_replicated_apply_add_callback(struct ldb_request
*req
,
1139 struct ldb_reply
*ares
)
1141 struct ldb_context
*ldb
;
1142 struct replmd_replicated_request
*ar
= talloc_get_type(req
->context
,
1143 struct replmd_replicated_request
);
1146 ldb
= ldb_module_get_ctx(ar
->module
);
1149 return ldb_module_done(ar
->req
, NULL
, NULL
,
1150 LDB_ERR_OPERATIONS_ERROR
);
1152 if (ares
->error
!= LDB_SUCCESS
) {
1153 return ldb_module_done(ar
->req
, ares
->controls
,
1154 ares
->response
, ares
->error
);
1157 if (ares
->type
!= LDB_REPLY_DONE
) {
1158 ldb_set_errstring(ldb
, "Invalid reply type\n!");
1159 return ldb_module_done(ar
->req
, NULL
, NULL
,
1160 LDB_ERR_OPERATIONS_ERROR
);
1164 ar
->index_current
++;
1166 ret
= replmd_replicated_apply_next(ar
);
1167 if (ret
!= LDB_SUCCESS
) {
1168 return ldb_module_done(ar
->req
, NULL
, NULL
, ret
);
1174 static int replmd_replicated_apply_add(struct replmd_replicated_request
*ar
)
1176 struct ldb_context
*ldb
;
1177 struct ldb_request
*change_req
;
1178 enum ndr_err_code ndr_err
;
1179 struct ldb_message
*msg
;
1180 struct replPropertyMetaDataBlob
*md
;
1181 struct ldb_val md_value
;
1187 * TODO: check if the parent object exist
1191 * TODO: handle the conflict case where an object with the
1195 ldb
= ldb_module_get_ctx(ar
->module
);
1196 msg
= ar
->objs
->objects
[ar
->index_current
].msg
;
1197 md
= ar
->objs
->objects
[ar
->index_current
].meta_data
;
1199 ret
= ldb_sequence_number(ldb
, LDB_SEQ_NEXT
, &seq_num
);
1200 if (ret
!= LDB_SUCCESS
) {
1201 return replmd_replicated_request_error(ar
, ret
);
1204 ret
= ldb_msg_add_value(msg
, "objectGUID", &ar
->objs
->objects
[ar
->index_current
].guid_value
, NULL
);
1205 if (ret
!= LDB_SUCCESS
) {
1206 return replmd_replicated_request_error(ar
, ret
);
1209 ret
= ldb_msg_add_string(msg
, "whenChanged", ar
->objs
->objects
[ar
->index_current
].when_changed
);
1210 if (ret
!= LDB_SUCCESS
) {
1211 return replmd_replicated_request_error(ar
, ret
);
1214 ret
= samdb_msg_add_uint64(ldb
, msg
, msg
, "uSNCreated", seq_num
);
1215 if (ret
!= LDB_SUCCESS
) {
1216 return replmd_replicated_request_error(ar
, ret
);
1219 ret
= samdb_msg_add_uint64(ldb
, msg
, msg
, "uSNChanged", seq_num
);
1220 if (ret
!= LDB_SUCCESS
) {
1221 return replmd_replicated_request_error(ar
, ret
);
1224 ret
= replmd_notify(ar
->module
, msg
->dn
, seq_num
);
1225 if (ret
!= LDB_SUCCESS
) {
1226 return replmd_replicated_request_error(ar
, ret
);
1229 /* remove any message elements that have zero values */
1230 for (i
=0; i
<msg
->num_elements
; i
++) {
1231 if (msg
->elements
[i
].num_values
== 0) {
1232 DEBUG(4,(__location__
": Removing attribute %s with num_values==0\n",
1233 msg
->elements
[i
].name
));
1234 memmove(&msg
->elements
[i
],
1235 &msg
->elements
[i
+1],
1236 sizeof(msg
->elements
[i
])*(msg
->num_elements
- (i
+1)));
1237 msg
->num_elements
--;
1243 * the meta data array is already sorted by the caller
1245 for (i
=0; i
< md
->ctr
.ctr1
.count
; i
++) {
1246 md
->ctr
.ctr1
.array
[i
].local_usn
= seq_num
;
1248 ndr_err
= ndr_push_struct_blob(&md_value
, msg
,
1249 lp_iconv_convenience(ldb_get_opaque(ldb
, "loadparm")),
1251 (ndr_push_flags_fn_t
)ndr_push_replPropertyMetaDataBlob
);
1252 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
1253 NTSTATUS nt_status
= ndr_map_error2ntstatus(ndr_err
);
1254 return replmd_replicated_request_werror(ar
, ntstatus_to_werror(nt_status
));
1256 ret
= ldb_msg_add_value(msg
, "replPropertyMetaData", &md_value
, NULL
);
1257 if (ret
!= LDB_SUCCESS
) {
1258 return replmd_replicated_request_error(ar
, ret
);
1261 replmd_ldb_message_sort(msg
, ar
->schema
);
1264 char *s
= ldb_ldif_message_string(ldb
, ar
, LDB_CHANGETYPE_ADD
, msg
);
1265 DEBUG(4, ("DRS replication add message:\n%s\n", s
));
1269 ret
= ldb_build_add_req(&change_req
,
1275 replmd_replicated_apply_add_callback
,
1277 if (ret
!= LDB_SUCCESS
) return replmd_replicated_request_error(ar
, ret
);
1279 return ldb_next_request(ar
->module
, change_req
);
1282 static int replmd_replPropertyMetaData1_conflict_compare(struct replPropertyMetaData1
*m1
,
1283 struct replPropertyMetaData1
*m2
)
1287 if (m1
->version
!= m2
->version
) {
1288 return m1
->version
- m2
->version
;
1291 if (m1
->originating_change_time
!= m2
->originating_change_time
) {
1292 return m1
->originating_change_time
- m2
->originating_change_time
;
1295 ret
= GUID_compare(&m1
->originating_invocation_id
, &m2
->originating_invocation_id
);
1300 return m1
->originating_usn
- m2
->originating_usn
;
1303 static int replmd_replicated_apply_merge_callback(struct ldb_request
*req
,
1304 struct ldb_reply
*ares
)
1306 struct ldb_context
*ldb
;
1307 struct replmd_replicated_request
*ar
= talloc_get_type(req
->context
,
1308 struct replmd_replicated_request
);
1311 ldb
= ldb_module_get_ctx(ar
->module
);
1314 return ldb_module_done(ar
->req
, NULL
, NULL
,
1315 LDB_ERR_OPERATIONS_ERROR
);
1317 if (ares
->error
!= LDB_SUCCESS
) {
1318 return ldb_module_done(ar
->req
, ares
->controls
,
1319 ares
->response
, ares
->error
);
1322 if (ares
->type
!= LDB_REPLY_DONE
) {
1323 ldb_set_errstring(ldb
, "Invalid reply type\n!");
1324 return ldb_module_done(ar
->req
, NULL
, NULL
,
1325 LDB_ERR_OPERATIONS_ERROR
);
1329 ar
->index_current
++;
1331 ret
= replmd_replicated_apply_next(ar
);
1332 if (ret
!= LDB_SUCCESS
) {
1333 return ldb_module_done(ar
->req
, NULL
, NULL
, ret
);
1339 static int replmd_replicated_apply_merge(struct replmd_replicated_request
*ar
)
1341 struct ldb_context
*ldb
;
1342 struct ldb_request
*change_req
;
1343 enum ndr_err_code ndr_err
;
1344 struct ldb_message
*msg
;
1345 struct replPropertyMetaDataBlob
*rmd
;
1346 struct replPropertyMetaDataBlob omd
;
1347 const struct ldb_val
*omd_value
;
1348 struct replPropertyMetaDataBlob nmd
;
1349 struct ldb_val nmd_value
;
1351 uint32_t removed_attrs
= 0;
1355 ldb
= ldb_module_get_ctx(ar
->module
);
1356 msg
= ar
->objs
->objects
[ar
->index_current
].msg
;
1357 rmd
= ar
->objs
->objects
[ar
->index_current
].meta_data
;
1362 * TODO: check repl data is correct after a rename
1364 if (ldb_dn_compare(msg
->dn
, ar
->search_msg
->dn
) != 0) {
1365 ldb_debug(ldb
, LDB_DEBUG_TRACE
, "replmd_replicated_request rename %s => %s\n",
1366 ldb_dn_get_linearized(ar
->search_msg
->dn
),
1367 ldb_dn_get_linearized(msg
->dn
));
1368 if (ldb_rename(ldb
, ar
->search_msg
->dn
, msg
->dn
) != LDB_SUCCESS
) {
1369 ldb_debug(ldb
, LDB_DEBUG_FATAL
, "replmd_replicated_request rename %s => %s failed - %s\n",
1370 ldb_dn_get_linearized(ar
->search_msg
->dn
),
1371 ldb_dn_get_linearized(msg
->dn
),
1372 ldb_errstring(ldb
));
1373 return replmd_replicated_request_werror(ar
, WERR_DS_DRA_DB_ERROR
);
1377 /* find existing meta data */
1378 omd_value
= ldb_msg_find_ldb_val(ar
->search_msg
, "replPropertyMetaData");
1380 ndr_err
= ndr_pull_struct_blob(omd_value
, ar
,
1381 lp_iconv_convenience(ldb_get_opaque(ldb
, "loadparm")), &omd
,
1382 (ndr_pull_flags_fn_t
)ndr_pull_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
));
1388 if (omd
.version
!= 1) {
1389 return replmd_replicated_request_werror(ar
, WERR_DS_DRA_INTERNAL_ERROR
);
1395 nmd
.ctr
.ctr1
.count
= omd
.ctr
.ctr1
.count
+ rmd
->ctr
.ctr1
.count
;
1396 nmd
.ctr
.ctr1
.array
= talloc_array(ar
,
1397 struct replPropertyMetaData1
,
1398 nmd
.ctr
.ctr1
.count
);
1399 if (!nmd
.ctr
.ctr1
.array
) return replmd_replicated_request_werror(ar
, WERR_NOMEM
);
1401 /* first copy the old meta data */
1402 for (i
=0; i
< omd
.ctr
.ctr1
.count
; i
++) {
1403 nmd
.ctr
.ctr1
.array
[ni
] = omd
.ctr
.ctr1
.array
[i
];
1407 /* now merge in the new meta data */
1408 for (i
=0; i
< rmd
->ctr
.ctr1
.count
; i
++) {
1411 for (j
=0; j
< ni
; j
++) {
1414 if (rmd
->ctr
.ctr1
.array
[i
].attid
!= nmd
.ctr
.ctr1
.array
[j
].attid
) {
1418 cmp
= replmd_replPropertyMetaData1_conflict_compare(&rmd
->ctr
.ctr1
.array
[i
],
1419 &nmd
.ctr
.ctr1
.array
[j
]);
1421 /* replace the entry */
1422 nmd
.ctr
.ctr1
.array
[j
] = rmd
->ctr
.ctr1
.array
[i
];
1427 /* we don't want to apply this change so remove the attribute */
1428 ldb_msg_remove_element(msg
, &msg
->elements
[i
-removed_attrs
]);
1435 if (found
) continue;
1437 nmd
.ctr
.ctr1
.array
[ni
] = rmd
->ctr
.ctr1
.array
[i
];
1442 * finally correct the size of the meta_data array
1444 nmd
.ctr
.ctr1
.count
= ni
;
1447 * the rdn attribute (the alias for the name attribute),
1448 * 'cn' for most objects is the last entry in the meta data array
1451 * sort the new meta data array
1453 ret
= replmd_replPropertyMetaDataCtr1_sort(&nmd
.ctr
.ctr1
, ar
->schema
, msg
->dn
);
1454 if (ret
!= LDB_SUCCESS
) {
1459 * check if some replicated attributes left, otherwise skip the ldb_modify() call
1461 if (msg
->num_elements
== 0) {
1462 ldb_debug(ldb
, LDB_DEBUG_TRACE
, "replmd_replicated_apply_merge[%u]: skip replace\n",
1465 ar
->index_current
++;
1466 return replmd_replicated_apply_next(ar
);
1469 ldb_debug(ldb
, LDB_DEBUG_TRACE
, "replmd_replicated_apply_merge[%u]: replace %u attributes\n",
1470 ar
->index_current
, msg
->num_elements
);
1472 ret
= ldb_sequence_number(ldb
, LDB_SEQ_NEXT
, &seq_num
);
1473 if (ret
!= LDB_SUCCESS
) {
1474 return replmd_replicated_request_error(ar
, ret
);
1477 for (i
=0; i
<ni
; i
++) {
1478 nmd
.ctr
.ctr1
.array
[i
].local_usn
= seq_num
;
1481 /* create the meta data value */
1482 ndr_err
= ndr_push_struct_blob(&nmd_value
, msg
,
1483 lp_iconv_convenience(ldb_get_opaque(ldb
, "loadparm")),
1485 (ndr_push_flags_fn_t
)ndr_push_replPropertyMetaDataBlob
);
1486 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
1487 NTSTATUS nt_status
= ndr_map_error2ntstatus(ndr_err
);
1488 return replmd_replicated_request_werror(ar
, ntstatus_to_werror(nt_status
));
1492 * when we know that we'll modify the record, add the whenChanged, uSNChanged
1493 * and replPopertyMetaData attributes
1495 ret
= ldb_msg_add_string(msg
, "whenChanged", ar
->objs
->objects
[ar
->index_current
].when_changed
);
1496 if (ret
!= LDB_SUCCESS
) {
1497 return replmd_replicated_request_error(ar
, ret
);
1499 ret
= samdb_msg_add_uint64(ldb
, msg
, msg
, "uSNChanged", seq_num
);
1500 if (ret
!= LDB_SUCCESS
) {
1501 return replmd_replicated_request_error(ar
, ret
);
1503 ret
= ldb_msg_add_value(msg
, "replPropertyMetaData", &nmd_value
, NULL
);
1504 if (ret
!= LDB_SUCCESS
) {
1505 return replmd_replicated_request_error(ar
, ret
);
1508 replmd_ldb_message_sort(msg
, ar
->schema
);
1510 /* we want to replace the old values */
1511 for (i
=0; i
< msg
->num_elements
; i
++) {
1512 msg
->elements
[i
].flags
= LDB_FLAG_MOD_REPLACE
;
1515 ret
= replmd_notify(ar
->module
, msg
->dn
, seq_num
);
1516 if (ret
!= LDB_SUCCESS
) {
1517 return replmd_replicated_request_error(ar
, ret
);
1521 char *s
= ldb_ldif_message_string(ldb
, ar
, LDB_CHANGETYPE_MODIFY
, msg
);
1522 DEBUG(4, ("DRS replication modify message:\n%s\n", s
));
1526 ret
= ldb_build_mod_req(&change_req
,
1532 replmd_replicated_apply_merge_callback
,
1534 if (ret
!= LDB_SUCCESS
) return replmd_replicated_request_error(ar
, ret
);
1536 return ldb_next_request(ar
->module
, change_req
);
1539 static int replmd_replicated_apply_search_callback(struct ldb_request
*req
,
1540 struct ldb_reply
*ares
)
1542 struct replmd_replicated_request
*ar
= talloc_get_type(req
->context
,
1543 struct replmd_replicated_request
);
1547 return ldb_module_done(ar
->req
, NULL
, NULL
,
1548 LDB_ERR_OPERATIONS_ERROR
);
1550 if (ares
->error
!= LDB_SUCCESS
&&
1551 ares
->error
!= LDB_ERR_NO_SUCH_OBJECT
) {
1552 return ldb_module_done(ar
->req
, ares
->controls
,
1553 ares
->response
, ares
->error
);
1556 switch (ares
->type
) {
1557 case LDB_REPLY_ENTRY
:
1558 ar
->search_msg
= talloc_steal(ar
, ares
->message
);
1561 case LDB_REPLY_REFERRAL
:
1562 /* we ignore referrals */
1565 case LDB_REPLY_DONE
:
1566 if (ar
->search_msg
!= NULL
) {
1567 ret
= replmd_replicated_apply_merge(ar
);
1569 ret
= replmd_replicated_apply_add(ar
);
1571 if (ret
!= LDB_SUCCESS
) {
1572 return ldb_module_done(ar
->req
, NULL
, NULL
, ret
);
1580 static int replmd_replicated_uptodate_vector(struct replmd_replicated_request
*ar
);
1582 static int replmd_replicated_apply_next(struct replmd_replicated_request
*ar
)
1584 struct ldb_context
*ldb
;
1588 struct ldb_request
*search_req
;
1590 if (ar
->index_current
>= ar
->objs
->num_objects
) {
1591 /* done with it, go to next stage */
1592 return replmd_replicated_uptodate_vector(ar
);
1595 ldb
= ldb_module_get_ctx(ar
->module
);
1596 ar
->search_msg
= NULL
;
1598 tmp_str
= ldb_binary_encode(ar
, ar
->objs
->objects
[ar
->index_current
].guid_value
);
1599 if (!tmp_str
) return replmd_replicated_request_werror(ar
, WERR_NOMEM
);
1601 filter
= talloc_asprintf(ar
, "(objectGUID=%s)", tmp_str
);
1602 if (!filter
) return replmd_replicated_request_werror(ar
, WERR_NOMEM
);
1603 talloc_free(tmp_str
);
1605 ret
= ldb_build_search_req(&search_req
,
1608 ar
->objs
->partition_dn
,
1614 replmd_replicated_apply_search_callback
,
1617 ret
= ldb_request_add_control(search_req
, LDB_CONTROL_SHOW_DELETED_OID
, true, NULL
);
1618 if (ret
!= LDB_SUCCESS
) {
1623 if (ret
!= LDB_SUCCESS
) return replmd_replicated_request_error(ar
, ret
);
1625 return ldb_next_request(ar
->module
, search_req
);
1628 static int replmd_replicated_uptodate_modify_callback(struct ldb_request
*req
,
1629 struct ldb_reply
*ares
)
1631 struct ldb_context
*ldb
;
1632 struct replmd_replicated_request
*ar
= talloc_get_type(req
->context
,
1633 struct replmd_replicated_request
);
1634 ldb
= ldb_module_get_ctx(ar
->module
);
1637 return ldb_module_done(ar
->req
, NULL
, NULL
,
1638 LDB_ERR_OPERATIONS_ERROR
);
1640 if (ares
->error
!= LDB_SUCCESS
) {
1641 return ldb_module_done(ar
->req
, ares
->controls
,
1642 ares
->response
, ares
->error
);
1645 if (ares
->type
!= LDB_REPLY_DONE
) {
1646 ldb_set_errstring(ldb
, "Invalid reply type\n!");
1647 return ldb_module_done(ar
->req
, NULL
, NULL
,
1648 LDB_ERR_OPERATIONS_ERROR
);
1653 return ldb_module_done(ar
->req
, NULL
, NULL
, LDB_SUCCESS
);
1656 static int replmd_replicated_uptodate_modify(struct replmd_replicated_request
*ar
)
1658 struct ldb_context
*ldb
;
1659 struct ldb_request
*change_req
;
1660 enum ndr_err_code ndr_err
;
1661 struct ldb_message
*msg
;
1662 struct replUpToDateVectorBlob ouv
;
1663 const struct ldb_val
*ouv_value
;
1664 const struct drsuapi_DsReplicaCursor2CtrEx
*ruv
;
1665 struct replUpToDateVectorBlob nuv
;
1666 struct ldb_val nuv_value
;
1667 struct ldb_message_element
*nuv_el
= NULL
;
1668 const struct GUID
*our_invocation_id
;
1669 struct ldb_message_element
*orf_el
= NULL
;
1670 struct repsFromToBlob nrf
;
1671 struct ldb_val
*nrf_value
= NULL
;
1672 struct ldb_message_element
*nrf_el
= NULL
;
1675 time_t t
= time(NULL
);
1679 ldb
= ldb_module_get_ctx(ar
->module
);
1680 ruv
= ar
->objs
->uptodateness_vector
;
1686 unix_to_nt_time(&now
, t
);
1689 * first create the new replUpToDateVector
1691 ouv_value
= ldb_msg_find_ldb_val(ar
->search_msg
, "replUpToDateVector");
1693 ndr_err
= ndr_pull_struct_blob(ouv_value
, ar
,
1694 lp_iconv_convenience(ldb_get_opaque(ldb
, "loadparm")), &ouv
,
1695 (ndr_pull_flags_fn_t
)ndr_pull_replUpToDateVectorBlob
);
1696 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
1697 NTSTATUS nt_status
= ndr_map_error2ntstatus(ndr_err
);
1698 return replmd_replicated_request_werror(ar
, ntstatus_to_werror(nt_status
));
1701 if (ouv
.version
!= 2) {
1702 return replmd_replicated_request_werror(ar
, WERR_DS_DRA_INTERNAL_ERROR
);
1707 * the new uptodateness vector will at least
1708 * contain 1 entry, one for the source_dsa
1710 * plus optional values from our old vector and the one from the source_dsa
1712 nuv
.ctr
.ctr2
.count
= 1 + ouv
.ctr
.ctr2
.count
;
1713 if (ruv
) nuv
.ctr
.ctr2
.count
+= ruv
->count
;
1714 nuv
.ctr
.ctr2
.cursors
= talloc_array(ar
,
1715 struct drsuapi_DsReplicaCursor2
,
1716 nuv
.ctr
.ctr2
.count
);
1717 if (!nuv
.ctr
.ctr2
.cursors
) return replmd_replicated_request_werror(ar
, WERR_NOMEM
);
1719 /* first copy the old vector */
1720 for (i
=0; i
< ouv
.ctr
.ctr2
.count
; i
++) {
1721 nuv
.ctr
.ctr2
.cursors
[ni
] = ouv
.ctr
.ctr2
.cursors
[i
];
1725 /* get our invocation_id if we have one already attached to the ldb */
1726 our_invocation_id
= samdb_ntds_invocation_id(ldb
);
1728 /* merge in the source_dsa vector is available */
1729 for (i
=0; (ruv
&& i
< ruv
->count
); i
++) {
1732 if (our_invocation_id
&&
1733 GUID_equal(&ruv
->cursors
[i
].source_dsa_invocation_id
,
1734 our_invocation_id
)) {
1738 for (j
=0; j
< ni
; j
++) {
1739 if (!GUID_equal(&ruv
->cursors
[i
].source_dsa_invocation_id
,
1740 &nuv
.ctr
.ctr2
.cursors
[j
].source_dsa_invocation_id
)) {
1747 * we update only the highest_usn and not the latest_sync_success time,
1748 * because the last success stands for direct replication
1750 if (ruv
->cursors
[i
].highest_usn
> nuv
.ctr
.ctr2
.cursors
[j
].highest_usn
) {
1751 nuv
.ctr
.ctr2
.cursors
[j
].highest_usn
= ruv
->cursors
[i
].highest_usn
;
1756 if (found
) continue;
1758 /* if it's not there yet, add it */
1759 nuv
.ctr
.ctr2
.cursors
[ni
] = ruv
->cursors
[i
];
1764 * merge in the current highwatermark for the source_dsa
1767 for (j
=0; j
< ni
; j
++) {
1768 if (!GUID_equal(&ar
->objs
->source_dsa
->source_dsa_invocation_id
,
1769 &nuv
.ctr
.ctr2
.cursors
[j
].source_dsa_invocation_id
)) {
1776 * here we update the highest_usn and last_sync_success time
1777 * because we're directly replicating from the source_dsa
1779 * and use the tmp_highest_usn because this is what we have just applied
1782 nuv
.ctr
.ctr2
.cursors
[j
].highest_usn
= ar
->objs
->source_dsa
->highwatermark
.tmp_highest_usn
;
1783 nuv
.ctr
.ctr2
.cursors
[j
].last_sync_success
= now
;
1788 * here we update the highest_usn and last_sync_success time
1789 * because we're directly replicating from the source_dsa
1791 * and use the tmp_highest_usn because this is what we have just applied
1794 nuv
.ctr
.ctr2
.cursors
[ni
].source_dsa_invocation_id
= ar
->objs
->source_dsa
->source_dsa_invocation_id
;
1795 nuv
.ctr
.ctr2
.cursors
[ni
].highest_usn
= ar
->objs
->source_dsa
->highwatermark
.tmp_highest_usn
;
1796 nuv
.ctr
.ctr2
.cursors
[ni
].last_sync_success
= now
;
1801 * finally correct the size of the cursors array
1803 nuv
.ctr
.ctr2
.count
= ni
;
1808 qsort(nuv
.ctr
.ctr2
.cursors
, nuv
.ctr
.ctr2
.count
,
1809 sizeof(struct drsuapi_DsReplicaCursor2
),
1810 (comparison_fn_t
)drsuapi_DsReplicaCursor2_compare
);
1813 * create the change ldb_message
1815 msg
= ldb_msg_new(ar
);
1816 if (!msg
) return replmd_replicated_request_werror(ar
, WERR_NOMEM
);
1817 msg
->dn
= ar
->search_msg
->dn
;
1819 ndr_err
= ndr_push_struct_blob(&nuv_value
, msg
,
1820 lp_iconv_convenience(ldb_get_opaque(ldb
, "loadparm")),
1822 (ndr_push_flags_fn_t
)ndr_push_replUpToDateVectorBlob
);
1823 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
1824 NTSTATUS nt_status
= ndr_map_error2ntstatus(ndr_err
);
1825 return replmd_replicated_request_werror(ar
, ntstatus_to_werror(nt_status
));
1827 ret
= ldb_msg_add_value(msg
, "replUpToDateVector", &nuv_value
, &nuv_el
);
1828 if (ret
!= LDB_SUCCESS
) {
1829 return replmd_replicated_request_error(ar
, ret
);
1831 nuv_el
->flags
= LDB_FLAG_MOD_REPLACE
;
1834 * now create the new repsFrom value from the given repsFromTo1 structure
1838 nrf
.ctr
.ctr1
= *ar
->objs
->source_dsa
;
1839 /* and fix some values... */
1840 nrf
.ctr
.ctr1
.consecutive_sync_failures
= 0;
1841 nrf
.ctr
.ctr1
.last_success
= now
;
1842 nrf
.ctr
.ctr1
.last_attempt
= now
;
1843 nrf
.ctr
.ctr1
.result_last_attempt
= WERR_OK
;
1844 nrf
.ctr
.ctr1
.highwatermark
.highest_usn
= nrf
.ctr
.ctr1
.highwatermark
.tmp_highest_usn
;
1847 * first see if we already have a repsFrom value for the current source dsa
1848 * if so we'll later replace this value
1850 orf_el
= ldb_msg_find_element(ar
->search_msg
, "repsFrom");
1852 for (i
=0; i
< orf_el
->num_values
; i
++) {
1853 struct repsFromToBlob
*trf
;
1855 trf
= talloc(ar
, struct repsFromToBlob
);
1856 if (!trf
) return replmd_replicated_request_werror(ar
, WERR_NOMEM
);
1858 ndr_err
= ndr_pull_struct_blob(&orf_el
->values
[i
], trf
, lp_iconv_convenience(ldb_get_opaque(ldb
, "loadparm")), trf
,
1859 (ndr_pull_flags_fn_t
)ndr_pull_repsFromToBlob
);
1860 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
1861 NTSTATUS nt_status
= ndr_map_error2ntstatus(ndr_err
);
1862 return replmd_replicated_request_werror(ar
, ntstatus_to_werror(nt_status
));
1865 if (trf
->version
!= 1) {
1866 return replmd_replicated_request_werror(ar
, WERR_DS_DRA_INTERNAL_ERROR
);
1870 * we compare the source dsa objectGUID not the invocation_id
1871 * because we want only one repsFrom value per source dsa
1872 * and when the invocation_id of the source dsa has changed we don't need
1873 * the old repsFrom with the old invocation_id
1875 if (!GUID_equal(&trf
->ctr
.ctr1
.source_dsa_obj_guid
,
1876 &ar
->objs
->source_dsa
->source_dsa_obj_guid
)) {
1882 nrf_value
= &orf_el
->values
[i
];
1887 * copy over all old values to the new ldb_message
1889 ret
= ldb_msg_add_empty(msg
, "repsFrom", 0, &nrf_el
);
1890 if (ret
!= LDB_SUCCESS
) return replmd_replicated_request_error(ar
, ret
);
1895 * if we haven't found an old repsFrom value for the current source dsa
1896 * we'll add a new value
1899 struct ldb_val zero_value
;
1900 ZERO_STRUCT(zero_value
);
1901 ret
= ldb_msg_add_value(msg
, "repsFrom", &zero_value
, &nrf_el
);
1902 if (ret
!= LDB_SUCCESS
) return replmd_replicated_request_error(ar
, ret
);
1904 nrf_value
= &nrf_el
->values
[nrf_el
->num_values
- 1];
1907 /* we now fill the value which is already attached to ldb_message */
1908 ndr_err
= ndr_push_struct_blob(nrf_value
, msg
,
1909 lp_iconv_convenience(ldb_get_opaque(ldb
, "loadparm")),
1911 (ndr_push_flags_fn_t
)ndr_push_repsFromToBlob
);
1912 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
1913 NTSTATUS nt_status
= ndr_map_error2ntstatus(ndr_err
);
1914 return replmd_replicated_request_werror(ar
, ntstatus_to_werror(nt_status
));
1918 * the ldb_message_element for the attribute, has all the old values and the new one
1919 * so we'll replace the whole attribute with all values
1921 nrf_el
->flags
= LDB_FLAG_MOD_REPLACE
;
1924 char *s
= ldb_ldif_message_string(ldb
, ar
, LDB_CHANGETYPE_MODIFY
, msg
);
1925 DEBUG(4, ("DRS replication uptodate modify message:\n%s\n", s
));
1929 /* prepare the ldb_modify() request */
1930 ret
= ldb_build_mod_req(&change_req
,
1936 replmd_replicated_uptodate_modify_callback
,
1938 if (ret
!= LDB_SUCCESS
) return replmd_replicated_request_error(ar
, ret
);
1940 return ldb_next_request(ar
->module
, change_req
);
1943 static int replmd_replicated_uptodate_search_callback(struct ldb_request
*req
,
1944 struct ldb_reply
*ares
)
1946 struct replmd_replicated_request
*ar
= talloc_get_type(req
->context
,
1947 struct replmd_replicated_request
);
1951 return ldb_module_done(ar
->req
, NULL
, NULL
,
1952 LDB_ERR_OPERATIONS_ERROR
);
1954 if (ares
->error
!= LDB_SUCCESS
&&
1955 ares
->error
!= LDB_ERR_NO_SUCH_OBJECT
) {
1956 return ldb_module_done(ar
->req
, ares
->controls
,
1957 ares
->response
, ares
->error
);
1960 switch (ares
->type
) {
1961 case LDB_REPLY_ENTRY
:
1962 ar
->search_msg
= talloc_steal(ar
, ares
->message
);
1965 case LDB_REPLY_REFERRAL
:
1966 /* we ignore referrals */
1969 case LDB_REPLY_DONE
:
1970 if (ar
->search_msg
== NULL
) {
1971 ret
= replmd_replicated_request_werror(ar
, WERR_DS_DRA_INTERNAL_ERROR
);
1973 ret
= replmd_replicated_uptodate_modify(ar
);
1975 if (ret
!= LDB_SUCCESS
) {
1976 return ldb_module_done(ar
->req
, NULL
, NULL
, ret
);
1985 static int replmd_replicated_uptodate_vector(struct replmd_replicated_request
*ar
)
1987 struct ldb_context
*ldb
;
1989 static const char *attrs
[] = {
1990 "replUpToDateVector",
1994 struct ldb_request
*search_req
;
1996 ldb
= ldb_module_get_ctx(ar
->module
);
1997 ar
->search_msg
= NULL
;
1999 ret
= ldb_build_search_req(&search_req
,
2002 ar
->objs
->partition_dn
,
2008 replmd_replicated_uptodate_search_callback
,
2010 if (ret
!= LDB_SUCCESS
) return replmd_replicated_request_error(ar
, ret
);
2012 return ldb_next_request(ar
->module
, search_req
);
2017 static int replmd_extended_replicated_objects(struct ldb_module
*module
, struct ldb_request
*req
)
2019 struct ldb_context
*ldb
;
2020 struct dsdb_extended_replicated_objects
*objs
;
2021 struct replmd_replicated_request
*ar
;
2022 struct ldb_control
**ctrls
;
2024 struct dsdb_control_current_partition
*partition_ctrl
;
2025 struct replmd_private
*replmd_private
=
2026 talloc_get_type(ldb_module_get_private(module
), struct replmd_private
);
2028 ldb
= ldb_module_get_ctx(module
);
2030 ldb_debug(ldb
, LDB_DEBUG_TRACE
, "replmd_extended_replicated_objects\n");
2032 objs
= talloc_get_type(req
->op
.extended
.data
, struct dsdb_extended_replicated_objects
);
2034 ldb_debug(ldb
, LDB_DEBUG_FATAL
, "replmd_extended_replicated_objects: invalid extended data\n");
2035 return LDB_ERR_PROTOCOL_ERROR
;
2038 if (objs
->version
!= DSDB_EXTENDED_REPLICATED_OBJECTS_VERSION
) {
2039 ldb_debug(ldb
, LDB_DEBUG_FATAL
, "replmd_extended_replicated_objects: extended data invalid version [%u != %u]\n",
2040 objs
->version
, DSDB_EXTENDED_REPLICATED_OBJECTS_VERSION
);
2041 return LDB_ERR_PROTOCOL_ERROR
;
2044 ar
= replmd_ctx_init(module
, req
);
2046 return LDB_ERR_OPERATIONS_ERROR
;
2049 ar
->schema
= dsdb_get_schema(ldb
);
2051 ldb_debug_set(ldb
, LDB_DEBUG_FATAL
, "replmd_ctx_init: no loaded schema found\n");
2053 DEBUG(0,(__location__
": %s\n", ldb_errstring(ldb
)));
2054 return LDB_ERR_CONSTRAINT_VIOLATION
;
2057 ctrls
= req
->controls
;
2059 if (req
->controls
) {
2060 req
->controls
= talloc_memdup(ar
, req
->controls
,
2061 talloc_get_size(req
->controls
));
2062 if (!req
->controls
) return replmd_replicated_request_werror(ar
, WERR_NOMEM
);
2065 ret
= ldb_request_add_control(req
, DSDB_CONTROL_REPLICATED_UPDATE_OID
, false, NULL
);
2066 if (ret
!= LDB_SUCCESS
) {
2071 add the DSDB_CONTROL_CURRENT_PARTITION_OID control. This
2072 tells the partition module which partition this request is
2073 directed at. That is important as the partition roots appear
2074 twice in the directory, once as mount points in the top
2075 level store, and once as the roots of each partition. The
2076 replication code wants to operate on the root of the
2077 partitions, not the top level mount points
2079 partition_ctrl
= talloc(req
, struct dsdb_control_current_partition
);
2080 if (partition_ctrl
== NULL
) {
2081 if (!partition_ctrl
) return replmd_replicated_request_werror(ar
, WERR_NOMEM
);
2083 partition_ctrl
->version
= DSDB_CONTROL_CURRENT_PARTITION_VERSION
;
2084 partition_ctrl
->dn
= objs
->partition_dn
;
2086 ret
= ldb_request_add_control(req
, DSDB_CONTROL_CURRENT_PARTITION_OID
, false, partition_ctrl
);
2087 if (ret
!= LDB_SUCCESS
) {
2091 ar
->controls
= req
->controls
;
2092 req
->controls
= ctrls
;
2094 DEBUG(4,("linked_attributes_count=%u\n", objs
->linked_attributes_count
));
2096 /* save away the linked attributes for the end of the
2098 for (i
=0; i
<ar
->objs
->linked_attributes_count
; i
++) {
2099 struct la_entry
*la_entry
;
2101 if (replmd_private
->la_ctx
== NULL
) {
2102 replmd_private
->la_ctx
= talloc_new(replmd_private
);
2104 la_entry
= talloc(replmd_private
->la_ctx
, struct la_entry
);
2105 if (la_entry
== NULL
) {
2107 return LDB_ERR_OPERATIONS_ERROR
;
2109 la_entry
->la
= talloc(la_entry
, struct drsuapi_DsReplicaLinkedAttribute
);
2110 if (la_entry
->la
== NULL
) {
2111 talloc_free(la_entry
);
2113 return LDB_ERR_OPERATIONS_ERROR
;
2115 *la_entry
->la
= ar
->objs
->linked_attributes
[i
];
2117 /* we need to steal the non-scalars so they stay
2118 around until the end of the transaction */
2119 talloc_steal(la_entry
->la
, la_entry
->la
->identifier
);
2120 talloc_steal(la_entry
->la
, la_entry
->la
->value
.blob
);
2122 DLIST_ADD(replmd_private
->la_list
, la_entry
);
2125 return replmd_replicated_apply_next(ar
);
2129 process one linked attribute structure
2131 static int replmd_process_linked_attribute(struct ldb_module
*module
,
2132 struct la_entry
*la_entry
)
2134 struct drsuapi_DsReplicaLinkedAttribute
*la
= la_entry
->la
;
2135 struct ldb_context
*ldb
= ldb_module_get_ctx(module
);
2136 struct drsuapi_DsReplicaObjectIdentifier3 target
;
2137 struct ldb_message
*msg
;
2138 struct ldb_message_element
*ret_el
;
2139 TALLOC_CTX
*tmp_ctx
= talloc_new(la_entry
);
2140 enum ndr_err_code ndr_err
;
2141 struct ldb_request
*mod_req
;
2143 const struct dsdb_attribute
*attr
;
2144 struct ldb_dn
*target_dn
;
2145 uint64_t seq_num
= 0;
2148 linked_attributes[0]:
2149 &objs->linked_attributes[i]: struct drsuapi_DsReplicaLinkedAttribute
2151 identifier: struct drsuapi_DsReplicaObjectIdentifier
2152 __ndr_size : 0x0000003a (58)
2153 __ndr_size_sid : 0x00000000 (0)
2154 guid : 8e95b6a9-13dd-4158-89db-3220a5be5cc7
2156 __ndr_size_dn : 0x00000000 (0)
2158 attid : DRSUAPI_ATTRIBUTE_member (0x1F)
2159 value: struct drsuapi_DsAttributeValue
2160 __ndr_size : 0x0000007e (126)
2162 blob : DATA_BLOB length=126
2163 flags : 0x00000001 (1)
2164 1: DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE
2165 originating_add_time : Wed Sep 2 22:20:01 2009 EST
2166 meta_data: struct drsuapi_DsReplicaMetaData
2167 version : 0x00000015 (21)
2168 originating_change_time : Wed Sep 2 23:39:07 2009 EST
2169 originating_invocation_id: 794640f3-18cf-40ee-a211-a93992b67a64
2170 originating_usn : 0x000000000001e19c (123292)
2171 &target: struct drsuapi_DsReplicaObjectIdentifier3
2172 __ndr_size : 0x0000007e (126)
2173 __ndr_size_sid : 0x0000001c (28)
2174 guid : 7639e594-db75-4086-b0d4-67890ae46031
2175 sid : S-1-5-21-2848215498-2472035911-1947525656-19924
2176 __ndr_size_dn : 0x00000022 (34)
2177 dn : 'CN=UOne,OU=TestOU,DC=vsofs8,DC=com'
2180 NDR_PRINT_DEBUG(drsuapi_DsReplicaLinkedAttribute
, la
);
2183 /* decode the target of the link */
2184 ndr_err
= ndr_pull_struct_blob(la
->value
.blob
,
2185 tmp_ctx
, lp_iconv_convenience(ldb_get_opaque(ldb
, "loadparm")),
2187 (ndr_pull_flags_fn_t
)ndr_pull_drsuapi_DsReplicaObjectIdentifier3
);
2188 if (ndr_err
!= NDR_ERR_SUCCESS
) {
2189 DEBUG(0,("Unable to decode linked_attribute target\n"));
2190 dump_data(4, la
->value
.blob
->data
, la
->value
.blob
->length
);
2191 talloc_free(tmp_ctx
);
2192 return LDB_ERR_OPERATIONS_ERROR
;
2195 NDR_PRINT_DEBUG(drsuapi_DsReplicaObjectIdentifier3
, &target
);
2198 /* construct a modify request for this attribute change */
2199 msg
= ldb_msg_new(tmp_ctx
);
2202 talloc_free(tmp_ctx
);
2203 return LDB_ERR_OPERATIONS_ERROR
;
2206 ret
= dsdb_find_dn_by_guid(ldb
, tmp_ctx
,
2207 GUID_string(tmp_ctx
, &la
->identifier
->guid
), &msg
->dn
);
2208 if (ret
!= LDB_SUCCESS
) {
2209 talloc_free(tmp_ctx
);
2213 /* find the attribute being modified */
2214 attr
= dsdb_attribute_by_attributeID_id(dsdb_get_schema(ldb
), la
->attid
);
2216 DEBUG(0, (__location__
": Unable to find attributeID 0x%x\n", la
->attid
));
2217 talloc_free(tmp_ctx
);
2218 return LDB_ERR_OPERATIONS_ERROR
;
2221 if (la
->flags
& DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE
) {
2222 ret
= ldb_msg_add_empty(msg
, attr
->lDAPDisplayName
,
2223 LDB_FLAG_MOD_ADD
, &ret_el
);
2225 ret
= ldb_msg_add_empty(msg
, attr
->lDAPDisplayName
,
2226 LDB_FLAG_MOD_DELETE
, &ret_el
);
2228 if (ret
!= LDB_SUCCESS
) {
2229 talloc_free(tmp_ctx
);
2232 /* we allocate two entries here, in case we need a remove/add
2234 ret_el
->values
= talloc_array(msg
, struct ldb_val
, 2);
2235 if (!ret_el
->values
) {
2237 talloc_free(tmp_ctx
);
2238 return LDB_ERR_OPERATIONS_ERROR
;
2240 ret_el
->num_values
= 1;
2242 ret
= dsdb_find_dn_by_guid(ldb
, tmp_ctx
, GUID_string(tmp_ctx
, &target
.guid
), &target_dn
);
2243 if (ret
!= LDB_SUCCESS
) {
2244 DEBUG(0,(__location__
": Failed to map GUID %s to DN\n", GUID_string(tmp_ctx
, &target
.guid
)));
2245 talloc_free(tmp_ctx
);
2246 return LDB_ERR_OPERATIONS_ERROR
;
2249 ret_el
->values
[0].data
= (uint8_t *)ldb_dn_get_extended_linearized(tmp_ctx
, target_dn
, 1);
2250 ret_el
->values
[0].length
= strlen((char *)ret_el
->values
[0].data
);
2252 ret
= replmd_update_rpmd(module
, msg
, &seq_num
);
2253 if (ret
!= LDB_SUCCESS
) {
2254 talloc_free(tmp_ctx
);
2258 /* we only change whenChanged and uSNChanged if the seq_num
2261 time_t t
= time(NULL
);
2263 if (add_time_element(msg
, "whenChanged", t
) != LDB_SUCCESS
) {
2264 talloc_free(tmp_ctx
);
2265 return LDB_ERR_OPERATIONS_ERROR
;
2268 if (add_uint64_element(msg
, "uSNChanged", seq_num
) != LDB_SUCCESS
) {
2269 talloc_free(tmp_ctx
);
2270 return LDB_ERR_OPERATIONS_ERROR
;
2274 ret
= ldb_build_mod_req(&mod_req
, ldb
, tmp_ctx
,
2278 ldb_op_default_callback
,
2280 if (ret
!= LDB_SUCCESS
) {
2281 talloc_free(tmp_ctx
);
2284 talloc_steal(mod_req
, msg
);
2287 DEBUG(4,("Applying DRS linked attribute change:\n%s\n",
2288 ldb_ldif_message_string(ldb
, tmp_ctx
, LDB_CHANGETYPE_MODIFY
, msg
)));
2291 /* Run the new request */
2292 ret
= ldb_next_request(module
, mod_req
);
2294 /* we need to wait for this to finish, as we are being called
2295 from the synchronous end_transaction hook of this module */
2296 if (ret
== LDB_SUCCESS
) {
2297 ret
= ldb_wait(mod_req
->handle
, LDB_WAIT_ALL
);
2300 if (ret
== LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS
) {
2301 /* the link destination exists, we need to update it
2302 * by deleting the old one for the same DN then adding
2304 msg
->elements
= talloc_realloc(msg
, msg
->elements
,
2305 struct ldb_message_element
,
2306 msg
->num_elements
+1);
2307 if (msg
->elements
== NULL
) {
2309 talloc_free(tmp_ctx
);
2310 return LDB_ERR_OPERATIONS_ERROR
;
2312 /* this relies on the backend matching the old entry
2313 only by the DN portion of the extended DN */
2314 msg
->elements
[1] = msg
->elements
[0];
2315 msg
->elements
[0].flags
= LDB_FLAG_MOD_DELETE
;
2316 msg
->num_elements
++;
2318 ret
= ldb_build_mod_req(&mod_req
, ldb
, tmp_ctx
,
2322 ldb_op_default_callback
,
2324 if (ret
!= LDB_SUCCESS
) {
2325 talloc_free(tmp_ctx
);
2329 /* Run the new request */
2330 ret
= ldb_next_request(module
, mod_req
);
2332 if (ret
== LDB_SUCCESS
) {
2333 ret
= ldb_wait(mod_req
->handle
, LDB_WAIT_ALL
);
2337 if (ret
!= LDB_SUCCESS
) {
2338 ldb_debug(ldb
, LDB_DEBUG_WARNING
, "Failed to apply linked attribute change '%s' %s\n",
2340 ldb_ldif_message_string(ldb
, tmp_ctx
, LDB_CHANGETYPE_MODIFY
, msg
));
2344 talloc_free(tmp_ctx
);
2349 static int replmd_extended(struct ldb_module
*module
, struct ldb_request
*req
)
2351 if (strcmp(req
->op
.extended
.oid
, DSDB_EXTENDED_REPLICATED_OBJECTS_OID
) == 0) {
2352 return replmd_extended_replicated_objects(module
, req
);
2355 return ldb_next_request(module
, req
);
2360 we hook into the transaction operations to allow us to
2361 perform the linked attribute updates at the end of the whole
2362 transaction. This allows a forward linked attribute to be created
2363 before the object is created. During a vampire, w2k8 sends us linked
2364 attributes before the objects they are part of.
2366 static int replmd_start_transaction(struct ldb_module
*module
)
2368 /* create our private structure for this transaction */
2370 struct replmd_private
*replmd_private
= talloc_get_type(ldb_module_get_private(module
),
2371 struct replmd_private
);
2372 talloc_free(replmd_private
->la_ctx
);
2373 replmd_private
->la_list
= NULL
;
2374 replmd_private
->la_ctx
= NULL
;
2376 for (i
=0; i
<replmd_private
->num_ncs
; i
++) {
2377 replmd_private
->ncs
[i
].mod_usn
= 0;
2380 return ldb_next_start_trans(module
);
2384 on prepare commit we loop over our queued la_context structures and
2387 static int replmd_prepare_commit(struct ldb_module
*module
)
2389 struct replmd_private
*replmd_private
=
2390 talloc_get_type(ldb_module_get_private(module
), struct replmd_private
);
2391 struct la_entry
*la
, *prev
;
2394 /* walk the list backwards, to do the first entry first, as we
2395 * added the entries with DLIST_ADD() which puts them at the
2396 * start of the list */
2397 for (la
= replmd_private
->la_list
; la
&& la
->next
; la
=la
->next
) ;
2399 for (; la
; la
=prev
) {
2401 DLIST_REMOVE(replmd_private
->la_list
, la
);
2402 ret
= replmd_process_linked_attribute(module
, la
);
2403 if (ret
!= LDB_SUCCESS
) {
2404 talloc_free(replmd_private
->la_ctx
);
2405 replmd_private
->la_list
= NULL
;
2406 replmd_private
->la_ctx
= NULL
;
2411 talloc_free(replmd_private
->la_ctx
);
2412 replmd_private
->la_list
= NULL
;
2413 replmd_private
->la_ctx
= NULL
;
2415 /* possibly change @REPLCHANGED */
2416 ret
= replmd_notify_store(module
);
2417 if (ret
!= LDB_SUCCESS
) {
2421 return ldb_next_prepare_commit(module
);
2424 static int replmd_del_transaction(struct ldb_module
*module
)
2426 struct replmd_private
*replmd_private
=
2427 talloc_get_type(ldb_module_get_private(module
), struct replmd_private
);
2428 talloc_free(replmd_private
->la_ctx
);
2429 replmd_private
->la_list
= NULL
;
2430 replmd_private
->la_ctx
= NULL
;
2431 return ldb_next_del_trans(module
);
2435 _PUBLIC_
const struct ldb_module_ops ldb_repl_meta_data_module_ops
= {
2436 .name
= "repl_meta_data",
2437 .init_context
= replmd_init
,
2439 .modify
= replmd_modify
,
2440 .rename
= replmd_rename
,
2441 .extended
= replmd_extended
,
2442 .start_transaction
= replmd_start_transaction
,
2443 .prepare_commit
= replmd_prepare_commit
,
2444 .del_transaction
= replmd_del_transaction
,