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;
53 struct nc_entry *prev, *next;
60 struct la_entry *next, *prev;
61 struct drsuapi_DsReplicaLinkedAttribute *la;
64 struct replmd_replicated_request {
65 struct ldb_module *module;
66 struct ldb_request *req;
68 const struct dsdb_schema *schema;
70 /* the controls we pass down */
71 struct ldb_control **controls;
73 /* details for the mode where we apply a bunch of inbound replication meessages */
75 uint32_t index_current;
76 struct dsdb_extended_replicated_objects *objs;
78 struct ldb_message *search_msg;
84 static int replmd_replicated_apply_next(struct replmd_replicated_request *ar);
88 allocate the private structure and build the list
89 of partition DNs for use by replmd_notify()
91 static int replmd_init(struct ldb_module *module)
93 struct replmd_private *replmd_private;
94 struct ldb_context *ldb = ldb_module_get_ctx(module);
96 replmd_private = talloc_zero(module, struct replmd_private);
97 if (replmd_private == NULL) {
99 return LDB_ERR_OPERATIONS_ERROR;
101 ldb_module_set_private(module, replmd_private);
103 return ldb_next_init(module);
108 * Callback for most write operations in this module:
110 * notify the repl task that a object has changed. The notifies are
111 * gathered up in the replmd_private structure then written to the
112 * @REPLCHANGED object in each partition during the prepare_commit
114 static int replmd_op_callback(struct ldb_request *req, struct ldb_reply *ares)
117 struct replmd_replicated_request *ac =
118 talloc_get_type_abort(req->context, struct replmd_replicated_request);
119 struct replmd_private *replmd_private =
120 talloc_get_type_abort(ldb_module_get_private(ac->module), struct replmd_private);
121 struct nc_entry *modified_partition;
122 struct ldb_control *partition_ctrl;
123 const struct dsdb_control_current_partition *partition;
125 struct ldb_control **controls;
127 partition_ctrl = ldb_reply_get_control(ares, DSDB_CONTROL_CURRENT_PARTITION_OID);
129 /* Remove the 'partition' control from what we pass up the chain */
130 controls = controls_except_specified(ares->controls, ares, partition_ctrl);
132 if (ares->error != LDB_SUCCESS) {
133 return ldb_module_done(ac->req, controls,
134 ares->response, ares->error);
137 if (ares->type != LDB_REPLY_DONE) {
138 ldb_set_errstring(ldb_module_get_ctx(ac->module), "Invalid reply type for notify\n!");
139 return ldb_module_done(ac->req, NULL,
140 NULL, LDB_ERR_OPERATIONS_ERROR);
143 if (!partition_ctrl) {
144 return ldb_module_done(ac->req, NULL,
145 NULL, LDB_ERR_OPERATIONS_ERROR);
148 partition = talloc_get_type_abort(partition_ctrl->data,
149 struct dsdb_control_current_partition);
151 if (ac->seq_num > 0) {
152 for (modified_partition = replmd_private->ncs; modified_partition;
153 modified_partition = modified_partition->next) {
154 if (ldb_dn_compare(modified_partition->dn, partition->dn) == 0) {
159 if (modified_partition == NULL) {
160 modified_partition = talloc_zero(replmd_private, struct nc_entry);
161 if (!modified_partition) {
162 ldb_oom(ldb_module_get_ctx(ac->module));
163 return ldb_module_done(ac->req, NULL,
164 NULL, LDB_ERR_OPERATIONS_ERROR);
166 modified_partition->dn = ldb_dn_copy(modified_partition, partition->dn);
167 if (!modified_partition->dn) {
168 ldb_oom(ldb_module_get_ctx(ac->module));
169 return ldb_module_done(ac->req, NULL,
170 NULL, LDB_ERR_OPERATIONS_ERROR);
172 DLIST_ADD(replmd_private->ncs, modified_partition);
175 if (ac->seq_num > modified_partition->mod_usn) {
176 modified_partition->mod_usn = ac->seq_num;
180 if (ac->apply_mode) {
184 ret = replmd_replicated_apply_next(ac);
185 if (ret != LDB_SUCCESS) {
186 return ldb_module_done(ac->req, NULL, NULL, ret);
190 /* free the partition control container here, for the
191 * common path. Other cases will have it cleaned up
192 * eventually with the ares */
193 talloc_free(partition_ctrl);
194 return ldb_module_done(ac->req,
195 controls_except_specified(controls, ares, partition_ctrl),
196 ares->response, LDB_SUCCESS);
202 * update a @REPLCHANGED record in each partition if there have been
203 * any writes of replicated data in the partition
205 static int replmd_notify_store(struct ldb_module *module)
207 struct replmd_private *replmd_private =
208 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
209 struct ldb_context *ldb = ldb_module_get_ctx(module);
211 while (replmd_private->ncs) {
213 struct nc_entry *modified_partition = replmd_private->ncs;
215 ret = dsdb_save_partition_usn(ldb, modified_partition->dn, modified_partition->mod_usn);
216 if (ret != LDB_SUCCESS) {
217 DEBUG(0,(__location__ ": Failed to save partition uSN for %s\n",
218 ldb_dn_get_linearized(modified_partition->dn)));
221 DLIST_REMOVE(replmd_private->ncs, modified_partition);
222 talloc_free(modified_partition);
230 created a replmd_replicated_request context
232 static struct replmd_replicated_request *replmd_ctx_init(struct ldb_module *module,
233 struct ldb_request *req)
235 struct ldb_context *ldb;
236 struct replmd_replicated_request *ac;
238 ldb = ldb_module_get_ctx(module);
240 ac = talloc_zero(req, struct replmd_replicated_request);
249 ac->schema = dsdb_get_schema(ldb);
251 ldb_debug_set(ldb, LDB_DEBUG_FATAL,
252 "replmd_modify: no dsdb_schema loaded");
253 DEBUG(0,(__location__ ": %s\n", ldb_errstring(ldb)));
261 add a time element to a record
263 static int add_time_element(struct ldb_message *msg, const char *attr, time_t t)
265 struct ldb_message_element *el;
268 if (ldb_msg_find_element(msg, attr) != NULL) {
272 s = ldb_timestring(msg, t);
274 return LDB_ERR_OPERATIONS_ERROR;
277 if (ldb_msg_add_string(msg, attr, s) != LDB_SUCCESS) {
278 return LDB_ERR_OPERATIONS_ERROR;
281 el = ldb_msg_find_element(msg, attr);
282 /* always set as replace. This works because on add ops, the flag
284 el->flags = LDB_FLAG_MOD_REPLACE;
290 add a uint64_t element to a record
292 static int add_uint64_element(struct ldb_message *msg, const char *attr, uint64_t v)
294 struct ldb_message_element *el;
296 if (ldb_msg_find_element(msg, attr) != NULL) {
300 if (ldb_msg_add_fmt(msg, attr, "%llu", (unsigned long long)v) != LDB_SUCCESS) {
301 return LDB_ERR_OPERATIONS_ERROR;
304 el = ldb_msg_find_element(msg, attr);
305 /* always set as replace. This works because on add ops, the flag
307 el->flags = LDB_FLAG_MOD_REPLACE;
312 static int replmd_replPropertyMetaData1_attid_sort(const struct replPropertyMetaData1 *m1,
313 const struct replPropertyMetaData1 *m2,
314 const uint32_t *rdn_attid)
316 if (m1->attid == m2->attid) {
321 * the rdn attribute should be at the end!
322 * so we need to return a value greater than zero
323 * which means m1 is greater than m2
325 if (m1->attid == *rdn_attid) {
330 * the rdn attribute should be at the end!
331 * so we need to return a value less than zero
332 * which means m2 is greater than m1
334 if (m2->attid == *rdn_attid) {
338 return m1->attid - m2->attid;
341 static int replmd_replPropertyMetaDataCtr1_sort(struct replPropertyMetaDataCtr1 *ctr1,
342 const struct dsdb_schema *schema,
345 const char *rdn_name;
346 const struct dsdb_attribute *rdn_sa;
348 rdn_name = ldb_dn_get_rdn_name(dn);
350 DEBUG(0,(__location__ ": No rDN for %s?\n", ldb_dn_get_linearized(dn)));
351 return LDB_ERR_OPERATIONS_ERROR;
354 rdn_sa = dsdb_attribute_by_lDAPDisplayName(schema, rdn_name);
355 if (rdn_sa == NULL) {
356 DEBUG(0,(__location__ ": No sa found for rDN %s for %s\n", rdn_name, ldb_dn_get_linearized(dn)));
357 return LDB_ERR_OPERATIONS_ERROR;
360 DEBUG(6,("Sorting rpmd with attid exception %u rDN=%s DN=%s\n",
361 rdn_sa->attributeID_id, rdn_name, ldb_dn_get_linearized(dn)));
363 ldb_qsort(ctr1->array, ctr1->count, sizeof(struct replPropertyMetaData1),
364 discard_const_p(void, &rdn_sa->attributeID_id),
365 (ldb_qsort_cmp_fn_t)replmd_replPropertyMetaData1_attid_sort);
370 static int replmd_ldb_message_element_attid_sort(const struct ldb_message_element *e1,
371 const struct ldb_message_element *e2,
372 const struct dsdb_schema *schema)
374 const struct dsdb_attribute *a1;
375 const struct dsdb_attribute *a2;
378 * TODO: make this faster by caching the dsdb_attribute pointer
379 * on the ldb_messag_element
382 a1 = dsdb_attribute_by_lDAPDisplayName(schema, e1->name);
383 a2 = dsdb_attribute_by_lDAPDisplayName(schema, e2->name);
386 * TODO: remove this check, we should rely on e1 and e2 having valid attribute names
390 return strcasecmp(e1->name, e2->name);
393 return a1->attributeID_id - a2->attributeID_id;
396 static void replmd_ldb_message_sort(struct ldb_message *msg,
397 const struct dsdb_schema *schema)
399 ldb_qsort(msg->elements, msg->num_elements, sizeof(struct ldb_message_element),
400 discard_const_p(void, schema), (ldb_qsort_cmp_fn_t)replmd_ldb_message_element_attid_sort);
403 static int replmd_add(struct ldb_module *module, struct ldb_request *req)
405 struct ldb_context *ldb;
406 struct ldb_control *control;
407 struct ldb_control **saved_controls;
408 struct replmd_replicated_request *ac;
409 enum ndr_err_code ndr_err;
410 struct ldb_request *down_req;
411 struct ldb_message *msg;
412 const DATA_BLOB *guid_blob;
414 struct replPropertyMetaDataBlob nmd;
415 struct ldb_val nmd_value;
416 const struct GUID *our_invocation_id;
417 time_t t = time(NULL);
422 bool allow_add_guid = false;
423 bool remove_current_guid = false;
425 /* check if there's a show relax control (used by provision to say 'I know what I'm doing') */
426 control = ldb_request_get_control(req, LDB_CONTROL_RELAX_OID);
431 /* do not manipulate our control entries */
432 if (ldb_dn_is_special(req->op.add.message->dn)) {
433 return ldb_next_request(module, req);
436 ldb = ldb_module_get_ctx(module);
438 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_add\n");
440 ac = replmd_ctx_init(module, req);
442 return LDB_ERR_OPERATIONS_ERROR;
445 guid_blob = ldb_msg_find_ldb_val(req->op.add.message, "objectGUID");
446 if ( guid_blob != NULL ) {
447 if( !allow_add_guid ) {
448 ldb_debug_set(ldb, LDB_DEBUG_ERROR,
449 "replmd_add: it's not allowed to add an object with objectGUID\n");
451 return LDB_ERR_UNWILLING_TO_PERFORM;
453 NTSTATUS status = GUID_from_data_blob(guid_blob,&guid);
454 if ( !NT_STATUS_IS_OK(status)) {
455 ldb_debug_set(ldb, LDB_DEBUG_ERROR,
456 "replmd_add: Unable to parse as a GUID the attribute objectGUID\n");
458 return LDB_ERR_UNWILLING_TO_PERFORM;
460 /* we remove this attribute as it can be a string and will not be treated
461 correctly and then we will readd it latter on in the good format*/
462 remove_current_guid = true;
466 guid = GUID_random();
469 /* Get a sequence number from the backend */
470 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &ac->seq_num);
471 if (ret != LDB_SUCCESS) {
476 /* get our invocationId */
477 our_invocation_id = samdb_ntds_invocation_id(ldb);
478 if (!our_invocation_id) {
479 ldb_debug_set(ldb, LDB_DEBUG_ERROR,
480 "replmd_add: unable to find invocationId\n");
482 return LDB_ERR_OPERATIONS_ERROR;
485 /* we have to copy the message as the caller might have it as a const */
486 msg = ldb_msg_copy_shallow(ac, req->op.add.message);
490 return LDB_ERR_OPERATIONS_ERROR;
493 /* generated times */
494 unix_to_nt_time(&now, t);
495 time_str = ldb_timestring(msg, t);
499 return LDB_ERR_OPERATIONS_ERROR;
501 if (remove_current_guid) {
502 ldb_msg_remove_attr(msg,"objectGUID");
506 * remove autogenerated attributes
508 ldb_msg_remove_attr(msg, "whenCreated");
509 ldb_msg_remove_attr(msg, "whenChanged");
510 ldb_msg_remove_attr(msg, "uSNCreated");
511 ldb_msg_remove_attr(msg, "uSNChanged");
512 ldb_msg_remove_attr(msg, "replPropertyMetaData");
515 * readd replicated attributes
517 ret = ldb_msg_add_string(msg, "whenCreated", time_str);
518 if (ret != LDB_SUCCESS) {
524 /* build the replication meta_data */
527 nmd.ctr.ctr1.count = msg->num_elements;
528 nmd.ctr.ctr1.array = talloc_array(msg,
529 struct replPropertyMetaData1,
531 if (!nmd.ctr.ctr1.array) {
534 return LDB_ERR_OPERATIONS_ERROR;
537 for (i=0; i < msg->num_elements; i++) {
538 struct ldb_message_element *e = &msg->elements[i];
539 struct replPropertyMetaData1 *m = &nmd.ctr.ctr1.array[ni];
540 const struct dsdb_attribute *sa;
542 if (e->name[0] == '@') continue;
544 sa = dsdb_attribute_by_lDAPDisplayName(ac->schema, e->name);
546 ldb_debug_set(ldb, LDB_DEBUG_ERROR,
547 "replmd_add: attribute '%s' not defined in schema\n",
550 return LDB_ERR_NO_SUCH_ATTRIBUTE;
553 if ((sa->systemFlags & DS_FLAG_ATTR_NOT_REPLICATED) || (sa->systemFlags & DS_FLAG_ATTR_IS_CONSTRUCTED)) {
554 /* if the attribute is not replicated (0x00000001)
555 * or constructed (0x00000004) it has no metadata
560 m->attid = sa->attributeID_id;
562 m->originating_change_time = now;
563 m->originating_invocation_id = *our_invocation_id;
564 m->originating_usn = ac->seq_num;
565 m->local_usn = ac->seq_num;
569 /* fix meta data count */
570 nmd.ctr.ctr1.count = ni;
573 * sort meta data array, and move the rdn attribute entry to the end
575 ret = replmd_replPropertyMetaDataCtr1_sort(&nmd.ctr.ctr1, ac->schema, msg->dn);
576 if (ret != LDB_SUCCESS) {
581 /* generated NDR encoded values */
582 ndr_err = ndr_push_struct_blob(&nmd_value, msg,
583 lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")),
585 (ndr_push_flags_fn_t)ndr_push_replPropertyMetaDataBlob);
586 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
589 return LDB_ERR_OPERATIONS_ERROR;
593 * add the autogenerated values
595 ret = dsdb_msg_add_guid(msg, &guid, "objectGUID");
596 if (ret != LDB_SUCCESS) {
601 ret = ldb_msg_add_string(msg, "whenChanged", time_str);
602 if (ret != LDB_SUCCESS) {
607 ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNCreated", ac->seq_num);
608 if (ret != LDB_SUCCESS) {
613 ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNChanged", ac->seq_num);
614 if (ret != LDB_SUCCESS) {
619 ret = ldb_msg_add_value(msg, "replPropertyMetaData", &nmd_value, NULL);
620 if (ret != LDB_SUCCESS) {
627 * sort the attributes by attid before storing the object
629 replmd_ldb_message_sort(msg, ac->schema);
631 ret = ldb_build_add_req(&down_req, ldb, ac,
634 ac, replmd_op_callback,
636 if (ret != LDB_SUCCESS) {
641 /* if a control is there remove if from the modified request */
642 if (control && !save_controls(control, down_req, &saved_controls)) {
644 return LDB_ERR_OPERATIONS_ERROR;
647 /* go on with the call chain */
648 return ldb_next_request(module, down_req);
653 * update the replPropertyMetaData for one element
655 static int replmd_update_rpmd_element(struct ldb_context *ldb,
656 struct ldb_message *msg,
657 struct ldb_message_element *el,
658 struct replPropertyMetaDataBlob *omd,
659 const struct dsdb_schema *schema,
661 const struct GUID *our_invocation_id,
665 const struct dsdb_attribute *a;
666 struct replPropertyMetaData1 *md1;
668 a = dsdb_attribute_by_lDAPDisplayName(schema, el->name);
670 DEBUG(0,(__location__ ": Unable to find attribute %s in schema\n",
672 return LDB_ERR_OPERATIONS_ERROR;
675 if ((a->systemFlags & DS_FLAG_ATTR_NOT_REPLICATED) || (a->systemFlags & DS_FLAG_ATTR_IS_CONSTRUCTED)) {
679 for (i=0; i<omd->ctr.ctr1.count; i++) {
680 if (a->attributeID_id == omd->ctr.ctr1.array[i].attid) break;
682 if (i == omd->ctr.ctr1.count) {
683 /* we need to add a new one */
684 omd->ctr.ctr1.array = talloc_realloc(msg, omd->ctr.ctr1.array,
685 struct replPropertyMetaData1, omd->ctr.ctr1.count+1);
686 if (omd->ctr.ctr1.array == NULL) {
688 return LDB_ERR_OPERATIONS_ERROR;
690 omd->ctr.ctr1.count++;
691 ZERO_STRUCT(omd->ctr.ctr1.array[i]);
694 /* Get a new sequence number from the backend. We only do this
695 * if we have a change that requires a new
696 * replPropertyMetaData element
699 int ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, seq_num);
700 if (ret != LDB_SUCCESS) {
701 return LDB_ERR_OPERATIONS_ERROR;
705 md1 = &omd->ctr.ctr1.array[i];
707 md1->attid = a->attributeID_id;
708 md1->originating_change_time = now;
709 md1->originating_invocation_id = *our_invocation_id;
710 md1->originating_usn = *seq_num;
711 md1->local_usn = *seq_num;
717 * update the replPropertyMetaData object each time we modify an
718 * object. This is needed for DRS replication, as the merge on the
719 * client is based on this object
721 static int replmd_update_rpmd(struct ldb_module *module,
722 const struct dsdb_schema *schema,
723 struct ldb_message *msg, uint64_t *seq_num)
725 const struct ldb_val *omd_value;
726 enum ndr_err_code ndr_err;
727 struct replPropertyMetaDataBlob omd;
729 time_t t = time(NULL);
731 const struct GUID *our_invocation_id;
733 const char *attrs[] = { "replPropertyMetaData" , NULL };
734 struct ldb_result *res;
735 struct ldb_context *ldb;
737 ldb = ldb_module_get_ctx(module);
739 our_invocation_id = samdb_ntds_invocation_id(ldb);
740 if (!our_invocation_id) {
741 /* this happens during an initial vampire while
742 updating the schema */
743 DEBUG(5,("No invocationID - skipping replPropertyMetaData update\n"));
747 unix_to_nt_time(&now, t);
749 /* search for the existing replPropertyMetaDataBlob */
750 ret = dsdb_search_dn_with_deleted(ldb, msg, &res, msg->dn, attrs);
751 if (ret != LDB_SUCCESS || res->count != 1) {
752 DEBUG(0,(__location__ ": Object %s failed to find replPropertyMetaData\n",
753 ldb_dn_get_linearized(msg->dn)));
754 return LDB_ERR_OPERATIONS_ERROR;
758 omd_value = ldb_msg_find_ldb_val(res->msgs[0], "replPropertyMetaData");
760 DEBUG(0,(__location__ ": Object %s does not have a replPropertyMetaData attribute\n",
761 ldb_dn_get_linearized(msg->dn)));
762 return LDB_ERR_OPERATIONS_ERROR;
765 ndr_err = ndr_pull_struct_blob(omd_value, msg,
766 lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")), &omd,
767 (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
768 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
769 DEBUG(0,(__location__ ": Failed to parse replPropertyMetaData for %s\n",
770 ldb_dn_get_linearized(msg->dn)));
771 return LDB_ERR_OPERATIONS_ERROR;
774 if (omd.version != 1) {
775 DEBUG(0,(__location__ ": bad version %u in replPropertyMetaData for %s\n",
776 omd.version, ldb_dn_get_linearized(msg->dn)));
777 return LDB_ERR_OPERATIONS_ERROR;
780 for (i=0; i<msg->num_elements; i++) {
781 ret = replmd_update_rpmd_element(ldb, msg, &msg->elements[i], &omd, schema, seq_num,
782 our_invocation_id, now);
783 if (ret != LDB_SUCCESS) {
789 * replmd_update_rpmd_element has done an update if the
793 struct ldb_val *md_value;
794 struct ldb_message_element *el;
796 md_value = talloc(msg, struct ldb_val);
797 if (md_value == NULL) {
799 return LDB_ERR_OPERATIONS_ERROR;
802 ret = replmd_replPropertyMetaDataCtr1_sort(&omd.ctr.ctr1, schema, msg->dn);
803 if (ret != LDB_SUCCESS) {
807 ndr_err = ndr_push_struct_blob(md_value, msg,
808 lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")),
810 (ndr_push_flags_fn_t)ndr_push_replPropertyMetaDataBlob);
811 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
812 DEBUG(0,(__location__ ": Failed to marshall replPropertyMetaData for %s\n",
813 ldb_dn_get_linearized(msg->dn)));
814 return LDB_ERR_OPERATIONS_ERROR;
817 ret = ldb_msg_add_empty(msg, "replPropertyMetaData", LDB_FLAG_MOD_REPLACE, &el);
818 if (ret != LDB_SUCCESS) {
819 DEBUG(0,(__location__ ": Failed to add updated replPropertyMetaData %s\n",
820 ldb_dn_get_linearized(msg->dn)));
825 el->values = md_value;
832 static int replmd_modify(struct ldb_module *module, struct ldb_request *req)
834 struct ldb_context *ldb;
835 struct replmd_replicated_request *ac;
836 struct ldb_request *down_req;
837 struct ldb_message *msg;
838 struct ldb_result *res;
839 time_t t = time(NULL);
840 uint64_t seq_num = 0;
843 /* do not manipulate our control entries */
844 if (ldb_dn_is_special(req->op.mod.message->dn)) {
845 return ldb_next_request(module, req);
848 ldb = ldb_module_get_ctx(module);
850 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_modify\n");
852 ac = replmd_ctx_init(module, req);
854 return LDB_ERR_OPERATIONS_ERROR;
857 /* we have to copy the message as the caller might have it as a const */
858 msg = ldb_msg_copy_shallow(ac, req->op.mod.message);
862 return LDB_ERR_OPERATIONS_ERROR;
866 * - give an error when a readonly attribute should
868 * - merge the changed into the old object
869 * if the caller set values to the same value
870 * ignore the attribute, return success when no
871 * attribute was changed
874 ret = dsdb_search_dn_with_deleted(ldb, msg, &res, msg->dn, NULL);
875 if (ret != LDB_SUCCESS) {
880 ret = replmd_update_rpmd(module, ac->schema, msg, &ac->seq_num);
881 if (ret != LDB_SUCCESS) {
887 * - replace the old object with the newly constructed one
890 ret = ldb_build_mod_req(&down_req, ldb, ac,
893 ac, replmd_op_callback,
895 if (ret != LDB_SUCCESS) {
899 talloc_steal(down_req, msg);
901 /* we only change whenChanged and uSNChanged if the seq_num
904 if (add_time_element(msg, "whenChanged", t) != LDB_SUCCESS) {
909 if (add_uint64_element(msg, "uSNChanged", seq_num) != LDB_SUCCESS) {
915 /* go on with the call chain */
916 return ldb_next_request(module, down_req);
919 static int replmd_rename_callback(struct ldb_request *req, struct ldb_reply *ares);
922 handle a rename request
924 On a rename we need to do an extra ldb_modify which sets the
925 whenChanged and uSNChanged attributes. We do this in a callback after the success.
927 static int replmd_rename(struct ldb_module *module, struct ldb_request *req)
929 struct ldb_context *ldb;
930 struct replmd_replicated_request *ac;
932 struct ldb_request *down_req;
934 /* do not manipulate our control entries */
935 if (ldb_dn_is_special(req->op.mod.message->dn)) {
936 return ldb_next_request(module, req);
939 ldb = ldb_module_get_ctx(module);
941 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_rename\n");
943 ac = replmd_ctx_init(module, req);
945 return LDB_ERR_OPERATIONS_ERROR;
947 ret = ldb_build_rename_req(&down_req, ldb, ac,
948 ac->req->op.rename.olddn,
949 ac->req->op.rename.newdn,
951 ac, replmd_rename_callback,
954 if (ret != LDB_SUCCESS) {
959 /* go on with the call chain */
960 return ldb_next_request(module, down_req);
963 /* After the rename is compleated, update the whenchanged etc */
964 static int replmd_rename_callback(struct ldb_request *req, struct ldb_reply *ares)
966 struct ldb_context *ldb;
967 struct replmd_replicated_request *ac;
968 struct ldb_request *down_req;
969 struct ldb_message *msg;
970 time_t t = time(NULL);
973 ac = talloc_get_type(req->context, struct replmd_replicated_request);
974 ldb = ldb_module_get_ctx(ac->module);
976 if (ares->error != LDB_SUCCESS) {
977 return ldb_module_done(ac->req, ares->controls,
978 ares->response, ares->error);
981 if (ares->type != LDB_REPLY_DONE) {
982 ldb_set_errstring(ldb,
983 "invalid ldb_reply_type in callback");
985 return ldb_module_done(ac->req, NULL, NULL,
986 LDB_ERR_OPERATIONS_ERROR);
989 /* Get a sequence number from the backend */
990 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &ac->seq_num);
991 if (ret != LDB_SUCCESS) {
996 * - replace the old object with the newly constructed one
999 msg = ldb_msg_new(ac);
1002 return LDB_ERR_OPERATIONS_ERROR;
1005 msg->dn = ac->req->op.rename.newdn;
1007 ret = ldb_build_mod_req(&down_req, ldb, ac,
1010 ac, replmd_op_callback,
1013 if (ret != LDB_SUCCESS) {
1017 talloc_steal(down_req, msg);
1019 if (add_time_element(msg, "whenChanged", t) != LDB_SUCCESS) {
1024 if (add_uint64_element(msg, "uSNChanged", ac->seq_num) != LDB_SUCCESS) {
1029 /* go on with the call chain - do the modify after the rename */
1030 return ldb_next_request(ac->module, down_req);
1034 static int replmd_replicated_request_error(struct replmd_replicated_request *ar, int ret)
1039 static int replmd_replicated_request_werror(struct replmd_replicated_request *ar, WERROR status)
1041 int ret = LDB_ERR_OTHER;
1042 /* TODO: do some error mapping */
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;
1058 * TODO: check if the parent object exist
1062 * TODO: handle the conflict case where an object with the
1066 ldb = ldb_module_get_ctx(ar->module);
1067 msg = ar->objs->objects[ar->index_current].msg;
1068 md = ar->objs->objects[ar->index_current].meta_data;
1070 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &ar->seq_num);
1071 if (ret != LDB_SUCCESS) {
1072 return replmd_replicated_request_error(ar, ret);
1075 ret = ldb_msg_add_value(msg, "objectGUID", &ar->objs->objects[ar->index_current].guid_value, NULL);
1076 if (ret != LDB_SUCCESS) {
1077 return replmd_replicated_request_error(ar, ret);
1080 ret = ldb_msg_add_string(msg, "whenChanged", ar->objs->objects[ar->index_current].when_changed);
1081 if (ret != LDB_SUCCESS) {
1082 return replmd_replicated_request_error(ar, ret);
1085 ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNCreated", ar->seq_num);
1086 if (ret != LDB_SUCCESS) {
1087 return replmd_replicated_request_error(ar, ret);
1090 ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNChanged", ar->seq_num);
1091 if (ret != LDB_SUCCESS) {
1092 return replmd_replicated_request_error(ar, ret);
1095 /* remove any message elements that have zero values */
1096 for (i=0; i<msg->num_elements; i++) {
1097 if (msg->elements[i].num_values == 0) {
1098 DEBUG(4,(__location__ ": Removing attribute %s with num_values==0\n",
1099 msg->elements[i].name));
1100 memmove(&msg->elements[i],
1101 &msg->elements[i+1],
1102 sizeof(msg->elements[i])*(msg->num_elements - (i+1)));
1103 msg->num_elements--;
1109 * the meta data array is already sorted by the caller
1111 for (i=0; i < md->ctr.ctr1.count; i++) {
1112 md->ctr.ctr1.array[i].local_usn = ar->seq_num;
1114 ndr_err = ndr_push_struct_blob(&md_value, msg,
1115 lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")),
1117 (ndr_push_flags_fn_t)ndr_push_replPropertyMetaDataBlob);
1118 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1119 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
1120 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
1122 ret = ldb_msg_add_value(msg, "replPropertyMetaData", &md_value, NULL);
1123 if (ret != LDB_SUCCESS) {
1124 return replmd_replicated_request_error(ar, ret);
1127 replmd_ldb_message_sort(msg, ar->schema);
1130 char *s = ldb_ldif_message_string(ldb, ar, LDB_CHANGETYPE_ADD, msg);
1131 DEBUG(4, ("DRS replication add message:\n%s\n", s));
1135 ret = ldb_build_add_req(&change_req,
1143 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
1145 return ldb_next_request(ar->module, change_req);
1148 static int replmd_replPropertyMetaData1_conflict_compare(struct replPropertyMetaData1 *m1,
1149 struct replPropertyMetaData1 *m2)
1153 if (m1->version != m2->version) {
1154 return m1->version - m2->version;
1157 if (m1->originating_change_time != m2->originating_change_time) {
1158 return m1->originating_change_time - m2->originating_change_time;
1161 ret = GUID_compare(&m1->originating_invocation_id, &m2->originating_invocation_id);
1166 return m1->originating_usn - m2->originating_usn;
1169 static int replmd_replicated_apply_merge(struct replmd_replicated_request *ar)
1171 struct ldb_context *ldb;
1172 struct ldb_request *change_req;
1173 enum ndr_err_code ndr_err;
1174 struct ldb_message *msg;
1175 struct replPropertyMetaDataBlob *rmd;
1176 struct replPropertyMetaDataBlob omd;
1177 const struct ldb_val *omd_value;
1178 struct replPropertyMetaDataBlob nmd;
1179 struct ldb_val nmd_value;
1181 uint32_t removed_attrs = 0;
1184 ldb = ldb_module_get_ctx(ar->module);
1185 msg = ar->objs->objects[ar->index_current].msg;
1186 rmd = ar->objs->objects[ar->index_current].meta_data;
1191 * TODO: check repl data is correct after a rename
1193 if (ldb_dn_compare(msg->dn, ar->search_msg->dn) != 0) {
1194 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_replicated_request rename %s => %s\n",
1195 ldb_dn_get_linearized(ar->search_msg->dn),
1196 ldb_dn_get_linearized(msg->dn));
1197 if (ldb_rename(ldb, ar->search_msg->dn, msg->dn) != LDB_SUCCESS) {
1198 ldb_debug(ldb, LDB_DEBUG_FATAL, "replmd_replicated_request rename %s => %s failed - %s\n",
1199 ldb_dn_get_linearized(ar->search_msg->dn),
1200 ldb_dn_get_linearized(msg->dn),
1201 ldb_errstring(ldb));
1202 return replmd_replicated_request_werror(ar, WERR_DS_DRA_DB_ERROR);
1206 /* find existing meta data */
1207 omd_value = ldb_msg_find_ldb_val(ar->search_msg, "replPropertyMetaData");
1209 ndr_err = ndr_pull_struct_blob(omd_value, ar,
1210 lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")), &omd,
1211 (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
1212 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1213 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
1214 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
1217 if (omd.version != 1) {
1218 return replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
1224 nmd.ctr.ctr1.count = omd.ctr.ctr1.count + rmd->ctr.ctr1.count;
1225 nmd.ctr.ctr1.array = talloc_array(ar,
1226 struct replPropertyMetaData1,
1227 nmd.ctr.ctr1.count);
1228 if (!nmd.ctr.ctr1.array) return replmd_replicated_request_werror(ar, WERR_NOMEM);
1230 /* first copy the old meta data */
1231 for (i=0; i < omd.ctr.ctr1.count; i++) {
1232 nmd.ctr.ctr1.array[ni] = omd.ctr.ctr1.array[i];
1236 /* now merge in the new meta data */
1237 for (i=0; i < rmd->ctr.ctr1.count; i++) {
1240 for (j=0; j < ni; j++) {
1243 if (rmd->ctr.ctr1.array[i].attid != nmd.ctr.ctr1.array[j].attid) {
1247 cmp = replmd_replPropertyMetaData1_conflict_compare(&rmd->ctr.ctr1.array[i],
1248 &nmd.ctr.ctr1.array[j]);
1250 /* replace the entry */
1251 nmd.ctr.ctr1.array[j] = rmd->ctr.ctr1.array[i];
1256 /* we don't want to apply this change so remove the attribute */
1257 ldb_msg_remove_element(msg, &msg->elements[i-removed_attrs]);
1264 if (found) continue;
1266 nmd.ctr.ctr1.array[ni] = rmd->ctr.ctr1.array[i];
1271 * finally correct the size of the meta_data array
1273 nmd.ctr.ctr1.count = ni;
1276 * the rdn attribute (the alias for the name attribute),
1277 * 'cn' for most objects is the last entry in the meta data array
1280 * sort the new meta data array
1282 ret = replmd_replPropertyMetaDataCtr1_sort(&nmd.ctr.ctr1, ar->schema, msg->dn);
1283 if (ret != LDB_SUCCESS) {
1288 * check if some replicated attributes left, otherwise skip the ldb_modify() call
1290 if (msg->num_elements == 0) {
1291 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_replicated_apply_merge[%u]: skip replace\n",
1294 ar->index_current++;
1295 return replmd_replicated_apply_next(ar);
1298 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_replicated_apply_merge[%u]: replace %u attributes\n",
1299 ar->index_current, msg->num_elements);
1301 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &ar->seq_num);
1302 if (ret != LDB_SUCCESS) {
1303 return replmd_replicated_request_error(ar, ret);
1306 for (i=0; i<ni; i++) {
1307 nmd.ctr.ctr1.array[i].local_usn = ar->seq_num;
1310 /* create the meta data value */
1311 ndr_err = ndr_push_struct_blob(&nmd_value, msg,
1312 lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")),
1314 (ndr_push_flags_fn_t)ndr_push_replPropertyMetaDataBlob);
1315 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1316 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
1317 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
1321 * when we know that we'll modify the record, add the whenChanged, uSNChanged
1322 * and replPopertyMetaData attributes
1324 ret = ldb_msg_add_string(msg, "whenChanged", ar->objs->objects[ar->index_current].when_changed);
1325 if (ret != LDB_SUCCESS) {
1326 return replmd_replicated_request_error(ar, ret);
1328 ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNChanged", ar->seq_num);
1329 if (ret != LDB_SUCCESS) {
1330 return replmd_replicated_request_error(ar, ret);
1332 ret = ldb_msg_add_value(msg, "replPropertyMetaData", &nmd_value, NULL);
1333 if (ret != LDB_SUCCESS) {
1334 return replmd_replicated_request_error(ar, ret);
1337 replmd_ldb_message_sort(msg, ar->schema);
1339 /* we want to replace the old values */
1340 for (i=0; i < msg->num_elements; i++) {
1341 msg->elements[i].flags = LDB_FLAG_MOD_REPLACE;
1345 char *s = ldb_ldif_message_string(ldb, ar, LDB_CHANGETYPE_MODIFY, msg);
1346 DEBUG(4, ("DRS replication modify message:\n%s\n", s));
1350 ret = ldb_build_mod_req(&change_req,
1358 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
1360 return ldb_next_request(ar->module, change_req);
1363 static int replmd_replicated_apply_search_callback(struct ldb_request *req,
1364 struct ldb_reply *ares)
1366 struct replmd_replicated_request *ar = talloc_get_type(req->context,
1367 struct replmd_replicated_request);
1371 return ldb_module_done(ar->req, NULL, NULL,
1372 LDB_ERR_OPERATIONS_ERROR);
1374 if (ares->error != LDB_SUCCESS &&
1375 ares->error != LDB_ERR_NO_SUCH_OBJECT) {
1376 return ldb_module_done(ar->req, ares->controls,
1377 ares->response, ares->error);
1380 switch (ares->type) {
1381 case LDB_REPLY_ENTRY:
1382 ar->search_msg = talloc_steal(ar, ares->message);
1385 case LDB_REPLY_REFERRAL:
1386 /* we ignore referrals */
1389 case LDB_REPLY_DONE:
1390 if (ar->search_msg != NULL) {
1391 ret = replmd_replicated_apply_merge(ar);
1393 ret = replmd_replicated_apply_add(ar);
1395 if (ret != LDB_SUCCESS) {
1396 return ldb_module_done(ar->req, NULL, NULL, ret);
1404 static int replmd_replicated_uptodate_vector(struct replmd_replicated_request *ar);
1406 static int replmd_replicated_apply_next(struct replmd_replicated_request *ar)
1408 struct ldb_context *ldb;
1412 struct ldb_request *search_req;
1413 struct ldb_search_options_control *options;
1415 if (ar->index_current >= ar->objs->num_objects) {
1416 /* done with it, go to next stage */
1417 return replmd_replicated_uptodate_vector(ar);
1420 ldb = ldb_module_get_ctx(ar->module);
1421 ar->search_msg = NULL;
1423 tmp_str = ldb_binary_encode(ar, ar->objs->objects[ar->index_current].guid_value);
1424 if (!tmp_str) return replmd_replicated_request_werror(ar, WERR_NOMEM);
1426 filter = talloc_asprintf(ar, "(objectGUID=%s)", tmp_str);
1427 if (!filter) return replmd_replicated_request_werror(ar, WERR_NOMEM);
1428 talloc_free(tmp_str);
1430 ret = ldb_build_search_req(&search_req,
1439 replmd_replicated_apply_search_callback,
1442 ret = ldb_request_add_control(search_req, LDB_CONTROL_SHOW_DELETED_OID, true, NULL);
1443 if (ret != LDB_SUCCESS) {
1447 /* we need to cope with cross-partition links, so search for
1448 the GUID over all partitions */
1449 options = talloc(search_req, struct ldb_search_options_control);
1450 if (options == NULL) {
1451 DEBUG(0, (__location__ ": out of memory\n"));
1452 return LDB_ERR_OPERATIONS_ERROR;
1454 options->search_options = LDB_SEARCH_OPTION_PHANTOM_ROOT;
1456 ret = ldb_request_add_control(search_req,
1457 LDB_CONTROL_SEARCH_OPTIONS_OID,
1459 if (ret != LDB_SUCCESS) {
1463 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
1465 return ldb_next_request(ar->module, search_req);
1468 static int replmd_replicated_uptodate_modify_callback(struct ldb_request *req,
1469 struct ldb_reply *ares)
1471 struct ldb_context *ldb;
1472 struct replmd_replicated_request *ar = talloc_get_type(req->context,
1473 struct replmd_replicated_request);
1474 ldb = ldb_module_get_ctx(ar->module);
1477 return ldb_module_done(ar->req, NULL, NULL,
1478 LDB_ERR_OPERATIONS_ERROR);
1480 if (ares->error != LDB_SUCCESS) {
1481 return ldb_module_done(ar->req, ares->controls,
1482 ares->response, ares->error);
1485 if (ares->type != LDB_REPLY_DONE) {
1486 ldb_set_errstring(ldb, "Invalid reply type\n!");
1487 return ldb_module_done(ar->req, NULL, NULL,
1488 LDB_ERR_OPERATIONS_ERROR);
1493 return ldb_module_done(ar->req, NULL, NULL, LDB_SUCCESS);
1496 static int replmd_replicated_uptodate_modify(struct replmd_replicated_request *ar)
1498 struct ldb_context *ldb;
1499 struct ldb_request *change_req;
1500 enum ndr_err_code ndr_err;
1501 struct ldb_message *msg;
1502 struct replUpToDateVectorBlob ouv;
1503 const struct ldb_val *ouv_value;
1504 const struct drsuapi_DsReplicaCursor2CtrEx *ruv;
1505 struct replUpToDateVectorBlob nuv;
1506 struct ldb_val nuv_value;
1507 struct ldb_message_element *nuv_el = NULL;
1508 const struct GUID *our_invocation_id;
1509 struct ldb_message_element *orf_el = NULL;
1510 struct repsFromToBlob nrf;
1511 struct ldb_val *nrf_value = NULL;
1512 struct ldb_message_element *nrf_el = NULL;
1515 time_t t = time(NULL);
1519 ldb = ldb_module_get_ctx(ar->module);
1520 ruv = ar->objs->uptodateness_vector;
1526 unix_to_nt_time(&now, t);
1529 * first create the new replUpToDateVector
1531 ouv_value = ldb_msg_find_ldb_val(ar->search_msg, "replUpToDateVector");
1533 ndr_err = ndr_pull_struct_blob(ouv_value, ar,
1534 lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")), &ouv,
1535 (ndr_pull_flags_fn_t)ndr_pull_replUpToDateVectorBlob);
1536 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1537 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
1538 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
1541 if (ouv.version != 2) {
1542 return replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
1547 * the new uptodateness vector will at least
1548 * contain 1 entry, one for the source_dsa
1550 * plus optional values from our old vector and the one from the source_dsa
1552 nuv.ctr.ctr2.count = 1 + ouv.ctr.ctr2.count;
1553 if (ruv) nuv.ctr.ctr2.count += ruv->count;
1554 nuv.ctr.ctr2.cursors = talloc_array(ar,
1555 struct drsuapi_DsReplicaCursor2,
1556 nuv.ctr.ctr2.count);
1557 if (!nuv.ctr.ctr2.cursors) return replmd_replicated_request_werror(ar, WERR_NOMEM);
1559 /* first copy the old vector */
1560 for (i=0; i < ouv.ctr.ctr2.count; i++) {
1561 nuv.ctr.ctr2.cursors[ni] = ouv.ctr.ctr2.cursors[i];
1565 /* get our invocation_id if we have one already attached to the ldb */
1566 our_invocation_id = samdb_ntds_invocation_id(ldb);
1568 /* merge in the source_dsa vector is available */
1569 for (i=0; (ruv && i < ruv->count); i++) {
1572 if (our_invocation_id &&
1573 GUID_equal(&ruv->cursors[i].source_dsa_invocation_id,
1574 our_invocation_id)) {
1578 for (j=0; j < ni; j++) {
1579 if (!GUID_equal(&ruv->cursors[i].source_dsa_invocation_id,
1580 &nuv.ctr.ctr2.cursors[j].source_dsa_invocation_id)) {
1587 * we update only the highest_usn and not the latest_sync_success time,
1588 * because the last success stands for direct replication
1590 if (ruv->cursors[i].highest_usn > nuv.ctr.ctr2.cursors[j].highest_usn) {
1591 nuv.ctr.ctr2.cursors[j].highest_usn = ruv->cursors[i].highest_usn;
1596 if (found) continue;
1598 /* if it's not there yet, add it */
1599 nuv.ctr.ctr2.cursors[ni] = ruv->cursors[i];
1604 * merge in the current highwatermark for the source_dsa
1607 for (j=0; j < ni; j++) {
1608 if (!GUID_equal(&ar->objs->source_dsa->source_dsa_invocation_id,
1609 &nuv.ctr.ctr2.cursors[j].source_dsa_invocation_id)) {
1616 * here we update the highest_usn and last_sync_success time
1617 * because we're directly replicating from the source_dsa
1619 * and use the tmp_highest_usn because this is what we have just applied
1622 nuv.ctr.ctr2.cursors[j].highest_usn = ar->objs->source_dsa->highwatermark.tmp_highest_usn;
1623 nuv.ctr.ctr2.cursors[j].last_sync_success = now;
1628 * here we update the highest_usn and last_sync_success time
1629 * because we're directly replicating from the source_dsa
1631 * and use the tmp_highest_usn because this is what we have just applied
1634 nuv.ctr.ctr2.cursors[ni].source_dsa_invocation_id= ar->objs->source_dsa->source_dsa_invocation_id;
1635 nuv.ctr.ctr2.cursors[ni].highest_usn = ar->objs->source_dsa->highwatermark.tmp_highest_usn;
1636 nuv.ctr.ctr2.cursors[ni].last_sync_success = now;
1641 * finally correct the size of the cursors array
1643 nuv.ctr.ctr2.count = ni;
1648 qsort(nuv.ctr.ctr2.cursors, nuv.ctr.ctr2.count,
1649 sizeof(struct drsuapi_DsReplicaCursor2),
1650 (comparison_fn_t)drsuapi_DsReplicaCursor2_compare);
1653 * create the change ldb_message
1655 msg = ldb_msg_new(ar);
1656 if (!msg) return replmd_replicated_request_werror(ar, WERR_NOMEM);
1657 msg->dn = ar->search_msg->dn;
1659 ndr_err = ndr_push_struct_blob(&nuv_value, msg,
1660 lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")),
1662 (ndr_push_flags_fn_t)ndr_push_replUpToDateVectorBlob);
1663 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1664 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
1665 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
1667 ret = ldb_msg_add_value(msg, "replUpToDateVector", &nuv_value, &nuv_el);
1668 if (ret != LDB_SUCCESS) {
1669 return replmd_replicated_request_error(ar, ret);
1671 nuv_el->flags = LDB_FLAG_MOD_REPLACE;
1674 * now create the new repsFrom value from the given repsFromTo1 structure
1678 nrf.ctr.ctr1 = *ar->objs->source_dsa;
1679 /* and fix some values... */
1680 nrf.ctr.ctr1.consecutive_sync_failures = 0;
1681 nrf.ctr.ctr1.last_success = now;
1682 nrf.ctr.ctr1.last_attempt = now;
1683 nrf.ctr.ctr1.result_last_attempt = WERR_OK;
1684 nrf.ctr.ctr1.highwatermark.highest_usn = nrf.ctr.ctr1.highwatermark.tmp_highest_usn;
1687 * first see if we already have a repsFrom value for the current source dsa
1688 * if so we'll later replace this value
1690 orf_el = ldb_msg_find_element(ar->search_msg, "repsFrom");
1692 for (i=0; i < orf_el->num_values; i++) {
1693 struct repsFromToBlob *trf;
1695 trf = talloc(ar, struct repsFromToBlob);
1696 if (!trf) return replmd_replicated_request_werror(ar, WERR_NOMEM);
1698 ndr_err = ndr_pull_struct_blob(&orf_el->values[i], trf, lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")), trf,
1699 (ndr_pull_flags_fn_t)ndr_pull_repsFromToBlob);
1700 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1701 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
1702 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
1705 if (trf->version != 1) {
1706 return replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
1710 * we compare the source dsa objectGUID not the invocation_id
1711 * because we want only one repsFrom value per source dsa
1712 * and when the invocation_id of the source dsa has changed we don't need
1713 * the old repsFrom with the old invocation_id
1715 if (!GUID_equal(&trf->ctr.ctr1.source_dsa_obj_guid,
1716 &ar->objs->source_dsa->source_dsa_obj_guid)) {
1722 nrf_value = &orf_el->values[i];
1727 * copy over all old values to the new ldb_message
1729 ret = ldb_msg_add_empty(msg, "repsFrom", 0, &nrf_el);
1730 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
1735 * if we haven't found an old repsFrom value for the current source dsa
1736 * we'll add a new value
1739 struct ldb_val zero_value;
1740 ZERO_STRUCT(zero_value);
1741 ret = ldb_msg_add_value(msg, "repsFrom", &zero_value, &nrf_el);
1742 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
1744 nrf_value = &nrf_el->values[nrf_el->num_values - 1];
1747 /* we now fill the value which is already attached to ldb_message */
1748 ndr_err = ndr_push_struct_blob(nrf_value, msg,
1749 lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")),
1751 (ndr_push_flags_fn_t)ndr_push_repsFromToBlob);
1752 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1753 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
1754 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
1758 * the ldb_message_element for the attribute, has all the old values and the new one
1759 * so we'll replace the whole attribute with all values
1761 nrf_el->flags = LDB_FLAG_MOD_REPLACE;
1764 char *s = ldb_ldif_message_string(ldb, ar, LDB_CHANGETYPE_MODIFY, msg);
1765 DEBUG(4, ("DRS replication uptodate modify message:\n%s\n", s));
1769 /* prepare the ldb_modify() request */
1770 ret = ldb_build_mod_req(&change_req,
1776 replmd_replicated_uptodate_modify_callback,
1778 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
1780 return ldb_next_request(ar->module, change_req);
1783 static int replmd_replicated_uptodate_search_callback(struct ldb_request *req,
1784 struct ldb_reply *ares)
1786 struct replmd_replicated_request *ar = talloc_get_type(req->context,
1787 struct replmd_replicated_request);
1791 return ldb_module_done(ar->req, NULL, NULL,
1792 LDB_ERR_OPERATIONS_ERROR);
1794 if (ares->error != LDB_SUCCESS &&
1795 ares->error != LDB_ERR_NO_SUCH_OBJECT) {
1796 return ldb_module_done(ar->req, ares->controls,
1797 ares->response, ares->error);
1800 switch (ares->type) {
1801 case LDB_REPLY_ENTRY:
1802 ar->search_msg = talloc_steal(ar, ares->message);
1805 case LDB_REPLY_REFERRAL:
1806 /* we ignore referrals */
1809 case LDB_REPLY_DONE:
1810 if (ar->search_msg == NULL) {
1811 ret = replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
1813 ret = replmd_replicated_uptodate_modify(ar);
1815 if (ret != LDB_SUCCESS) {
1816 return ldb_module_done(ar->req, NULL, NULL, ret);
1825 static int replmd_replicated_uptodate_vector(struct replmd_replicated_request *ar)
1827 struct ldb_context *ldb;
1829 static const char *attrs[] = {
1830 "replUpToDateVector",
1834 struct ldb_request *search_req;
1836 ldb = ldb_module_get_ctx(ar->module);
1837 ar->search_msg = NULL;
1839 ret = ldb_build_search_req(&search_req,
1842 ar->objs->partition_dn,
1848 replmd_replicated_uptodate_search_callback,
1850 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
1852 return ldb_next_request(ar->module, search_req);
1857 static int replmd_extended_replicated_objects(struct ldb_module *module, struct ldb_request *req)
1859 struct ldb_context *ldb;
1860 struct dsdb_extended_replicated_objects *objs;
1861 struct replmd_replicated_request *ar;
1862 struct ldb_control **ctrls;
1864 struct replmd_private *replmd_private =
1865 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
1867 ldb = ldb_module_get_ctx(module);
1869 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_extended_replicated_objects\n");
1871 objs = talloc_get_type(req->op.extended.data, struct dsdb_extended_replicated_objects);
1873 ldb_debug(ldb, LDB_DEBUG_FATAL, "replmd_extended_replicated_objects: invalid extended data\n");
1874 return LDB_ERR_PROTOCOL_ERROR;
1877 if (objs->version != DSDB_EXTENDED_REPLICATED_OBJECTS_VERSION) {
1878 ldb_debug(ldb, LDB_DEBUG_FATAL, "replmd_extended_replicated_objects: extended data invalid version [%u != %u]\n",
1879 objs->version, DSDB_EXTENDED_REPLICATED_OBJECTS_VERSION);
1880 return LDB_ERR_PROTOCOL_ERROR;
1883 ar = replmd_ctx_init(module, req);
1885 return LDB_ERR_OPERATIONS_ERROR;
1887 /* Set the flags to have the replmd_op_callback run over the full set of objects */
1888 ar->apply_mode = true;
1890 ar->schema = dsdb_get_schema(ldb);
1892 ldb_debug_set(ldb, LDB_DEBUG_FATAL, "replmd_ctx_init: no loaded schema found\n");
1894 DEBUG(0,(__location__ ": %s\n", ldb_errstring(ldb)));
1895 return LDB_ERR_CONSTRAINT_VIOLATION;
1898 ctrls = req->controls;
1900 if (req->controls) {
1901 req->controls = talloc_memdup(ar, req->controls,
1902 talloc_get_size(req->controls));
1903 if (!req->controls) return replmd_replicated_request_werror(ar, WERR_NOMEM);
1906 ret = ldb_request_add_control(req, DSDB_CONTROL_REPLICATED_UPDATE_OID, false, NULL);
1907 if (ret != LDB_SUCCESS) {
1911 ar->controls = req->controls;
1912 req->controls = ctrls;
1914 DEBUG(4,("linked_attributes_count=%u\n", objs->linked_attributes_count));
1916 /* save away the linked attributes for the end of the
1918 for (i=0; i<ar->objs->linked_attributes_count; i++) {
1919 struct la_entry *la_entry;
1921 if (replmd_private->la_ctx == NULL) {
1922 replmd_private->la_ctx = talloc_new(replmd_private);
1924 la_entry = talloc(replmd_private->la_ctx, struct la_entry);
1925 if (la_entry == NULL) {
1927 return LDB_ERR_OPERATIONS_ERROR;
1929 la_entry->la = talloc(la_entry, struct drsuapi_DsReplicaLinkedAttribute);
1930 if (la_entry->la == NULL) {
1931 talloc_free(la_entry);
1933 return LDB_ERR_OPERATIONS_ERROR;
1935 *la_entry->la = ar->objs->linked_attributes[i];
1937 /* we need to steal the non-scalars so they stay
1938 around until the end of the transaction */
1939 talloc_steal(la_entry->la, la_entry->la->identifier);
1940 talloc_steal(la_entry->la, la_entry->la->value.blob);
1942 DLIST_ADD(replmd_private->la_list, la_entry);
1945 return replmd_replicated_apply_next(ar);
1949 process one linked attribute structure
1951 static int replmd_process_linked_attribute(struct ldb_module *module,
1952 struct la_entry *la_entry)
1954 struct drsuapi_DsReplicaLinkedAttribute *la = la_entry->la;
1955 struct ldb_context *ldb = ldb_module_get_ctx(module);
1956 struct dsdb_schema *schema = dsdb_get_schema(ldb);
1957 struct drsuapi_DsReplicaObjectIdentifier3 target;
1958 struct ldb_message *msg;
1959 TALLOC_CTX *tmp_ctx = talloc_new(la_entry);
1960 struct ldb_request *mod_req;
1962 const struct dsdb_attribute *attr;
1963 struct ldb_dn *target_dn;
1964 struct dsdb_dn *dsdb_dn;
1965 uint64_t seq_num = 0;
1966 struct drsuapi_DsReplicaAttribute drs;
1967 struct drsuapi_DsAttributeValue val;
1968 struct ldb_message_element el;
1969 const struct ldb_val *guid;
1972 drs.value_ctr.num_values = 1;
1973 drs.value_ctr.values = &val;
1974 val.blob = la->value.blob;
1977 linked_attributes[0]:
1978 &objs->linked_attributes[i]: struct drsuapi_DsReplicaLinkedAttribute
1980 identifier: struct drsuapi_DsReplicaObjectIdentifier
1981 __ndr_size : 0x0000003a (58)
1982 __ndr_size_sid : 0x00000000 (0)
1983 guid : 8e95b6a9-13dd-4158-89db-3220a5be5cc7
1985 __ndr_size_dn : 0x00000000 (0)
1987 attid : DRSUAPI_ATTRIBUTE_member (0x1F)
1988 value: struct drsuapi_DsAttributeValue
1989 __ndr_size : 0x0000007e (126)
1991 blob : DATA_BLOB length=126
1992 flags : 0x00000001 (1)
1993 1: DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE
1994 originating_add_time : Wed Sep 2 22:20:01 2009 EST
1995 meta_data: struct drsuapi_DsReplicaMetaData
1996 version : 0x00000015 (21)
1997 originating_change_time : Wed Sep 2 23:39:07 2009 EST
1998 originating_invocation_id: 794640f3-18cf-40ee-a211-a93992b67a64
1999 originating_usn : 0x000000000001e19c (123292)
2001 (for cases where the link is to a normal DN)
2002 &target: struct drsuapi_DsReplicaObjectIdentifier3
2003 __ndr_size : 0x0000007e (126)
2004 __ndr_size_sid : 0x0000001c (28)
2005 guid : 7639e594-db75-4086-b0d4-67890ae46031
2006 sid : S-1-5-21-2848215498-2472035911-1947525656-19924
2007 __ndr_size_dn : 0x00000022 (34)
2008 dn : 'CN=UOne,OU=TestOU,DC=vsofs8,DC=com'
2011 /* find the attribute being modified */
2012 attr = dsdb_attribute_by_attributeID_id(schema, la->attid);
2014 DEBUG(0, (__location__ ": Unable to find attributeID 0x%x\n", la->attid));
2015 talloc_free(tmp_ctx);
2016 return LDB_ERR_OPERATIONS_ERROR;
2019 status = attr->syntax->drsuapi_to_ldb(ldb, schema, attr, &drs, tmp_ctx, &el);
2021 /* construct a modify request for this attribute change */
2022 msg = ldb_msg_new(tmp_ctx);
2025 talloc_free(tmp_ctx);
2026 return LDB_ERR_OPERATIONS_ERROR;
2029 ret = dsdb_find_dn_by_guid(ldb, tmp_ctx,
2030 GUID_string(tmp_ctx, &la->identifier->guid), &msg->dn);
2031 if (ret != LDB_SUCCESS) {
2032 talloc_free(tmp_ctx);
2036 el.name = attr->lDAPDisplayName;
2037 if (la->flags & DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE) {
2038 ret = ldb_msg_add(msg, &el, LDB_FLAG_MOD_ADD);
2040 ret = ldb_msg_add(msg, &el, LDB_FLAG_MOD_DELETE);
2042 if (ret != LDB_SUCCESS) {
2043 talloc_free(tmp_ctx);
2047 dsdb_dn = dsdb_dn_parse(tmp_ctx, ldb, &el.values[0], attr->syntax->ldap_oid);
2049 DEBUG(0,(__location__ ": Failed to parse just-generated DN\n"));
2050 talloc_free(tmp_ctx);
2051 return LDB_ERR_INVALID_DN_SYNTAX;
2054 guid = ldb_dn_get_extended_component(dsdb_dn->dn, "GUID");
2056 DEBUG(0,(__location__ ": Failed to parse GUID from just-generated DN\n"));
2057 talloc_free(tmp_ctx);
2058 return LDB_ERR_INVALID_DN_SYNTAX;
2061 ret = dsdb_find_dn_by_guid(ldb, tmp_ctx, ldb_binary_encode(tmp_ctx, *guid), &target_dn);
2062 if (ret != LDB_SUCCESS) {
2063 /* If this proves to be a problem in the future, then
2064 * just remove the return - perhaps we can just use
2065 * the details the replication peer supplied */
2067 DEBUG(0,(__location__ ": Failed to map GUID %s to DN\n", GUID_string(tmp_ctx, &target.guid)));
2068 talloc_free(tmp_ctx);
2069 return LDB_ERR_OPERATIONS_ERROR;
2072 /* Now update with full DN we just found in the DB (including extended components) */
2073 dsdb_dn->dn = target_dn;
2074 /* Now make a linearized version, using the original binary components (if any) */
2075 el.values[0] = data_blob_string_const(dsdb_dn_get_extended_linearized(tmp_ctx, dsdb_dn, 1));
2078 ret = replmd_update_rpmd(module, schema, msg, &seq_num);
2079 if (ret != LDB_SUCCESS) {
2080 talloc_free(tmp_ctx);
2084 /* we only change whenChanged and uSNChanged if the seq_num
2087 time_t t = time(NULL);
2089 if (add_time_element(msg, "whenChanged", t) != LDB_SUCCESS) {
2090 talloc_free(tmp_ctx);
2091 return LDB_ERR_OPERATIONS_ERROR;
2094 if (add_uint64_element(msg, "uSNChanged", seq_num) != LDB_SUCCESS) {
2095 talloc_free(tmp_ctx);
2096 return LDB_ERR_OPERATIONS_ERROR;
2100 ret = ldb_build_mod_req(&mod_req, ldb, tmp_ctx,
2104 ldb_op_default_callback,
2106 if (ret != LDB_SUCCESS) {
2107 talloc_free(tmp_ctx);
2110 talloc_steal(mod_req, msg);
2113 DEBUG(4,("Applying DRS linked attribute change:\n%s\n",
2114 ldb_ldif_message_string(ldb, tmp_ctx, LDB_CHANGETYPE_MODIFY, msg)));
2117 /* Run the new request */
2118 ret = ldb_next_request(module, mod_req);
2120 /* we need to wait for this to finish, as we are being called
2121 from the synchronous end_transaction hook of this module */
2122 if (ret == LDB_SUCCESS) {
2123 ret = ldb_wait(mod_req->handle, LDB_WAIT_ALL);
2126 if (ret == LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS) {
2127 /* the link destination exists, we need to update it
2128 * by deleting the old one for the same DN then adding
2130 msg->elements = talloc_realloc(msg, msg->elements,
2131 struct ldb_message_element,
2132 msg->num_elements+1);
2133 if (msg->elements == NULL) {
2135 talloc_free(tmp_ctx);
2136 return LDB_ERR_OPERATIONS_ERROR;
2138 /* this relies on the backend matching the old entry
2139 only by the DN portion of the extended DN */
2140 msg->elements[1] = msg->elements[0];
2141 msg->elements[0].flags = LDB_FLAG_MOD_DELETE;
2142 msg->num_elements++;
2144 ret = ldb_build_mod_req(&mod_req, ldb, tmp_ctx,
2148 ldb_op_default_callback,
2150 if (ret != LDB_SUCCESS) {
2151 talloc_free(tmp_ctx);
2155 /* Run the new request */
2156 ret = ldb_next_request(module, mod_req);
2158 if (ret == LDB_SUCCESS) {
2159 ret = ldb_wait(mod_req->handle, LDB_WAIT_ALL);
2163 if (ret != LDB_SUCCESS) {
2164 ldb_debug(ldb, LDB_DEBUG_WARNING, "Failed to apply linked attribute change '%s' %s\n",
2166 ldb_ldif_message_string(ldb, tmp_ctx, LDB_CHANGETYPE_MODIFY, msg));
2170 talloc_free(tmp_ctx);
2175 static int replmd_extended(struct ldb_module *module, struct ldb_request *req)
2177 if (strcmp(req->op.extended.oid, DSDB_EXTENDED_REPLICATED_OBJECTS_OID) == 0) {
2178 return replmd_extended_replicated_objects(module, req);
2181 return ldb_next_request(module, req);
2186 we hook into the transaction operations to allow us to
2187 perform the linked attribute updates at the end of the whole
2188 transaction. This allows a forward linked attribute to be created
2189 before the object is created. During a vampire, w2k8 sends us linked
2190 attributes before the objects they are part of.
2192 static int replmd_start_transaction(struct ldb_module *module)
2194 /* create our private structure for this transaction */
2195 struct replmd_private *replmd_private = talloc_get_type(ldb_module_get_private(module),
2196 struct replmd_private);
2197 talloc_free(replmd_private->la_ctx);
2198 replmd_private->la_list = NULL;
2199 replmd_private->la_ctx = NULL;
2201 /* free any leftover mod_usn records from cancelled
2203 while (replmd_private->ncs) {
2204 struct nc_entry *e = replmd_private->ncs;
2205 DLIST_REMOVE(replmd_private->ncs, e);
2209 return ldb_next_start_trans(module);
2213 on prepare commit we loop over our queued la_context structures and
2216 static int replmd_prepare_commit(struct ldb_module *module)
2218 struct replmd_private *replmd_private =
2219 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
2220 struct la_entry *la, *prev;
2223 /* walk the list backwards, to do the first entry first, as we
2224 * added the entries with DLIST_ADD() which puts them at the
2225 * start of the list */
2226 for (la = replmd_private->la_list; la && la->next; la=la->next) ;
2228 for (; la; la=prev) {
2230 DLIST_REMOVE(replmd_private->la_list, la);
2231 ret = replmd_process_linked_attribute(module, la);
2232 if (ret != LDB_SUCCESS) {
2233 talloc_free(replmd_private->la_ctx);
2234 replmd_private->la_list = NULL;
2235 replmd_private->la_ctx = NULL;
2240 talloc_free(replmd_private->la_ctx);
2241 replmd_private->la_list = NULL;
2242 replmd_private->la_ctx = NULL;
2244 /* possibly change @REPLCHANGED */
2245 ret = replmd_notify_store(module);
2246 if (ret != LDB_SUCCESS) {
2250 return ldb_next_prepare_commit(module);
2253 static int replmd_del_transaction(struct ldb_module *module)
2255 struct replmd_private *replmd_private =
2256 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
2257 talloc_free(replmd_private->la_ctx);
2258 replmd_private->la_list = NULL;
2259 replmd_private->la_ctx = NULL;
2260 return ldb_next_del_trans(module);
2264 _PUBLIC_ const struct ldb_module_ops ldb_repl_meta_data_module_ops = {
2265 .name = "repl_meta_data",
2266 .init_context = replmd_init,
2268 .modify = replmd_modify,
2269 .rename = replmd_rename,
2270 .extended = replmd_extended,
2271 .start_transaction = replmd_start_transaction,
2272 .prepare_commit = replmd_prepare_commit,
2273 .del_transaction = replmd_del_transaction,