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 {
50 struct la_entry *la_list;
56 struct dsdb_control_current_partition *p_ctrl;
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 DEBUG(0,(__location__ ": Failed to load GUID for %s\n",
169 ldb_dn_get_linearized(replmd_private->ncs[i].dn)));
170 return LDB_ERR_OPERATIONS_ERROR;
172 replmd_private->ncs[i].guid =
173 samdb_result_guid(res->msgs[0], "objectGUID");
177 /* sort the NCs into order, most to least specific */
178 qsort(replmd_private->ncs, replmd_private->num_ncs,
179 sizeof(replmd_private->ncs[0]), QSORT_CAST nc_compare);
182 /* pre-create the partition control used in
183 replmd_notify_store() */
184 for (i=0; i<replmd_private->num_ncs; i++) {
185 replmd_private->ncs[i].p_ctrl = talloc(replmd_private->ncs,
186 struct dsdb_control_current_partition);
187 if (replmd_private->ncs[i].p_ctrl == NULL) {
189 return LDB_ERR_OPERATIONS_ERROR;
191 replmd_private->ncs[i].p_ctrl->version = DSDB_CONTROL_CURRENT_PARTITION_VERSION;
192 replmd_private->ncs[i].p_ctrl->dn = replmd_private->ncs[i].dn;
195 talloc_free(tmp_ctx);
202 * notify the repl task that a object has changed. The notifies are
203 * gathered up in the replmd_private structure then written to the
204 * @REPLCHANGED object in each partition during the prepare_commit
206 static int replmd_notify(struct ldb_module *module, struct ldb_dn *dn, uint64_t uSN)
209 struct replmd_private *replmd_private =
210 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
212 ret = replmd_load_NCs(module);
213 if (ret != LDB_SUCCESS) {
217 for (i=0; i<replmd_private->num_ncs; i++) {
218 if (ldb_dn_compare_base(replmd_private->ncs[i].dn, dn) == 0) {
222 if (i == replmd_private->num_ncs) {
223 DEBUG(0,(__location__ ": DN not within known NCs '%s'\n",
224 ldb_dn_get_linearized(dn)));
225 return LDB_ERR_OPERATIONS_ERROR;
228 if (uSN > replmd_private->ncs[i].mod_usn) {
229 replmd_private->ncs[i].mod_usn = uSN;
237 * update a @REPLCHANGED record in each partition if there have been
238 * any writes of replicated data in the partition
240 static int replmd_notify_store(struct ldb_module *module)
243 struct replmd_private *replmd_private =
244 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
245 struct ldb_context *ldb = ldb_module_get_ctx(module);
247 for (i=0; i<replmd_private->num_ncs; i++) {
248 struct ldb_message *msg;
249 struct ldb_request *req;
251 if (replmd_private->ncs[i].mod_usn == 0) {
252 /* this partition has not changed in this
257 msg = ldb_msg_new(module);
260 return LDB_ERR_OPERATIONS_ERROR;
263 msg->dn = ldb_dn_new(msg, ldb, "@REPLCHANGED");
264 if (msg->dn == NULL) {
267 return LDB_ERR_OPERATIONS_ERROR;
270 ret = ldb_msg_add_fmt(msg, "uSNHighest", "%llu",
271 (unsigned long long)replmd_private->ncs[i].mod_usn);
272 if (ret != LDB_SUCCESS) {
276 msg->elements[0].flags = LDB_FLAG_MOD_REPLACE;
278 ret = ldb_build_mod_req(&req, ldb, msg,
281 NULL, ldb_op_default_callback,
284 if (ret != LDB_SUCCESS) {
289 ret = ldb_request_add_control(req,
290 DSDB_CONTROL_CURRENT_PARTITION_OID,
291 false, replmd_private->ncs[i].p_ctrl);
292 if (ret != LDB_SUCCESS) {
298 /* Run the new request */
299 ret = ldb_next_request(module, req);
301 if (ret == LDB_SUCCESS) {
302 ret = ldb_wait(req->handle, LDB_WAIT_ALL);
304 if (ret == LDB_ERR_NO_SUCH_OBJECT) {
305 ret = ldb_build_add_req(&req, ldb, msg,
308 NULL, ldb_op_default_callback,
315 if (ret != LDB_SUCCESS) {
325 created a replmd_replicated_request context
327 static struct replmd_replicated_request *replmd_ctx_init(struct ldb_module *module,
328 struct ldb_request *req)
330 struct ldb_context *ldb;
331 struct replmd_replicated_request *ac;
333 ldb = ldb_module_get_ctx(module);
335 ac = talloc_zero(req, struct replmd_replicated_request);
347 add a time element to a record
349 static int add_time_element(struct ldb_message *msg, const char *attr, time_t t)
351 struct ldb_message_element *el;
354 if (ldb_msg_find_element(msg, attr) != NULL) {
358 s = ldb_timestring(msg, t);
360 return LDB_ERR_OPERATIONS_ERROR;
363 if (ldb_msg_add_string(msg, attr, s) != LDB_SUCCESS) {
364 return LDB_ERR_OPERATIONS_ERROR;
367 el = ldb_msg_find_element(msg, attr);
368 /* always set as replace. This works because on add ops, the flag
370 el->flags = LDB_FLAG_MOD_REPLACE;
376 add a uint64_t element to a record
378 static int add_uint64_element(struct ldb_message *msg, const char *attr, uint64_t v)
380 struct ldb_message_element *el;
382 if (ldb_msg_find_element(msg, attr) != NULL) {
386 if (ldb_msg_add_fmt(msg, attr, "%llu", (unsigned long long)v) != LDB_SUCCESS) {
387 return LDB_ERR_OPERATIONS_ERROR;
390 el = ldb_msg_find_element(msg, attr);
391 /* always set as replace. This works because on add ops, the flag
393 el->flags = LDB_FLAG_MOD_REPLACE;
398 static int replmd_replPropertyMetaData1_attid_sort(const struct replPropertyMetaData1 *m1,
399 const struct replPropertyMetaData1 *m2,
400 const uint32_t *rdn_attid)
402 if (m1->attid == m2->attid) {
407 * the rdn attribute should be at the end!
408 * so we need to return a value greater than zero
409 * which means m1 is greater than m2
411 if (m1->attid == *rdn_attid) {
416 * the rdn attribute should be at the end!
417 * so we need to return a value less than zero
418 * which means m2 is greater than m1
420 if (m2->attid == *rdn_attid) {
424 return m1->attid - m2->attid;
427 static void replmd_replPropertyMetaDataCtr1_sort(struct replPropertyMetaDataCtr1 *ctr1,
428 const uint32_t *rdn_attid)
430 ldb_qsort(ctr1->array, ctr1->count, sizeof(struct replPropertyMetaData1),
431 discard_const_p(void, rdn_attid), (ldb_qsort_cmp_fn_t)replmd_replPropertyMetaData1_attid_sort);
434 static int replmd_ldb_message_element_attid_sort(const struct ldb_message_element *e1,
435 const struct ldb_message_element *e2,
436 const struct dsdb_schema *schema)
438 const struct dsdb_attribute *a1;
439 const struct dsdb_attribute *a2;
442 * TODO: make this faster by caching the dsdb_attribute pointer
443 * on the ldb_messag_element
446 a1 = dsdb_attribute_by_lDAPDisplayName(schema, e1->name);
447 a2 = dsdb_attribute_by_lDAPDisplayName(schema, e2->name);
450 * TODO: remove this check, we should rely on e1 and e2 having valid attribute names
454 return strcasecmp(e1->name, e2->name);
457 return a1->attributeID_id - a2->attributeID_id;
460 static void replmd_ldb_message_sort(struct ldb_message *msg,
461 const struct dsdb_schema *schema)
463 ldb_qsort(msg->elements, msg->num_elements, sizeof(struct ldb_message_element),
464 discard_const_p(void, schema), (ldb_qsort_cmp_fn_t)replmd_ldb_message_element_attid_sort);
467 static int replmd_op_callback(struct ldb_request *req, struct ldb_reply *ares)
469 struct ldb_context *ldb;
470 struct replmd_replicated_request *ac;
472 ac = talloc_get_type(req->context, struct replmd_replicated_request);
473 ldb = ldb_module_get_ctx(ac->module);
476 return ldb_module_done(ac->req, NULL, NULL,
477 LDB_ERR_OPERATIONS_ERROR);
479 if (ares->error != LDB_SUCCESS) {
480 return ldb_module_done(ac->req, ares->controls,
481 ares->response, ares->error);
484 if (ares->type != LDB_REPLY_DONE) {
485 ldb_set_errstring(ldb,
486 "invalid ldb_reply_type in callback");
488 return ldb_module_done(ac->req, NULL, NULL,
489 LDB_ERR_OPERATIONS_ERROR);
492 return ldb_module_done(ac->req, ares->controls,
493 ares->response, LDB_SUCCESS);
496 static int replmd_add(struct ldb_module *module, struct ldb_request *req)
498 struct ldb_context *ldb;
499 struct replmd_replicated_request *ac;
500 const struct dsdb_schema *schema;
501 enum ndr_err_code ndr_err;
502 struct ldb_request *down_req;
503 struct ldb_message *msg;
504 const struct dsdb_attribute *rdn_attr = NULL;
506 struct ldb_val guid_value;
507 struct replPropertyMetaDataBlob nmd;
508 struct ldb_val nmd_value;
510 const struct GUID *our_invocation_id;
511 time_t t = time(NULL);
517 /* do not manipulate our control entries */
518 if (ldb_dn_is_special(req->op.add.message->dn)) {
519 return ldb_next_request(module, req);
522 ldb = ldb_module_get_ctx(module);
524 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_add\n");
526 schema = dsdb_get_schema(ldb);
528 ldb_debug_set(ldb, LDB_DEBUG_FATAL,
529 "replmd_add: no dsdb_schema loaded");
530 return LDB_ERR_CONSTRAINT_VIOLATION;
533 ac = replmd_ctx_init(module, req);
535 return LDB_ERR_OPERATIONS_ERROR;
540 if (ldb_msg_find_element(req->op.add.message, "objectGUID") != NULL) {
541 ldb_debug_set(ldb, LDB_DEBUG_ERROR,
542 "replmd_add: it's not allowed to add an object with objectGUID\n");
543 return LDB_ERR_UNWILLING_TO_PERFORM;
546 /* Get a sequence number from the backend */
547 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &seq_num);
548 if (ret != LDB_SUCCESS) {
553 guid = GUID_random();
555 /* get our invocationId */
556 our_invocation_id = samdb_ntds_invocation_id(ldb);
557 if (!our_invocation_id) {
558 ldb_debug_set(ldb, LDB_DEBUG_ERROR,
559 "replmd_add: unable to find invocationId\n");
560 return LDB_ERR_OPERATIONS_ERROR;
563 /* we have to copy the message as the caller might have it as a const */
564 msg = ldb_msg_copy_shallow(ac, req->op.add.message);
567 return LDB_ERR_OPERATIONS_ERROR;
570 /* generated times */
571 unix_to_nt_time(&now, t);
572 time_str = ldb_timestring(msg, t);
574 return LDB_ERR_OPERATIONS_ERROR;
578 * remove autogenerated attributes
580 ldb_msg_remove_attr(msg, "whenCreated");
581 ldb_msg_remove_attr(msg, "whenChanged");
582 ldb_msg_remove_attr(msg, "uSNCreated");
583 ldb_msg_remove_attr(msg, "uSNChanged");
584 ldb_msg_remove_attr(msg, "replPropertyMetaData");
587 * readd replicated attributes
589 ret = ldb_msg_add_string(msg, "whenCreated", time_str);
590 if (ret != LDB_SUCCESS) {
592 return LDB_ERR_OPERATIONS_ERROR;
595 /* build the replication meta_data */
598 nmd.ctr.ctr1.count = msg->num_elements;
599 nmd.ctr.ctr1.array = talloc_array(msg,
600 struct replPropertyMetaData1,
602 if (!nmd.ctr.ctr1.array) {
604 return LDB_ERR_OPERATIONS_ERROR;
607 for (i=0; i < msg->num_elements; i++) {
608 struct ldb_message_element *e = &msg->elements[i];
609 struct replPropertyMetaData1 *m = &nmd.ctr.ctr1.array[ni];
610 const struct dsdb_attribute *sa;
612 if (e->name[0] == '@') continue;
614 sa = dsdb_attribute_by_lDAPDisplayName(schema, e->name);
616 ldb_debug_set(ldb, LDB_DEBUG_ERROR,
617 "replmd_add: attribute '%s' not defined in schema\n",
619 return LDB_ERR_NO_SUCH_ATTRIBUTE;
622 if ((sa->systemFlags & 0x00000001) || (sa->systemFlags & 0x00000004)) {
623 /* if the attribute is not replicated (0x00000001)
624 * or constructed (0x00000004) it has no metadata
629 m->attid = sa->attributeID_id;
631 m->originating_change_time = now;
632 m->originating_invocation_id = *our_invocation_id;
633 m->originating_usn = seq_num;
634 m->local_usn = seq_num;
637 if (ldb_attr_cmp(e->name, ldb_dn_get_rdn_name(msg->dn))) {
642 /* fix meta data count */
643 nmd.ctr.ctr1.count = ni;
646 * sort meta data array, and move the rdn attribute entry to the end
648 replmd_replPropertyMetaDataCtr1_sort(&nmd.ctr.ctr1, &rdn_attr->attributeID_id);
650 /* generated NDR encoded values */
651 ndr_err = ndr_push_struct_blob(&guid_value, msg,
654 (ndr_push_flags_fn_t)ndr_push_GUID);
655 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
657 return LDB_ERR_OPERATIONS_ERROR;
659 ndr_err = ndr_push_struct_blob(&nmd_value, msg,
660 lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")),
662 (ndr_push_flags_fn_t)ndr_push_replPropertyMetaDataBlob);
663 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
665 return LDB_ERR_OPERATIONS_ERROR;
669 * add the autogenerated values
671 ret = ldb_msg_add_value(msg, "objectGUID", &guid_value, NULL);
672 if (ret != LDB_SUCCESS) {
674 return LDB_ERR_OPERATIONS_ERROR;
676 ret = ldb_msg_add_string(msg, "whenChanged", time_str);
677 if (ret != LDB_SUCCESS) {
679 return LDB_ERR_OPERATIONS_ERROR;
681 ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNCreated", seq_num);
682 if (ret != LDB_SUCCESS) {
684 return LDB_ERR_OPERATIONS_ERROR;
686 ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNChanged", seq_num);
687 if (ret != LDB_SUCCESS) {
689 return LDB_ERR_OPERATIONS_ERROR;
691 ret = ldb_msg_add_value(msg, "replPropertyMetaData", &nmd_value, NULL);
692 if (ret != LDB_SUCCESS) {
694 return LDB_ERR_OPERATIONS_ERROR;
698 * sort the attributes by attid before storing the object
700 replmd_ldb_message_sort(msg, schema);
702 ret = ldb_build_add_req(&down_req, ldb, ac,
705 ac, replmd_op_callback,
707 if (ret != LDB_SUCCESS) {
711 ret = replmd_notify(module, msg->dn, seq_num);
712 if (ret != LDB_SUCCESS) {
716 /* go on with the call chain */
717 return ldb_next_request(module, down_req);
722 * update the replPropertyMetaData for one element
724 static int replmd_update_rpmd_element(struct ldb_context *ldb,
725 struct ldb_message *msg,
726 struct ldb_message_element *el,
727 struct replPropertyMetaDataBlob *omd,
728 struct dsdb_schema *schema,
730 const struct GUID *our_invocation_id,
734 const struct dsdb_attribute *a;
735 struct replPropertyMetaData1 *md1;
737 a = dsdb_attribute_by_lDAPDisplayName(schema, el->name);
739 DEBUG(0,(__location__ ": Unable to find attribute %s in schema\n",
741 return LDB_ERR_OPERATIONS_ERROR;
744 if ((a->systemFlags & 0x00000001) || (a->systemFlags & 0x00000004)) {
745 /* if the attribute is not replicated (0x00000001)
746 * or constructed (0x00000004) it has no metadata
751 for (i=0; i<omd->ctr.ctr1.count; i++) {
752 if (a->attributeID_id == omd->ctr.ctr1.array[i].attid) break;
754 if (i == omd->ctr.ctr1.count) {
755 /* we need to add a new one */
756 omd->ctr.ctr1.array = talloc_realloc(msg, omd->ctr.ctr1.array,
757 struct replPropertyMetaData1, omd->ctr.ctr1.count+1);
758 if (omd->ctr.ctr1.array == NULL) {
760 return LDB_ERR_OPERATIONS_ERROR;
762 omd->ctr.ctr1.count++;
763 ZERO_STRUCT(omd->ctr.ctr1.array[i]);
766 /* Get a new sequence number from the backend. We only do this
767 * if we have a change that requires a new
768 * replPropertyMetaData element
771 int ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, seq_num);
772 if (ret != LDB_SUCCESS) {
773 return LDB_ERR_OPERATIONS_ERROR;
777 md1 = &omd->ctr.ctr1.array[i];
779 md1->attid = a->attributeID_id;
780 md1->originating_change_time = now;
781 md1->originating_invocation_id = *our_invocation_id;
782 md1->originating_usn = *seq_num;
783 md1->local_usn = *seq_num;
789 * update the replPropertyMetaData object each time we modify an
790 * object. This is needed for DRS replication, as the merge on the
791 * client is based on this object
793 static int replmd_update_rpmd(struct ldb_module *module,
794 struct ldb_message *msg, uint64_t *seq_num)
796 const struct ldb_val *omd_value;
797 enum ndr_err_code ndr_err;
798 struct replPropertyMetaDataBlob omd;
800 struct dsdb_schema *schema;
801 time_t t = time(NULL);
803 const struct GUID *our_invocation_id;
805 const char *attrs[] = { "replPropertyMetaData" , NULL };
806 struct ldb_result *res;
807 struct ldb_context *ldb;
809 ldb = ldb_module_get_ctx(module);
811 our_invocation_id = samdb_ntds_invocation_id(ldb);
812 if (!our_invocation_id) {
813 /* this happens during an initial vampire while
814 updating the schema */
815 DEBUG(5,("No invocationID - skipping replPropertyMetaData update\n"));
819 unix_to_nt_time(&now, t);
821 /* search for the existing replPropertyMetaDataBlob */
822 ret = ldb_search(ldb, msg, &res, msg->dn, LDB_SCOPE_BASE, attrs, NULL);
823 if (ret != LDB_SUCCESS || res->count < 1) {
824 DEBUG(0,(__location__ ": Object %s failed to find replPropertyMetaData\n",
825 ldb_dn_get_linearized(msg->dn)));
826 return LDB_ERR_OPERATIONS_ERROR;
830 omd_value = ldb_msg_find_ldb_val(res->msgs[0], "replPropertyMetaData");
832 DEBUG(0,(__location__ ": Object %s does not have a replPropertyMetaData attribute\n",
833 ldb_dn_get_linearized(msg->dn)));
834 return LDB_ERR_OPERATIONS_ERROR;
837 ndr_err = ndr_pull_struct_blob(omd_value, msg,
838 lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")), &omd,
839 (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
840 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
841 DEBUG(0,(__location__ ": Failed to parse replPropertyMetaData for %s\n",
842 ldb_dn_get_linearized(msg->dn)));
843 return LDB_ERR_OPERATIONS_ERROR;
846 if (omd.version != 1) {
847 DEBUG(0,(__location__ ": bad version %u in replPropertyMetaData for %s\n",
848 omd.version, ldb_dn_get_linearized(msg->dn)));
849 return LDB_ERR_OPERATIONS_ERROR;
852 schema = dsdb_get_schema(ldb);
854 for (i=0; i<msg->num_elements; i++) {
855 ret = replmd_update_rpmd_element(ldb, msg, &msg->elements[i], &omd, schema, seq_num,
856 our_invocation_id, now);
857 if (ret != LDB_SUCCESS) {
863 * replmd_update_rpmd_element has done an update if the
867 struct ldb_val *md_value;
868 struct ldb_message_element *el;
870 md_value = talloc(msg, struct ldb_val);
871 if (md_value == NULL) {
873 return LDB_ERR_OPERATIONS_ERROR;
876 ndr_err = ndr_push_struct_blob(md_value, msg,
877 lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")),
879 (ndr_push_flags_fn_t)ndr_push_replPropertyMetaDataBlob);
880 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
881 DEBUG(0,(__location__ ": Failed to marshall replPropertyMetaData for %s\n",
882 ldb_dn_get_linearized(msg->dn)));
883 return LDB_ERR_OPERATIONS_ERROR;
886 ret = ldb_msg_add_empty(msg, "replPropertyMetaData", LDB_FLAG_MOD_REPLACE, &el);
887 if (ret != LDB_SUCCESS) {
888 DEBUG(0,(__location__ ": Failed to add updated replPropertyMetaData %s\n",
889 ldb_dn_get_linearized(msg->dn)));
893 ret = replmd_notify(module, msg->dn, *seq_num);
894 if (ret != LDB_SUCCESS) {
899 el->values = md_value;
906 static int replmd_modify(struct ldb_module *module, struct ldb_request *req)
908 struct ldb_context *ldb;
909 struct replmd_replicated_request *ac;
910 const struct dsdb_schema *schema;
911 struct ldb_request *down_req;
912 struct ldb_message *msg;
914 time_t t = time(NULL);
915 uint64_t seq_num = 0;
917 /* do not manipulate our control entries */
918 if (ldb_dn_is_special(req->op.mod.message->dn)) {
919 return ldb_next_request(module, req);
922 ldb = ldb_module_get_ctx(module);
924 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_modify\n");
926 schema = dsdb_get_schema(ldb);
928 ldb_debug_set(ldb, LDB_DEBUG_FATAL,
929 "replmd_modify: no dsdb_schema loaded");
930 return LDB_ERR_CONSTRAINT_VIOLATION;
933 ac = replmd_ctx_init(module, req);
935 return LDB_ERR_OPERATIONS_ERROR;
940 /* we have to copy the message as the caller might have it as a const */
941 msg = ldb_msg_copy_shallow(ac, req->op.mod.message);
944 return LDB_ERR_OPERATIONS_ERROR;
948 * - get the whole old object
949 * - if the old object doesn't exist report an error
950 * - give an error when a readonly attribute should
952 * - merge the changed into the old object
953 * if the caller set values to the same value
954 * ignore the attribute, return success when no
955 * attribute was changed
958 ret = replmd_update_rpmd(module, msg, &seq_num);
959 if (ret != LDB_SUCCESS) {
964 * - sort the attributes by attid with replmd_ldb_message_sort()
965 * - replace the old object with the newly constructed one
968 ret = ldb_build_mod_req(&down_req, ldb, ac,
971 ac, replmd_op_callback,
973 if (ret != LDB_SUCCESS) {
976 talloc_steal(down_req, msg);
978 /* we only change whenChanged and uSNChanged if the seq_num
981 if (add_time_element(msg, "whenChanged", t) != LDB_SUCCESS) {
983 return LDB_ERR_OPERATIONS_ERROR;
986 if (add_uint64_element(msg, "uSNChanged", seq_num) != LDB_SUCCESS) {
988 return LDB_ERR_OPERATIONS_ERROR;
992 /* go on with the call chain */
993 return ldb_next_request(module, down_req);
996 static int replmd_replicated_request_error(struct replmd_replicated_request *ar, int ret)
1001 static int replmd_replicated_request_werror(struct replmd_replicated_request *ar, WERROR status)
1003 int ret = LDB_ERR_OTHER;
1004 /* TODO: do some error mapping */
1008 static int replmd_replicated_apply_next(struct replmd_replicated_request *ar);
1010 static int replmd_replicated_apply_add_callback(struct ldb_request *req,
1011 struct ldb_reply *ares)
1013 struct ldb_context *ldb;
1014 struct replmd_replicated_request *ar = talloc_get_type(req->context,
1015 struct replmd_replicated_request);
1018 ldb = ldb_module_get_ctx(ar->module);
1021 return ldb_module_done(ar->req, NULL, NULL,
1022 LDB_ERR_OPERATIONS_ERROR);
1024 if (ares->error != LDB_SUCCESS) {
1025 return ldb_module_done(ar->req, ares->controls,
1026 ares->response, ares->error);
1029 if (ares->type != LDB_REPLY_DONE) {
1030 ldb_set_errstring(ldb, "Invalid reply type\n!");
1031 return ldb_module_done(ar->req, NULL, NULL,
1032 LDB_ERR_OPERATIONS_ERROR);
1036 ar->index_current++;
1038 ret = replmd_replicated_apply_next(ar);
1039 if (ret != LDB_SUCCESS) {
1040 return ldb_module_done(ar->req, NULL, NULL, ret);
1046 static int replmd_replicated_apply_add(struct replmd_replicated_request *ar)
1048 struct ldb_context *ldb;
1049 struct ldb_request *change_req;
1050 enum ndr_err_code ndr_err;
1051 struct ldb_message *msg;
1052 struct replPropertyMetaDataBlob *md;
1053 struct ldb_val md_value;
1059 * TODO: check if the parent object exist
1063 * TODO: handle the conflict case where an object with the
1067 ldb = ldb_module_get_ctx(ar->module);
1068 msg = ar->objs->objects[ar->index_current].msg;
1069 md = ar->objs->objects[ar->index_current].meta_data;
1071 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &seq_num);
1072 if (ret != LDB_SUCCESS) {
1073 return replmd_replicated_request_error(ar, ret);
1076 ret = ldb_msg_add_value(msg, "objectGUID", &ar->objs->objects[ar->index_current].guid_value, NULL);
1077 if (ret != LDB_SUCCESS) {
1078 return replmd_replicated_request_error(ar, ret);
1081 ret = ldb_msg_add_string(msg, "whenChanged", ar->objs->objects[ar->index_current].when_changed);
1082 if (ret != LDB_SUCCESS) {
1083 return replmd_replicated_request_error(ar, ret);
1086 ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNCreated", seq_num);
1087 if (ret != LDB_SUCCESS) {
1088 return replmd_replicated_request_error(ar, ret);
1091 ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNChanged", seq_num);
1092 if (ret != LDB_SUCCESS) {
1093 return replmd_replicated_request_error(ar, ret);
1096 ret = replmd_notify(ar->module, msg->dn, seq_num);
1097 if (ret != LDB_SUCCESS) {
1098 return replmd_replicated_request_error(ar, ret);
1102 * the meta data array is already sorted by the caller
1104 for (i=0; i < md->ctr.ctr1.count; i++) {
1105 md->ctr.ctr1.array[i].local_usn = seq_num;
1107 ndr_err = ndr_push_struct_blob(&md_value, msg,
1108 lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")),
1110 (ndr_push_flags_fn_t)ndr_push_replPropertyMetaDataBlob);
1111 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1112 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
1113 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
1115 ret = ldb_msg_add_value(msg, "replPropertyMetaData", &md_value, NULL);
1116 if (ret != LDB_SUCCESS) {
1117 return replmd_replicated_request_error(ar, ret);
1120 replmd_ldb_message_sort(msg, ar->schema);
1123 char *s = ldb_ldif_message_string(ldb, ar, LDB_CHANGETYPE_ADD, msg);
1124 DEBUG(4, ("DRS replication add message:\n%s\n", s));
1128 ret = ldb_build_add_req(&change_req,
1134 replmd_replicated_apply_add_callback,
1136 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
1138 return ldb_next_request(ar->module, change_req);
1141 static int replmd_replPropertyMetaData1_conflict_compare(struct replPropertyMetaData1 *m1,
1142 struct replPropertyMetaData1 *m2)
1146 if (m1->version != m2->version) {
1147 return m1->version - m2->version;
1150 if (m1->originating_change_time != m2->originating_change_time) {
1151 return m1->originating_change_time - m2->originating_change_time;
1154 ret = GUID_compare(&m1->originating_invocation_id, &m2->originating_invocation_id);
1159 return m1->originating_usn - m2->originating_usn;
1162 static int replmd_replicated_apply_merge_callback(struct ldb_request *req,
1163 struct ldb_reply *ares)
1165 struct ldb_context *ldb;
1166 struct replmd_replicated_request *ar = talloc_get_type(req->context,
1167 struct replmd_replicated_request);
1170 ldb = ldb_module_get_ctx(ar->module);
1173 return ldb_module_done(ar->req, NULL, NULL,
1174 LDB_ERR_OPERATIONS_ERROR);
1176 if (ares->error != LDB_SUCCESS) {
1177 return ldb_module_done(ar->req, ares->controls,
1178 ares->response, ares->error);
1181 if (ares->type != LDB_REPLY_DONE) {
1182 ldb_set_errstring(ldb, "Invalid reply type\n!");
1183 return ldb_module_done(ar->req, NULL, NULL,
1184 LDB_ERR_OPERATIONS_ERROR);
1188 ar->index_current++;
1190 ret = replmd_replicated_apply_next(ar);
1191 if (ret != LDB_SUCCESS) {
1192 return ldb_module_done(ar->req, NULL, NULL, ret);
1198 static int replmd_replicated_apply_merge(struct replmd_replicated_request *ar)
1200 struct ldb_context *ldb;
1201 struct ldb_request *change_req;
1202 enum ndr_err_code ndr_err;
1203 struct ldb_message *msg;
1204 struct replPropertyMetaDataBlob *rmd;
1205 struct replPropertyMetaDataBlob omd;
1206 const struct ldb_val *omd_value;
1207 struct replPropertyMetaDataBlob nmd;
1208 struct ldb_val nmd_value;
1210 uint32_t removed_attrs = 0;
1214 ldb = ldb_module_get_ctx(ar->module);
1215 msg = ar->objs->objects[ar->index_current].msg;
1216 rmd = ar->objs->objects[ar->index_current].meta_data;
1221 * TODO: check repl data is correct after a rename
1223 if (ldb_dn_compare(msg->dn, ar->search_msg->dn) != 0) {
1224 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_replicated_request rename %s => %s\n",
1225 ldb_dn_get_linearized(ar->search_msg->dn),
1226 ldb_dn_get_linearized(msg->dn));
1227 if (ldb_rename(ldb, ar->search_msg->dn, msg->dn) != LDB_SUCCESS) {
1228 ldb_debug(ldb, LDB_DEBUG_FATAL, "replmd_replicated_request rename %s => %s failed - %s\n",
1229 ldb_dn_get_linearized(ar->search_msg->dn),
1230 ldb_dn_get_linearized(msg->dn),
1231 ldb_errstring(ldb));
1232 return replmd_replicated_request_werror(ar, WERR_DS_DRA_DB_ERROR);
1236 /* find existing meta data */
1237 omd_value = ldb_msg_find_ldb_val(ar->search_msg, "replPropertyMetaData");
1239 ndr_err = ndr_pull_struct_blob(omd_value, ar,
1240 lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")), &omd,
1241 (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
1242 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1243 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
1244 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
1247 if (omd.version != 1) {
1248 return replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
1254 nmd.ctr.ctr1.count = omd.ctr.ctr1.count + rmd->ctr.ctr1.count;
1255 nmd.ctr.ctr1.array = talloc_array(ar,
1256 struct replPropertyMetaData1,
1257 nmd.ctr.ctr1.count);
1258 if (!nmd.ctr.ctr1.array) return replmd_replicated_request_werror(ar, WERR_NOMEM);
1260 /* first copy the old meta data */
1261 for (i=0; i < omd.ctr.ctr1.count; i++) {
1262 nmd.ctr.ctr1.array[ni] = omd.ctr.ctr1.array[i];
1266 /* now merge in the new meta data */
1267 for (i=0; i < rmd->ctr.ctr1.count; i++) {
1270 for (j=0; j < ni; j++) {
1273 if (rmd->ctr.ctr1.array[i].attid != nmd.ctr.ctr1.array[j].attid) {
1277 cmp = replmd_replPropertyMetaData1_conflict_compare(&rmd->ctr.ctr1.array[i],
1278 &nmd.ctr.ctr1.array[j]);
1280 /* replace the entry */
1281 nmd.ctr.ctr1.array[j] = rmd->ctr.ctr1.array[i];
1286 /* we don't want to apply this change so remove the attribute */
1287 ldb_msg_remove_element(msg, &msg->elements[i-removed_attrs]);
1294 if (found) continue;
1296 nmd.ctr.ctr1.array[ni] = rmd->ctr.ctr1.array[i];
1301 * finally correct the size of the meta_data array
1303 nmd.ctr.ctr1.count = ni;
1306 * the rdn attribute (the alias for the name attribute),
1307 * 'cn' for most objects is the last entry in the meta data array
1310 * sort the new meta data array
1313 struct replPropertyMetaData1 *rdn_p;
1314 uint32_t rdn_idx = omd.ctr.ctr1.count - 1;
1316 rdn_p = &nmd.ctr.ctr1.array[rdn_idx];
1317 replmd_replPropertyMetaDataCtr1_sort(&nmd.ctr.ctr1, &rdn_p->attid);
1320 /* create the meta data value */
1321 ndr_err = ndr_push_struct_blob(&nmd_value, msg,
1322 lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")),
1324 (ndr_push_flags_fn_t)ndr_push_replPropertyMetaDataBlob);
1325 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1326 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
1327 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
1331 * check if some replicated attributes left, otherwise skip the ldb_modify() call
1333 if (msg->num_elements == 0) {
1334 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_replicated_apply_merge[%u]: skip replace\n",
1337 ar->index_current++;
1338 return replmd_replicated_apply_next(ar);
1341 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_replicated_apply_merge[%u]: replace %u attributes\n",
1342 ar->index_current, msg->num_elements);
1344 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &seq_num);
1345 if (ret != LDB_SUCCESS) {
1346 return replmd_replicated_request_error(ar, ret);
1349 for (i=0; i<ni; i++) {
1350 nmd.ctr.ctr1.array[i].local_usn = seq_num;
1354 * when we know that we'll modify the record, add the whenChanged, uSNChanged
1355 * and replPopertyMetaData attributes
1357 ret = ldb_msg_add_string(msg, "whenChanged", ar->objs->objects[ar->index_current].when_changed);
1358 if (ret != LDB_SUCCESS) {
1359 return replmd_replicated_request_error(ar, ret);
1361 ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNChanged", seq_num);
1362 if (ret != LDB_SUCCESS) {
1363 return replmd_replicated_request_error(ar, ret);
1365 ret = ldb_msg_add_value(msg, "replPropertyMetaData", &nmd_value, NULL);
1366 if (ret != LDB_SUCCESS) {
1367 return replmd_replicated_request_error(ar, ret);
1370 replmd_ldb_message_sort(msg, ar->schema);
1372 /* we want to replace the old values */
1373 for (i=0; i < msg->num_elements; i++) {
1374 msg->elements[i].flags = LDB_FLAG_MOD_REPLACE;
1377 ret = replmd_notify(ar->module, msg->dn, seq_num);
1378 if (ret != LDB_SUCCESS) {
1379 return replmd_replicated_request_error(ar, ret);
1383 char *s = ldb_ldif_message_string(ldb, ar, LDB_CHANGETYPE_MODIFY, msg);
1384 DEBUG(4, ("DRS replication modify message:\n%s\n", s));
1388 ret = ldb_build_mod_req(&change_req,
1394 replmd_replicated_apply_merge_callback,
1396 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
1398 return ldb_next_request(ar->module, change_req);
1401 static int replmd_replicated_apply_search_callback(struct ldb_request *req,
1402 struct ldb_reply *ares)
1404 struct replmd_replicated_request *ar = talloc_get_type(req->context,
1405 struct replmd_replicated_request);
1409 return ldb_module_done(ar->req, NULL, NULL,
1410 LDB_ERR_OPERATIONS_ERROR);
1412 if (ares->error != LDB_SUCCESS &&
1413 ares->error != LDB_ERR_NO_SUCH_OBJECT) {
1414 return ldb_module_done(ar->req, ares->controls,
1415 ares->response, ares->error);
1418 switch (ares->type) {
1419 case LDB_REPLY_ENTRY:
1420 ar->search_msg = talloc_steal(ar, ares->message);
1423 case LDB_REPLY_REFERRAL:
1424 /* we ignore referrals */
1427 case LDB_REPLY_DONE:
1428 if (ar->search_msg != NULL) {
1429 ret = replmd_replicated_apply_merge(ar);
1431 ret = replmd_replicated_apply_add(ar);
1433 if (ret != LDB_SUCCESS) {
1434 return ldb_module_done(ar->req, NULL, NULL, ret);
1442 static int replmd_replicated_uptodate_vector(struct replmd_replicated_request *ar);
1444 static int replmd_replicated_apply_next(struct replmd_replicated_request *ar)
1446 struct ldb_context *ldb;
1450 struct ldb_request *search_req;
1452 if (ar->index_current >= ar->objs->num_objects) {
1453 /* done with it, go to next stage */
1454 return replmd_replicated_uptodate_vector(ar);
1457 ldb = ldb_module_get_ctx(ar->module);
1458 ar->search_msg = NULL;
1460 tmp_str = ldb_binary_encode(ar, ar->objs->objects[ar->index_current].guid_value);
1461 if (!tmp_str) return replmd_replicated_request_werror(ar, WERR_NOMEM);
1463 filter = talloc_asprintf(ar, "(objectGUID=%s)", tmp_str);
1464 if (!filter) return replmd_replicated_request_werror(ar, WERR_NOMEM);
1465 talloc_free(tmp_str);
1467 ret = ldb_build_search_req(&search_req,
1470 ar->objs->partition_dn,
1476 replmd_replicated_apply_search_callback,
1478 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
1480 return ldb_next_request(ar->module, search_req);
1483 static int replmd_replicated_uptodate_modify_callback(struct ldb_request *req,
1484 struct ldb_reply *ares)
1486 struct ldb_context *ldb;
1487 struct replmd_replicated_request *ar = talloc_get_type(req->context,
1488 struct replmd_replicated_request);
1489 ldb = ldb_module_get_ctx(ar->module);
1492 return ldb_module_done(ar->req, NULL, NULL,
1493 LDB_ERR_OPERATIONS_ERROR);
1495 if (ares->error != LDB_SUCCESS) {
1496 return ldb_module_done(ar->req, ares->controls,
1497 ares->response, ares->error);
1500 if (ares->type != LDB_REPLY_DONE) {
1501 ldb_set_errstring(ldb, "Invalid reply type\n!");
1502 return ldb_module_done(ar->req, NULL, NULL,
1503 LDB_ERR_OPERATIONS_ERROR);
1508 return ldb_module_done(ar->req, NULL, NULL, LDB_SUCCESS);
1511 static int replmd_drsuapi_DsReplicaCursor2_compare(const struct drsuapi_DsReplicaCursor2 *c1,
1512 const struct drsuapi_DsReplicaCursor2 *c2)
1514 return GUID_compare(&c1->source_dsa_invocation_id, &c2->source_dsa_invocation_id);
1517 static int replmd_replicated_uptodate_modify(struct replmd_replicated_request *ar)
1519 struct ldb_context *ldb;
1520 struct ldb_request *change_req;
1521 enum ndr_err_code ndr_err;
1522 struct ldb_message *msg;
1523 struct replUpToDateVectorBlob ouv;
1524 const struct ldb_val *ouv_value;
1525 const struct drsuapi_DsReplicaCursor2CtrEx *ruv;
1526 struct replUpToDateVectorBlob nuv;
1527 struct ldb_val nuv_value;
1528 struct ldb_message_element *nuv_el = NULL;
1529 const struct GUID *our_invocation_id;
1530 struct ldb_message_element *orf_el = NULL;
1531 struct repsFromToBlob nrf;
1532 struct ldb_val *nrf_value = NULL;
1533 struct ldb_message_element *nrf_el = NULL;
1536 time_t t = time(NULL);
1540 ldb = ldb_module_get_ctx(ar->module);
1541 ruv = ar->objs->uptodateness_vector;
1547 unix_to_nt_time(&now, t);
1550 * first create the new replUpToDateVector
1552 ouv_value = ldb_msg_find_ldb_val(ar->search_msg, "replUpToDateVector");
1554 ndr_err = ndr_pull_struct_blob(ouv_value, ar,
1555 lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")), &ouv,
1556 (ndr_pull_flags_fn_t)ndr_pull_replUpToDateVectorBlob);
1557 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1558 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
1559 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
1562 if (ouv.version != 2) {
1563 return replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
1568 * the new uptodateness vector will at least
1569 * contain 1 entry, one for the source_dsa
1571 * plus optional values from our old vector and the one from the source_dsa
1573 nuv.ctr.ctr2.count = 1 + ouv.ctr.ctr2.count;
1574 if (ruv) nuv.ctr.ctr2.count += ruv->count;
1575 nuv.ctr.ctr2.cursors = talloc_array(ar,
1576 struct drsuapi_DsReplicaCursor2,
1577 nuv.ctr.ctr2.count);
1578 if (!nuv.ctr.ctr2.cursors) return replmd_replicated_request_werror(ar, WERR_NOMEM);
1580 /* first copy the old vector */
1581 for (i=0; i < ouv.ctr.ctr2.count; i++) {
1582 nuv.ctr.ctr2.cursors[ni] = ouv.ctr.ctr2.cursors[i];
1586 /* get our invocation_id if we have one already attached to the ldb */
1587 our_invocation_id = samdb_ntds_invocation_id(ldb);
1589 /* merge in the source_dsa vector is available */
1590 for (i=0; (ruv && i < ruv->count); i++) {
1593 if (our_invocation_id &&
1594 GUID_equal(&ruv->cursors[i].source_dsa_invocation_id,
1595 our_invocation_id)) {
1599 for (j=0; j < ni; j++) {
1600 if (!GUID_equal(&ruv->cursors[i].source_dsa_invocation_id,
1601 &nuv.ctr.ctr2.cursors[j].source_dsa_invocation_id)) {
1608 * we update only the highest_usn and not the latest_sync_success time,
1609 * because the last success stands for direct replication
1611 if (ruv->cursors[i].highest_usn > nuv.ctr.ctr2.cursors[j].highest_usn) {
1612 nuv.ctr.ctr2.cursors[j].highest_usn = ruv->cursors[i].highest_usn;
1617 if (found) continue;
1619 /* if it's not there yet, add it */
1620 nuv.ctr.ctr2.cursors[ni] = ruv->cursors[i];
1625 * merge in the current highwatermark for the source_dsa
1628 for (j=0; j < ni; j++) {
1629 if (!GUID_equal(&ar->objs->source_dsa->source_dsa_invocation_id,
1630 &nuv.ctr.ctr2.cursors[j].source_dsa_invocation_id)) {
1637 * here we update the highest_usn and last_sync_success time
1638 * because we're directly replicating from the source_dsa
1640 * and use the tmp_highest_usn because this is what we have just applied
1643 nuv.ctr.ctr2.cursors[j].highest_usn = ar->objs->source_dsa->highwatermark.tmp_highest_usn;
1644 nuv.ctr.ctr2.cursors[j].last_sync_success = now;
1649 * here we update the highest_usn and last_sync_success time
1650 * because we're directly replicating from the source_dsa
1652 * and use the tmp_highest_usn because this is what we have just applied
1655 nuv.ctr.ctr2.cursors[ni].source_dsa_invocation_id= ar->objs->source_dsa->source_dsa_invocation_id;
1656 nuv.ctr.ctr2.cursors[ni].highest_usn = ar->objs->source_dsa->highwatermark.tmp_highest_usn;
1657 nuv.ctr.ctr2.cursors[ni].last_sync_success = now;
1662 * finally correct the size of the cursors array
1664 nuv.ctr.ctr2.count = ni;
1669 qsort(nuv.ctr.ctr2.cursors, nuv.ctr.ctr2.count,
1670 sizeof(struct drsuapi_DsReplicaCursor2),
1671 (comparison_fn_t)replmd_drsuapi_DsReplicaCursor2_compare);
1674 * create the change ldb_message
1676 msg = ldb_msg_new(ar);
1677 if (!msg) return replmd_replicated_request_werror(ar, WERR_NOMEM);
1678 msg->dn = ar->search_msg->dn;
1680 ndr_err = ndr_push_struct_blob(&nuv_value, msg,
1681 lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")),
1683 (ndr_push_flags_fn_t)ndr_push_replUpToDateVectorBlob);
1684 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1685 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
1686 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
1688 ret = ldb_msg_add_value(msg, "replUpToDateVector", &nuv_value, &nuv_el);
1689 if (ret != LDB_SUCCESS) {
1690 return replmd_replicated_request_error(ar, ret);
1692 nuv_el->flags = LDB_FLAG_MOD_REPLACE;
1695 * now create the new repsFrom value from the given repsFromTo1 structure
1699 nrf.ctr.ctr1 = *ar->objs->source_dsa;
1700 /* and fix some values... */
1701 nrf.ctr.ctr1.consecutive_sync_failures = 0;
1702 nrf.ctr.ctr1.last_success = now;
1703 nrf.ctr.ctr1.last_attempt = now;
1704 nrf.ctr.ctr1.result_last_attempt = WERR_OK;
1705 nrf.ctr.ctr1.highwatermark.highest_usn = nrf.ctr.ctr1.highwatermark.tmp_highest_usn;
1708 * first see if we already have a repsFrom value for the current source dsa
1709 * if so we'll later replace this value
1711 orf_el = ldb_msg_find_element(ar->search_msg, "repsFrom");
1713 for (i=0; i < orf_el->num_values; i++) {
1714 struct repsFromToBlob *trf;
1716 trf = talloc(ar, struct repsFromToBlob);
1717 if (!trf) return replmd_replicated_request_werror(ar, WERR_NOMEM);
1719 ndr_err = ndr_pull_struct_blob(&orf_el->values[i], trf, lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")), trf,
1720 (ndr_pull_flags_fn_t)ndr_pull_repsFromToBlob);
1721 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1722 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
1723 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
1726 if (trf->version != 1) {
1727 return replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
1731 * we compare the source dsa objectGUID not the invocation_id
1732 * because we want only one repsFrom value per source dsa
1733 * and when the invocation_id of the source dsa has changed we don't need
1734 * the old repsFrom with the old invocation_id
1736 if (!GUID_equal(&trf->ctr.ctr1.source_dsa_obj_guid,
1737 &ar->objs->source_dsa->source_dsa_obj_guid)) {
1743 nrf_value = &orf_el->values[i];
1748 * copy over all old values to the new ldb_message
1750 ret = ldb_msg_add_empty(msg, "repsFrom", 0, &nrf_el);
1751 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
1756 * if we haven't found an old repsFrom value for the current source dsa
1757 * we'll add a new value
1760 struct ldb_val zero_value;
1761 ZERO_STRUCT(zero_value);
1762 ret = ldb_msg_add_value(msg, "repsFrom", &zero_value, &nrf_el);
1763 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
1765 nrf_value = &nrf_el->values[nrf_el->num_values - 1];
1768 /* we now fill the value which is already attached to ldb_message */
1769 ndr_err = ndr_push_struct_blob(nrf_value, msg,
1770 lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")),
1772 (ndr_push_flags_fn_t)ndr_push_repsFromToBlob);
1773 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1774 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
1775 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
1779 * the ldb_message_element for the attribute, has all the old values and the new one
1780 * so we'll replace the whole attribute with all values
1782 nrf_el->flags = LDB_FLAG_MOD_REPLACE;
1785 char *s = ldb_ldif_message_string(ldb, ar, LDB_CHANGETYPE_MODIFY, msg);
1786 DEBUG(4, ("DRS replication uptodate modify message:\n%s\n", s));
1790 /* prepare the ldb_modify() request */
1791 ret = ldb_build_mod_req(&change_req,
1797 replmd_replicated_uptodate_modify_callback,
1799 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
1801 return ldb_next_request(ar->module, change_req);
1804 static int replmd_replicated_uptodate_search_callback(struct ldb_request *req,
1805 struct ldb_reply *ares)
1807 struct replmd_replicated_request *ar = talloc_get_type(req->context,
1808 struct replmd_replicated_request);
1812 return ldb_module_done(ar->req, NULL, NULL,
1813 LDB_ERR_OPERATIONS_ERROR);
1815 if (ares->error != LDB_SUCCESS &&
1816 ares->error != LDB_ERR_NO_SUCH_OBJECT) {
1817 return ldb_module_done(ar->req, ares->controls,
1818 ares->response, ares->error);
1821 switch (ares->type) {
1822 case LDB_REPLY_ENTRY:
1823 ar->search_msg = talloc_steal(ar, ares->message);
1826 case LDB_REPLY_REFERRAL:
1827 /* we ignore referrals */
1830 case LDB_REPLY_DONE:
1831 if (ar->search_msg == NULL) {
1832 ret = replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
1834 ret = replmd_replicated_uptodate_modify(ar);
1836 if (ret != LDB_SUCCESS) {
1837 return ldb_module_done(ar->req, NULL, NULL, ret);
1846 static int replmd_replicated_uptodate_vector(struct replmd_replicated_request *ar)
1848 struct ldb_context *ldb;
1850 static const char *attrs[] = {
1851 "replUpToDateVector",
1855 struct ldb_request *search_req;
1857 ldb = ldb_module_get_ctx(ar->module);
1858 ar->search_msg = NULL;
1860 ret = ldb_build_search_req(&search_req,
1863 ar->objs->partition_dn,
1869 replmd_replicated_uptodate_search_callback,
1871 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
1873 return ldb_next_request(ar->module, search_req);
1878 static int replmd_extended_replicated_objects(struct ldb_module *module, struct ldb_request *req)
1880 struct ldb_context *ldb;
1881 struct dsdb_extended_replicated_objects *objs;
1882 struct replmd_replicated_request *ar;
1883 struct ldb_control **ctrls;
1885 struct dsdb_control_current_partition *partition_ctrl;
1886 struct replmd_private *replmd_private =
1887 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
1889 ldb = ldb_module_get_ctx(module);
1891 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_extended_replicated_objects\n");
1893 objs = talloc_get_type(req->op.extended.data, struct dsdb_extended_replicated_objects);
1895 ldb_debug(ldb, LDB_DEBUG_FATAL, "replmd_extended_replicated_objects: invalid extended data\n");
1896 return LDB_ERR_PROTOCOL_ERROR;
1899 if (objs->version != DSDB_EXTENDED_REPLICATED_OBJECTS_VERSION) {
1900 ldb_debug(ldb, LDB_DEBUG_FATAL, "replmd_extended_replicated_objects: extended data invalid version [%u != %u]\n",
1901 objs->version, DSDB_EXTENDED_REPLICATED_OBJECTS_VERSION);
1902 return LDB_ERR_PROTOCOL_ERROR;
1905 ar = replmd_ctx_init(module, req);
1907 return LDB_ERR_OPERATIONS_ERROR;
1910 ar->schema = dsdb_get_schema(ldb);
1912 ldb_debug_set(ldb, LDB_DEBUG_FATAL, "replmd_ctx_init: no loaded schema found\n");
1914 return LDB_ERR_CONSTRAINT_VIOLATION;
1917 ctrls = req->controls;
1919 if (req->controls) {
1920 req->controls = talloc_memdup(ar, req->controls,
1921 talloc_get_size(req->controls));
1922 if (!req->controls) return replmd_replicated_request_werror(ar, WERR_NOMEM);
1925 ret = ldb_request_add_control(req, DSDB_CONTROL_REPLICATED_UPDATE_OID, false, NULL);
1926 if (ret != LDB_SUCCESS) {
1931 add the DSDB_CONTROL_CURRENT_PARTITION_OID control. This
1932 tells the partition module which partition this request is
1933 directed at. That is important as the partition roots appear
1934 twice in the directory, once as mount points in the top
1935 level store, and once as the roots of each partition. The
1936 replication code wants to operate on the root of the
1937 partitions, not the top level mount points
1939 partition_ctrl = talloc(req, struct dsdb_control_current_partition);
1940 if (partition_ctrl == NULL) {
1941 if (!partition_ctrl) return replmd_replicated_request_werror(ar, WERR_NOMEM);
1943 partition_ctrl->version = DSDB_CONTROL_CURRENT_PARTITION_VERSION;
1944 partition_ctrl->dn = objs->partition_dn;
1946 ret = ldb_request_add_control(req, DSDB_CONTROL_CURRENT_PARTITION_OID, false, partition_ctrl);
1947 if (ret != LDB_SUCCESS) {
1951 ar->controls = req->controls;
1952 req->controls = ctrls;
1954 DEBUG(4,("linked_attributes_count=%u\n", objs->linked_attributes_count));
1956 /* save away the linked attributes for the end of the
1958 for (i=0; i<ar->objs->linked_attributes_count; i++) {
1959 struct la_entry *la_entry;
1961 if (replmd_private->la_list) {
1962 la_entry = talloc(replmd_private->la_list,
1965 la_entry = talloc(replmd_private,
1968 if (la_entry == NULL) {
1970 return LDB_ERR_OPERATIONS_ERROR;
1972 la_entry->la = talloc(la_entry, struct drsuapi_DsReplicaLinkedAttribute);
1973 if (la_entry->la == NULL) {
1974 talloc_free(la_entry);
1976 return LDB_ERR_OPERATIONS_ERROR;
1978 *la_entry->la = ar->objs->linked_attributes[i];
1980 /* we need to steal the non-scalars so they stay
1981 around until the end of the transaction */
1982 talloc_steal(la_entry->la, la_entry->la->identifier);
1983 talloc_steal(la_entry->la, la_entry->la->value.blob);
1985 DLIST_ADD(replmd_private->la_list, la_entry);
1988 return replmd_replicated_apply_next(ar);
1992 process one linked attribute structure
1994 static int replmd_process_linked_attribute(struct ldb_module *module,
1995 struct la_entry *la_entry)
1997 struct drsuapi_DsReplicaLinkedAttribute *la = la_entry->la;
1998 struct ldb_context *ldb = ldb_module_get_ctx(module);
1999 struct drsuapi_DsReplicaObjectIdentifier3 target;
2000 struct ldb_message *msg;
2001 struct ldb_message_element *ret_el;
2002 TALLOC_CTX *tmp_ctx = talloc_new(la_entry);
2003 enum ndr_err_code ndr_err;
2005 struct ldb_request *mod_req;
2007 const struct dsdb_attribute *attr;
2010 linked_attributes[0]:
2011 &objs->linked_attributes[i]: struct drsuapi_DsReplicaLinkedAttribute
2013 identifier: struct drsuapi_DsReplicaObjectIdentifier
2014 __ndr_size : 0x0000003a (58)
2015 __ndr_size_sid : 0x00000000 (0)
2016 guid : 8e95b6a9-13dd-4158-89db-3220a5be5cc7
2018 __ndr_size_dn : 0x00000000 (0)
2020 attid : DRSUAPI_ATTRIBUTE_member (0x1F)
2021 value: struct drsuapi_DsAttributeValue
2022 __ndr_size : 0x0000007e (126)
2024 blob : DATA_BLOB length=126
2025 flags : 0x00000001 (1)
2026 1: DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE
2027 originating_add_time : Wed Sep 2 22:20:01 2009 EST
2028 meta_data: struct drsuapi_DsReplicaMetaData
2029 version : 0x00000015 (21)
2030 originating_change_time : Wed Sep 2 23:39:07 2009 EST
2031 originating_invocation_id: 794640f3-18cf-40ee-a211-a93992b67a64
2032 originating_usn : 0x000000000001e19c (123292)
2033 &target: struct drsuapi_DsReplicaObjectIdentifier3
2034 __ndr_size : 0x0000007e (126)
2035 __ndr_size_sid : 0x0000001c (28)
2036 guid : 7639e594-db75-4086-b0d4-67890ae46031
2037 sid : S-1-5-21-2848215498-2472035911-1947525656-19924
2038 __ndr_size_dn : 0x00000022 (34)
2039 dn : 'CN=UOne,OU=TestOU,DC=vsofs8,DC=com'
2042 NDR_PRINT_DEBUG(drsuapi_DsReplicaLinkedAttribute, la);
2045 /* decode the target of the link */
2046 ndr_err = ndr_pull_struct_blob(la->value.blob,
2047 tmp_ctx, lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")),
2049 (ndr_pull_flags_fn_t)ndr_pull_drsuapi_DsReplicaObjectIdentifier3);
2050 if (ndr_err != NDR_ERR_SUCCESS) {
2051 DEBUG(0,("Unable to decode linked_attribute target\n"));
2052 dump_data(4, la->value.blob->data, la->value.blob->length);
2053 talloc_free(tmp_ctx);
2054 return LDB_ERR_OPERATIONS_ERROR;
2057 NDR_PRINT_DEBUG(drsuapi_DsReplicaObjectIdentifier3, &target);
2060 /* construct a modify request for this attribute change */
2061 msg = ldb_msg_new(tmp_ctx);
2064 talloc_free(tmp_ctx);
2065 return LDB_ERR_OPERATIONS_ERROR;
2068 ret = dsdb_find_dn_by_guid(ldb, tmp_ctx,
2069 GUID_string(tmp_ctx, &la->identifier->guid), &msg->dn);
2070 if (ret != LDB_SUCCESS) {
2071 talloc_free(tmp_ctx);
2075 /* find the attribute being modified */
2076 attr = dsdb_attribute_by_attributeID_id(dsdb_get_schema(ldb), la->attid);
2078 DEBUG(0, (__location__ ": Unable to find attributeID 0x%x\n", la->attid));
2079 talloc_free(tmp_ctx);
2080 return LDB_ERR_OPERATIONS_ERROR;
2083 if (la->flags & DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE) {
2084 ret = ldb_msg_add_empty(msg, attr->lDAPDisplayName,
2085 LDB_FLAG_MOD_ADD, &ret_el);
2087 ret = ldb_msg_add_empty(msg, attr->lDAPDisplayName,
2088 LDB_FLAG_MOD_DELETE, &ret_el);
2090 if (ret != LDB_SUCCESS) {
2091 talloc_free(tmp_ctx);
2094 ret_el->values = talloc_array(msg, struct ldb_val, 1);
2095 if (!ret_el->values) {
2097 talloc_free(tmp_ctx);
2098 return LDB_ERR_OPERATIONS_ERROR;
2100 ret_el->num_values = 1;
2102 target_dn = talloc_asprintf(tmp_ctx, "<GUID=%s>;<SID=%s>;%s",
2103 GUID_string(tmp_ctx, &target.guid),
2104 dom_sid_string(tmp_ctx, &target.sid),
2106 if (target_dn == NULL) {
2108 talloc_free(tmp_ctx);
2109 return LDB_ERR_OPERATIONS_ERROR;
2111 ret_el->values[0] = data_blob_string_const(target_dn);
2113 ret = ldb_build_mod_req(&mod_req, ldb, tmp_ctx,
2117 ldb_op_default_callback,
2119 if (ret != LDB_SUCCESS) {
2120 talloc_free(tmp_ctx);
2123 talloc_steal(mod_req, msg);
2126 DEBUG(4,("Applying DRS linked attribute change:\n%s\n",
2127 ldb_ldif_message_string(ldb, tmp_ctx, LDB_CHANGETYPE_MODIFY, msg)));
2130 /* Run the new request */
2131 ret = ldb_next_request(module, mod_req);
2133 /* we need to wait for this to finish, as we are being called
2134 from the synchronous end_transaction hook of this module */
2135 if (ret == LDB_SUCCESS) {
2136 ret = ldb_wait(mod_req->handle, LDB_WAIT_ALL);
2139 if (ret != LDB_SUCCESS) {
2140 ldb_debug(ldb, LDB_DEBUG_WARNING, "Failed to apply linked attribute change '%s' %s\n",
2142 ldb_ldif_message_string(ldb, tmp_ctx, LDB_CHANGETYPE_MODIFY, msg));
2145 talloc_free(tmp_ctx);
2150 static int replmd_extended(struct ldb_module *module, struct ldb_request *req)
2152 if (strcmp(req->op.extended.oid, DSDB_EXTENDED_REPLICATED_OBJECTS_OID) == 0) {
2153 return replmd_extended_replicated_objects(module, req);
2156 return ldb_next_request(module, req);
2161 we hook into the transaction operations to allow us to
2162 perform the linked attribute updates at the end of the whole
2163 transaction. This allows a forward linked attribute to be created
2164 before the object is created. During a vampire, w2k8 sends us linked
2165 attributes before the objects they are part of.
2167 static int replmd_start_transaction(struct ldb_module *module)
2169 /* create our private structure for this transaction */
2171 struct replmd_private *replmd_private = talloc_get_type(ldb_module_get_private(module),
2172 struct replmd_private);
2173 talloc_free(replmd_private->la_list);
2174 replmd_private->la_list = NULL;
2176 for (i=0; i<replmd_private->num_ncs; i++) {
2177 replmd_private->ncs[i].mod_usn = 0;
2180 return ldb_next_start_trans(module);
2184 on prepare commit we loop over our queued la_context structures and
2187 static int replmd_prepare_commit(struct ldb_module *module)
2189 struct replmd_private *replmd_private =
2190 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
2191 struct la_entry *la, *prev;
2194 /* walk the list backwards, to do the first entry first, as we
2195 * added the entries with DLIST_ADD() which puts them at the
2196 * start of the list */
2197 for (la = replmd_private->la_list; la && la->next; la=la->next) ;
2199 for (; la; la=prev) {
2201 DLIST_REMOVE(replmd_private->la_list, la);
2202 ret = replmd_process_linked_attribute(module, la);
2204 if (ret != LDB_SUCCESS) {
2209 talloc_free(replmd_private->la_list);
2210 replmd_private->la_list = NULL;
2212 /* possibly change @REPLCHANGED */
2213 ret = replmd_notify_store(module);
2214 if (ret != LDB_SUCCESS) {
2218 return ldb_next_prepare_commit(module);
2221 static int replmd_del_transaction(struct ldb_module *module)
2223 struct replmd_private *replmd_private =
2224 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
2225 talloc_free(replmd_private->la_list);
2226 replmd_private->la_list = NULL;
2227 return ldb_next_del_trans(module);
2231 _PUBLIC_ const struct ldb_module_ops ldb_repl_meta_data_module_ops = {
2232 .name = "repl_meta_data",
2233 .init_context = replmd_init,
2235 .modify = replmd_modify,
2236 .extended = replmd_extended,
2237 .start_transaction = replmd_start_transaction,
2238 .prepare_commit = replmd_prepare_commit,
2239 .del_transaction = replmd_del_transaction,