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;
54 struct nc_entry *prev, *next;
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 /* the controls we pass down */
72 struct ldb_control **controls;
74 /* details for the mode where we apply a bunch of inbound replication meessages */
76 uint32_t index_current;
77 struct dsdb_extended_replicated_objects *objs;
79 struct ldb_message *search_msg;
85 static int replmd_replicated_apply_next(struct replmd_replicated_request *ar);
89 allocate the private structure and build the list
90 of partition DNs for use by replmd_notify()
92 static int replmd_init(struct ldb_module *module)
94 struct replmd_private *replmd_private;
95 struct ldb_context *ldb = ldb_module_get_ctx(module);
97 replmd_private = talloc_zero(module, struct replmd_private);
98 if (replmd_private == NULL) {
100 return LDB_ERR_OPERATIONS_ERROR;
102 ldb_module_set_private(module, replmd_private);
104 return ldb_next_init(module);
109 * Callback for most write operations in this module:
111 * notify the repl task that a object has changed. The notifies are
112 * gathered up in the replmd_private structure then written to the
113 * @REPLCHANGED object in each partition during the prepare_commit
115 static int replmd_op_callback(struct ldb_request *req, struct ldb_reply *ares)
118 struct replmd_replicated_request *ac =
119 talloc_get_type_abort(req->context, struct replmd_replicated_request);
120 struct replmd_private *replmd_private =
121 talloc_get_type_abort(ldb_module_get_private(ac->module), struct replmd_private);
122 struct nc_entry *modified_partition;
123 struct ldb_control *partition_ctrl;
124 const struct dsdb_control_current_partition *partition;
126 if (ares->error != LDB_SUCCESS) {
127 return ldb_module_done(ac->req, ares->controls,
128 ares->response, ares->error);
131 if (ares->type != LDB_REPLY_DONE) {
132 ldb_set_errstring(ldb_module_get_ctx(ac->module), "Invalid reply type for notify\n!");
133 return ldb_module_done(ac->req, NULL,
134 NULL, LDB_ERR_OPERATIONS_ERROR);
137 partition_ctrl = ldb_reply_get_control(ares, DSDB_CONTROL_CURRENT_PARTITION_OID);
138 if (!partition_ctrl) {
139 return ldb_module_done(ac->req, NULL,
140 NULL, LDB_ERR_OPERATIONS_ERROR);
142 partition = talloc_get_type_abort(partition_ctrl->data,
143 struct dsdb_control_current_partition);
145 if (ac->seq_num > 0) {
146 for (modified_partition = replmd_private->ncs; modified_partition;
147 modified_partition = modified_partition->next) {
148 if (ldb_dn_compare(modified_partition->dn, partition->dn) == 0) {
153 if (modified_partition == NULL) {
154 modified_partition = talloc_zero(replmd_private, struct nc_entry);
155 if (!modified_partition) {
156 ldb_oom(ldb_module_get_ctx(ac->module));
157 return ldb_module_done(ac->req, NULL,
158 NULL, LDB_ERR_OPERATIONS_ERROR);
160 modified_partition->dn = ldb_dn_copy(modified_partition, partition->dn);
161 if (!modified_partition->dn) {
162 ldb_oom(ldb_module_get_ctx(ac->module));
163 return ldb_module_done(ac->req, NULL,
164 NULL, LDB_ERR_OPERATIONS_ERROR);
166 DLIST_ADD(replmd_private->ncs, modified_partition);
169 if (ac->seq_num > modified_partition->mod_usn) {
170 modified_partition->mod_usn = ac->seq_num;
174 if (ac->apply_mode) {
178 ret = replmd_replicated_apply_next(ac);
179 if (ret != LDB_SUCCESS) {
180 return ldb_module_done(ac->req, NULL, NULL, ret);
184 return ldb_module_done(ac->req, ares->controls,
185 ares->response, LDB_SUCCESS);
191 * update a @REPLCHANGED record in each partition if there have been
192 * any writes of replicated data in the partition
194 static int replmd_notify_store(struct ldb_module *module)
196 struct replmd_private *replmd_private =
197 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
198 struct ldb_context *ldb = ldb_module_get_ctx(module);
199 struct nc_entry *modified_partition;
201 for (modified_partition = replmd_private->ncs; modified_partition;
202 modified_partition = modified_partition->next) {
205 ret = dsdb_save_partition_usn(ldb, modified_partition->dn, modified_partition->mod_usn);
206 if (ret != LDB_SUCCESS) {
207 DEBUG(0,(__location__ ": Failed to save partition uSN for %s\n",
208 ldb_dn_get_linearized(modified_partition->dn)));
218 created a replmd_replicated_request context
220 static struct replmd_replicated_request *replmd_ctx_init(struct ldb_module *module,
221 struct ldb_request *req)
223 struct ldb_context *ldb;
224 struct replmd_replicated_request *ac;
226 ldb = ldb_module_get_ctx(module);
228 ac = talloc_zero(req, struct replmd_replicated_request);
237 ac->schema = dsdb_get_schema(ldb);
239 ldb_debug_set(ldb, LDB_DEBUG_FATAL,
240 "replmd_modify: no dsdb_schema loaded");
241 DEBUG(0,(__location__ ": %s\n", ldb_errstring(ldb)));
249 add a time element to a record
251 static int add_time_element(struct ldb_message *msg, const char *attr, time_t t)
253 struct ldb_message_element *el;
256 if (ldb_msg_find_element(msg, attr) != NULL) {
260 s = ldb_timestring(msg, t);
262 return LDB_ERR_OPERATIONS_ERROR;
265 if (ldb_msg_add_string(msg, attr, s) != LDB_SUCCESS) {
266 return LDB_ERR_OPERATIONS_ERROR;
269 el = ldb_msg_find_element(msg, attr);
270 /* always set as replace. This works because on add ops, the flag
272 el->flags = LDB_FLAG_MOD_REPLACE;
278 add a uint64_t element to a record
280 static int add_uint64_element(struct ldb_message *msg, const char *attr, uint64_t v)
282 struct ldb_message_element *el;
284 if (ldb_msg_find_element(msg, attr) != NULL) {
288 if (ldb_msg_add_fmt(msg, attr, "%llu", (unsigned long long)v) != LDB_SUCCESS) {
289 return LDB_ERR_OPERATIONS_ERROR;
292 el = ldb_msg_find_element(msg, attr);
293 /* always set as replace. This works because on add ops, the flag
295 el->flags = LDB_FLAG_MOD_REPLACE;
300 static int replmd_replPropertyMetaData1_attid_sort(const struct replPropertyMetaData1 *m1,
301 const struct replPropertyMetaData1 *m2,
302 const uint32_t *rdn_attid)
304 if (m1->attid == m2->attid) {
309 * the rdn attribute should be at the end!
310 * so we need to return a value greater than zero
311 * which means m1 is greater than m2
313 if (m1->attid == *rdn_attid) {
318 * the rdn attribute should be at the end!
319 * so we need to return a value less than zero
320 * which means m2 is greater than m1
322 if (m2->attid == *rdn_attid) {
326 return m1->attid - m2->attid;
329 static int replmd_replPropertyMetaDataCtr1_sort(struct replPropertyMetaDataCtr1 *ctr1,
330 const struct dsdb_schema *schema,
333 const char *rdn_name;
334 const struct dsdb_attribute *rdn_sa;
336 rdn_name = ldb_dn_get_rdn_name(dn);
338 DEBUG(0,(__location__ ": No rDN for %s?\n", ldb_dn_get_linearized(dn)));
339 return LDB_ERR_OPERATIONS_ERROR;
342 rdn_sa = dsdb_attribute_by_lDAPDisplayName(schema, rdn_name);
343 if (rdn_sa == NULL) {
344 DEBUG(0,(__location__ ": No sa found for rDN %s for %s\n", rdn_name, ldb_dn_get_linearized(dn)));
345 return LDB_ERR_OPERATIONS_ERROR;
348 DEBUG(6,("Sorting rpmd with attid exception %u rDN=%s DN=%s\n",
349 rdn_sa->attributeID_id, rdn_name, ldb_dn_get_linearized(dn)));
351 ldb_qsort(ctr1->array, ctr1->count, sizeof(struct replPropertyMetaData1),
352 discard_const_p(void, &rdn_sa->attributeID_id),
353 (ldb_qsort_cmp_fn_t)replmd_replPropertyMetaData1_attid_sort);
358 static int replmd_ldb_message_element_attid_sort(const struct ldb_message_element *e1,
359 const struct ldb_message_element *e2,
360 const struct dsdb_schema *schema)
362 const struct dsdb_attribute *a1;
363 const struct dsdb_attribute *a2;
366 * TODO: make this faster by caching the dsdb_attribute pointer
367 * on the ldb_messag_element
370 a1 = dsdb_attribute_by_lDAPDisplayName(schema, e1->name);
371 a2 = dsdb_attribute_by_lDAPDisplayName(schema, e2->name);
374 * TODO: remove this check, we should rely on e1 and e2 having valid attribute names
378 return strcasecmp(e1->name, e2->name);
381 return a1->attributeID_id - a2->attributeID_id;
384 static void replmd_ldb_message_sort(struct ldb_message *msg,
385 const struct dsdb_schema *schema)
387 ldb_qsort(msg->elements, msg->num_elements, sizeof(struct ldb_message_element),
388 discard_const_p(void, schema), (ldb_qsort_cmp_fn_t)replmd_ldb_message_element_attid_sort);
391 static int replmd_add(struct ldb_module *module, struct ldb_request *req)
393 struct ldb_context *ldb;
394 struct ldb_control *control;
395 struct ldb_control **saved_controls;
396 struct replmd_replicated_request *ac;
397 enum ndr_err_code ndr_err;
398 struct ldb_request *down_req;
399 struct ldb_message *msg;
400 const DATA_BLOB *guid_blob;
402 struct ldb_val guid_value;
403 struct replPropertyMetaDataBlob nmd;
404 struct ldb_val nmd_value;
405 const struct GUID *our_invocation_id;
406 time_t t = time(NULL);
411 bool allow_add_guid = false;
412 bool remove_current_guid = false;
414 /* check if there's a show relax control (used by provision to say 'I know what I'm doing') */
415 control = ldb_request_get_control(req, LDB_CONTROL_RELAX_OID);
420 /* do not manipulate our control entries */
421 if (ldb_dn_is_special(req->op.add.message->dn)) {
422 return ldb_next_request(module, req);
425 ldb = ldb_module_get_ctx(module);
427 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_add\n");
429 ac = replmd_ctx_init(module, req);
431 return LDB_ERR_OPERATIONS_ERROR;
434 guid_blob = ldb_msg_find_ldb_val(req->op.add.message, "objectGUID");
435 if ( guid_blob != NULL ) {
436 if( !allow_add_guid ) {
437 ldb_debug_set(ldb, LDB_DEBUG_ERROR,
438 "replmd_add: it's not allowed to add an object with objectGUID\n");
440 return LDB_ERR_UNWILLING_TO_PERFORM;
442 NTSTATUS status = GUID_from_data_blob(guid_blob,&guid);
443 if ( !NT_STATUS_IS_OK(status)) {
444 ldb_debug_set(ldb, LDB_DEBUG_ERROR,
445 "replmd_add: Unable to parse as a GUID the attribute objectGUID\n");
447 return LDB_ERR_UNWILLING_TO_PERFORM;
449 /* we remove this attribute as it can be a string and will not be treated
450 correctly and then we will readd it latter on in the good format*/
451 remove_current_guid = true;
455 guid = GUID_random();
458 /* Get a sequence number from the backend */
459 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &ac->seq_num);
460 if (ret != LDB_SUCCESS) {
465 /* get our invocationId */
466 our_invocation_id = samdb_ntds_invocation_id(ldb);
467 if (!our_invocation_id) {
468 ldb_debug_set(ldb, LDB_DEBUG_ERROR,
469 "replmd_add: unable to find invocationId\n");
471 return LDB_ERR_OPERATIONS_ERROR;
474 /* we have to copy the message as the caller might have it as a const */
475 msg = ldb_msg_copy_shallow(ac, req->op.add.message);
479 return LDB_ERR_OPERATIONS_ERROR;
482 /* generated times */
483 unix_to_nt_time(&now, t);
484 time_str = ldb_timestring(msg, t);
488 return LDB_ERR_OPERATIONS_ERROR;
490 if (remove_current_guid) {
491 ldb_msg_remove_attr(msg,"objectGUID");
495 * remove autogenerated attributes
497 ldb_msg_remove_attr(msg, "whenCreated");
498 ldb_msg_remove_attr(msg, "whenChanged");
499 ldb_msg_remove_attr(msg, "uSNCreated");
500 ldb_msg_remove_attr(msg, "uSNChanged");
501 ldb_msg_remove_attr(msg, "replPropertyMetaData");
503 if (!ldb_msg_find_element(req->op.add.message, "instanceType")) {
504 ret = ldb_msg_add_fmt(msg, "instanceType", "%u", INSTANCE_TYPE_WRITE);
505 if (ret != LDB_SUCCESS) {
513 * readd replicated attributes
515 ret = ldb_msg_add_string(msg, "whenCreated", time_str);
516 if (ret != LDB_SUCCESS) {
522 /* build the replication meta_data */
525 nmd.ctr.ctr1.count = msg->num_elements;
526 nmd.ctr.ctr1.array = talloc_array(msg,
527 struct replPropertyMetaData1,
529 if (!nmd.ctr.ctr1.array) {
532 return LDB_ERR_OPERATIONS_ERROR;
535 for (i=0; i < msg->num_elements; i++) {
536 struct ldb_message_element *e = &msg->elements[i];
537 struct replPropertyMetaData1 *m = &nmd.ctr.ctr1.array[ni];
538 const struct dsdb_attribute *sa;
540 if (e->name[0] == '@') continue;
542 sa = dsdb_attribute_by_lDAPDisplayName(ac->schema, e->name);
544 ldb_debug_set(ldb, LDB_DEBUG_ERROR,
545 "replmd_add: attribute '%s' not defined in schema\n",
548 return LDB_ERR_NO_SUCH_ATTRIBUTE;
551 if ((sa->systemFlags & DS_FLAG_ATTR_NOT_REPLICATED) || (sa->systemFlags & DS_FLAG_ATTR_IS_CONSTRUCTED)) {
552 /* if the attribute is not replicated (0x00000001)
553 * or constructed (0x00000004) it has no metadata
558 m->attid = sa->attributeID_id;
560 m->originating_change_time = now;
561 m->originating_invocation_id = *our_invocation_id;
562 m->originating_usn = ac->seq_num;
563 m->local_usn = ac->seq_num;
567 /* fix meta data count */
568 nmd.ctr.ctr1.count = ni;
571 * sort meta data array, and move the rdn attribute entry to the end
573 ret = replmd_replPropertyMetaDataCtr1_sort(&nmd.ctr.ctr1, ac->schema, msg->dn);
574 if (ret != LDB_SUCCESS) {
579 /* generated NDR encoded values */
580 ndr_err = ndr_push_struct_blob(&guid_value, msg,
583 (ndr_push_flags_fn_t)ndr_push_GUID);
584 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
587 return LDB_ERR_OPERATIONS_ERROR;
589 ndr_err = ndr_push_struct_blob(&nmd_value, msg,
590 lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")),
592 (ndr_push_flags_fn_t)ndr_push_replPropertyMetaDataBlob);
593 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
596 return LDB_ERR_OPERATIONS_ERROR;
600 * add the autogenerated values
602 ret = ldb_msg_add_value(msg, "objectGUID", &guid_value, NULL);
603 if (ret != LDB_SUCCESS) {
608 ret = ldb_msg_add_string(msg, "whenChanged", time_str);
609 if (ret != LDB_SUCCESS) {
614 ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNCreated", ac->seq_num);
615 if (ret != LDB_SUCCESS) {
620 ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNChanged", ac->seq_num);
621 if (ret != LDB_SUCCESS) {
626 ret = ldb_msg_add_value(msg, "replPropertyMetaData", &nmd_value, NULL);
627 if (ret != LDB_SUCCESS) {
634 * sort the attributes by attid before storing the object
636 replmd_ldb_message_sort(msg, ac->schema);
638 ret = ldb_build_add_req(&down_req, ldb, ac,
641 ac, replmd_op_callback,
643 if (ret != LDB_SUCCESS) {
648 /* if a control is there remove if from the modified request */
649 if (control && !save_controls(control, down_req, &saved_controls)) {
651 return LDB_ERR_OPERATIONS_ERROR;
654 /* go on with the call chain */
655 return ldb_next_request(module, down_req);
660 * update the replPropertyMetaData for one element
662 static int replmd_update_rpmd_element(struct ldb_context *ldb,
663 struct ldb_message *msg,
664 struct ldb_message_element *el,
665 struct replPropertyMetaDataBlob *omd,
666 const struct dsdb_schema *schema,
668 const struct GUID *our_invocation_id,
672 const struct dsdb_attribute *a;
673 struct replPropertyMetaData1 *md1;
675 a = dsdb_attribute_by_lDAPDisplayName(schema, el->name);
677 DEBUG(0,(__location__ ": Unable to find attribute %s in schema\n",
679 return LDB_ERR_OPERATIONS_ERROR;
682 if ((a->systemFlags & DS_FLAG_ATTR_NOT_REPLICATED) || (a->systemFlags & DS_FLAG_ATTR_IS_CONSTRUCTED)) {
686 for (i=0; i<omd->ctr.ctr1.count; i++) {
687 if (a->attributeID_id == omd->ctr.ctr1.array[i].attid) break;
689 if (i == omd->ctr.ctr1.count) {
690 /* we need to add a new one */
691 omd->ctr.ctr1.array = talloc_realloc(msg, omd->ctr.ctr1.array,
692 struct replPropertyMetaData1, omd->ctr.ctr1.count+1);
693 if (omd->ctr.ctr1.array == NULL) {
695 return LDB_ERR_OPERATIONS_ERROR;
697 omd->ctr.ctr1.count++;
698 ZERO_STRUCT(omd->ctr.ctr1.array[i]);
701 /* Get a new sequence number from the backend. We only do this
702 * if we have a change that requires a new
703 * replPropertyMetaData element
706 int ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, seq_num);
707 if (ret != LDB_SUCCESS) {
708 return LDB_ERR_OPERATIONS_ERROR;
712 md1 = &omd->ctr.ctr1.array[i];
714 md1->attid = a->attributeID_id;
715 md1->originating_change_time = now;
716 md1->originating_invocation_id = *our_invocation_id;
717 md1->originating_usn = *seq_num;
718 md1->local_usn = *seq_num;
724 * update the replPropertyMetaData object each time we modify an
725 * object. This is needed for DRS replication, as the merge on the
726 * client is based on this object
728 static int replmd_update_rpmd(struct ldb_module *module,
729 const struct dsdb_schema *schema,
730 struct ldb_message *msg, uint64_t *seq_num)
732 const struct ldb_val *omd_value;
733 enum ndr_err_code ndr_err;
734 struct replPropertyMetaDataBlob omd;
736 time_t t = time(NULL);
738 const struct GUID *our_invocation_id;
740 const char *attrs[] = { "replPropertyMetaData" , NULL };
741 struct ldb_result *res;
742 struct ldb_context *ldb;
744 ldb = ldb_module_get_ctx(module);
746 our_invocation_id = samdb_ntds_invocation_id(ldb);
747 if (!our_invocation_id) {
748 /* this happens during an initial vampire while
749 updating the schema */
750 DEBUG(5,("No invocationID - skipping replPropertyMetaData update\n"));
754 unix_to_nt_time(&now, t);
756 /* search for the existing replPropertyMetaDataBlob */
757 ret = dsdb_search_dn_with_deleted(ldb, msg, &res, msg->dn, attrs);
758 if (ret != LDB_SUCCESS || res->count != 1) {
759 DEBUG(0,(__location__ ": Object %s failed to find replPropertyMetaData\n",
760 ldb_dn_get_linearized(msg->dn)));
761 return LDB_ERR_OPERATIONS_ERROR;
765 omd_value = ldb_msg_find_ldb_val(res->msgs[0], "replPropertyMetaData");
767 DEBUG(0,(__location__ ": Object %s does not have a replPropertyMetaData attribute\n",
768 ldb_dn_get_linearized(msg->dn)));
769 return LDB_ERR_OPERATIONS_ERROR;
772 ndr_err = ndr_pull_struct_blob(omd_value, msg,
773 lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")), &omd,
774 (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
775 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
776 DEBUG(0,(__location__ ": Failed to parse replPropertyMetaData for %s\n",
777 ldb_dn_get_linearized(msg->dn)));
778 return LDB_ERR_OPERATIONS_ERROR;
781 if (omd.version != 1) {
782 DEBUG(0,(__location__ ": bad version %u in replPropertyMetaData for %s\n",
783 omd.version, ldb_dn_get_linearized(msg->dn)));
784 return LDB_ERR_OPERATIONS_ERROR;
787 for (i=0; i<msg->num_elements; i++) {
788 ret = replmd_update_rpmd_element(ldb, msg, &msg->elements[i], &omd, schema, seq_num,
789 our_invocation_id, now);
790 if (ret != LDB_SUCCESS) {
796 * replmd_update_rpmd_element has done an update if the
800 struct ldb_val *md_value;
801 struct ldb_message_element *el;
803 md_value = talloc(msg, struct ldb_val);
804 if (md_value == NULL) {
806 return LDB_ERR_OPERATIONS_ERROR;
809 ret = replmd_replPropertyMetaDataCtr1_sort(&omd.ctr.ctr1, schema, msg->dn);
810 if (ret != LDB_SUCCESS) {
814 ndr_err = ndr_push_struct_blob(md_value, msg,
815 lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")),
817 (ndr_push_flags_fn_t)ndr_push_replPropertyMetaDataBlob);
818 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
819 DEBUG(0,(__location__ ": Failed to marshall replPropertyMetaData for %s\n",
820 ldb_dn_get_linearized(msg->dn)));
821 return LDB_ERR_OPERATIONS_ERROR;
824 ret = ldb_msg_add_empty(msg, "replPropertyMetaData", LDB_FLAG_MOD_REPLACE, &el);
825 if (ret != LDB_SUCCESS) {
826 DEBUG(0,(__location__ ": Failed to add updated replPropertyMetaData %s\n",
827 ldb_dn_get_linearized(msg->dn)));
832 el->values = md_value;
839 static int replmd_modify(struct ldb_module *module, struct ldb_request *req)
841 struct ldb_context *ldb;
842 struct replmd_replicated_request *ac;
843 struct ldb_request *down_req;
844 struct ldb_message *msg;
845 struct ldb_result *res;
846 time_t t = time(NULL);
847 uint64_t seq_num = 0;
850 /* do not manipulate our control entries */
851 if (ldb_dn_is_special(req->op.mod.message->dn)) {
852 return ldb_next_request(module, req);
855 ldb = ldb_module_get_ctx(module);
857 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_modify\n");
859 ac = replmd_ctx_init(module, req);
861 return LDB_ERR_OPERATIONS_ERROR;
864 /* we have to copy the message as the caller might have it as a const */
865 msg = ldb_msg_copy_shallow(ac, req->op.mod.message);
869 return LDB_ERR_OPERATIONS_ERROR;
873 * - give an error when a readonly attribute should
875 * - merge the changed into the old object
876 * if the caller set values to the same value
877 * ignore the attribute, return success when no
878 * attribute was changed
881 ret = dsdb_search_dn_with_deleted(ldb, msg, &res, msg->dn, NULL);
882 if (ret != LDB_SUCCESS) {
887 ret = replmd_update_rpmd(module, ac->schema, msg, &ac->seq_num);
888 if (ret != LDB_SUCCESS) {
894 * - replace the old object with the newly constructed one
897 ret = ldb_build_mod_req(&down_req, ldb, ac,
900 ac, replmd_op_callback,
902 if (ret != LDB_SUCCESS) {
906 talloc_steal(down_req, msg);
908 /* we only change whenChanged and uSNChanged if the seq_num
911 if (add_time_element(msg, "whenChanged", t) != LDB_SUCCESS) {
916 if (add_uint64_element(msg, "uSNChanged", seq_num) != LDB_SUCCESS) {
922 /* go on with the call chain */
923 return ldb_next_request(module, down_req);
926 static int replmd_rename_callback(struct ldb_request *req, struct ldb_reply *ares);
929 handle a rename request
931 On a rename we need to do an extra ldb_modify which sets the
932 whenChanged and uSNChanged attributes. We do this in a callback after the success.
934 static int replmd_rename(struct ldb_module *module, struct ldb_request *req)
936 struct ldb_context *ldb;
937 struct replmd_replicated_request *ac;
939 struct ldb_request *down_req;
941 /* do not manipulate our control entries */
942 if (ldb_dn_is_special(req->op.mod.message->dn)) {
943 return ldb_next_request(module, req);
946 ldb = ldb_module_get_ctx(module);
948 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_rename\n");
950 ac = replmd_ctx_init(module, req);
952 return LDB_ERR_OPERATIONS_ERROR;
954 ret = ldb_build_rename_req(&down_req, ldb, ac,
955 ac->req->op.rename.olddn,
956 ac->req->op.rename.newdn,
958 ac, replmd_rename_callback,
961 if (ret != LDB_SUCCESS) {
966 /* go on with the call chain */
967 return ldb_next_request(module, down_req);
970 /* After the rename is compleated, update the whenchanged etc */
971 static int replmd_rename_callback(struct ldb_request *req, struct ldb_reply *ares)
973 struct ldb_context *ldb;
974 struct replmd_replicated_request *ac;
975 struct ldb_request *down_req;
976 struct ldb_message *msg;
977 time_t t = time(NULL);
980 ac = talloc_get_type(req->context, struct replmd_replicated_request);
981 ldb = ldb_module_get_ctx(ac->module);
983 if (ares->error != LDB_SUCCESS) {
984 return ldb_module_done(ac->req, ares->controls,
985 ares->response, ares->error);
988 if (ares->type != LDB_REPLY_DONE) {
989 ldb_set_errstring(ldb,
990 "invalid ldb_reply_type in callback");
992 return ldb_module_done(ac->req, NULL, NULL,
993 LDB_ERR_OPERATIONS_ERROR);
996 /* Get a sequence number from the backend */
997 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &ac->seq_num);
998 if (ret != LDB_SUCCESS) {
1003 * - replace the old object with the newly constructed one
1006 msg = ldb_msg_new(ac);
1009 return LDB_ERR_OPERATIONS_ERROR;
1012 msg->dn = ac->req->op.rename.newdn;
1014 ret = ldb_build_mod_req(&down_req, ldb, ac,
1017 ac, replmd_op_callback,
1020 if (ret != LDB_SUCCESS) {
1024 talloc_steal(down_req, msg);
1026 if (add_time_element(msg, "whenChanged", t) != LDB_SUCCESS) {
1031 if (add_uint64_element(msg, "uSNChanged", ac->seq_num) != LDB_SUCCESS) {
1036 /* go on with the call chain - do the modify after the rename */
1037 return ldb_next_request(ac->module, down_req);
1041 static int replmd_replicated_request_error(struct replmd_replicated_request *ar, int ret)
1046 static int replmd_replicated_request_werror(struct replmd_replicated_request *ar, WERROR status)
1048 int ret = LDB_ERR_OTHER;
1049 /* TODO: do some error mapping */
1053 static int replmd_replicated_apply_add(struct replmd_replicated_request *ar)
1055 struct ldb_context *ldb;
1056 struct ldb_request *change_req;
1057 enum ndr_err_code ndr_err;
1058 struct ldb_message *msg;
1059 struct replPropertyMetaDataBlob *md;
1060 struct ldb_val md_value;
1065 * TODO: check if the parent object exist
1069 * TODO: handle the conflict case where an object with the
1073 ldb = ldb_module_get_ctx(ar->module);
1074 msg = ar->objs->objects[ar->index_current].msg;
1075 md = ar->objs->objects[ar->index_current].meta_data;
1077 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &ar->seq_num);
1078 if (ret != LDB_SUCCESS) {
1079 return replmd_replicated_request_error(ar, ret);
1082 ret = ldb_msg_add_value(msg, "objectGUID", &ar->objs->objects[ar->index_current].guid_value, NULL);
1083 if (ret != LDB_SUCCESS) {
1084 return replmd_replicated_request_error(ar, ret);
1087 ret = ldb_msg_add_string(msg, "whenChanged", ar->objs->objects[ar->index_current].when_changed);
1088 if (ret != LDB_SUCCESS) {
1089 return replmd_replicated_request_error(ar, ret);
1092 ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNCreated", ar->seq_num);
1093 if (ret != LDB_SUCCESS) {
1094 return replmd_replicated_request_error(ar, ret);
1097 ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNChanged", ar->seq_num);
1098 if (ret != LDB_SUCCESS) {
1099 return replmd_replicated_request_error(ar, ret);
1102 /* remove any message elements that have zero values */
1103 for (i=0; i<msg->num_elements; i++) {
1104 if (msg->elements[i].num_values == 0) {
1105 DEBUG(4,(__location__ ": Removing attribute %s with num_values==0\n",
1106 msg->elements[i].name));
1107 memmove(&msg->elements[i],
1108 &msg->elements[i+1],
1109 sizeof(msg->elements[i])*(msg->num_elements - (i+1)));
1110 msg->num_elements--;
1116 * the meta data array is already sorted by the caller
1118 for (i=0; i < md->ctr.ctr1.count; i++) {
1119 md->ctr.ctr1.array[i].local_usn = ar->seq_num;
1121 ndr_err = ndr_push_struct_blob(&md_value, msg,
1122 lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")),
1124 (ndr_push_flags_fn_t)ndr_push_replPropertyMetaDataBlob);
1125 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1126 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
1127 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
1129 ret = ldb_msg_add_value(msg, "replPropertyMetaData", &md_value, NULL);
1130 if (ret != LDB_SUCCESS) {
1131 return replmd_replicated_request_error(ar, ret);
1134 replmd_ldb_message_sort(msg, ar->schema);
1137 char *s = ldb_ldif_message_string(ldb, ar, LDB_CHANGETYPE_ADD, msg);
1138 DEBUG(4, ("DRS replication add message:\n%s\n", s));
1142 ret = ldb_build_add_req(&change_req,
1150 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
1152 return ldb_next_request(ar->module, change_req);
1155 static int replmd_replPropertyMetaData1_conflict_compare(struct replPropertyMetaData1 *m1,
1156 struct replPropertyMetaData1 *m2)
1160 if (m1->version != m2->version) {
1161 return m1->version - m2->version;
1164 if (m1->originating_change_time != m2->originating_change_time) {
1165 return m1->originating_change_time - m2->originating_change_time;
1168 ret = GUID_compare(&m1->originating_invocation_id, &m2->originating_invocation_id);
1173 return m1->originating_usn - m2->originating_usn;
1176 static int replmd_replicated_apply_merge(struct replmd_replicated_request *ar)
1178 struct ldb_context *ldb;
1179 struct ldb_request *change_req;
1180 enum ndr_err_code ndr_err;
1181 struct ldb_message *msg;
1182 struct replPropertyMetaDataBlob *rmd;
1183 struct replPropertyMetaDataBlob omd;
1184 const struct ldb_val *omd_value;
1185 struct replPropertyMetaDataBlob nmd;
1186 struct ldb_val nmd_value;
1188 uint32_t removed_attrs = 0;
1191 ldb = ldb_module_get_ctx(ar->module);
1192 msg = ar->objs->objects[ar->index_current].msg;
1193 rmd = ar->objs->objects[ar->index_current].meta_data;
1198 * TODO: check repl data is correct after a rename
1200 if (ldb_dn_compare(msg->dn, ar->search_msg->dn) != 0) {
1201 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_replicated_request rename %s => %s\n",
1202 ldb_dn_get_linearized(ar->search_msg->dn),
1203 ldb_dn_get_linearized(msg->dn));
1204 if (ldb_rename(ldb, ar->search_msg->dn, msg->dn) != LDB_SUCCESS) {
1205 ldb_debug(ldb, LDB_DEBUG_FATAL, "replmd_replicated_request rename %s => %s failed - %s\n",
1206 ldb_dn_get_linearized(ar->search_msg->dn),
1207 ldb_dn_get_linearized(msg->dn),
1208 ldb_errstring(ldb));
1209 return replmd_replicated_request_werror(ar, WERR_DS_DRA_DB_ERROR);
1213 /* find existing meta data */
1214 omd_value = ldb_msg_find_ldb_val(ar->search_msg, "replPropertyMetaData");
1216 ndr_err = ndr_pull_struct_blob(omd_value, ar,
1217 lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")), &omd,
1218 (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
1219 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1220 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
1221 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
1224 if (omd.version != 1) {
1225 return replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
1231 nmd.ctr.ctr1.count = omd.ctr.ctr1.count + rmd->ctr.ctr1.count;
1232 nmd.ctr.ctr1.array = talloc_array(ar,
1233 struct replPropertyMetaData1,
1234 nmd.ctr.ctr1.count);
1235 if (!nmd.ctr.ctr1.array) return replmd_replicated_request_werror(ar, WERR_NOMEM);
1237 /* first copy the old meta data */
1238 for (i=0; i < omd.ctr.ctr1.count; i++) {
1239 nmd.ctr.ctr1.array[ni] = omd.ctr.ctr1.array[i];
1243 /* now merge in the new meta data */
1244 for (i=0; i < rmd->ctr.ctr1.count; i++) {
1247 for (j=0; j < ni; j++) {
1250 if (rmd->ctr.ctr1.array[i].attid != nmd.ctr.ctr1.array[j].attid) {
1254 cmp = replmd_replPropertyMetaData1_conflict_compare(&rmd->ctr.ctr1.array[i],
1255 &nmd.ctr.ctr1.array[j]);
1257 /* replace the entry */
1258 nmd.ctr.ctr1.array[j] = rmd->ctr.ctr1.array[i];
1263 /* we don't want to apply this change so remove the attribute */
1264 ldb_msg_remove_element(msg, &msg->elements[i-removed_attrs]);
1271 if (found) continue;
1273 nmd.ctr.ctr1.array[ni] = rmd->ctr.ctr1.array[i];
1278 * finally correct the size of the meta_data array
1280 nmd.ctr.ctr1.count = ni;
1283 * the rdn attribute (the alias for the name attribute),
1284 * 'cn' for most objects is the last entry in the meta data array
1287 * sort the new meta data array
1289 ret = replmd_replPropertyMetaDataCtr1_sort(&nmd.ctr.ctr1, ar->schema, msg->dn);
1290 if (ret != LDB_SUCCESS) {
1295 * check if some replicated attributes left, otherwise skip the ldb_modify() call
1297 if (msg->num_elements == 0) {
1298 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_replicated_apply_merge[%u]: skip replace\n",
1301 ar->index_current++;
1302 return replmd_replicated_apply_next(ar);
1305 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_replicated_apply_merge[%u]: replace %u attributes\n",
1306 ar->index_current, msg->num_elements);
1308 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &ar->seq_num);
1309 if (ret != LDB_SUCCESS) {
1310 return replmd_replicated_request_error(ar, ret);
1313 for (i=0; i<ni; i++) {
1314 nmd.ctr.ctr1.array[i].local_usn = ar->seq_num;
1317 /* create the meta data value */
1318 ndr_err = ndr_push_struct_blob(&nmd_value, msg,
1319 lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")),
1321 (ndr_push_flags_fn_t)ndr_push_replPropertyMetaDataBlob);
1322 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1323 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
1324 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
1328 * when we know that we'll modify the record, add the whenChanged, uSNChanged
1329 * and replPopertyMetaData attributes
1331 ret = ldb_msg_add_string(msg, "whenChanged", ar->objs->objects[ar->index_current].when_changed);
1332 if (ret != LDB_SUCCESS) {
1333 return replmd_replicated_request_error(ar, ret);
1335 ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNChanged", ar->seq_num);
1336 if (ret != LDB_SUCCESS) {
1337 return replmd_replicated_request_error(ar, ret);
1339 ret = ldb_msg_add_value(msg, "replPropertyMetaData", &nmd_value, NULL);
1340 if (ret != LDB_SUCCESS) {
1341 return replmd_replicated_request_error(ar, ret);
1344 replmd_ldb_message_sort(msg, ar->schema);
1346 /* we want to replace the old values */
1347 for (i=0; i < msg->num_elements; i++) {
1348 msg->elements[i].flags = LDB_FLAG_MOD_REPLACE;
1352 char *s = ldb_ldif_message_string(ldb, ar, LDB_CHANGETYPE_MODIFY, msg);
1353 DEBUG(4, ("DRS replication modify message:\n%s\n", s));
1357 ret = ldb_build_mod_req(&change_req,
1365 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
1367 return ldb_next_request(ar->module, change_req);
1370 static int replmd_replicated_apply_search_callback(struct ldb_request *req,
1371 struct ldb_reply *ares)
1373 struct replmd_replicated_request *ar = talloc_get_type(req->context,
1374 struct replmd_replicated_request);
1378 return ldb_module_done(ar->req, NULL, NULL,
1379 LDB_ERR_OPERATIONS_ERROR);
1381 if (ares->error != LDB_SUCCESS &&
1382 ares->error != LDB_ERR_NO_SUCH_OBJECT) {
1383 return ldb_module_done(ar->req, ares->controls,
1384 ares->response, ares->error);
1387 switch (ares->type) {
1388 case LDB_REPLY_ENTRY:
1389 ar->search_msg = talloc_steal(ar, ares->message);
1392 case LDB_REPLY_REFERRAL:
1393 /* we ignore referrals */
1396 case LDB_REPLY_DONE:
1397 if (ar->search_msg != NULL) {
1398 ret = replmd_replicated_apply_merge(ar);
1400 ret = replmd_replicated_apply_add(ar);
1402 if (ret != LDB_SUCCESS) {
1403 return ldb_module_done(ar->req, NULL, NULL, ret);
1411 static int replmd_replicated_uptodate_vector(struct replmd_replicated_request *ar);
1413 static int replmd_replicated_apply_next(struct replmd_replicated_request *ar)
1415 struct ldb_context *ldb;
1419 struct ldb_request *search_req;
1420 struct ldb_search_options_control *options;
1422 if (ar->index_current >= ar->objs->num_objects) {
1423 /* done with it, go to next stage */
1424 return replmd_replicated_uptodate_vector(ar);
1427 ldb = ldb_module_get_ctx(ar->module);
1428 ar->search_msg = NULL;
1430 tmp_str = ldb_binary_encode(ar, ar->objs->objects[ar->index_current].guid_value);
1431 if (!tmp_str) return replmd_replicated_request_werror(ar, WERR_NOMEM);
1433 filter = talloc_asprintf(ar, "(objectGUID=%s)", tmp_str);
1434 if (!filter) return replmd_replicated_request_werror(ar, WERR_NOMEM);
1435 talloc_free(tmp_str);
1437 ret = ldb_build_search_req(&search_req,
1446 replmd_replicated_apply_search_callback,
1449 ret = ldb_request_add_control(search_req, LDB_CONTROL_SHOW_DELETED_OID, true, NULL);
1450 if (ret != LDB_SUCCESS) {
1454 /* we need to cope with cross-partition links, so search for
1455 the GUID over all partitions */
1456 options = talloc(search_req, struct ldb_search_options_control);
1457 if (options == NULL) {
1458 DEBUG(0, (__location__ ": out of memory\n"));
1459 return LDB_ERR_OPERATIONS_ERROR;
1461 options->search_options = LDB_SEARCH_OPTION_PHANTOM_ROOT;
1463 ret = ldb_request_add_control(search_req,
1464 LDB_CONTROL_SEARCH_OPTIONS_OID,
1466 if (ret != LDB_SUCCESS) {
1470 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
1472 return ldb_next_request(ar->module, search_req);
1475 static int replmd_replicated_uptodate_modify_callback(struct ldb_request *req,
1476 struct ldb_reply *ares)
1478 struct ldb_context *ldb;
1479 struct replmd_replicated_request *ar = talloc_get_type(req->context,
1480 struct replmd_replicated_request);
1481 ldb = ldb_module_get_ctx(ar->module);
1484 return ldb_module_done(ar->req, NULL, NULL,
1485 LDB_ERR_OPERATIONS_ERROR);
1487 if (ares->error != LDB_SUCCESS) {
1488 return ldb_module_done(ar->req, ares->controls,
1489 ares->response, ares->error);
1492 if (ares->type != LDB_REPLY_DONE) {
1493 ldb_set_errstring(ldb, "Invalid reply type\n!");
1494 return ldb_module_done(ar->req, NULL, NULL,
1495 LDB_ERR_OPERATIONS_ERROR);
1500 return ldb_module_done(ar->req, NULL, NULL, LDB_SUCCESS);
1503 static int replmd_replicated_uptodate_modify(struct replmd_replicated_request *ar)
1505 struct ldb_context *ldb;
1506 struct ldb_request *change_req;
1507 enum ndr_err_code ndr_err;
1508 struct ldb_message *msg;
1509 struct replUpToDateVectorBlob ouv;
1510 const struct ldb_val *ouv_value;
1511 const struct drsuapi_DsReplicaCursor2CtrEx *ruv;
1512 struct replUpToDateVectorBlob nuv;
1513 struct ldb_val nuv_value;
1514 struct ldb_message_element *nuv_el = NULL;
1515 const struct GUID *our_invocation_id;
1516 struct ldb_message_element *orf_el = NULL;
1517 struct repsFromToBlob nrf;
1518 struct ldb_val *nrf_value = NULL;
1519 struct ldb_message_element *nrf_el = NULL;
1522 time_t t = time(NULL);
1526 ldb = ldb_module_get_ctx(ar->module);
1527 ruv = ar->objs->uptodateness_vector;
1533 unix_to_nt_time(&now, t);
1536 * first create the new replUpToDateVector
1538 ouv_value = ldb_msg_find_ldb_val(ar->search_msg, "replUpToDateVector");
1540 ndr_err = ndr_pull_struct_blob(ouv_value, ar,
1541 lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")), &ouv,
1542 (ndr_pull_flags_fn_t)ndr_pull_replUpToDateVectorBlob);
1543 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1544 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
1545 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
1548 if (ouv.version != 2) {
1549 return replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
1554 * the new uptodateness vector will at least
1555 * contain 1 entry, one for the source_dsa
1557 * plus optional values from our old vector and the one from the source_dsa
1559 nuv.ctr.ctr2.count = 1 + ouv.ctr.ctr2.count;
1560 if (ruv) nuv.ctr.ctr2.count += ruv->count;
1561 nuv.ctr.ctr2.cursors = talloc_array(ar,
1562 struct drsuapi_DsReplicaCursor2,
1563 nuv.ctr.ctr2.count);
1564 if (!nuv.ctr.ctr2.cursors) return replmd_replicated_request_werror(ar, WERR_NOMEM);
1566 /* first copy the old vector */
1567 for (i=0; i < ouv.ctr.ctr2.count; i++) {
1568 nuv.ctr.ctr2.cursors[ni] = ouv.ctr.ctr2.cursors[i];
1572 /* get our invocation_id if we have one already attached to the ldb */
1573 our_invocation_id = samdb_ntds_invocation_id(ldb);
1575 /* merge in the source_dsa vector is available */
1576 for (i=0; (ruv && i < ruv->count); i++) {
1579 if (our_invocation_id &&
1580 GUID_equal(&ruv->cursors[i].source_dsa_invocation_id,
1581 our_invocation_id)) {
1585 for (j=0; j < ni; j++) {
1586 if (!GUID_equal(&ruv->cursors[i].source_dsa_invocation_id,
1587 &nuv.ctr.ctr2.cursors[j].source_dsa_invocation_id)) {
1594 * we update only the highest_usn and not the latest_sync_success time,
1595 * because the last success stands for direct replication
1597 if (ruv->cursors[i].highest_usn > nuv.ctr.ctr2.cursors[j].highest_usn) {
1598 nuv.ctr.ctr2.cursors[j].highest_usn = ruv->cursors[i].highest_usn;
1603 if (found) continue;
1605 /* if it's not there yet, add it */
1606 nuv.ctr.ctr2.cursors[ni] = ruv->cursors[i];
1611 * merge in the current highwatermark for the source_dsa
1614 for (j=0; j < ni; j++) {
1615 if (!GUID_equal(&ar->objs->source_dsa->source_dsa_invocation_id,
1616 &nuv.ctr.ctr2.cursors[j].source_dsa_invocation_id)) {
1623 * here we update the highest_usn and last_sync_success time
1624 * because we're directly replicating from the source_dsa
1626 * and use the tmp_highest_usn because this is what we have just applied
1629 nuv.ctr.ctr2.cursors[j].highest_usn = ar->objs->source_dsa->highwatermark.tmp_highest_usn;
1630 nuv.ctr.ctr2.cursors[j].last_sync_success = now;
1635 * here we update the highest_usn and last_sync_success time
1636 * because we're directly replicating from the source_dsa
1638 * and use the tmp_highest_usn because this is what we have just applied
1641 nuv.ctr.ctr2.cursors[ni].source_dsa_invocation_id= ar->objs->source_dsa->source_dsa_invocation_id;
1642 nuv.ctr.ctr2.cursors[ni].highest_usn = ar->objs->source_dsa->highwatermark.tmp_highest_usn;
1643 nuv.ctr.ctr2.cursors[ni].last_sync_success = now;
1648 * finally correct the size of the cursors array
1650 nuv.ctr.ctr2.count = ni;
1655 qsort(nuv.ctr.ctr2.cursors, nuv.ctr.ctr2.count,
1656 sizeof(struct drsuapi_DsReplicaCursor2),
1657 (comparison_fn_t)drsuapi_DsReplicaCursor2_compare);
1660 * create the change ldb_message
1662 msg = ldb_msg_new(ar);
1663 if (!msg) return replmd_replicated_request_werror(ar, WERR_NOMEM);
1664 msg->dn = ar->search_msg->dn;
1666 ndr_err = ndr_push_struct_blob(&nuv_value, msg,
1667 lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")),
1669 (ndr_push_flags_fn_t)ndr_push_replUpToDateVectorBlob);
1670 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1671 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
1672 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
1674 ret = ldb_msg_add_value(msg, "replUpToDateVector", &nuv_value, &nuv_el);
1675 if (ret != LDB_SUCCESS) {
1676 return replmd_replicated_request_error(ar, ret);
1678 nuv_el->flags = LDB_FLAG_MOD_REPLACE;
1681 * now create the new repsFrom value from the given repsFromTo1 structure
1685 nrf.ctr.ctr1 = *ar->objs->source_dsa;
1686 /* and fix some values... */
1687 nrf.ctr.ctr1.consecutive_sync_failures = 0;
1688 nrf.ctr.ctr1.last_success = now;
1689 nrf.ctr.ctr1.last_attempt = now;
1690 nrf.ctr.ctr1.result_last_attempt = WERR_OK;
1691 nrf.ctr.ctr1.highwatermark.highest_usn = nrf.ctr.ctr1.highwatermark.tmp_highest_usn;
1694 * first see if we already have a repsFrom value for the current source dsa
1695 * if so we'll later replace this value
1697 orf_el = ldb_msg_find_element(ar->search_msg, "repsFrom");
1699 for (i=0; i < orf_el->num_values; i++) {
1700 struct repsFromToBlob *trf;
1702 trf = talloc(ar, struct repsFromToBlob);
1703 if (!trf) return replmd_replicated_request_werror(ar, WERR_NOMEM);
1705 ndr_err = ndr_pull_struct_blob(&orf_el->values[i], trf, lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")), trf,
1706 (ndr_pull_flags_fn_t)ndr_pull_repsFromToBlob);
1707 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1708 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
1709 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
1712 if (trf->version != 1) {
1713 return replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
1717 * we compare the source dsa objectGUID not the invocation_id
1718 * because we want only one repsFrom value per source dsa
1719 * and when the invocation_id of the source dsa has changed we don't need
1720 * the old repsFrom with the old invocation_id
1722 if (!GUID_equal(&trf->ctr.ctr1.source_dsa_obj_guid,
1723 &ar->objs->source_dsa->source_dsa_obj_guid)) {
1729 nrf_value = &orf_el->values[i];
1734 * copy over all old values to the new ldb_message
1736 ret = ldb_msg_add_empty(msg, "repsFrom", 0, &nrf_el);
1737 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
1742 * if we haven't found an old repsFrom value for the current source dsa
1743 * we'll add a new value
1746 struct ldb_val zero_value;
1747 ZERO_STRUCT(zero_value);
1748 ret = ldb_msg_add_value(msg, "repsFrom", &zero_value, &nrf_el);
1749 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
1751 nrf_value = &nrf_el->values[nrf_el->num_values - 1];
1754 /* we now fill the value which is already attached to ldb_message */
1755 ndr_err = ndr_push_struct_blob(nrf_value, msg,
1756 lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")),
1758 (ndr_push_flags_fn_t)ndr_push_repsFromToBlob);
1759 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1760 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
1761 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
1765 * the ldb_message_element for the attribute, has all the old values and the new one
1766 * so we'll replace the whole attribute with all values
1768 nrf_el->flags = LDB_FLAG_MOD_REPLACE;
1771 char *s = ldb_ldif_message_string(ldb, ar, LDB_CHANGETYPE_MODIFY, msg);
1772 DEBUG(4, ("DRS replication uptodate modify message:\n%s\n", s));
1776 /* prepare the ldb_modify() request */
1777 ret = ldb_build_mod_req(&change_req,
1783 replmd_replicated_uptodate_modify_callback,
1785 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
1787 return ldb_next_request(ar->module, change_req);
1790 static int replmd_replicated_uptodate_search_callback(struct ldb_request *req,
1791 struct ldb_reply *ares)
1793 struct replmd_replicated_request *ar = talloc_get_type(req->context,
1794 struct replmd_replicated_request);
1798 return ldb_module_done(ar->req, NULL, NULL,
1799 LDB_ERR_OPERATIONS_ERROR);
1801 if (ares->error != LDB_SUCCESS &&
1802 ares->error != LDB_ERR_NO_SUCH_OBJECT) {
1803 return ldb_module_done(ar->req, ares->controls,
1804 ares->response, ares->error);
1807 switch (ares->type) {
1808 case LDB_REPLY_ENTRY:
1809 ar->search_msg = talloc_steal(ar, ares->message);
1812 case LDB_REPLY_REFERRAL:
1813 /* we ignore referrals */
1816 case LDB_REPLY_DONE:
1817 if (ar->search_msg == NULL) {
1818 ret = replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
1820 ret = replmd_replicated_uptodate_modify(ar);
1822 if (ret != LDB_SUCCESS) {
1823 return ldb_module_done(ar->req, NULL, NULL, ret);
1832 static int replmd_replicated_uptodate_vector(struct replmd_replicated_request *ar)
1834 struct ldb_context *ldb;
1836 static const char *attrs[] = {
1837 "replUpToDateVector",
1841 struct ldb_request *search_req;
1843 ldb = ldb_module_get_ctx(ar->module);
1844 ar->search_msg = NULL;
1846 ret = ldb_build_search_req(&search_req,
1849 ar->objs->partition_dn,
1855 replmd_replicated_uptodate_search_callback,
1857 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
1859 return ldb_next_request(ar->module, search_req);
1864 static int replmd_extended_replicated_objects(struct ldb_module *module, struct ldb_request *req)
1866 struct ldb_context *ldb;
1867 struct dsdb_extended_replicated_objects *objs;
1868 struct replmd_replicated_request *ar;
1869 struct ldb_control **ctrls;
1871 struct replmd_private *replmd_private =
1872 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
1874 ldb = ldb_module_get_ctx(module);
1876 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_extended_replicated_objects\n");
1878 objs = talloc_get_type(req->op.extended.data, struct dsdb_extended_replicated_objects);
1880 ldb_debug(ldb, LDB_DEBUG_FATAL, "replmd_extended_replicated_objects: invalid extended data\n");
1881 return LDB_ERR_PROTOCOL_ERROR;
1884 if (objs->version != DSDB_EXTENDED_REPLICATED_OBJECTS_VERSION) {
1885 ldb_debug(ldb, LDB_DEBUG_FATAL, "replmd_extended_replicated_objects: extended data invalid version [%u != %u]\n",
1886 objs->version, DSDB_EXTENDED_REPLICATED_OBJECTS_VERSION);
1887 return LDB_ERR_PROTOCOL_ERROR;
1890 ar = replmd_ctx_init(module, req);
1892 return LDB_ERR_OPERATIONS_ERROR;
1894 /* Set the flags to have the replmd_op_callback run over the full set of objects */
1895 ar->apply_mode = true;
1897 ar->schema = dsdb_get_schema(ldb);
1899 ldb_debug_set(ldb, LDB_DEBUG_FATAL, "replmd_ctx_init: no loaded schema found\n");
1901 DEBUG(0,(__location__ ": %s\n", ldb_errstring(ldb)));
1902 return LDB_ERR_CONSTRAINT_VIOLATION;
1905 ctrls = req->controls;
1907 if (req->controls) {
1908 req->controls = talloc_memdup(ar, req->controls,
1909 talloc_get_size(req->controls));
1910 if (!req->controls) return replmd_replicated_request_werror(ar, WERR_NOMEM);
1913 ret = ldb_request_add_control(req, DSDB_CONTROL_REPLICATED_UPDATE_OID, false, NULL);
1914 if (ret != LDB_SUCCESS) {
1918 ar->controls = req->controls;
1919 req->controls = ctrls;
1921 DEBUG(4,("linked_attributes_count=%u\n", objs->linked_attributes_count));
1923 /* save away the linked attributes for the end of the
1925 for (i=0; i<ar->objs->linked_attributes_count; i++) {
1926 struct la_entry *la_entry;
1928 if (replmd_private->la_ctx == NULL) {
1929 replmd_private->la_ctx = talloc_new(replmd_private);
1931 la_entry = talloc(replmd_private->la_ctx, struct la_entry);
1932 if (la_entry == NULL) {
1934 return LDB_ERR_OPERATIONS_ERROR;
1936 la_entry->la = talloc(la_entry, struct drsuapi_DsReplicaLinkedAttribute);
1937 if (la_entry->la == NULL) {
1938 talloc_free(la_entry);
1940 return LDB_ERR_OPERATIONS_ERROR;
1942 *la_entry->la = ar->objs->linked_attributes[i];
1944 /* we need to steal the non-scalars so they stay
1945 around until the end of the transaction */
1946 talloc_steal(la_entry->la, la_entry->la->identifier);
1947 talloc_steal(la_entry->la, la_entry->la->value.blob);
1949 DLIST_ADD(replmd_private->la_list, la_entry);
1952 return replmd_replicated_apply_next(ar);
1956 process one linked attribute structure
1958 static int replmd_process_linked_attribute(struct ldb_module *module,
1959 struct la_entry *la_entry)
1961 struct drsuapi_DsReplicaLinkedAttribute *la = la_entry->la;
1962 struct ldb_context *ldb = ldb_module_get_ctx(module);
1963 struct dsdb_schema *schema = dsdb_get_schema(ldb);
1964 struct drsuapi_DsReplicaObjectIdentifier3 target;
1965 struct ldb_message *msg;
1966 struct ldb_message_element *ret_el;
1967 TALLOC_CTX *tmp_ctx = talloc_new(la_entry);
1968 enum ndr_err_code ndr_err;
1969 struct ldb_request *mod_req;
1971 const struct dsdb_attribute *attr;
1972 struct ldb_dn *target_dn;
1973 uint64_t seq_num = 0;
1976 linked_attributes[0]:
1977 &objs->linked_attributes[i]: struct drsuapi_DsReplicaLinkedAttribute
1979 identifier: struct drsuapi_DsReplicaObjectIdentifier
1980 __ndr_size : 0x0000003a (58)
1981 __ndr_size_sid : 0x00000000 (0)
1982 guid : 8e95b6a9-13dd-4158-89db-3220a5be5cc7
1984 __ndr_size_dn : 0x00000000 (0)
1986 attid : DRSUAPI_ATTRIBUTE_member (0x1F)
1987 value: struct drsuapi_DsAttributeValue
1988 __ndr_size : 0x0000007e (126)
1990 blob : DATA_BLOB length=126
1991 flags : 0x00000001 (1)
1992 1: DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE
1993 originating_add_time : Wed Sep 2 22:20:01 2009 EST
1994 meta_data: struct drsuapi_DsReplicaMetaData
1995 version : 0x00000015 (21)
1996 originating_change_time : Wed Sep 2 23:39:07 2009 EST
1997 originating_invocation_id: 794640f3-18cf-40ee-a211-a93992b67a64
1998 originating_usn : 0x000000000001e19c (123292)
1999 &target: struct drsuapi_DsReplicaObjectIdentifier3
2000 __ndr_size : 0x0000007e (126)
2001 __ndr_size_sid : 0x0000001c (28)
2002 guid : 7639e594-db75-4086-b0d4-67890ae46031
2003 sid : S-1-5-21-2848215498-2472035911-1947525656-19924
2004 __ndr_size_dn : 0x00000022 (34)
2005 dn : 'CN=UOne,OU=TestOU,DC=vsofs8,DC=com'
2008 NDR_PRINT_DEBUG(drsuapi_DsReplicaLinkedAttribute, la);
2011 /* decode the target of the link */
2012 ndr_err = ndr_pull_struct_blob(la->value.blob,
2013 tmp_ctx, lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")),
2015 (ndr_pull_flags_fn_t)ndr_pull_drsuapi_DsReplicaObjectIdentifier3);
2016 if (ndr_err != NDR_ERR_SUCCESS) {
2017 DEBUG(0,("Unable to decode linked_attribute target\n"));
2018 dump_data(4, la->value.blob->data, la->value.blob->length);
2019 talloc_free(tmp_ctx);
2020 return LDB_ERR_OPERATIONS_ERROR;
2023 NDR_PRINT_DEBUG(drsuapi_DsReplicaObjectIdentifier3, &target);
2026 /* construct a modify request for this attribute change */
2027 msg = ldb_msg_new(tmp_ctx);
2030 talloc_free(tmp_ctx);
2031 return LDB_ERR_OPERATIONS_ERROR;
2034 ret = dsdb_find_dn_by_guid(ldb, tmp_ctx,
2035 GUID_string(tmp_ctx, &la->identifier->guid), &msg->dn);
2036 if (ret != LDB_SUCCESS) {
2037 talloc_free(tmp_ctx);
2041 /* find the attribute being modified */
2042 attr = dsdb_attribute_by_attributeID_id(schema, la->attid);
2044 DEBUG(0, (__location__ ": Unable to find attributeID 0x%x\n", la->attid));
2045 talloc_free(tmp_ctx);
2046 return LDB_ERR_OPERATIONS_ERROR;
2049 if (la->flags & DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE) {
2050 ret = ldb_msg_add_empty(msg, attr->lDAPDisplayName,
2051 LDB_FLAG_MOD_ADD, &ret_el);
2053 ret = ldb_msg_add_empty(msg, attr->lDAPDisplayName,
2054 LDB_FLAG_MOD_DELETE, &ret_el);
2056 if (ret != LDB_SUCCESS) {
2057 talloc_free(tmp_ctx);
2060 /* we allocate two entries here, in case we need a remove/add
2062 ret_el->values = talloc_array(msg, struct ldb_val, 2);
2063 if (!ret_el->values) {
2065 talloc_free(tmp_ctx);
2066 return LDB_ERR_OPERATIONS_ERROR;
2068 ret_el->num_values = 1;
2070 ret = dsdb_find_dn_by_guid(ldb, tmp_ctx, GUID_string(tmp_ctx, &target.guid), &target_dn);
2071 if (ret != LDB_SUCCESS) {
2072 DEBUG(0,(__location__ ": Failed to map GUID %s to DN\n", GUID_string(tmp_ctx, &target.guid)));
2073 talloc_free(tmp_ctx);
2074 return LDB_ERR_OPERATIONS_ERROR;
2077 ret_el->values[0].data = (uint8_t *)ldb_dn_get_extended_linearized(tmp_ctx, target_dn, 1);
2078 ret_el->values[0].length = strlen((char *)ret_el->values[0].data);
2080 ret = replmd_update_rpmd(module, schema, msg, &seq_num);
2081 if (ret != LDB_SUCCESS) {
2082 talloc_free(tmp_ctx);
2086 /* we only change whenChanged and uSNChanged if the seq_num
2089 time_t t = time(NULL);
2091 if (add_time_element(msg, "whenChanged", t) != LDB_SUCCESS) {
2092 talloc_free(tmp_ctx);
2093 return LDB_ERR_OPERATIONS_ERROR;
2096 if (add_uint64_element(msg, "uSNChanged", seq_num) != LDB_SUCCESS) {
2097 talloc_free(tmp_ctx);
2098 return LDB_ERR_OPERATIONS_ERROR;
2102 ret = ldb_build_mod_req(&mod_req, ldb, tmp_ctx,
2106 ldb_op_default_callback,
2108 if (ret != LDB_SUCCESS) {
2109 talloc_free(tmp_ctx);
2112 talloc_steal(mod_req, msg);
2115 DEBUG(4,("Applying DRS linked attribute change:\n%s\n",
2116 ldb_ldif_message_string(ldb, tmp_ctx, LDB_CHANGETYPE_MODIFY, msg)));
2119 /* Run the new request */
2120 ret = ldb_next_request(module, mod_req);
2122 /* we need to wait for this to finish, as we are being called
2123 from the synchronous end_transaction hook of this module */
2124 if (ret == LDB_SUCCESS) {
2125 ret = ldb_wait(mod_req->handle, LDB_WAIT_ALL);
2128 if (ret == LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS) {
2129 /* the link destination exists, we need to update it
2130 * by deleting the old one for the same DN then adding
2132 msg->elements = talloc_realloc(msg, msg->elements,
2133 struct ldb_message_element,
2134 msg->num_elements+1);
2135 if (msg->elements == NULL) {
2137 talloc_free(tmp_ctx);
2138 return LDB_ERR_OPERATIONS_ERROR;
2140 /* this relies on the backend matching the old entry
2141 only by the DN portion of the extended DN */
2142 msg->elements[1] = msg->elements[0];
2143 msg->elements[0].flags = LDB_FLAG_MOD_DELETE;
2144 msg->num_elements++;
2146 ret = ldb_build_mod_req(&mod_req, ldb, tmp_ctx,
2150 ldb_op_default_callback,
2152 if (ret != LDB_SUCCESS) {
2153 talloc_free(tmp_ctx);
2157 /* Run the new request */
2158 ret = ldb_next_request(module, mod_req);
2160 if (ret == LDB_SUCCESS) {
2161 ret = ldb_wait(mod_req->handle, LDB_WAIT_ALL);
2165 if (ret != LDB_SUCCESS) {
2166 ldb_debug(ldb, LDB_DEBUG_WARNING, "Failed to apply linked attribute change '%s' %s\n",
2168 ldb_ldif_message_string(ldb, tmp_ctx, LDB_CHANGETYPE_MODIFY, msg));
2172 talloc_free(tmp_ctx);
2177 static int replmd_extended(struct ldb_module *module, struct ldb_request *req)
2179 if (strcmp(req->op.extended.oid, DSDB_EXTENDED_REPLICATED_OBJECTS_OID) == 0) {
2180 return replmd_extended_replicated_objects(module, req);
2183 return ldb_next_request(module, req);
2188 we hook into the transaction operations to allow us to
2189 perform the linked attribute updates at the end of the whole
2190 transaction. This allows a forward linked attribute to be created
2191 before the object is created. During a vampire, w2k8 sends us linked
2192 attributes before the objects they are part of.
2194 static int replmd_start_transaction(struct ldb_module *module)
2196 /* create our private structure for this transaction */
2198 struct replmd_private *replmd_private = talloc_get_type(ldb_module_get_private(module),
2199 struct replmd_private);
2200 talloc_free(replmd_private->la_ctx);
2201 replmd_private->la_list = NULL;
2202 replmd_private->la_ctx = NULL;
2204 for (i=0; i<replmd_private->num_ncs; i++) {
2205 replmd_private->ncs[i].mod_usn = 0;
2208 return ldb_next_start_trans(module);
2212 on prepare commit we loop over our queued la_context structures and
2215 static int replmd_prepare_commit(struct ldb_module *module)
2217 struct replmd_private *replmd_private =
2218 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
2219 struct la_entry *la, *prev;
2222 /* walk the list backwards, to do the first entry first, as we
2223 * added the entries with DLIST_ADD() which puts them at the
2224 * start of the list */
2225 for (la = replmd_private->la_list; la && la->next; la=la->next) ;
2227 for (; la; la=prev) {
2229 DLIST_REMOVE(replmd_private->la_list, la);
2230 ret = replmd_process_linked_attribute(module, la);
2231 if (ret != LDB_SUCCESS) {
2232 talloc_free(replmd_private->la_ctx);
2233 replmd_private->la_list = NULL;
2234 replmd_private->la_ctx = NULL;
2239 talloc_free(replmd_private->la_ctx);
2240 replmd_private->la_list = NULL;
2241 replmd_private->la_ctx = NULL;
2243 /* possibly change @REPLCHANGED */
2244 ret = replmd_notify_store(module);
2245 if (ret != LDB_SUCCESS) {
2249 return ldb_next_prepare_commit(module);
2252 static int replmd_del_transaction(struct ldb_module *module)
2254 struct replmd_private *replmd_private =
2255 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
2256 talloc_free(replmd_private->la_ctx);
2257 replmd_private->la_list = NULL;
2258 replmd_private->la_ctx = NULL;
2259 return ldb_next_del_trans(module);
2263 _PUBLIC_ const struct ldb_module_ops ldb_repl_meta_data_module_ops = {
2264 .name = "repl_meta_data",
2265 .init_context = replmd_init,
2267 .modify = replmd_modify,
2268 .rename = replmd_rename,
2269 .extended = replmd_extended,
2270 .start_transaction = replmd_start_transaction,
2271 .prepare_commit = replmd_prepare_commit,
2272 .del_transaction = replmd_del_transaction,