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 struct ldb_control **controls;
128 partition_ctrl = ldb_reply_get_control(ares, DSDB_CONTROL_CURRENT_PARTITION_OID);
130 /* Remove the 'partition' control from what we pass up the chain */
131 controls = controls_except_specified(ares->controls, ares, partition_ctrl);
133 if (ares->error != LDB_SUCCESS) {
134 return ldb_module_done(ac->req, controls,
135 ares->response, ares->error);
138 if (ares->type != LDB_REPLY_DONE) {
139 ldb_set_errstring(ldb_module_get_ctx(ac->module), "Invalid reply type for notify\n!");
140 return ldb_module_done(ac->req, NULL,
141 NULL, LDB_ERR_OPERATIONS_ERROR);
144 if (!partition_ctrl) {
145 return ldb_module_done(ac->req, NULL,
146 NULL, LDB_ERR_OPERATIONS_ERROR);
149 partition = talloc_get_type_abort(partition_ctrl->data,
150 struct dsdb_control_current_partition);
152 if (ac->seq_num > 0) {
153 for (modified_partition = replmd_private->ncs; modified_partition;
154 modified_partition = modified_partition->next) {
155 if (ldb_dn_compare(modified_partition->dn, partition->dn) == 0) {
160 if (modified_partition == NULL) {
161 modified_partition = talloc_zero(replmd_private, struct nc_entry);
162 if (!modified_partition) {
163 ldb_oom(ldb_module_get_ctx(ac->module));
164 return ldb_module_done(ac->req, NULL,
165 NULL, LDB_ERR_OPERATIONS_ERROR);
167 modified_partition->dn = ldb_dn_copy(modified_partition, partition->dn);
168 if (!modified_partition->dn) {
169 ldb_oom(ldb_module_get_ctx(ac->module));
170 return ldb_module_done(ac->req, NULL,
171 NULL, LDB_ERR_OPERATIONS_ERROR);
173 DLIST_ADD(replmd_private->ncs, modified_partition);
176 if (ac->seq_num > modified_partition->mod_usn) {
177 modified_partition->mod_usn = ac->seq_num;
181 if (ac->apply_mode) {
185 ret = replmd_replicated_apply_next(ac);
186 if (ret != LDB_SUCCESS) {
187 return ldb_module_done(ac->req, NULL, NULL, ret);
191 /* free the partition control container here, for the
192 * common path. Other cases will have it cleaned up
193 * eventually with the ares */
194 talloc_free(partition_ctrl);
195 return ldb_module_done(ac->req,
196 controls_except_specified(controls, ares, partition_ctrl),
197 ares->response, LDB_SUCCESS);
203 * update a @REPLCHANGED record in each partition if there have been
204 * any writes of replicated data in the partition
206 static int replmd_notify_store(struct ldb_module *module)
208 struct replmd_private *replmd_private =
209 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
210 struct ldb_context *ldb = ldb_module_get_ctx(module);
211 struct nc_entry *modified_partition;
213 for (modified_partition = replmd_private->ncs; modified_partition;
214 modified_partition = modified_partition->next) {
217 ret = dsdb_save_partition_usn(ldb, modified_partition->dn, modified_partition->mod_usn);
218 if (ret != LDB_SUCCESS) {
219 DEBUG(0,(__location__ ": Failed to save partition uSN for %s\n",
220 ldb_dn_get_linearized(modified_partition->dn)));
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 ldb_val guid_value;
415 struct replPropertyMetaDataBlob nmd;
416 struct ldb_val nmd_value;
417 const struct GUID *our_invocation_id;
418 time_t t = time(NULL);
423 bool allow_add_guid = false;
424 bool remove_current_guid = false;
426 /* check if there's a show relax control (used by provision to say 'I know what I'm doing') */
427 control = ldb_request_get_control(req, LDB_CONTROL_RELAX_OID);
432 /* do not manipulate our control entries */
433 if (ldb_dn_is_special(req->op.add.message->dn)) {
434 return ldb_next_request(module, req);
437 ldb = ldb_module_get_ctx(module);
439 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_add\n");
441 ac = replmd_ctx_init(module, req);
443 return LDB_ERR_OPERATIONS_ERROR;
446 guid_blob = ldb_msg_find_ldb_val(req->op.add.message, "objectGUID");
447 if ( guid_blob != NULL ) {
448 if( !allow_add_guid ) {
449 ldb_debug_set(ldb, LDB_DEBUG_ERROR,
450 "replmd_add: it's not allowed to add an object with objectGUID\n");
452 return LDB_ERR_UNWILLING_TO_PERFORM;
454 NTSTATUS status = GUID_from_data_blob(guid_blob,&guid);
455 if ( !NT_STATUS_IS_OK(status)) {
456 ldb_debug_set(ldb, LDB_DEBUG_ERROR,
457 "replmd_add: Unable to parse as a GUID the attribute objectGUID\n");
459 return LDB_ERR_UNWILLING_TO_PERFORM;
461 /* we remove this attribute as it can be a string and will not be treated
462 correctly and then we will readd it latter on in the good format*/
463 remove_current_guid = true;
467 guid = GUID_random();
470 /* Get a sequence number from the backend */
471 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &ac->seq_num);
472 if (ret != LDB_SUCCESS) {
477 /* get our invocationId */
478 our_invocation_id = samdb_ntds_invocation_id(ldb);
479 if (!our_invocation_id) {
480 ldb_debug_set(ldb, LDB_DEBUG_ERROR,
481 "replmd_add: unable to find invocationId\n");
483 return LDB_ERR_OPERATIONS_ERROR;
486 /* we have to copy the message as the caller might have it as a const */
487 msg = ldb_msg_copy_shallow(ac, req->op.add.message);
491 return LDB_ERR_OPERATIONS_ERROR;
494 /* generated times */
495 unix_to_nt_time(&now, t);
496 time_str = ldb_timestring(msg, t);
500 return LDB_ERR_OPERATIONS_ERROR;
502 if (remove_current_guid) {
503 ldb_msg_remove_attr(msg,"objectGUID");
507 * remove autogenerated attributes
509 ldb_msg_remove_attr(msg, "whenCreated");
510 ldb_msg_remove_attr(msg, "whenChanged");
511 ldb_msg_remove_attr(msg, "uSNCreated");
512 ldb_msg_remove_attr(msg, "uSNChanged");
513 ldb_msg_remove_attr(msg, "replPropertyMetaData");
516 * readd replicated attributes
518 ret = ldb_msg_add_string(msg, "whenCreated", time_str);
519 if (ret != LDB_SUCCESS) {
525 /* build the replication meta_data */
528 nmd.ctr.ctr1.count = msg->num_elements;
529 nmd.ctr.ctr1.array = talloc_array(msg,
530 struct replPropertyMetaData1,
532 if (!nmd.ctr.ctr1.array) {
535 return LDB_ERR_OPERATIONS_ERROR;
538 for (i=0; i < msg->num_elements; i++) {
539 struct ldb_message_element *e = &msg->elements[i];
540 struct replPropertyMetaData1 *m = &nmd.ctr.ctr1.array[ni];
541 const struct dsdb_attribute *sa;
543 if (e->name[0] == '@') continue;
545 sa = dsdb_attribute_by_lDAPDisplayName(ac->schema, e->name);
547 ldb_debug_set(ldb, LDB_DEBUG_ERROR,
548 "replmd_add: attribute '%s' not defined in schema\n",
551 return LDB_ERR_NO_SUCH_ATTRIBUTE;
554 if ((sa->systemFlags & DS_FLAG_ATTR_NOT_REPLICATED) || (sa->systemFlags & DS_FLAG_ATTR_IS_CONSTRUCTED)) {
555 /* if the attribute is not replicated (0x00000001)
556 * or constructed (0x00000004) it has no metadata
561 m->attid = sa->attributeID_id;
563 m->originating_change_time = now;
564 m->originating_invocation_id = *our_invocation_id;
565 m->originating_usn = ac->seq_num;
566 m->local_usn = ac->seq_num;
570 /* fix meta data count */
571 nmd.ctr.ctr1.count = ni;
574 * sort meta data array, and move the rdn attribute entry to the end
576 ret = replmd_replPropertyMetaDataCtr1_sort(&nmd.ctr.ctr1, ac->schema, msg->dn);
577 if (ret != LDB_SUCCESS) {
582 /* generated NDR encoded values */
583 ndr_err = ndr_push_struct_blob(&guid_value, msg,
586 (ndr_push_flags_fn_t)ndr_push_GUID);
587 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
590 return LDB_ERR_OPERATIONS_ERROR;
592 ndr_err = ndr_push_struct_blob(&nmd_value, msg,
593 lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")),
595 (ndr_push_flags_fn_t)ndr_push_replPropertyMetaDataBlob);
596 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
599 return LDB_ERR_OPERATIONS_ERROR;
603 * add the autogenerated values
605 ret = ldb_msg_add_value(msg, "objectGUID", &guid_value, NULL);
606 if (ret != LDB_SUCCESS) {
611 ret = ldb_msg_add_string(msg, "whenChanged", time_str);
612 if (ret != LDB_SUCCESS) {
617 ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNCreated", ac->seq_num);
618 if (ret != LDB_SUCCESS) {
623 ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNChanged", ac->seq_num);
624 if (ret != LDB_SUCCESS) {
629 ret = ldb_msg_add_value(msg, "replPropertyMetaData", &nmd_value, NULL);
630 if (ret != LDB_SUCCESS) {
637 * sort the attributes by attid before storing the object
639 replmd_ldb_message_sort(msg, ac->schema);
641 ret = ldb_build_add_req(&down_req, ldb, ac,
644 ac, replmd_op_callback,
646 if (ret != LDB_SUCCESS) {
651 /* if a control is there remove if from the modified request */
652 if (control && !save_controls(control, down_req, &saved_controls)) {
654 return LDB_ERR_OPERATIONS_ERROR;
657 /* go on with the call chain */
658 return ldb_next_request(module, down_req);
663 * update the replPropertyMetaData for one element
665 static int replmd_update_rpmd_element(struct ldb_context *ldb,
666 struct ldb_message *msg,
667 struct ldb_message_element *el,
668 struct replPropertyMetaDataBlob *omd,
669 const struct dsdb_schema *schema,
671 const struct GUID *our_invocation_id,
675 const struct dsdb_attribute *a;
676 struct replPropertyMetaData1 *md1;
678 a = dsdb_attribute_by_lDAPDisplayName(schema, el->name);
680 DEBUG(0,(__location__ ": Unable to find attribute %s in schema\n",
682 return LDB_ERR_OPERATIONS_ERROR;
685 if ((a->systemFlags & DS_FLAG_ATTR_NOT_REPLICATED) || (a->systemFlags & DS_FLAG_ATTR_IS_CONSTRUCTED)) {
689 for (i=0; i<omd->ctr.ctr1.count; i++) {
690 if (a->attributeID_id == omd->ctr.ctr1.array[i].attid) break;
692 if (i == omd->ctr.ctr1.count) {
693 /* we need to add a new one */
694 omd->ctr.ctr1.array = talloc_realloc(msg, omd->ctr.ctr1.array,
695 struct replPropertyMetaData1, omd->ctr.ctr1.count+1);
696 if (omd->ctr.ctr1.array == NULL) {
698 return LDB_ERR_OPERATIONS_ERROR;
700 omd->ctr.ctr1.count++;
701 ZERO_STRUCT(omd->ctr.ctr1.array[i]);
704 /* Get a new sequence number from the backend. We only do this
705 * if we have a change that requires a new
706 * replPropertyMetaData element
709 int ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, seq_num);
710 if (ret != LDB_SUCCESS) {
711 return LDB_ERR_OPERATIONS_ERROR;
715 md1 = &omd->ctr.ctr1.array[i];
717 md1->attid = a->attributeID_id;
718 md1->originating_change_time = now;
719 md1->originating_invocation_id = *our_invocation_id;
720 md1->originating_usn = *seq_num;
721 md1->local_usn = *seq_num;
727 * update the replPropertyMetaData object each time we modify an
728 * object. This is needed for DRS replication, as the merge on the
729 * client is based on this object
731 static int replmd_update_rpmd(struct ldb_module *module,
732 const struct dsdb_schema *schema,
733 struct ldb_message *msg, uint64_t *seq_num)
735 const struct ldb_val *omd_value;
736 enum ndr_err_code ndr_err;
737 struct replPropertyMetaDataBlob omd;
739 time_t t = time(NULL);
741 const struct GUID *our_invocation_id;
743 const char *attrs[] = { "replPropertyMetaData" , NULL };
744 struct ldb_result *res;
745 struct ldb_context *ldb;
747 ldb = ldb_module_get_ctx(module);
749 our_invocation_id = samdb_ntds_invocation_id(ldb);
750 if (!our_invocation_id) {
751 /* this happens during an initial vampire while
752 updating the schema */
753 DEBUG(5,("No invocationID - skipping replPropertyMetaData update\n"));
757 unix_to_nt_time(&now, t);
759 /* search for the existing replPropertyMetaDataBlob */
760 ret = dsdb_search_dn_with_deleted(ldb, msg, &res, msg->dn, attrs);
761 if (ret != LDB_SUCCESS || res->count != 1) {
762 DEBUG(0,(__location__ ": Object %s failed to find replPropertyMetaData\n",
763 ldb_dn_get_linearized(msg->dn)));
764 return LDB_ERR_OPERATIONS_ERROR;
768 omd_value = ldb_msg_find_ldb_val(res->msgs[0], "replPropertyMetaData");
770 DEBUG(0,(__location__ ": Object %s does not have a replPropertyMetaData attribute\n",
771 ldb_dn_get_linearized(msg->dn)));
772 return LDB_ERR_OPERATIONS_ERROR;
775 ndr_err = ndr_pull_struct_blob(omd_value, msg,
776 lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")), &omd,
777 (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
778 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
779 DEBUG(0,(__location__ ": Failed to parse replPropertyMetaData for %s\n",
780 ldb_dn_get_linearized(msg->dn)));
781 return LDB_ERR_OPERATIONS_ERROR;
784 if (omd.version != 1) {
785 DEBUG(0,(__location__ ": bad version %u in replPropertyMetaData for %s\n",
786 omd.version, ldb_dn_get_linearized(msg->dn)));
787 return LDB_ERR_OPERATIONS_ERROR;
790 for (i=0; i<msg->num_elements; i++) {
791 ret = replmd_update_rpmd_element(ldb, msg, &msg->elements[i], &omd, schema, seq_num,
792 our_invocation_id, now);
793 if (ret != LDB_SUCCESS) {
799 * replmd_update_rpmd_element has done an update if the
803 struct ldb_val *md_value;
804 struct ldb_message_element *el;
806 md_value = talloc(msg, struct ldb_val);
807 if (md_value == NULL) {
809 return LDB_ERR_OPERATIONS_ERROR;
812 ret = replmd_replPropertyMetaDataCtr1_sort(&omd.ctr.ctr1, schema, msg->dn);
813 if (ret != LDB_SUCCESS) {
817 ndr_err = ndr_push_struct_blob(md_value, msg,
818 lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")),
820 (ndr_push_flags_fn_t)ndr_push_replPropertyMetaDataBlob);
821 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
822 DEBUG(0,(__location__ ": Failed to marshall replPropertyMetaData for %s\n",
823 ldb_dn_get_linearized(msg->dn)));
824 return LDB_ERR_OPERATIONS_ERROR;
827 ret = ldb_msg_add_empty(msg, "replPropertyMetaData", LDB_FLAG_MOD_REPLACE, &el);
828 if (ret != LDB_SUCCESS) {
829 DEBUG(0,(__location__ ": Failed to add updated replPropertyMetaData %s\n",
830 ldb_dn_get_linearized(msg->dn)));
835 el->values = md_value;
842 static int replmd_modify(struct ldb_module *module, struct ldb_request *req)
844 struct ldb_context *ldb;
845 struct replmd_replicated_request *ac;
846 struct ldb_request *down_req;
847 struct ldb_message *msg;
848 struct ldb_result *res;
849 time_t t = time(NULL);
850 uint64_t seq_num = 0;
853 /* do not manipulate our control entries */
854 if (ldb_dn_is_special(req->op.mod.message->dn)) {
855 return ldb_next_request(module, req);
858 ldb = ldb_module_get_ctx(module);
860 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_modify\n");
862 ac = replmd_ctx_init(module, req);
864 return LDB_ERR_OPERATIONS_ERROR;
867 /* we have to copy the message as the caller might have it as a const */
868 msg = ldb_msg_copy_shallow(ac, req->op.mod.message);
872 return LDB_ERR_OPERATIONS_ERROR;
876 * - give an error when a readonly attribute should
878 * - merge the changed into the old object
879 * if the caller set values to the same value
880 * ignore the attribute, return success when no
881 * attribute was changed
884 ret = dsdb_search_dn_with_deleted(ldb, msg, &res, msg->dn, NULL);
885 if (ret != LDB_SUCCESS) {
890 ret = replmd_update_rpmd(module, ac->schema, msg, &ac->seq_num);
891 if (ret != LDB_SUCCESS) {
897 * - replace the old object with the newly constructed one
900 ret = ldb_build_mod_req(&down_req, ldb, ac,
903 ac, replmd_op_callback,
905 if (ret != LDB_SUCCESS) {
909 talloc_steal(down_req, msg);
911 /* we only change whenChanged and uSNChanged if the seq_num
914 if (add_time_element(msg, "whenChanged", t) != LDB_SUCCESS) {
919 if (add_uint64_element(msg, "uSNChanged", seq_num) != LDB_SUCCESS) {
925 /* go on with the call chain */
926 return ldb_next_request(module, down_req);
929 static int replmd_rename_callback(struct ldb_request *req, struct ldb_reply *ares);
932 handle a rename request
934 On a rename we need to do an extra ldb_modify which sets the
935 whenChanged and uSNChanged attributes. We do this in a callback after the success.
937 static int replmd_rename(struct ldb_module *module, struct ldb_request *req)
939 struct ldb_context *ldb;
940 struct replmd_replicated_request *ac;
942 struct ldb_request *down_req;
944 /* do not manipulate our control entries */
945 if (ldb_dn_is_special(req->op.mod.message->dn)) {
946 return ldb_next_request(module, req);
949 ldb = ldb_module_get_ctx(module);
951 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_rename\n");
953 ac = replmd_ctx_init(module, req);
955 return LDB_ERR_OPERATIONS_ERROR;
957 ret = ldb_build_rename_req(&down_req, ldb, ac,
958 ac->req->op.rename.olddn,
959 ac->req->op.rename.newdn,
961 ac, replmd_rename_callback,
964 if (ret != LDB_SUCCESS) {
969 /* go on with the call chain */
970 return ldb_next_request(module, down_req);
973 /* After the rename is compleated, update the whenchanged etc */
974 static int replmd_rename_callback(struct ldb_request *req, struct ldb_reply *ares)
976 struct ldb_context *ldb;
977 struct replmd_replicated_request *ac;
978 struct ldb_request *down_req;
979 struct ldb_message *msg;
980 time_t t = time(NULL);
983 ac = talloc_get_type(req->context, struct replmd_replicated_request);
984 ldb = ldb_module_get_ctx(ac->module);
986 if (ares->error != LDB_SUCCESS) {
987 return ldb_module_done(ac->req, ares->controls,
988 ares->response, ares->error);
991 if (ares->type != LDB_REPLY_DONE) {
992 ldb_set_errstring(ldb,
993 "invalid ldb_reply_type in callback");
995 return ldb_module_done(ac->req, NULL, NULL,
996 LDB_ERR_OPERATIONS_ERROR);
999 /* Get a sequence number from the backend */
1000 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &ac->seq_num);
1001 if (ret != LDB_SUCCESS) {
1006 * - replace the old object with the newly constructed one
1009 msg = ldb_msg_new(ac);
1012 return LDB_ERR_OPERATIONS_ERROR;
1015 msg->dn = ac->req->op.rename.newdn;
1017 ret = ldb_build_mod_req(&down_req, ldb, ac,
1020 ac, replmd_op_callback,
1023 if (ret != LDB_SUCCESS) {
1027 talloc_steal(down_req, msg);
1029 if (add_time_element(msg, "whenChanged", t) != LDB_SUCCESS) {
1034 if (add_uint64_element(msg, "uSNChanged", ac->seq_num) != LDB_SUCCESS) {
1039 /* go on with the call chain - do the modify after the rename */
1040 return ldb_next_request(ac->module, down_req);
1044 static int replmd_replicated_request_error(struct replmd_replicated_request *ar, int ret)
1049 static int replmd_replicated_request_werror(struct replmd_replicated_request *ar, WERROR status)
1051 int ret = LDB_ERR_OTHER;
1052 /* TODO: do some error mapping */
1056 static int replmd_replicated_apply_add(struct replmd_replicated_request *ar)
1058 struct ldb_context *ldb;
1059 struct ldb_request *change_req;
1060 enum ndr_err_code ndr_err;
1061 struct ldb_message *msg;
1062 struct replPropertyMetaDataBlob *md;
1063 struct ldb_val md_value;
1068 * TODO: check if the parent object exist
1072 * TODO: handle the conflict case where an object with the
1076 ldb = ldb_module_get_ctx(ar->module);
1077 msg = ar->objs->objects[ar->index_current].msg;
1078 md = ar->objs->objects[ar->index_current].meta_data;
1080 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &ar->seq_num);
1081 if (ret != LDB_SUCCESS) {
1082 return replmd_replicated_request_error(ar, ret);
1085 ret = ldb_msg_add_value(msg, "objectGUID", &ar->objs->objects[ar->index_current].guid_value, NULL);
1086 if (ret != LDB_SUCCESS) {
1087 return replmd_replicated_request_error(ar, ret);
1090 ret = ldb_msg_add_string(msg, "whenChanged", ar->objs->objects[ar->index_current].when_changed);
1091 if (ret != LDB_SUCCESS) {
1092 return replmd_replicated_request_error(ar, ret);
1095 ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNCreated", ar->seq_num);
1096 if (ret != LDB_SUCCESS) {
1097 return replmd_replicated_request_error(ar, ret);
1100 ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNChanged", ar->seq_num);
1101 if (ret != LDB_SUCCESS) {
1102 return replmd_replicated_request_error(ar, ret);
1105 /* remove any message elements that have zero values */
1106 for (i=0; i<msg->num_elements; i++) {
1107 if (msg->elements[i].num_values == 0) {
1108 DEBUG(4,(__location__ ": Removing attribute %s with num_values==0\n",
1109 msg->elements[i].name));
1110 memmove(&msg->elements[i],
1111 &msg->elements[i+1],
1112 sizeof(msg->elements[i])*(msg->num_elements - (i+1)));
1113 msg->num_elements--;
1119 * the meta data array is already sorted by the caller
1121 for (i=0; i < md->ctr.ctr1.count; i++) {
1122 md->ctr.ctr1.array[i].local_usn = ar->seq_num;
1124 ndr_err = ndr_push_struct_blob(&md_value, msg,
1125 lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")),
1127 (ndr_push_flags_fn_t)ndr_push_replPropertyMetaDataBlob);
1128 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1129 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
1130 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
1132 ret = ldb_msg_add_value(msg, "replPropertyMetaData", &md_value, NULL);
1133 if (ret != LDB_SUCCESS) {
1134 return replmd_replicated_request_error(ar, ret);
1137 replmd_ldb_message_sort(msg, ar->schema);
1140 char *s = ldb_ldif_message_string(ldb, ar, LDB_CHANGETYPE_ADD, msg);
1141 DEBUG(4, ("DRS replication add message:\n%s\n", s));
1145 ret = ldb_build_add_req(&change_req,
1153 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
1155 return ldb_next_request(ar->module, change_req);
1158 static int replmd_replPropertyMetaData1_conflict_compare(struct replPropertyMetaData1 *m1,
1159 struct replPropertyMetaData1 *m2)
1163 if (m1->version != m2->version) {
1164 return m1->version - m2->version;
1167 if (m1->originating_change_time != m2->originating_change_time) {
1168 return m1->originating_change_time - m2->originating_change_time;
1171 ret = GUID_compare(&m1->originating_invocation_id, &m2->originating_invocation_id);
1176 return m1->originating_usn - m2->originating_usn;
1179 static int replmd_replicated_apply_merge(struct replmd_replicated_request *ar)
1181 struct ldb_context *ldb;
1182 struct ldb_request *change_req;
1183 enum ndr_err_code ndr_err;
1184 struct ldb_message *msg;
1185 struct replPropertyMetaDataBlob *rmd;
1186 struct replPropertyMetaDataBlob omd;
1187 const struct ldb_val *omd_value;
1188 struct replPropertyMetaDataBlob nmd;
1189 struct ldb_val nmd_value;
1191 uint32_t removed_attrs = 0;
1194 ldb = ldb_module_get_ctx(ar->module);
1195 msg = ar->objs->objects[ar->index_current].msg;
1196 rmd = ar->objs->objects[ar->index_current].meta_data;
1201 * TODO: check repl data is correct after a rename
1203 if (ldb_dn_compare(msg->dn, ar->search_msg->dn) != 0) {
1204 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_replicated_request rename %s => %s\n",
1205 ldb_dn_get_linearized(ar->search_msg->dn),
1206 ldb_dn_get_linearized(msg->dn));
1207 if (ldb_rename(ldb, ar->search_msg->dn, msg->dn) != LDB_SUCCESS) {
1208 ldb_debug(ldb, LDB_DEBUG_FATAL, "replmd_replicated_request rename %s => %s failed - %s\n",
1209 ldb_dn_get_linearized(ar->search_msg->dn),
1210 ldb_dn_get_linearized(msg->dn),
1211 ldb_errstring(ldb));
1212 return replmd_replicated_request_werror(ar, WERR_DS_DRA_DB_ERROR);
1216 /* find existing meta data */
1217 omd_value = ldb_msg_find_ldb_val(ar->search_msg, "replPropertyMetaData");
1219 ndr_err = ndr_pull_struct_blob(omd_value, ar,
1220 lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")), &omd,
1221 (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
1222 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1223 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
1224 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
1227 if (omd.version != 1) {
1228 return replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
1234 nmd.ctr.ctr1.count = omd.ctr.ctr1.count + rmd->ctr.ctr1.count;
1235 nmd.ctr.ctr1.array = talloc_array(ar,
1236 struct replPropertyMetaData1,
1237 nmd.ctr.ctr1.count);
1238 if (!nmd.ctr.ctr1.array) return replmd_replicated_request_werror(ar, WERR_NOMEM);
1240 /* first copy the old meta data */
1241 for (i=0; i < omd.ctr.ctr1.count; i++) {
1242 nmd.ctr.ctr1.array[ni] = omd.ctr.ctr1.array[i];
1246 /* now merge in the new meta data */
1247 for (i=0; i < rmd->ctr.ctr1.count; i++) {
1250 for (j=0; j < ni; j++) {
1253 if (rmd->ctr.ctr1.array[i].attid != nmd.ctr.ctr1.array[j].attid) {
1257 cmp = replmd_replPropertyMetaData1_conflict_compare(&rmd->ctr.ctr1.array[i],
1258 &nmd.ctr.ctr1.array[j]);
1260 /* replace the entry */
1261 nmd.ctr.ctr1.array[j] = rmd->ctr.ctr1.array[i];
1266 /* we don't want to apply this change so remove the attribute */
1267 ldb_msg_remove_element(msg, &msg->elements[i-removed_attrs]);
1274 if (found) continue;
1276 nmd.ctr.ctr1.array[ni] = rmd->ctr.ctr1.array[i];
1281 * finally correct the size of the meta_data array
1283 nmd.ctr.ctr1.count = ni;
1286 * the rdn attribute (the alias for the name attribute),
1287 * 'cn' for most objects is the last entry in the meta data array
1290 * sort the new meta data array
1292 ret = replmd_replPropertyMetaDataCtr1_sort(&nmd.ctr.ctr1, ar->schema, msg->dn);
1293 if (ret != LDB_SUCCESS) {
1298 * check if some replicated attributes left, otherwise skip the ldb_modify() call
1300 if (msg->num_elements == 0) {
1301 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_replicated_apply_merge[%u]: skip replace\n",
1304 ar->index_current++;
1305 return replmd_replicated_apply_next(ar);
1308 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_replicated_apply_merge[%u]: replace %u attributes\n",
1309 ar->index_current, msg->num_elements);
1311 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &ar->seq_num);
1312 if (ret != LDB_SUCCESS) {
1313 return replmd_replicated_request_error(ar, ret);
1316 for (i=0; i<ni; i++) {
1317 nmd.ctr.ctr1.array[i].local_usn = ar->seq_num;
1320 /* create the meta data value */
1321 ndr_err = ndr_push_struct_blob(&nmd_value, msg,
1322 lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")),
1324 (ndr_push_flags_fn_t)ndr_push_replPropertyMetaDataBlob);
1325 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1326 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
1327 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
1331 * when we know that we'll modify the record, add the whenChanged, uSNChanged
1332 * and replPopertyMetaData attributes
1334 ret = ldb_msg_add_string(msg, "whenChanged", ar->objs->objects[ar->index_current].when_changed);
1335 if (ret != LDB_SUCCESS) {
1336 return replmd_replicated_request_error(ar, ret);
1338 ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNChanged", ar->seq_num);
1339 if (ret != LDB_SUCCESS) {
1340 return replmd_replicated_request_error(ar, ret);
1342 ret = ldb_msg_add_value(msg, "replPropertyMetaData", &nmd_value, NULL);
1343 if (ret != LDB_SUCCESS) {
1344 return replmd_replicated_request_error(ar, ret);
1347 replmd_ldb_message_sort(msg, ar->schema);
1349 /* we want to replace the old values */
1350 for (i=0; i < msg->num_elements; i++) {
1351 msg->elements[i].flags = LDB_FLAG_MOD_REPLACE;
1355 char *s = ldb_ldif_message_string(ldb, ar, LDB_CHANGETYPE_MODIFY, msg);
1356 DEBUG(4, ("DRS replication modify message:\n%s\n", s));
1360 ret = ldb_build_mod_req(&change_req,
1368 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
1370 return ldb_next_request(ar->module, change_req);
1373 static int replmd_replicated_apply_search_callback(struct ldb_request *req,
1374 struct ldb_reply *ares)
1376 struct replmd_replicated_request *ar = talloc_get_type(req->context,
1377 struct replmd_replicated_request);
1381 return ldb_module_done(ar->req, NULL, NULL,
1382 LDB_ERR_OPERATIONS_ERROR);
1384 if (ares->error != LDB_SUCCESS &&
1385 ares->error != LDB_ERR_NO_SUCH_OBJECT) {
1386 return ldb_module_done(ar->req, ares->controls,
1387 ares->response, ares->error);
1390 switch (ares->type) {
1391 case LDB_REPLY_ENTRY:
1392 ar->search_msg = talloc_steal(ar, ares->message);
1395 case LDB_REPLY_REFERRAL:
1396 /* we ignore referrals */
1399 case LDB_REPLY_DONE:
1400 if (ar->search_msg != NULL) {
1401 ret = replmd_replicated_apply_merge(ar);
1403 ret = replmd_replicated_apply_add(ar);
1405 if (ret != LDB_SUCCESS) {
1406 return ldb_module_done(ar->req, NULL, NULL, ret);
1414 static int replmd_replicated_uptodate_vector(struct replmd_replicated_request *ar);
1416 static int replmd_replicated_apply_next(struct replmd_replicated_request *ar)
1418 struct ldb_context *ldb;
1422 struct ldb_request *search_req;
1423 struct ldb_search_options_control *options;
1425 if (ar->index_current >= ar->objs->num_objects) {
1426 /* done with it, go to next stage */
1427 return replmd_replicated_uptodate_vector(ar);
1430 ldb = ldb_module_get_ctx(ar->module);
1431 ar->search_msg = NULL;
1433 tmp_str = ldb_binary_encode(ar, ar->objs->objects[ar->index_current].guid_value);
1434 if (!tmp_str) return replmd_replicated_request_werror(ar, WERR_NOMEM);
1436 filter = talloc_asprintf(ar, "(objectGUID=%s)", tmp_str);
1437 if (!filter) return replmd_replicated_request_werror(ar, WERR_NOMEM);
1438 talloc_free(tmp_str);
1440 ret = ldb_build_search_req(&search_req,
1449 replmd_replicated_apply_search_callback,
1452 ret = ldb_request_add_control(search_req, LDB_CONTROL_SHOW_DELETED_OID, true, NULL);
1453 if (ret != LDB_SUCCESS) {
1457 /* we need to cope with cross-partition links, so search for
1458 the GUID over all partitions */
1459 options = talloc(search_req, struct ldb_search_options_control);
1460 if (options == NULL) {
1461 DEBUG(0, (__location__ ": out of memory\n"));
1462 return LDB_ERR_OPERATIONS_ERROR;
1464 options->search_options = LDB_SEARCH_OPTION_PHANTOM_ROOT;
1466 ret = ldb_request_add_control(search_req,
1467 LDB_CONTROL_SEARCH_OPTIONS_OID,
1469 if (ret != LDB_SUCCESS) {
1473 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
1475 return ldb_next_request(ar->module, search_req);
1478 static int replmd_replicated_uptodate_modify_callback(struct ldb_request *req,
1479 struct ldb_reply *ares)
1481 struct ldb_context *ldb;
1482 struct replmd_replicated_request *ar = talloc_get_type(req->context,
1483 struct replmd_replicated_request);
1484 ldb = ldb_module_get_ctx(ar->module);
1487 return ldb_module_done(ar->req, NULL, NULL,
1488 LDB_ERR_OPERATIONS_ERROR);
1490 if (ares->error != LDB_SUCCESS) {
1491 return ldb_module_done(ar->req, ares->controls,
1492 ares->response, ares->error);
1495 if (ares->type != LDB_REPLY_DONE) {
1496 ldb_set_errstring(ldb, "Invalid reply type\n!");
1497 return ldb_module_done(ar->req, NULL, NULL,
1498 LDB_ERR_OPERATIONS_ERROR);
1503 return ldb_module_done(ar->req, NULL, NULL, LDB_SUCCESS);
1506 static int replmd_replicated_uptodate_modify(struct replmd_replicated_request *ar)
1508 struct ldb_context *ldb;
1509 struct ldb_request *change_req;
1510 enum ndr_err_code ndr_err;
1511 struct ldb_message *msg;
1512 struct replUpToDateVectorBlob ouv;
1513 const struct ldb_val *ouv_value;
1514 const struct drsuapi_DsReplicaCursor2CtrEx *ruv;
1515 struct replUpToDateVectorBlob nuv;
1516 struct ldb_val nuv_value;
1517 struct ldb_message_element *nuv_el = NULL;
1518 const struct GUID *our_invocation_id;
1519 struct ldb_message_element *orf_el = NULL;
1520 struct repsFromToBlob nrf;
1521 struct ldb_val *nrf_value = NULL;
1522 struct ldb_message_element *nrf_el = NULL;
1525 time_t t = time(NULL);
1529 ldb = ldb_module_get_ctx(ar->module);
1530 ruv = ar->objs->uptodateness_vector;
1536 unix_to_nt_time(&now, t);
1539 * first create the new replUpToDateVector
1541 ouv_value = ldb_msg_find_ldb_val(ar->search_msg, "replUpToDateVector");
1543 ndr_err = ndr_pull_struct_blob(ouv_value, ar,
1544 lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")), &ouv,
1545 (ndr_pull_flags_fn_t)ndr_pull_replUpToDateVectorBlob);
1546 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1547 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
1548 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
1551 if (ouv.version != 2) {
1552 return replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
1557 * the new uptodateness vector will at least
1558 * contain 1 entry, one for the source_dsa
1560 * plus optional values from our old vector and the one from the source_dsa
1562 nuv.ctr.ctr2.count = 1 + ouv.ctr.ctr2.count;
1563 if (ruv) nuv.ctr.ctr2.count += ruv->count;
1564 nuv.ctr.ctr2.cursors = talloc_array(ar,
1565 struct drsuapi_DsReplicaCursor2,
1566 nuv.ctr.ctr2.count);
1567 if (!nuv.ctr.ctr2.cursors) return replmd_replicated_request_werror(ar, WERR_NOMEM);
1569 /* first copy the old vector */
1570 for (i=0; i < ouv.ctr.ctr2.count; i++) {
1571 nuv.ctr.ctr2.cursors[ni] = ouv.ctr.ctr2.cursors[i];
1575 /* get our invocation_id if we have one already attached to the ldb */
1576 our_invocation_id = samdb_ntds_invocation_id(ldb);
1578 /* merge in the source_dsa vector is available */
1579 for (i=0; (ruv && i < ruv->count); i++) {
1582 if (our_invocation_id &&
1583 GUID_equal(&ruv->cursors[i].source_dsa_invocation_id,
1584 our_invocation_id)) {
1588 for (j=0; j < ni; j++) {
1589 if (!GUID_equal(&ruv->cursors[i].source_dsa_invocation_id,
1590 &nuv.ctr.ctr2.cursors[j].source_dsa_invocation_id)) {
1597 * we update only the highest_usn and not the latest_sync_success time,
1598 * because the last success stands for direct replication
1600 if (ruv->cursors[i].highest_usn > nuv.ctr.ctr2.cursors[j].highest_usn) {
1601 nuv.ctr.ctr2.cursors[j].highest_usn = ruv->cursors[i].highest_usn;
1606 if (found) continue;
1608 /* if it's not there yet, add it */
1609 nuv.ctr.ctr2.cursors[ni] = ruv->cursors[i];
1614 * merge in the current highwatermark for the source_dsa
1617 for (j=0; j < ni; j++) {
1618 if (!GUID_equal(&ar->objs->source_dsa->source_dsa_invocation_id,
1619 &nuv.ctr.ctr2.cursors[j].source_dsa_invocation_id)) {
1626 * here we update the highest_usn and last_sync_success time
1627 * because we're directly replicating from the source_dsa
1629 * and use the tmp_highest_usn because this is what we have just applied
1632 nuv.ctr.ctr2.cursors[j].highest_usn = ar->objs->source_dsa->highwatermark.tmp_highest_usn;
1633 nuv.ctr.ctr2.cursors[j].last_sync_success = now;
1638 * here we update the highest_usn and last_sync_success time
1639 * because we're directly replicating from the source_dsa
1641 * and use the tmp_highest_usn because this is what we have just applied
1644 nuv.ctr.ctr2.cursors[ni].source_dsa_invocation_id= ar->objs->source_dsa->source_dsa_invocation_id;
1645 nuv.ctr.ctr2.cursors[ni].highest_usn = ar->objs->source_dsa->highwatermark.tmp_highest_usn;
1646 nuv.ctr.ctr2.cursors[ni].last_sync_success = now;
1651 * finally correct the size of the cursors array
1653 nuv.ctr.ctr2.count = ni;
1658 qsort(nuv.ctr.ctr2.cursors, nuv.ctr.ctr2.count,
1659 sizeof(struct drsuapi_DsReplicaCursor2),
1660 (comparison_fn_t)drsuapi_DsReplicaCursor2_compare);
1663 * create the change ldb_message
1665 msg = ldb_msg_new(ar);
1666 if (!msg) return replmd_replicated_request_werror(ar, WERR_NOMEM);
1667 msg->dn = ar->search_msg->dn;
1669 ndr_err = ndr_push_struct_blob(&nuv_value, msg,
1670 lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")),
1672 (ndr_push_flags_fn_t)ndr_push_replUpToDateVectorBlob);
1673 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1674 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
1675 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
1677 ret = ldb_msg_add_value(msg, "replUpToDateVector", &nuv_value, &nuv_el);
1678 if (ret != LDB_SUCCESS) {
1679 return replmd_replicated_request_error(ar, ret);
1681 nuv_el->flags = LDB_FLAG_MOD_REPLACE;
1684 * now create the new repsFrom value from the given repsFromTo1 structure
1688 nrf.ctr.ctr1 = *ar->objs->source_dsa;
1689 /* and fix some values... */
1690 nrf.ctr.ctr1.consecutive_sync_failures = 0;
1691 nrf.ctr.ctr1.last_success = now;
1692 nrf.ctr.ctr1.last_attempt = now;
1693 nrf.ctr.ctr1.result_last_attempt = WERR_OK;
1694 nrf.ctr.ctr1.highwatermark.highest_usn = nrf.ctr.ctr1.highwatermark.tmp_highest_usn;
1697 * first see if we already have a repsFrom value for the current source dsa
1698 * if so we'll later replace this value
1700 orf_el = ldb_msg_find_element(ar->search_msg, "repsFrom");
1702 for (i=0; i < orf_el->num_values; i++) {
1703 struct repsFromToBlob *trf;
1705 trf = talloc(ar, struct repsFromToBlob);
1706 if (!trf) return replmd_replicated_request_werror(ar, WERR_NOMEM);
1708 ndr_err = ndr_pull_struct_blob(&orf_el->values[i], trf, lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")), trf,
1709 (ndr_pull_flags_fn_t)ndr_pull_repsFromToBlob);
1710 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1711 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
1712 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
1715 if (trf->version != 1) {
1716 return replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
1720 * we compare the source dsa objectGUID not the invocation_id
1721 * because we want only one repsFrom value per source dsa
1722 * and when the invocation_id of the source dsa has changed we don't need
1723 * the old repsFrom with the old invocation_id
1725 if (!GUID_equal(&trf->ctr.ctr1.source_dsa_obj_guid,
1726 &ar->objs->source_dsa->source_dsa_obj_guid)) {
1732 nrf_value = &orf_el->values[i];
1737 * copy over all old values to the new ldb_message
1739 ret = ldb_msg_add_empty(msg, "repsFrom", 0, &nrf_el);
1740 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
1745 * if we haven't found an old repsFrom value for the current source dsa
1746 * we'll add a new value
1749 struct ldb_val zero_value;
1750 ZERO_STRUCT(zero_value);
1751 ret = ldb_msg_add_value(msg, "repsFrom", &zero_value, &nrf_el);
1752 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
1754 nrf_value = &nrf_el->values[nrf_el->num_values - 1];
1757 /* we now fill the value which is already attached to ldb_message */
1758 ndr_err = ndr_push_struct_blob(nrf_value, msg,
1759 lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")),
1761 (ndr_push_flags_fn_t)ndr_push_repsFromToBlob);
1762 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1763 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
1764 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
1768 * the ldb_message_element for the attribute, has all the old values and the new one
1769 * so we'll replace the whole attribute with all values
1771 nrf_el->flags = LDB_FLAG_MOD_REPLACE;
1774 char *s = ldb_ldif_message_string(ldb, ar, LDB_CHANGETYPE_MODIFY, msg);
1775 DEBUG(4, ("DRS replication uptodate modify message:\n%s\n", s));
1779 /* prepare the ldb_modify() request */
1780 ret = ldb_build_mod_req(&change_req,
1786 replmd_replicated_uptodate_modify_callback,
1788 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
1790 return ldb_next_request(ar->module, change_req);
1793 static int replmd_replicated_uptodate_search_callback(struct ldb_request *req,
1794 struct ldb_reply *ares)
1796 struct replmd_replicated_request *ar = talloc_get_type(req->context,
1797 struct replmd_replicated_request);
1801 return ldb_module_done(ar->req, NULL, NULL,
1802 LDB_ERR_OPERATIONS_ERROR);
1804 if (ares->error != LDB_SUCCESS &&
1805 ares->error != LDB_ERR_NO_SUCH_OBJECT) {
1806 return ldb_module_done(ar->req, ares->controls,
1807 ares->response, ares->error);
1810 switch (ares->type) {
1811 case LDB_REPLY_ENTRY:
1812 ar->search_msg = talloc_steal(ar, ares->message);
1815 case LDB_REPLY_REFERRAL:
1816 /* we ignore referrals */
1819 case LDB_REPLY_DONE:
1820 if (ar->search_msg == NULL) {
1821 ret = replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
1823 ret = replmd_replicated_uptodate_modify(ar);
1825 if (ret != LDB_SUCCESS) {
1826 return ldb_module_done(ar->req, NULL, NULL, ret);
1835 static int replmd_replicated_uptodate_vector(struct replmd_replicated_request *ar)
1837 struct ldb_context *ldb;
1839 static const char *attrs[] = {
1840 "replUpToDateVector",
1844 struct ldb_request *search_req;
1846 ldb = ldb_module_get_ctx(ar->module);
1847 ar->search_msg = NULL;
1849 ret = ldb_build_search_req(&search_req,
1852 ar->objs->partition_dn,
1858 replmd_replicated_uptodate_search_callback,
1860 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
1862 return ldb_next_request(ar->module, search_req);
1867 static int replmd_extended_replicated_objects(struct ldb_module *module, struct ldb_request *req)
1869 struct ldb_context *ldb;
1870 struct dsdb_extended_replicated_objects *objs;
1871 struct replmd_replicated_request *ar;
1872 struct ldb_control **ctrls;
1874 struct replmd_private *replmd_private =
1875 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
1877 ldb = ldb_module_get_ctx(module);
1879 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_extended_replicated_objects\n");
1881 objs = talloc_get_type(req->op.extended.data, struct dsdb_extended_replicated_objects);
1883 ldb_debug(ldb, LDB_DEBUG_FATAL, "replmd_extended_replicated_objects: invalid extended data\n");
1884 return LDB_ERR_PROTOCOL_ERROR;
1887 if (objs->version != DSDB_EXTENDED_REPLICATED_OBJECTS_VERSION) {
1888 ldb_debug(ldb, LDB_DEBUG_FATAL, "replmd_extended_replicated_objects: extended data invalid version [%u != %u]\n",
1889 objs->version, DSDB_EXTENDED_REPLICATED_OBJECTS_VERSION);
1890 return LDB_ERR_PROTOCOL_ERROR;
1893 ar = replmd_ctx_init(module, req);
1895 return LDB_ERR_OPERATIONS_ERROR;
1897 /* Set the flags to have the replmd_op_callback run over the full set of objects */
1898 ar->apply_mode = true;
1900 ar->schema = dsdb_get_schema(ldb);
1902 ldb_debug_set(ldb, LDB_DEBUG_FATAL, "replmd_ctx_init: no loaded schema found\n");
1904 DEBUG(0,(__location__ ": %s\n", ldb_errstring(ldb)));
1905 return LDB_ERR_CONSTRAINT_VIOLATION;
1908 ctrls = req->controls;
1910 if (req->controls) {
1911 req->controls = talloc_memdup(ar, req->controls,
1912 talloc_get_size(req->controls));
1913 if (!req->controls) return replmd_replicated_request_werror(ar, WERR_NOMEM);
1916 ret = ldb_request_add_control(req, DSDB_CONTROL_REPLICATED_UPDATE_OID, false, NULL);
1917 if (ret != LDB_SUCCESS) {
1921 ar->controls = req->controls;
1922 req->controls = ctrls;
1924 DEBUG(4,("linked_attributes_count=%u\n", objs->linked_attributes_count));
1926 /* save away the linked attributes for the end of the
1928 for (i=0; i<ar->objs->linked_attributes_count; i++) {
1929 struct la_entry *la_entry;
1931 if (replmd_private->la_ctx == NULL) {
1932 replmd_private->la_ctx = talloc_new(replmd_private);
1934 la_entry = talloc(replmd_private->la_ctx, struct la_entry);
1935 if (la_entry == NULL) {
1937 return LDB_ERR_OPERATIONS_ERROR;
1939 la_entry->la = talloc(la_entry, struct drsuapi_DsReplicaLinkedAttribute);
1940 if (la_entry->la == NULL) {
1941 talloc_free(la_entry);
1943 return LDB_ERR_OPERATIONS_ERROR;
1945 *la_entry->la = ar->objs->linked_attributes[i];
1947 /* we need to steal the non-scalars so they stay
1948 around until the end of the transaction */
1949 talloc_steal(la_entry->la, la_entry->la->identifier);
1950 talloc_steal(la_entry->la, la_entry->la->value.blob);
1952 DLIST_ADD(replmd_private->la_list, la_entry);
1955 return replmd_replicated_apply_next(ar);
1959 process one linked attribute structure
1961 static int replmd_process_linked_attribute(struct ldb_module *module,
1962 struct la_entry *la_entry)
1964 struct drsuapi_DsReplicaLinkedAttribute *la = la_entry->la;
1965 struct ldb_context *ldb = ldb_module_get_ctx(module);
1966 struct dsdb_schema *schema = dsdb_get_schema(ldb);
1967 struct drsuapi_DsReplicaObjectIdentifier3 target;
1968 struct ldb_message *msg;
1969 struct ldb_message_element *ret_el;
1970 TALLOC_CTX *tmp_ctx = talloc_new(la_entry);
1971 enum ndr_err_code ndr_err;
1972 struct ldb_request *mod_req;
1974 const struct dsdb_attribute *attr;
1975 struct ldb_dn *target_dn;
1976 uint64_t seq_num = 0;
1979 linked_attributes[0]:
1980 &objs->linked_attributes[i]: struct drsuapi_DsReplicaLinkedAttribute
1982 identifier: struct drsuapi_DsReplicaObjectIdentifier
1983 __ndr_size : 0x0000003a (58)
1984 __ndr_size_sid : 0x00000000 (0)
1985 guid : 8e95b6a9-13dd-4158-89db-3220a5be5cc7
1987 __ndr_size_dn : 0x00000000 (0)
1989 attid : DRSUAPI_ATTRIBUTE_member (0x1F)
1990 value: struct drsuapi_DsAttributeValue
1991 __ndr_size : 0x0000007e (126)
1993 blob : DATA_BLOB length=126
1994 flags : 0x00000001 (1)
1995 1: DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE
1996 originating_add_time : Wed Sep 2 22:20:01 2009 EST
1997 meta_data: struct drsuapi_DsReplicaMetaData
1998 version : 0x00000015 (21)
1999 originating_change_time : Wed Sep 2 23:39:07 2009 EST
2000 originating_invocation_id: 794640f3-18cf-40ee-a211-a93992b67a64
2001 originating_usn : 0x000000000001e19c (123292)
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 NDR_PRINT_DEBUG(drsuapi_DsReplicaLinkedAttribute, la);
2014 /* decode the target of the link */
2015 ndr_err = ndr_pull_struct_blob(la->value.blob,
2016 tmp_ctx, lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")),
2018 (ndr_pull_flags_fn_t)ndr_pull_drsuapi_DsReplicaObjectIdentifier3);
2019 if (ndr_err != NDR_ERR_SUCCESS) {
2020 DEBUG(0,("Unable to decode linked_attribute target\n"));
2021 dump_data(4, la->value.blob->data, la->value.blob->length);
2022 talloc_free(tmp_ctx);
2023 return LDB_ERR_OPERATIONS_ERROR;
2026 NDR_PRINT_DEBUG(drsuapi_DsReplicaObjectIdentifier3, &target);
2029 /* construct a modify request for this attribute change */
2030 msg = ldb_msg_new(tmp_ctx);
2033 talloc_free(tmp_ctx);
2034 return LDB_ERR_OPERATIONS_ERROR;
2037 ret = dsdb_find_dn_by_guid(ldb, tmp_ctx,
2038 GUID_string(tmp_ctx, &la->identifier->guid), &msg->dn);
2039 if (ret != LDB_SUCCESS) {
2040 talloc_free(tmp_ctx);
2044 /* find the attribute being modified */
2045 attr = dsdb_attribute_by_attributeID_id(schema, la->attid);
2047 DEBUG(0, (__location__ ": Unable to find attributeID 0x%x\n", la->attid));
2048 talloc_free(tmp_ctx);
2049 return LDB_ERR_OPERATIONS_ERROR;
2052 if (la->flags & DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE) {
2053 ret = ldb_msg_add_empty(msg, attr->lDAPDisplayName,
2054 LDB_FLAG_MOD_ADD, &ret_el);
2056 ret = ldb_msg_add_empty(msg, attr->lDAPDisplayName,
2057 LDB_FLAG_MOD_DELETE, &ret_el);
2059 if (ret != LDB_SUCCESS) {
2060 talloc_free(tmp_ctx);
2063 /* we allocate two entries here, in case we need a remove/add
2065 ret_el->values = talloc_array(msg, struct ldb_val, 2);
2066 if (!ret_el->values) {
2068 talloc_free(tmp_ctx);
2069 return LDB_ERR_OPERATIONS_ERROR;
2071 ret_el->num_values = 1;
2073 ret = dsdb_find_dn_by_guid(ldb, tmp_ctx, GUID_string(tmp_ctx, &target.guid), &target_dn);
2074 if (ret != LDB_SUCCESS) {
2075 DEBUG(0,(__location__ ": Failed to map GUID %s to DN\n", GUID_string(tmp_ctx, &target.guid)));
2076 talloc_free(tmp_ctx);
2077 return LDB_ERR_OPERATIONS_ERROR;
2080 ret_el->values[0].data = (uint8_t *)ldb_dn_get_extended_linearized(tmp_ctx, target_dn, 1);
2081 ret_el->values[0].length = strlen((char *)ret_el->values[0].data);
2083 ret = replmd_update_rpmd(module, schema, msg, &seq_num);
2084 if (ret != LDB_SUCCESS) {
2085 talloc_free(tmp_ctx);
2089 /* we only change whenChanged and uSNChanged if the seq_num
2092 time_t t = time(NULL);
2094 if (add_time_element(msg, "whenChanged", t) != LDB_SUCCESS) {
2095 talloc_free(tmp_ctx);
2096 return LDB_ERR_OPERATIONS_ERROR;
2099 if (add_uint64_element(msg, "uSNChanged", seq_num) != LDB_SUCCESS) {
2100 talloc_free(tmp_ctx);
2101 return LDB_ERR_OPERATIONS_ERROR;
2105 ret = ldb_build_mod_req(&mod_req, ldb, tmp_ctx,
2109 ldb_op_default_callback,
2111 if (ret != LDB_SUCCESS) {
2112 talloc_free(tmp_ctx);
2115 talloc_steal(mod_req, msg);
2118 DEBUG(4,("Applying DRS linked attribute change:\n%s\n",
2119 ldb_ldif_message_string(ldb, tmp_ctx, LDB_CHANGETYPE_MODIFY, msg)));
2122 /* Run the new request */
2123 ret = ldb_next_request(module, mod_req);
2125 /* we need to wait for this to finish, as we are being called
2126 from the synchronous end_transaction hook of this module */
2127 if (ret == LDB_SUCCESS) {
2128 ret = ldb_wait(mod_req->handle, LDB_WAIT_ALL);
2131 if (ret == LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS) {
2132 /* the link destination exists, we need to update it
2133 * by deleting the old one for the same DN then adding
2135 msg->elements = talloc_realloc(msg, msg->elements,
2136 struct ldb_message_element,
2137 msg->num_elements+1);
2138 if (msg->elements == NULL) {
2140 talloc_free(tmp_ctx);
2141 return LDB_ERR_OPERATIONS_ERROR;
2143 /* this relies on the backend matching the old entry
2144 only by the DN portion of the extended DN */
2145 msg->elements[1] = msg->elements[0];
2146 msg->elements[0].flags = LDB_FLAG_MOD_DELETE;
2147 msg->num_elements++;
2149 ret = ldb_build_mod_req(&mod_req, ldb, tmp_ctx,
2153 ldb_op_default_callback,
2155 if (ret != LDB_SUCCESS) {
2156 talloc_free(tmp_ctx);
2160 /* Run the new request */
2161 ret = ldb_next_request(module, mod_req);
2163 if (ret == LDB_SUCCESS) {
2164 ret = ldb_wait(mod_req->handle, LDB_WAIT_ALL);
2168 if (ret != LDB_SUCCESS) {
2169 ldb_debug(ldb, LDB_DEBUG_WARNING, "Failed to apply linked attribute change '%s' %s\n",
2171 ldb_ldif_message_string(ldb, tmp_ctx, LDB_CHANGETYPE_MODIFY, msg));
2175 talloc_free(tmp_ctx);
2180 static int replmd_extended(struct ldb_module *module, struct ldb_request *req)
2182 if (strcmp(req->op.extended.oid, DSDB_EXTENDED_REPLICATED_OBJECTS_OID) == 0) {
2183 return replmd_extended_replicated_objects(module, req);
2186 return ldb_next_request(module, req);
2191 we hook into the transaction operations to allow us to
2192 perform the linked attribute updates at the end of the whole
2193 transaction. This allows a forward linked attribute to be created
2194 before the object is created. During a vampire, w2k8 sends us linked
2195 attributes before the objects they are part of.
2197 static int replmd_start_transaction(struct ldb_module *module)
2199 /* create our private structure for this transaction */
2201 struct replmd_private *replmd_private = talloc_get_type(ldb_module_get_private(module),
2202 struct replmd_private);
2203 talloc_free(replmd_private->la_ctx);
2204 replmd_private->la_list = NULL;
2205 replmd_private->la_ctx = NULL;
2207 for (i=0; i<replmd_private->num_ncs; i++) {
2208 replmd_private->ncs[i].mod_usn = 0;
2211 return ldb_next_start_trans(module);
2215 on prepare commit we loop over our queued la_context structures and
2218 static int replmd_prepare_commit(struct ldb_module *module)
2220 struct replmd_private *replmd_private =
2221 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
2222 struct la_entry *la, *prev;
2225 /* walk the list backwards, to do the first entry first, as we
2226 * added the entries with DLIST_ADD() which puts them at the
2227 * start of the list */
2228 for (la = replmd_private->la_list; la && la->next; la=la->next) ;
2230 for (; la; la=prev) {
2232 DLIST_REMOVE(replmd_private->la_list, la);
2233 ret = replmd_process_linked_attribute(module, la);
2234 if (ret != LDB_SUCCESS) {
2235 talloc_free(replmd_private->la_ctx);
2236 replmd_private->la_list = NULL;
2237 replmd_private->la_ctx = NULL;
2242 talloc_free(replmd_private->la_ctx);
2243 replmd_private->la_list = NULL;
2244 replmd_private->la_ctx = NULL;
2246 /* possibly change @REPLCHANGED */
2247 ret = replmd_notify_store(module);
2248 if (ret != LDB_SUCCESS) {
2252 return ldb_next_prepare_commit(module);
2255 static int replmd_del_transaction(struct ldb_module *module)
2257 struct replmd_private *replmd_private =
2258 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
2259 talloc_free(replmd_private->la_ctx);
2260 replmd_private->la_list = NULL;
2261 replmd_private->la_ctx = NULL;
2262 return ldb_next_del_trans(module);
2266 _PUBLIC_ const struct ldb_module_ops ldb_repl_meta_data_module_ops = {
2267 .name = "repl_meta_data",
2268 .init_context = replmd_init,
2270 .modify = replmd_modify,
2271 .rename = replmd_rename,
2272 .extended = replmd_extended,
2273 .start_transaction = replmd_start_transaction,
2274 .prepare_commit = replmd_prepare_commit,
2275 .del_transaction = replmd_del_transaction,