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"
48 #include "dsdb/samdb/ldb_modules/util.h"
49 #include "lib/util/binsearch.h"
51 #define W2K3_LINKED_ATTRIBUTES 1
53 struct replmd_private {
55 struct la_entry *la_list;
57 struct nc_entry *prev, *next;
64 struct la_entry *next, *prev;
65 struct drsuapi_DsReplicaLinkedAttribute *la;
68 struct replmd_replicated_request {
69 struct ldb_module *module;
70 struct ldb_request *req;
72 const struct dsdb_schema *schema;
74 /* the controls we pass down */
75 struct ldb_control **controls;
77 /* details for the mode where we apply a bunch of inbound replication meessages */
79 uint32_t index_current;
80 struct dsdb_extended_replicated_objects *objs;
82 struct ldb_message *search_msg;
88 static int replmd_replicated_apply_next(struct replmd_replicated_request *ar);
92 allocate the private structure and build the list
93 of partition DNs for use by replmd_notify()
95 static int replmd_init(struct ldb_module *module)
97 struct replmd_private *replmd_private;
98 struct ldb_context *ldb = ldb_module_get_ctx(module);
100 replmd_private = talloc_zero(module, struct replmd_private);
101 if (replmd_private == NULL) {
103 return LDB_ERR_OPERATIONS_ERROR;
105 ldb_module_set_private(module, replmd_private);
107 return ldb_next_init(module);
112 * Callback for most write operations in this module:
114 * notify the repl task that a object has changed. The notifies are
115 * gathered up in the replmd_private structure then written to the
116 * @REPLCHANGED object in each partition during the prepare_commit
118 static int replmd_op_callback(struct ldb_request *req, struct ldb_reply *ares)
121 struct replmd_replicated_request *ac =
122 talloc_get_type_abort(req->context, struct replmd_replicated_request);
123 struct replmd_private *replmd_private =
124 talloc_get_type_abort(ldb_module_get_private(ac->module), struct replmd_private);
125 struct nc_entry *modified_partition;
126 struct ldb_control *partition_ctrl;
127 const struct dsdb_control_current_partition *partition;
129 struct ldb_control **controls;
131 partition_ctrl = ldb_reply_get_control(ares, DSDB_CONTROL_CURRENT_PARTITION_OID);
133 /* Remove the 'partition' control from what we pass up the chain */
134 controls = controls_except_specified(ares->controls, ares, partition_ctrl);
136 if (ares->error != LDB_SUCCESS) {
137 return ldb_module_done(ac->req, controls,
138 ares->response, ares->error);
141 if (ares->type != LDB_REPLY_DONE) {
142 ldb_set_errstring(ldb_module_get_ctx(ac->module), "Invalid reply type for notify\n!");
143 return ldb_module_done(ac->req, NULL,
144 NULL, LDB_ERR_OPERATIONS_ERROR);
147 if (!partition_ctrl) {
148 return ldb_module_done(ac->req, NULL,
149 NULL, LDB_ERR_OPERATIONS_ERROR);
152 partition = talloc_get_type_abort(partition_ctrl->data,
153 struct dsdb_control_current_partition);
155 if (ac->seq_num > 0) {
156 for (modified_partition = replmd_private->ncs; modified_partition;
157 modified_partition = modified_partition->next) {
158 if (ldb_dn_compare(modified_partition->dn, partition->dn) == 0) {
163 if (modified_partition == NULL) {
164 modified_partition = talloc_zero(replmd_private, struct nc_entry);
165 if (!modified_partition) {
166 ldb_oom(ldb_module_get_ctx(ac->module));
167 return ldb_module_done(ac->req, NULL,
168 NULL, LDB_ERR_OPERATIONS_ERROR);
170 modified_partition->dn = ldb_dn_copy(modified_partition, partition->dn);
171 if (!modified_partition->dn) {
172 ldb_oom(ldb_module_get_ctx(ac->module));
173 return ldb_module_done(ac->req, NULL,
174 NULL, LDB_ERR_OPERATIONS_ERROR);
176 DLIST_ADD(replmd_private->ncs, modified_partition);
179 if (ac->seq_num > modified_partition->mod_usn) {
180 modified_partition->mod_usn = ac->seq_num;
184 if (ac->apply_mode) {
188 ret = replmd_replicated_apply_next(ac);
189 if (ret != LDB_SUCCESS) {
190 return ldb_module_done(ac->req, NULL, NULL, ret);
194 /* free the partition control container here, for the
195 * common path. Other cases will have it cleaned up
196 * eventually with the ares */
197 talloc_free(partition_ctrl);
198 return ldb_module_done(ac->req,
199 controls_except_specified(controls, ares, partition_ctrl),
200 ares->response, LDB_SUCCESS);
206 * update a @REPLCHANGED record in each partition if there have been
207 * any writes of replicated data in the partition
209 static int replmd_notify_store(struct ldb_module *module)
211 struct replmd_private *replmd_private =
212 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
213 struct ldb_context *ldb = ldb_module_get_ctx(module);
215 while (replmd_private->ncs) {
217 struct nc_entry *modified_partition = replmd_private->ncs;
219 ret = dsdb_save_partition_usn(ldb, modified_partition->dn, modified_partition->mod_usn);
220 if (ret != LDB_SUCCESS) {
221 DEBUG(0,(__location__ ": Failed to save partition uSN for %s\n",
222 ldb_dn_get_linearized(modified_partition->dn)));
225 DLIST_REMOVE(replmd_private->ncs, modified_partition);
226 talloc_free(modified_partition);
234 created a replmd_replicated_request context
236 static struct replmd_replicated_request *replmd_ctx_init(struct ldb_module *module,
237 struct ldb_request *req)
239 struct ldb_context *ldb;
240 struct replmd_replicated_request *ac;
242 ldb = ldb_module_get_ctx(module);
244 ac = talloc_zero(req, struct replmd_replicated_request);
253 ac->schema = dsdb_get_schema(ldb);
255 ldb_debug_set(ldb, LDB_DEBUG_FATAL,
256 "replmd_modify: no dsdb_schema loaded");
257 DEBUG(0,(__location__ ": %s\n", ldb_errstring(ldb)));
265 add a time element to a record
267 static int add_time_element(struct ldb_message *msg, const char *attr, time_t t)
269 struct ldb_message_element *el;
272 if (ldb_msg_find_element(msg, attr) != NULL) {
276 s = ldb_timestring(msg, t);
278 return LDB_ERR_OPERATIONS_ERROR;
281 if (ldb_msg_add_string(msg, attr, s) != LDB_SUCCESS) {
282 return LDB_ERR_OPERATIONS_ERROR;
285 el = ldb_msg_find_element(msg, attr);
286 /* always set as replace. This works because on add ops, the flag
288 el->flags = LDB_FLAG_MOD_REPLACE;
294 add a uint64_t element to a record
296 static int add_uint64_element(struct ldb_message *msg, const char *attr, uint64_t v)
298 struct ldb_message_element *el;
300 if (ldb_msg_find_element(msg, attr) != NULL) {
304 if (ldb_msg_add_fmt(msg, attr, "%llu", (unsigned long long)v) != LDB_SUCCESS) {
305 return LDB_ERR_OPERATIONS_ERROR;
308 el = ldb_msg_find_element(msg, attr);
309 /* always set as replace. This works because on add ops, the flag
311 el->flags = LDB_FLAG_MOD_REPLACE;
316 static int replmd_replPropertyMetaData1_attid_sort(const struct replPropertyMetaData1 *m1,
317 const struct replPropertyMetaData1 *m2,
318 const uint32_t *rdn_attid)
320 if (m1->attid == m2->attid) {
325 * the rdn attribute should be at the end!
326 * so we need to return a value greater than zero
327 * which means m1 is greater than m2
329 if (m1->attid == *rdn_attid) {
334 * the rdn attribute should be at the end!
335 * so we need to return a value less than zero
336 * which means m2 is greater than m1
338 if (m2->attid == *rdn_attid) {
342 return m1->attid > m2->attid ? 1 : -1;
345 static int replmd_replPropertyMetaDataCtr1_sort(struct replPropertyMetaDataCtr1 *ctr1,
346 const struct dsdb_schema *schema,
349 const char *rdn_name;
350 const struct dsdb_attribute *rdn_sa;
352 rdn_name = ldb_dn_get_rdn_name(dn);
354 DEBUG(0,(__location__ ": No rDN for %s?\n", ldb_dn_get_linearized(dn)));
355 return LDB_ERR_OPERATIONS_ERROR;
358 rdn_sa = dsdb_attribute_by_lDAPDisplayName(schema, rdn_name);
359 if (rdn_sa == NULL) {
360 DEBUG(0,(__location__ ": No sa found for rDN %s for %s\n", rdn_name, ldb_dn_get_linearized(dn)));
361 return LDB_ERR_OPERATIONS_ERROR;
364 DEBUG(6,("Sorting rpmd with attid exception %u rDN=%s DN=%s\n",
365 rdn_sa->attributeID_id, rdn_name, ldb_dn_get_linearized(dn)));
367 ldb_qsort(ctr1->array, ctr1->count, sizeof(struct replPropertyMetaData1),
368 discard_const_p(void, &rdn_sa->attributeID_id),
369 (ldb_qsort_cmp_fn_t)replmd_replPropertyMetaData1_attid_sort);
374 static int replmd_ldb_message_element_attid_sort(const struct ldb_message_element *e1,
375 const struct ldb_message_element *e2,
376 const struct dsdb_schema *schema)
378 const struct dsdb_attribute *a1;
379 const struct dsdb_attribute *a2;
382 * TODO: make this faster by caching the dsdb_attribute pointer
383 * on the ldb_messag_element
386 a1 = dsdb_attribute_by_lDAPDisplayName(schema, e1->name);
387 a2 = dsdb_attribute_by_lDAPDisplayName(schema, e2->name);
390 * TODO: remove this check, we should rely on e1 and e2 having valid attribute names
394 return strcasecmp(e1->name, e2->name);
396 if (a1->attributeID_id == a2->attributeID_id) {
399 return a1->attributeID_id > a2->attributeID_id ? 1 : -1;
402 static void replmd_ldb_message_sort(struct ldb_message *msg,
403 const struct dsdb_schema *schema)
405 ldb_qsort(msg->elements, msg->num_elements, sizeof(struct ldb_message_element),
406 discard_const_p(void, schema), (ldb_qsort_cmp_fn_t)replmd_ldb_message_element_attid_sort);
409 static int replmd_add(struct ldb_module *module, struct ldb_request *req)
411 struct ldb_context *ldb;
412 struct ldb_control *control;
413 struct replmd_replicated_request *ac;
414 enum ndr_err_code ndr_err;
415 struct ldb_request *down_req;
416 struct ldb_message *msg;
417 const DATA_BLOB *guid_blob;
419 struct replPropertyMetaDataBlob nmd;
420 struct ldb_val nmd_value;
421 const struct GUID *our_invocation_id;
422 time_t t = time(NULL);
427 bool allow_add_guid = false;
428 bool remove_current_guid = false;
430 /* check if there's a show relax control (used by provision to say 'I know what I'm doing') */
431 control = ldb_request_get_control(req, LDB_CONTROL_RELAX_OID);
436 /* do not manipulate our control entries */
437 if (ldb_dn_is_special(req->op.add.message->dn)) {
438 return ldb_next_request(module, req);
441 ldb = ldb_module_get_ctx(module);
443 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_add\n");
445 ac = replmd_ctx_init(module, req);
447 return LDB_ERR_OPERATIONS_ERROR;
450 guid_blob = ldb_msg_find_ldb_val(req->op.add.message, "objectGUID");
451 if ( guid_blob != NULL ) {
452 if( !allow_add_guid ) {
453 ldb_debug_set(ldb, LDB_DEBUG_ERROR,
454 "replmd_add: it's not allowed to add an object with objectGUID\n");
456 return LDB_ERR_UNWILLING_TO_PERFORM;
458 NTSTATUS status = GUID_from_data_blob(guid_blob,&guid);
459 if ( !NT_STATUS_IS_OK(status)) {
460 ldb_debug_set(ldb, LDB_DEBUG_ERROR,
461 "replmd_add: Unable to parse as a GUID the attribute objectGUID\n");
463 return LDB_ERR_UNWILLING_TO_PERFORM;
465 /* we remove this attribute as it can be a string and will not be treated
466 correctly and then we will readd it latter on in the good format*/
467 remove_current_guid = true;
471 guid = GUID_random();
474 /* Get a sequence number from the backend */
475 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &ac->seq_num);
476 if (ret != LDB_SUCCESS) {
481 /* get our invocationId */
482 our_invocation_id = samdb_ntds_invocation_id(ldb);
483 if (!our_invocation_id) {
484 ldb_debug_set(ldb, LDB_DEBUG_ERROR,
485 "replmd_add: unable to find invocationId\n");
487 return LDB_ERR_OPERATIONS_ERROR;
490 /* we have to copy the message as the caller might have it as a const */
491 msg = ldb_msg_copy_shallow(ac, req->op.add.message);
495 return LDB_ERR_OPERATIONS_ERROR;
498 /* generated times */
499 unix_to_nt_time(&now, t);
500 time_str = ldb_timestring(msg, t);
504 return LDB_ERR_OPERATIONS_ERROR;
506 if (remove_current_guid) {
507 ldb_msg_remove_attr(msg,"objectGUID");
511 * remove autogenerated attributes
513 ldb_msg_remove_attr(msg, "whenCreated");
514 ldb_msg_remove_attr(msg, "whenChanged");
515 ldb_msg_remove_attr(msg, "uSNCreated");
516 ldb_msg_remove_attr(msg, "uSNChanged");
517 ldb_msg_remove_attr(msg, "replPropertyMetaData");
520 * readd replicated attributes
522 ret = ldb_msg_add_string(msg, "whenCreated", time_str);
523 if (ret != LDB_SUCCESS) {
529 /* build the replication meta_data */
532 nmd.ctr.ctr1.count = msg->num_elements;
533 nmd.ctr.ctr1.array = talloc_array(msg,
534 struct replPropertyMetaData1,
536 if (!nmd.ctr.ctr1.array) {
539 return LDB_ERR_OPERATIONS_ERROR;
542 for (i=0; i < msg->num_elements; i++) {
543 struct ldb_message_element *e = &msg->elements[i];
544 struct replPropertyMetaData1 *m = &nmd.ctr.ctr1.array[ni];
545 const struct dsdb_attribute *sa;
547 if (e->name[0] == '@') continue;
549 sa = dsdb_attribute_by_lDAPDisplayName(ac->schema, e->name);
551 ldb_debug_set(ldb, LDB_DEBUG_ERROR,
552 "replmd_add: attribute '%s' not defined in schema\n",
555 return LDB_ERR_NO_SUCH_ATTRIBUTE;
558 if ((sa->systemFlags & DS_FLAG_ATTR_NOT_REPLICATED) || (sa->systemFlags & DS_FLAG_ATTR_IS_CONSTRUCTED)) {
559 /* if the attribute is not replicated (0x00000001)
560 * or constructed (0x00000004) it has no metadata
565 m->attid = sa->attributeID_id;
567 m->originating_change_time = now;
568 m->originating_invocation_id = *our_invocation_id;
569 m->originating_usn = ac->seq_num;
570 m->local_usn = ac->seq_num;
574 /* fix meta data count */
575 nmd.ctr.ctr1.count = ni;
578 * sort meta data array, and move the rdn attribute entry to the end
580 ret = replmd_replPropertyMetaDataCtr1_sort(&nmd.ctr.ctr1, ac->schema, msg->dn);
581 if (ret != LDB_SUCCESS) {
586 /* generated NDR encoded values */
587 ndr_err = ndr_push_struct_blob(&nmd_value, msg,
588 lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")),
590 (ndr_push_flags_fn_t)ndr_push_replPropertyMetaDataBlob);
591 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
594 return LDB_ERR_OPERATIONS_ERROR;
598 * add the autogenerated values
600 ret = dsdb_msg_add_guid(msg, &guid, "objectGUID");
601 if (ret != LDB_SUCCESS) {
606 ret = ldb_msg_add_string(msg, "whenChanged", time_str);
607 if (ret != LDB_SUCCESS) {
612 ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNCreated", ac->seq_num);
613 if (ret != LDB_SUCCESS) {
618 ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNChanged", ac->seq_num);
619 if (ret != LDB_SUCCESS) {
624 ret = ldb_msg_add_value(msg, "replPropertyMetaData", &nmd_value, NULL);
625 if (ret != LDB_SUCCESS) {
632 * sort the attributes by attid before storing the object
634 replmd_ldb_message_sort(msg, ac->schema);
636 ret = ldb_build_add_req(&down_req, ldb, ac,
639 ac, replmd_op_callback,
641 if (ret != LDB_SUCCESS) {
646 /* mark the control done */
648 control->critical = 0;
651 /* go on with the call chain */
652 return ldb_next_request(module, down_req);
657 * update the replPropertyMetaData for one element
659 static int replmd_update_rpmd_element(struct ldb_context *ldb,
660 struct ldb_message *msg,
661 struct ldb_message_element *el,
662 struct replPropertyMetaDataBlob *omd,
663 const struct dsdb_schema *schema,
665 const struct GUID *our_invocation_id,
669 const struct dsdb_attribute *a;
670 struct replPropertyMetaData1 *md1;
672 a = dsdb_attribute_by_lDAPDisplayName(schema, el->name);
674 DEBUG(0,(__location__ ": Unable to find attribute %s in schema\n",
676 return LDB_ERR_OPERATIONS_ERROR;
679 if ((a->systemFlags & DS_FLAG_ATTR_NOT_REPLICATED) || (a->systemFlags & DS_FLAG_ATTR_IS_CONSTRUCTED)) {
683 for (i=0; i<omd->ctr.ctr1.count; i++) {
684 if (a->attributeID_id == omd->ctr.ctr1.array[i].attid) break;
687 #if W2K3_LINKED_ATTRIBUTES
688 if (a->linkID != 0 && dsdb_functional_level(ldb) > DS_DOMAIN_FUNCTION_2000) {
689 /* linked attributes are not stored in
690 replPropertyMetaData in FL above w2k, but we do
691 raise the seqnum for the object */
693 ldb_sequence_number(ldb, LDB_SEQ_NEXT, seq_num) != LDB_SUCCESS) {
694 return LDB_ERR_OPERATIONS_ERROR;
700 if (i == omd->ctr.ctr1.count) {
701 /* we need to add a new one */
702 omd->ctr.ctr1.array = talloc_realloc(msg, omd->ctr.ctr1.array,
703 struct replPropertyMetaData1, omd->ctr.ctr1.count+1);
704 if (omd->ctr.ctr1.array == NULL) {
706 return LDB_ERR_OPERATIONS_ERROR;
708 omd->ctr.ctr1.count++;
709 ZERO_STRUCT(omd->ctr.ctr1.array[i]);
712 /* Get a new sequence number from the backend. We only do this
713 * if we have a change that requires a new
714 * replPropertyMetaData element
717 int ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, seq_num);
718 if (ret != LDB_SUCCESS) {
719 return LDB_ERR_OPERATIONS_ERROR;
723 md1 = &omd->ctr.ctr1.array[i];
725 md1->attid = a->attributeID_id;
726 md1->originating_change_time = now;
727 md1->originating_invocation_id = *our_invocation_id;
728 md1->originating_usn = *seq_num;
729 md1->local_usn = *seq_num;
735 * update the replPropertyMetaData object each time we modify an
736 * object. This is needed for DRS replication, as the merge on the
737 * client is based on this object
739 static int replmd_update_rpmd(struct ldb_module *module,
740 const struct dsdb_schema *schema,
741 struct ldb_message *msg, uint64_t *seq_num,
744 const struct ldb_val *omd_value;
745 enum ndr_err_code ndr_err;
746 struct replPropertyMetaDataBlob omd;
749 const struct GUID *our_invocation_id;
751 const char *attrs[] = { "replPropertyMetaData" , NULL };
752 struct ldb_result *res;
753 struct ldb_context *ldb;
755 ldb = ldb_module_get_ctx(module);
757 our_invocation_id = samdb_ntds_invocation_id(ldb);
758 if (!our_invocation_id) {
759 /* this happens during an initial vampire while
760 updating the schema */
761 DEBUG(5,("No invocationID - skipping replPropertyMetaData update\n"));
765 unix_to_nt_time(&now, t);
767 /* search for the existing replPropertyMetaDataBlob */
768 ret = dsdb_search_dn_with_deleted(ldb, msg, &res, msg->dn, attrs);
769 if (ret != LDB_SUCCESS || res->count != 1) {
770 DEBUG(0,(__location__ ": Object %s failed to find replPropertyMetaData\n",
771 ldb_dn_get_linearized(msg->dn)));
772 return LDB_ERR_OPERATIONS_ERROR;
776 omd_value = ldb_msg_find_ldb_val(res->msgs[0], "replPropertyMetaData");
778 DEBUG(0,(__location__ ": Object %s does not have a replPropertyMetaData attribute\n",
779 ldb_dn_get_linearized(msg->dn)));
780 return LDB_ERR_OPERATIONS_ERROR;
783 ndr_err = ndr_pull_struct_blob(omd_value, msg,
784 lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")), &omd,
785 (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
786 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
787 DEBUG(0,(__location__ ": Failed to parse replPropertyMetaData for %s\n",
788 ldb_dn_get_linearized(msg->dn)));
789 return LDB_ERR_OPERATIONS_ERROR;
792 if (omd.version != 1) {
793 DEBUG(0,(__location__ ": bad version %u in replPropertyMetaData for %s\n",
794 omd.version, ldb_dn_get_linearized(msg->dn)));
795 return LDB_ERR_OPERATIONS_ERROR;
798 for (i=0; i<msg->num_elements; i++) {
799 ret = replmd_update_rpmd_element(ldb, msg, &msg->elements[i], &omd, schema, seq_num,
800 our_invocation_id, now);
801 if (ret != LDB_SUCCESS) {
807 * replmd_update_rpmd_element has done an update if the
811 struct ldb_val *md_value;
812 struct ldb_message_element *el;
814 md_value = talloc(msg, struct ldb_val);
815 if (md_value == NULL) {
817 return LDB_ERR_OPERATIONS_ERROR;
820 ret = replmd_replPropertyMetaDataCtr1_sort(&omd.ctr.ctr1, schema, msg->dn);
821 if (ret != LDB_SUCCESS) {
825 ndr_err = ndr_push_struct_blob(md_value, msg,
826 lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")),
828 (ndr_push_flags_fn_t)ndr_push_replPropertyMetaDataBlob);
829 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
830 DEBUG(0,(__location__ ": Failed to marshall replPropertyMetaData for %s\n",
831 ldb_dn_get_linearized(msg->dn)));
832 return LDB_ERR_OPERATIONS_ERROR;
835 ret = ldb_msg_add_empty(msg, "replPropertyMetaData", LDB_FLAG_MOD_REPLACE, &el);
836 if (ret != LDB_SUCCESS) {
837 DEBUG(0,(__location__ ": Failed to add updated replPropertyMetaData %s\n",
838 ldb_dn_get_linearized(msg->dn)));
843 el->values = md_value;
851 struct dsdb_dn *dsdb_dn;
856 static int parsed_dn_compare(struct parsed_dn *pdn1, struct parsed_dn *pdn2)
858 return GUID_compare(pdn1->guid, pdn2->guid);
861 static struct parsed_dn *parsed_dn_find(struct parsed_dn *pdn, int count, struct GUID *guid)
863 struct parsed_dn *ret;
864 BINARY_ARRAY_SEARCH(pdn, count, guid, guid, GUID_compare, ret);
869 get a series of message element values as an array of DNs and GUIDs
870 the result is sorted by GUID
872 static int get_parsed_dns(struct ldb_module *module, TALLOC_CTX *mem_ctx,
873 struct ldb_message_element *el, struct parsed_dn **pdn,
874 const char *ldap_oid)
877 struct ldb_context *ldb = ldb_module_get_ctx(module);
884 (*pdn) = talloc_array(mem_ctx, struct parsed_dn, el->num_values);
886 ldb_module_oom(module);
887 return LDB_ERR_OPERATIONS_ERROR;
890 for (i=0; i<el->num_values; i++) {
891 struct ldb_val *v = &el->values[i];
898 p->dsdb_dn = dsdb_dn_parse(*pdn, ldb, v, ldap_oid);
899 if (p->dsdb_dn == NULL) {
900 return LDB_ERR_INVALID_DN_SYNTAX;
905 p->guid = talloc(*pdn, struct GUID);
906 if (p->guid == NULL) {
907 ldb_module_oom(module);
908 return LDB_ERR_OPERATIONS_ERROR;
911 status = dsdb_get_extended_dn_guid(dn, p->guid);
912 if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
913 /* we got a DN without a GUID - go find the GUID */
914 int ret = dsdb_find_guid_by_dn(ldb, dn, p->guid);
915 if (ret != LDB_SUCCESS) {
916 ldb_asprintf_errstring(ldb, "Unable to find GUID for DN %s\n",
917 ldb_dn_get_linearized(dn));
920 } else if (!NT_STATUS_IS_OK(status)) {
921 return LDB_ERR_OPERATIONS_ERROR;
924 /* keep a pointer to the original ldb_val */
928 qsort(*pdn, el->num_values, sizeof((*pdn)[0]), (comparison_fn_t)parsed_dn_compare);
934 build a new extended DN, including all meta data fields
936 DELETED = 1 or missing
937 RMD_ADDTIME = originating_add_time
938 RMD_INVOCID = originating_invocation_id
939 RMD_CHANGETIME = originating_change_time
940 RMD_USN = originating_usn
941 RMD_VERSION = version
943 static int replmd_build_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct parsed_dn *p,
944 const struct GUID *invocation_id, uint64_t seq_num, time_t t)
946 struct ldb_dn *dn = p->dsdb_dn->dn;
948 const char *tstring, *usn_string;
955 const char *dnstring;
957 unix_to_nt_time(&now, t);
958 tstring = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)now);
960 return LDB_ERR_OPERATIONS_ERROR;
962 tval = data_blob_string_const(tstring);
964 usn_string = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)seq_num);
966 return LDB_ERR_OPERATIONS_ERROR;
968 usnv = data_blob_string_const(usn_string);
970 vers = data_blob_string_const("0");
972 status = GUID_to_ndr_blob(invocation_id, dn, &iid);
973 if (!NT_STATUS_IS_OK(status)) {
974 return LDB_ERR_OPERATIONS_ERROR;
977 ret = ldb_dn_set_extended_component(dn, "DELETED", NULL);
978 if (ret != LDB_SUCCESS) return ret;
979 ret = ldb_dn_set_extended_component(dn, "RMD_ADDTIME", &tval);
980 if (ret != LDB_SUCCESS) return ret;
981 ret = ldb_dn_set_extended_component(dn, "RMD_INVOCID", &iid);
982 if (ret != LDB_SUCCESS) return ret;
983 ret = ldb_dn_set_extended_component(dn, "RMD_CHANGETIME", &tval);
984 if (ret != LDB_SUCCESS) return ret;
985 ret = ldb_dn_set_extended_component(dn, "RMD_USN", &usnv);
986 if (ret != LDB_SUCCESS) return ret;
987 ret = ldb_dn_set_extended_component(dn, "RMD_VERSION", &vers);
988 if (ret != LDB_SUCCESS) return ret;
990 dnstring = dsdb_dn_get_extended_linearized(mem_ctx, p->dsdb_dn, 1);
991 if (dnstring == NULL) {
992 return LDB_ERR_OPERATIONS_ERROR;
994 *v = data_blob_string_const(dnstring);
1001 update an extended DN, including all meta data fields
1003 see replmd_build_la_val for value names
1005 static int replmd_update_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct parsed_dn *p,
1006 struct parsed_dn *old_p, const struct GUID *invocation_id,
1007 uint64_t seq_num, time_t t, bool deleted)
1009 struct ldb_dn *dn = p->dsdb_dn->dn;
1011 const char *tstring, *usn_string;
1012 struct ldb_val tval;
1014 struct ldb_val usnv;
1015 struct ldb_val vers;
1016 const struct ldb_val *old_addtime, *old_version;
1019 const char *dnstring;
1021 unix_to_nt_time(&now, t);
1022 tstring = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)now);
1024 return LDB_ERR_OPERATIONS_ERROR;
1026 tval = data_blob_string_const(tstring);
1028 usn_string = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)seq_num);
1030 return LDB_ERR_OPERATIONS_ERROR;
1032 usnv = data_blob_string_const(usn_string);
1034 status = GUID_to_ndr_blob(invocation_id, dn, &iid);
1035 if (!NT_STATUS_IS_OK(status)) {
1036 return LDB_ERR_OPERATIONS_ERROR;
1041 dv = data_blob_string_const("1");
1042 ret = ldb_dn_set_extended_component(dn, "DELETED", &dv);
1044 ret = ldb_dn_set_extended_component(dn, "DELETED", NULL);
1046 if (ret != LDB_SUCCESS) return ret;
1048 /* get the ADDTIME from the original */
1049 old_addtime = ldb_dn_get_extended_component(old_p->dsdb_dn->dn, "RMD_ADDTIME");
1050 if (old_addtime == NULL) {
1051 old_addtime = &tval;
1054 ret = ldb_dn_set_extended_component(dn, "RMD_ADDTIME", old_addtime);
1055 if (ret != LDB_SUCCESS) return ret;
1058 /* use our invocation id */
1059 ret = ldb_dn_set_extended_component(dn, "RMD_INVOCID", &iid);
1060 if (ret != LDB_SUCCESS) return ret;
1062 /* changetime is the current time */
1063 ret = ldb_dn_set_extended_component(dn, "RMD_CHANGETIME", &tval);
1064 if (ret != LDB_SUCCESS) return ret;
1066 /* update the USN */
1067 ret = ldb_dn_set_extended_component(dn, "RMD_USN", &usnv);
1068 if (ret != LDB_SUCCESS) return ret;
1070 /* increase the version by 1 */
1071 old_version = ldb_dn_get_extended_component(old_p->dsdb_dn->dn, "RMD_VERSION");
1072 if (old_version == NULL) {
1073 vers = data_blob_string_const("0");
1076 vstring = talloc_strndup(dn, (const char *)old_version->data, old_version->length);
1078 return LDB_ERR_OPERATIONS_ERROR;
1080 vstring = talloc_asprintf(dn, "%lu",
1081 (unsigned long)strtoul(vstring, NULL, 0)+1);
1082 vers = data_blob_string_const(vstring);
1084 ret = ldb_dn_set_extended_component(dn, "RMD_VERSION", &vers);
1085 if (ret != LDB_SUCCESS) return ret;
1087 dnstring = dsdb_dn_get_extended_linearized(mem_ctx, p->dsdb_dn, 1);
1088 if (dnstring == NULL) {
1089 return LDB_ERR_OPERATIONS_ERROR;
1091 *v = data_blob_string_const(dnstring);
1097 handle adding a linked attribute
1099 static int replmd_modify_la_add(struct ldb_module *module,
1100 struct ldb_message *msg,
1101 struct ldb_message_element *el,
1102 struct ldb_message_element *old_el,
1103 const struct dsdb_attribute *schema_attr,
1108 struct parsed_dn *dns, *old_dns;
1109 TALLOC_CTX *tmp_ctx = talloc_new(msg);
1111 struct ldb_val *new_values = NULL;
1112 unsigned int num_new_values = 0;
1113 unsigned old_num_values = old_el?old_el->num_values:0;
1114 const struct GUID *invocation_id;
1115 struct ldb_context *ldb = ldb_module_get_ctx(module);
1117 ret = get_parsed_dns(module, tmp_ctx, el, &dns, schema_attr->syntax->ldap_oid);
1118 if (ret != LDB_SUCCESS) {
1119 talloc_free(tmp_ctx);
1123 ret = get_parsed_dns(module, tmp_ctx, old_el, &old_dns, schema_attr->syntax->ldap_oid);
1124 if (ret != LDB_SUCCESS) {
1125 talloc_free(tmp_ctx);
1129 invocation_id = samdb_ntds_invocation_id(ldb);
1130 if (!invocation_id) {
1131 return LDB_ERR_OPERATIONS_ERROR;
1134 /* for each new value, see if it exists already with the same GUID */
1135 for (i=0; i<el->num_values; i++) {
1136 struct parsed_dn *p = parsed_dn_find(old_dns, old_num_values, dns[i].guid);
1138 /* this is a new linked attribute value */
1139 new_values = talloc_realloc(tmp_ctx, new_values, struct ldb_val, num_new_values+1);
1140 if (new_values == NULL) {
1141 ldb_module_oom(module);
1142 talloc_free(tmp_ctx);
1143 return LDB_ERR_OPERATIONS_ERROR;
1145 ret = replmd_build_la_val(new_values, &new_values[num_new_values], &dns[i],
1146 invocation_id, seq_num, t);
1147 if (ret != LDB_SUCCESS) {
1148 talloc_free(tmp_ctx);
1153 /* this is only allowed if the GUID was
1154 previously deleted. */
1155 const struct ldb_val *v;
1156 v = ldb_dn_get_extended_component(p->dsdb_dn->dn, "DELETED");
1158 ldb_asprintf_errstring(ldb, "Attribute %s already exists for target GUID %s",
1159 el->name, GUID_string(tmp_ctx, p->guid));
1160 talloc_free(tmp_ctx);
1161 return LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS;
1163 ret = replmd_update_la_val(old_el->values, p->v, &dns[i], p, invocation_id, seq_num, t, false);
1164 if (ret != LDB_SUCCESS) {
1165 talloc_free(tmp_ctx);
1171 /* add the new ones on to the end of the old values, constructing a new el->values */
1172 el->values = talloc_realloc(msg->elements, old_el?old_el->values:NULL,
1174 old_num_values+num_new_values);
1175 if (el->values == NULL) {
1176 ldb_module_oom(module);
1177 return LDB_ERR_OPERATIONS_ERROR;
1180 memcpy(&el->values[old_num_values], new_values, num_new_values*sizeof(struct ldb_val));
1181 el->num_values = old_num_values + num_new_values;
1183 talloc_steal(msg->elements, el->values);
1184 talloc_steal(el->values, new_values);
1186 talloc_free(tmp_ctx);
1188 /* we now tell the backend to replace all existing values
1189 with the one we have constructed */
1190 el->flags = LDB_FLAG_MOD_REPLACE;
1197 handle deleting all active linked attributes
1199 static int replmd_modify_la_delete(struct ldb_module *module,
1200 struct ldb_message *msg,
1201 struct ldb_message_element *el,
1202 struct ldb_message_element *old_el,
1203 const struct dsdb_attribute *schema_attr,
1208 struct parsed_dn *dns, *old_dns;
1209 TALLOC_CTX *tmp_ctx = talloc_new(msg);
1211 const struct GUID *invocation_id;
1212 struct ldb_context *ldb = ldb_module_get_ctx(module);
1214 /* check if there is nothing to delete */
1215 if ((!old_el || old_el->num_values == 0) &&
1216 el->num_values == 0) {
1220 if (!old_el || old_el->num_values == 0) {
1221 return LDB_ERR_NO_SUCH_ATTRIBUTE;
1224 ret = get_parsed_dns(module, tmp_ctx, el, &dns, schema_attr->syntax->ldap_oid);
1225 if (ret != LDB_SUCCESS) {
1226 talloc_free(tmp_ctx);
1230 ret = get_parsed_dns(module, tmp_ctx, old_el, &old_dns, schema_attr->syntax->ldap_oid);
1231 if (ret != LDB_SUCCESS) {
1232 talloc_free(tmp_ctx);
1236 invocation_id = samdb_ntds_invocation_id(ldb);
1237 if (!invocation_id) {
1238 return LDB_ERR_OPERATIONS_ERROR;
1243 /* see if we are being asked to delete any links that
1244 don't exist or are already deleted */
1245 for (i=0; i<el->num_values; i++) {
1246 struct parsed_dn *p = &dns[i];
1247 struct parsed_dn *p2;
1248 const struct ldb_val *v;
1250 p2 = parsed_dn_find(old_dns, old_el->num_values, p->guid);
1252 ldb_asprintf_errstring(ldb, "Attribute %s doesn't exist for target GUID %s",
1253 el->name, GUID_string(tmp_ctx, p->guid));
1254 return LDB_ERR_NO_SUCH_ATTRIBUTE;
1256 v = ldb_dn_get_extended_component(p2->dsdb_dn->dn, "DELETED");
1258 ldb_asprintf_errstring(ldb, "Attribute %s already deleted for target GUID %s",
1259 el->name, GUID_string(tmp_ctx, p->guid));
1260 return LDB_ERR_NO_SUCH_ATTRIBUTE;
1264 /* for each new value, see if it exists already with the same GUID
1265 if it is not already deleted and matches the delete list then delete it
1267 for (i=0; i<old_el->num_values; i++) {
1268 struct parsed_dn *p = &old_dns[i];
1269 const struct ldb_val *v;
1271 if (dns && parsed_dn_find(dns, el->num_values, p->guid) == NULL) {
1275 v = ldb_dn_get_extended_component(p->dsdb_dn->dn, "DELETED");
1276 if (v != NULL) continue;
1278 ret = replmd_update_la_val(old_el->values, p->v, p, p, invocation_id, seq_num, t, true);
1279 if (ret != LDB_SUCCESS) {
1280 talloc_free(tmp_ctx);
1285 el->values = talloc_steal(msg->elements, old_el->values);
1286 el->num_values = old_el->num_values;
1288 talloc_free(tmp_ctx);
1290 /* we now tell the backend to replace all existing values
1291 with the one we have constructed */
1292 el->flags = LDB_FLAG_MOD_REPLACE;
1298 handle replacing a linked attribute
1300 static int replmd_modify_la_replace(struct ldb_module *module,
1301 struct ldb_message *msg,
1302 struct ldb_message_element *el,
1303 struct ldb_message_element *old_el,
1304 const struct dsdb_attribute *schema_attr,
1309 struct parsed_dn *dns, *old_dns;
1310 TALLOC_CTX *tmp_ctx = talloc_new(msg);
1312 const struct GUID *invocation_id;
1313 struct ldb_context *ldb = ldb_module_get_ctx(module);
1314 struct ldb_val *new_values = NULL;
1315 uint32_t num_new_values = 0;
1316 unsigned old_num_values = old_el?old_el->num_values:0;
1318 /* check if there is nothing to replace */
1319 if ((!old_el || old_el->num_values == 0) &&
1320 el->num_values == 0) {
1324 ret = get_parsed_dns(module, tmp_ctx, el, &dns, schema_attr->syntax->ldap_oid);
1325 if (ret != LDB_SUCCESS) {
1326 talloc_free(tmp_ctx);
1330 ret = get_parsed_dns(module, tmp_ctx, old_el, &old_dns, schema_attr->syntax->ldap_oid);
1331 if (ret != LDB_SUCCESS) {
1332 talloc_free(tmp_ctx);
1336 invocation_id = samdb_ntds_invocation_id(ldb);
1337 if (!invocation_id) {
1338 return LDB_ERR_OPERATIONS_ERROR;
1341 /* mark all the old ones as deleted */
1342 for (i=0; i<old_num_values; i++) {
1343 struct parsed_dn *old_p = &old_dns[i];
1344 struct parsed_dn *p;
1345 const struct ldb_val *v;
1347 p = parsed_dn_find(dns, el->num_values, old_p->guid);
1349 /* we don't delete it if we are re-adding it */
1352 v = ldb_dn_get_extended_component(old_p->dsdb_dn->dn, "DELETED");
1355 ret = replmd_update_la_val(old_el->values, old_p->v, old_p, old_p,
1356 invocation_id, seq_num, t, true);
1357 if (ret != LDB_SUCCESS) {
1358 talloc_free(tmp_ctx);
1363 /* for each new value, either update its meta-data, or add it
1366 for (i=0; i<el->num_values; i++) {
1367 struct parsed_dn *p = &dns[i], *old_p;
1370 (old_p = parsed_dn_find(old_dns,
1371 old_num_values, p->guid)) != NULL) {
1372 /* update in place */
1373 ret = replmd_update_la_val(old_el->values, old_p->v, old_p,
1374 old_p, invocation_id,
1376 if (ret != LDB_SUCCESS) {
1377 talloc_free(tmp_ctx);
1382 new_values = talloc_realloc(tmp_ctx, new_values, struct ldb_val,
1384 if (new_values == NULL) {
1385 ldb_module_oom(module);
1386 talloc_free(tmp_ctx);
1387 return LDB_ERR_OPERATIONS_ERROR;
1389 ret = replmd_build_la_val(new_values, &new_values[num_new_values], &dns[i],
1390 invocation_id, seq_num, t);
1391 if (ret != LDB_SUCCESS) {
1392 talloc_free(tmp_ctx);
1399 /* add the new values to the end of old_el */
1400 if (num_new_values != 0) {
1401 el->values = talloc_realloc(msg->elements, old_el?old_el->values:NULL,
1402 struct ldb_val, old_num_values+num_new_values);
1403 if (el->values == NULL) {
1404 ldb_module_oom(module);
1405 return LDB_ERR_OPERATIONS_ERROR;
1407 memcpy(&el->values[old_num_values], &new_values[0],
1408 sizeof(struct ldb_val)*num_new_values);
1409 el->num_values = old_num_values + num_new_values;
1410 talloc_steal(msg->elements, new_values);
1412 el->values = old_el->values;
1413 el->num_values = old_el->num_values;
1414 talloc_steal(msg->elements, el->values);
1417 talloc_free(tmp_ctx);
1419 /* we now tell the backend to replace all existing values
1420 with the one we have constructed */
1421 el->flags = LDB_FLAG_MOD_REPLACE;
1428 handle linked attributes in modify requests
1430 static int replmd_modify_handle_linked_attribs(struct ldb_module *module,
1431 struct ldb_message *msg,
1432 uint64_t seq_num, time_t t)
1434 struct ldb_result *res;
1436 struct ldb_context *ldb = ldb_module_get_ctx(module);
1437 struct ldb_message *old_msg;
1438 struct dsdb_schema *schema = dsdb_get_schema(ldb);
1441 /* there the replmd_update_rpmd code has already
1442 * checked and saw that there are no linked
1447 #if !W2K3_LINKED_ATTRIBUTES
1451 if (dsdb_functional_level(ldb) == DS_DOMAIN_FUNCTION_2000) {
1452 /* don't do anything special for linked attributes */
1456 ret = dsdb_module_search_dn(module, msg, &res, msg->dn, NULL,
1457 DSDB_SEARCH_SHOW_DELETED |
1458 DSDB_SEARCH_REVEAL_INTERNALS |
1459 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT);
1460 if (ret != LDB_SUCCESS) {
1463 old_msg = res->msgs[0];
1465 for (i=0; i<msg->num_elements; i++) {
1466 struct ldb_message_element *el = &msg->elements[i];
1467 struct ldb_message_element *old_el, *new_el;
1468 const struct dsdb_attribute *schema_attr
1469 = dsdb_attribute_by_lDAPDisplayName(schema, el->name);
1471 ldb_asprintf_errstring(ldb,
1472 "attribute %s is not a valid attribute in schema", el->name);
1473 return LDB_ERR_OBJECT_CLASS_VIOLATION;
1475 if (schema_attr->linkID == 0) {
1478 if ((schema_attr->linkID & 1) == 1) {
1479 /* Odd is for the target. Illegal to modify */
1480 ldb_asprintf_errstring(ldb,
1481 "attribute %s must not be modified directly, it is a linked attribute", el->name);
1482 return LDB_ERR_UNWILLING_TO_PERFORM;
1484 old_el = ldb_msg_find_element(old_msg, el->name);
1485 switch (el->flags & LDB_FLAG_MOD_MASK) {
1486 case LDB_FLAG_MOD_REPLACE:
1487 ret = replmd_modify_la_replace(module, msg, el, old_el, schema_attr, seq_num, t);
1489 case LDB_FLAG_MOD_DELETE:
1490 ret = replmd_modify_la_delete(module, msg, el, old_el, schema_attr, seq_num, t);
1492 case LDB_FLAG_MOD_ADD:
1493 ret = replmd_modify_la_add(module, msg, el, old_el, schema_attr, seq_num, t);
1496 ldb_asprintf_errstring(ldb,
1497 "invalid flags 0x%x for %s linked attribute",
1498 el->flags, el->name);
1499 return LDB_ERR_UNWILLING_TO_PERFORM;
1501 if (ret != LDB_SUCCESS) {
1505 ldb_msg_remove_attr(old_msg, el->name);
1507 ldb_msg_add_empty(old_msg, el->name, 0, &new_el);
1508 new_el->num_values = el->num_values;
1509 new_el->values = el->values;
1511 /* TODO: this relises a bit too heavily on the exact
1512 behaviour of ldb_msg_find_element and
1513 ldb_msg_remove_element */
1514 old_el = ldb_msg_find_element(msg, el->name);
1516 ldb_msg_remove_element(msg, old_el);
1527 static int replmd_modify(struct ldb_module *module, struct ldb_request *req)
1529 struct ldb_context *ldb;
1530 struct replmd_replicated_request *ac;
1531 struct ldb_request *down_req;
1532 struct ldb_message *msg;
1533 time_t t = time(NULL);
1536 /* do not manipulate our control entries */
1537 if (ldb_dn_is_special(req->op.mod.message->dn)) {
1538 return ldb_next_request(module, req);
1541 ldb = ldb_module_get_ctx(module);
1543 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_modify\n");
1545 ac = replmd_ctx_init(module, req);
1547 return LDB_ERR_OPERATIONS_ERROR;
1550 /* we have to copy the message as the caller might have it as a const */
1551 msg = ldb_msg_copy_shallow(ac, req->op.mod.message);
1555 return LDB_ERR_OPERATIONS_ERROR;
1558 ret = replmd_update_rpmd(module, ac->schema, msg, &ac->seq_num, t);
1559 if (ret != LDB_SUCCESS) {
1564 ret = replmd_modify_handle_linked_attribs(module, msg, ac->seq_num, t);
1565 if (ret != LDB_SUCCESS) {
1571 * - replace the old object with the newly constructed one
1574 ret = ldb_build_mod_req(&down_req, ldb, ac,
1577 ac, replmd_op_callback,
1579 if (ret != LDB_SUCCESS) {
1583 talloc_steal(down_req, msg);
1585 /* we only change whenChanged and uSNChanged if the seq_num
1587 if (ac->seq_num != 0) {
1588 if (add_time_element(msg, "whenChanged", t) != LDB_SUCCESS) {
1593 if (add_uint64_element(msg, "uSNChanged", ac->seq_num) != LDB_SUCCESS) {
1599 /* go on with the call chain */
1600 return ldb_next_request(module, down_req);
1603 static int replmd_rename_callback(struct ldb_request *req, struct ldb_reply *ares);
1606 handle a rename request
1608 On a rename we need to do an extra ldb_modify which sets the
1609 whenChanged and uSNChanged attributes. We do this in a callback after the success.
1611 static int replmd_rename(struct ldb_module *module, struct ldb_request *req)
1613 struct ldb_context *ldb;
1614 struct replmd_replicated_request *ac;
1616 struct ldb_request *down_req;
1618 /* do not manipulate our control entries */
1619 if (ldb_dn_is_special(req->op.mod.message->dn)) {
1620 return ldb_next_request(module, req);
1623 ldb = ldb_module_get_ctx(module);
1625 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_rename\n");
1627 ac = replmd_ctx_init(module, req);
1629 return LDB_ERR_OPERATIONS_ERROR;
1631 ret = ldb_build_rename_req(&down_req, ldb, ac,
1632 ac->req->op.rename.olddn,
1633 ac->req->op.rename.newdn,
1635 ac, replmd_rename_callback,
1638 if (ret != LDB_SUCCESS) {
1643 /* go on with the call chain */
1644 return ldb_next_request(module, down_req);
1647 /* After the rename is compleated, update the whenchanged etc */
1648 static int replmd_rename_callback(struct ldb_request *req, struct ldb_reply *ares)
1650 struct ldb_context *ldb;
1651 struct replmd_replicated_request *ac;
1652 struct ldb_request *down_req;
1653 struct ldb_message *msg;
1654 time_t t = time(NULL);
1657 ac = talloc_get_type(req->context, struct replmd_replicated_request);
1658 ldb = ldb_module_get_ctx(ac->module);
1660 if (ares->error != LDB_SUCCESS) {
1661 return ldb_module_done(ac->req, ares->controls,
1662 ares->response, ares->error);
1665 if (ares->type != LDB_REPLY_DONE) {
1666 ldb_set_errstring(ldb,
1667 "invalid ldb_reply_type in callback");
1669 return ldb_module_done(ac->req, NULL, NULL,
1670 LDB_ERR_OPERATIONS_ERROR);
1673 /* Get a sequence number from the backend */
1674 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &ac->seq_num);
1675 if (ret != LDB_SUCCESS) {
1680 * - replace the old object with the newly constructed one
1683 msg = ldb_msg_new(ac);
1686 return LDB_ERR_OPERATIONS_ERROR;
1689 msg->dn = ac->req->op.rename.newdn;
1691 ret = ldb_build_mod_req(&down_req, ldb, ac,
1694 ac, replmd_op_callback,
1697 if (ret != LDB_SUCCESS) {
1701 talloc_steal(down_req, msg);
1703 if (add_time_element(msg, "whenChanged", t) != LDB_SUCCESS) {
1708 if (add_uint64_element(msg, "uSNChanged", ac->seq_num) != LDB_SUCCESS) {
1713 /* go on with the call chain - do the modify after the rename */
1714 return ldb_next_request(ac->module, down_req);
1718 static int replmd_replicated_request_error(struct replmd_replicated_request *ar, int ret)
1723 static int replmd_replicated_request_werror(struct replmd_replicated_request *ar, WERROR status)
1725 int ret = LDB_ERR_OTHER;
1726 /* TODO: do some error mapping */
1730 static int replmd_replicated_apply_add(struct replmd_replicated_request *ar)
1732 struct ldb_context *ldb;
1733 struct ldb_request *change_req;
1734 enum ndr_err_code ndr_err;
1735 struct ldb_message *msg;
1736 struct replPropertyMetaDataBlob *md;
1737 struct ldb_val md_value;
1742 * TODO: check if the parent object exist
1746 * TODO: handle the conflict case where an object with the
1750 ldb = ldb_module_get_ctx(ar->module);
1751 msg = ar->objs->objects[ar->index_current].msg;
1752 md = ar->objs->objects[ar->index_current].meta_data;
1754 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &ar->seq_num);
1755 if (ret != LDB_SUCCESS) {
1756 return replmd_replicated_request_error(ar, ret);
1759 ret = ldb_msg_add_value(msg, "objectGUID", &ar->objs->objects[ar->index_current].guid_value, NULL);
1760 if (ret != LDB_SUCCESS) {
1761 return replmd_replicated_request_error(ar, ret);
1764 ret = ldb_msg_add_string(msg, "whenChanged", ar->objs->objects[ar->index_current].when_changed);
1765 if (ret != LDB_SUCCESS) {
1766 return replmd_replicated_request_error(ar, ret);
1769 ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNCreated", ar->seq_num);
1770 if (ret != LDB_SUCCESS) {
1771 return replmd_replicated_request_error(ar, ret);
1774 ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNChanged", ar->seq_num);
1775 if (ret != LDB_SUCCESS) {
1776 return replmd_replicated_request_error(ar, ret);
1779 /* remove any message elements that have zero values */
1780 for (i=0; i<msg->num_elements; i++) {
1781 if (msg->elements[i].num_values == 0) {
1782 DEBUG(4,(__location__ ": Removing attribute %s with num_values==0\n",
1783 msg->elements[i].name));
1784 memmove(&msg->elements[i],
1785 &msg->elements[i+1],
1786 sizeof(msg->elements[i])*(msg->num_elements - (i+1)));
1787 msg->num_elements--;
1793 * the meta data array is already sorted by the caller
1795 for (i=0; i < md->ctr.ctr1.count; i++) {
1796 md->ctr.ctr1.array[i].local_usn = ar->seq_num;
1798 ndr_err = ndr_push_struct_blob(&md_value, msg,
1799 lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")),
1801 (ndr_push_flags_fn_t)ndr_push_replPropertyMetaDataBlob);
1802 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1803 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
1804 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
1806 ret = ldb_msg_add_value(msg, "replPropertyMetaData", &md_value, NULL);
1807 if (ret != LDB_SUCCESS) {
1808 return replmd_replicated_request_error(ar, ret);
1811 replmd_ldb_message_sort(msg, ar->schema);
1814 char *s = ldb_ldif_message_string(ldb, ar, LDB_CHANGETYPE_ADD, msg);
1815 DEBUG(4, ("DRS replication add message:\n%s\n", s));
1819 ret = ldb_build_add_req(&change_req,
1827 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
1829 return ldb_next_request(ar->module, change_req);
1832 static int replmd_replPropertyMetaData1_conflict_compare(struct replPropertyMetaData1 *m1,
1833 struct replPropertyMetaData1 *m2)
1837 if (m1->version != m2->version) {
1838 return m1->version - m2->version;
1841 if (m1->originating_change_time != m2->originating_change_time) {
1842 return m1->originating_change_time - m2->originating_change_time;
1845 ret = GUID_compare(&m1->originating_invocation_id, &m2->originating_invocation_id);
1850 return m1->originating_usn - m2->originating_usn;
1853 static int replmd_replicated_apply_merge(struct replmd_replicated_request *ar)
1855 struct ldb_context *ldb;
1856 struct ldb_request *change_req;
1857 enum ndr_err_code ndr_err;
1858 struct ldb_message *msg;
1859 struct replPropertyMetaDataBlob *rmd;
1860 struct replPropertyMetaDataBlob omd;
1861 const struct ldb_val *omd_value;
1862 struct replPropertyMetaDataBlob nmd;
1863 struct ldb_val nmd_value;
1865 uint32_t removed_attrs = 0;
1868 ldb = ldb_module_get_ctx(ar->module);
1869 msg = ar->objs->objects[ar->index_current].msg;
1870 rmd = ar->objs->objects[ar->index_current].meta_data;
1875 * TODO: check repl data is correct after a rename
1877 if (ldb_dn_compare(msg->dn, ar->search_msg->dn) != 0) {
1878 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_replicated_request rename %s => %s\n",
1879 ldb_dn_get_linearized(ar->search_msg->dn),
1880 ldb_dn_get_linearized(msg->dn));
1881 if (ldb_rename(ldb, ar->search_msg->dn, msg->dn) != LDB_SUCCESS) {
1882 ldb_debug(ldb, LDB_DEBUG_FATAL, "replmd_replicated_request rename %s => %s failed - %s\n",
1883 ldb_dn_get_linearized(ar->search_msg->dn),
1884 ldb_dn_get_linearized(msg->dn),
1885 ldb_errstring(ldb));
1886 return replmd_replicated_request_werror(ar, WERR_DS_DRA_DB_ERROR);
1890 /* find existing meta data */
1891 omd_value = ldb_msg_find_ldb_val(ar->search_msg, "replPropertyMetaData");
1893 ndr_err = ndr_pull_struct_blob(omd_value, ar,
1894 lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")), &omd,
1895 (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
1896 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1897 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
1898 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
1901 if (omd.version != 1) {
1902 return replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
1908 nmd.ctr.ctr1.count = omd.ctr.ctr1.count + rmd->ctr.ctr1.count;
1909 nmd.ctr.ctr1.array = talloc_array(ar,
1910 struct replPropertyMetaData1,
1911 nmd.ctr.ctr1.count);
1912 if (!nmd.ctr.ctr1.array) return replmd_replicated_request_werror(ar, WERR_NOMEM);
1914 /* first copy the old meta data */
1915 for (i=0; i < omd.ctr.ctr1.count; i++) {
1916 nmd.ctr.ctr1.array[ni] = omd.ctr.ctr1.array[i];
1920 /* now merge in the new meta data */
1921 for (i=0; i < rmd->ctr.ctr1.count; i++) {
1924 for (j=0; j < ni; j++) {
1927 if (rmd->ctr.ctr1.array[i].attid != nmd.ctr.ctr1.array[j].attid) {
1931 cmp = replmd_replPropertyMetaData1_conflict_compare(&rmd->ctr.ctr1.array[i],
1932 &nmd.ctr.ctr1.array[j]);
1934 /* replace the entry */
1935 nmd.ctr.ctr1.array[j] = rmd->ctr.ctr1.array[i];
1940 /* we don't want to apply this change so remove the attribute */
1941 ldb_msg_remove_element(msg, &msg->elements[i-removed_attrs]);
1948 if (found) continue;
1950 nmd.ctr.ctr1.array[ni] = rmd->ctr.ctr1.array[i];
1955 * finally correct the size of the meta_data array
1957 nmd.ctr.ctr1.count = ni;
1960 * the rdn attribute (the alias for the name attribute),
1961 * 'cn' for most objects is the last entry in the meta data array
1964 * sort the new meta data array
1966 ret = replmd_replPropertyMetaDataCtr1_sort(&nmd.ctr.ctr1, ar->schema, msg->dn);
1967 if (ret != LDB_SUCCESS) {
1972 * check if some replicated attributes left, otherwise skip the ldb_modify() call
1974 if (msg->num_elements == 0) {
1975 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_replicated_apply_merge[%u]: skip replace\n",
1978 ar->index_current++;
1979 return replmd_replicated_apply_next(ar);
1982 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_replicated_apply_merge[%u]: replace %u attributes\n",
1983 ar->index_current, msg->num_elements);
1985 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &ar->seq_num);
1986 if (ret != LDB_SUCCESS) {
1987 return replmd_replicated_request_error(ar, ret);
1990 for (i=0; i<ni; i++) {
1991 nmd.ctr.ctr1.array[i].local_usn = ar->seq_num;
1994 /* create the meta data value */
1995 ndr_err = ndr_push_struct_blob(&nmd_value, msg,
1996 lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")),
1998 (ndr_push_flags_fn_t)ndr_push_replPropertyMetaDataBlob);
1999 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
2000 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
2001 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
2005 * when we know that we'll modify the record, add the whenChanged, uSNChanged
2006 * and replPopertyMetaData attributes
2008 ret = ldb_msg_add_string(msg, "whenChanged", ar->objs->objects[ar->index_current].when_changed);
2009 if (ret != LDB_SUCCESS) {
2010 return replmd_replicated_request_error(ar, ret);
2012 ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNChanged", ar->seq_num);
2013 if (ret != LDB_SUCCESS) {
2014 return replmd_replicated_request_error(ar, ret);
2016 ret = ldb_msg_add_value(msg, "replPropertyMetaData", &nmd_value, NULL);
2017 if (ret != LDB_SUCCESS) {
2018 return replmd_replicated_request_error(ar, ret);
2021 replmd_ldb_message_sort(msg, ar->schema);
2023 /* we want to replace the old values */
2024 for (i=0; i < msg->num_elements; i++) {
2025 msg->elements[i].flags = LDB_FLAG_MOD_REPLACE;
2029 char *s = ldb_ldif_message_string(ldb, ar, LDB_CHANGETYPE_MODIFY, msg);
2030 DEBUG(4, ("DRS replication modify message:\n%s\n", s));
2034 ret = ldb_build_mod_req(&change_req,
2042 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
2044 return ldb_next_request(ar->module, change_req);
2047 static int replmd_replicated_apply_search_callback(struct ldb_request *req,
2048 struct ldb_reply *ares)
2050 struct replmd_replicated_request *ar = talloc_get_type(req->context,
2051 struct replmd_replicated_request);
2055 return ldb_module_done(ar->req, NULL, NULL,
2056 LDB_ERR_OPERATIONS_ERROR);
2058 if (ares->error != LDB_SUCCESS &&
2059 ares->error != LDB_ERR_NO_SUCH_OBJECT) {
2060 return ldb_module_done(ar->req, ares->controls,
2061 ares->response, ares->error);
2064 switch (ares->type) {
2065 case LDB_REPLY_ENTRY:
2066 ar->search_msg = talloc_steal(ar, ares->message);
2069 case LDB_REPLY_REFERRAL:
2070 /* we ignore referrals */
2073 case LDB_REPLY_DONE:
2074 if (ar->search_msg != NULL) {
2075 ret = replmd_replicated_apply_merge(ar);
2077 ret = replmd_replicated_apply_add(ar);
2079 if (ret != LDB_SUCCESS) {
2080 return ldb_module_done(ar->req, NULL, NULL, ret);
2088 static int replmd_replicated_uptodate_vector(struct replmd_replicated_request *ar);
2090 static int replmd_replicated_apply_next(struct replmd_replicated_request *ar)
2092 struct ldb_context *ldb;
2096 struct ldb_request *search_req;
2097 struct ldb_search_options_control *options;
2099 if (ar->index_current >= ar->objs->num_objects) {
2100 /* done with it, go to next stage */
2101 return replmd_replicated_uptodate_vector(ar);
2104 ldb = ldb_module_get_ctx(ar->module);
2105 ar->search_msg = NULL;
2107 tmp_str = ldb_binary_encode(ar, ar->objs->objects[ar->index_current].guid_value);
2108 if (!tmp_str) return replmd_replicated_request_werror(ar, WERR_NOMEM);
2110 filter = talloc_asprintf(ar, "(objectGUID=%s)", tmp_str);
2111 if (!filter) return replmd_replicated_request_werror(ar, WERR_NOMEM);
2112 talloc_free(tmp_str);
2114 ret = ldb_build_search_req(&search_req,
2123 replmd_replicated_apply_search_callback,
2126 ret = ldb_request_add_control(search_req, LDB_CONTROL_SHOW_DELETED_OID, true, NULL);
2127 if (ret != LDB_SUCCESS) {
2131 /* we need to cope with cross-partition links, so search for
2132 the GUID over all partitions */
2133 options = talloc(search_req, struct ldb_search_options_control);
2134 if (options == NULL) {
2135 DEBUG(0, (__location__ ": out of memory\n"));
2136 return LDB_ERR_OPERATIONS_ERROR;
2138 options->search_options = LDB_SEARCH_OPTION_PHANTOM_ROOT;
2140 ret = ldb_request_add_control(search_req,
2141 LDB_CONTROL_SEARCH_OPTIONS_OID,
2143 if (ret != LDB_SUCCESS) {
2147 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
2149 return ldb_next_request(ar->module, search_req);
2152 static int replmd_replicated_uptodate_modify_callback(struct ldb_request *req,
2153 struct ldb_reply *ares)
2155 struct ldb_context *ldb;
2156 struct replmd_replicated_request *ar = talloc_get_type(req->context,
2157 struct replmd_replicated_request);
2158 ldb = ldb_module_get_ctx(ar->module);
2161 return ldb_module_done(ar->req, NULL, NULL,
2162 LDB_ERR_OPERATIONS_ERROR);
2164 if (ares->error != LDB_SUCCESS) {
2165 return ldb_module_done(ar->req, ares->controls,
2166 ares->response, ares->error);
2169 if (ares->type != LDB_REPLY_DONE) {
2170 ldb_set_errstring(ldb, "Invalid reply type\n!");
2171 return ldb_module_done(ar->req, NULL, NULL,
2172 LDB_ERR_OPERATIONS_ERROR);
2177 return ldb_module_done(ar->req, NULL, NULL, LDB_SUCCESS);
2180 static int replmd_replicated_uptodate_modify(struct replmd_replicated_request *ar)
2182 struct ldb_context *ldb;
2183 struct ldb_request *change_req;
2184 enum ndr_err_code ndr_err;
2185 struct ldb_message *msg;
2186 struct replUpToDateVectorBlob ouv;
2187 const struct ldb_val *ouv_value;
2188 const struct drsuapi_DsReplicaCursor2CtrEx *ruv;
2189 struct replUpToDateVectorBlob nuv;
2190 struct ldb_val nuv_value;
2191 struct ldb_message_element *nuv_el = NULL;
2192 const struct GUID *our_invocation_id;
2193 struct ldb_message_element *orf_el = NULL;
2194 struct repsFromToBlob nrf;
2195 struct ldb_val *nrf_value = NULL;
2196 struct ldb_message_element *nrf_el = NULL;
2199 time_t t = time(NULL);
2203 ldb = ldb_module_get_ctx(ar->module);
2204 ruv = ar->objs->uptodateness_vector;
2210 unix_to_nt_time(&now, t);
2213 * first create the new replUpToDateVector
2215 ouv_value = ldb_msg_find_ldb_val(ar->search_msg, "replUpToDateVector");
2217 ndr_err = ndr_pull_struct_blob(ouv_value, ar,
2218 lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")), &ouv,
2219 (ndr_pull_flags_fn_t)ndr_pull_replUpToDateVectorBlob);
2220 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
2221 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
2222 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
2225 if (ouv.version != 2) {
2226 return replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
2231 * the new uptodateness vector will at least
2232 * contain 1 entry, one for the source_dsa
2234 * plus optional values from our old vector and the one from the source_dsa
2236 nuv.ctr.ctr2.count = 1 + ouv.ctr.ctr2.count;
2237 if (ruv) nuv.ctr.ctr2.count += ruv->count;
2238 nuv.ctr.ctr2.cursors = talloc_array(ar,
2239 struct drsuapi_DsReplicaCursor2,
2240 nuv.ctr.ctr2.count);
2241 if (!nuv.ctr.ctr2.cursors) return replmd_replicated_request_werror(ar, WERR_NOMEM);
2243 /* first copy the old vector */
2244 for (i=0; i < ouv.ctr.ctr2.count; i++) {
2245 nuv.ctr.ctr2.cursors[ni] = ouv.ctr.ctr2.cursors[i];
2249 /* get our invocation_id if we have one already attached to the ldb */
2250 our_invocation_id = samdb_ntds_invocation_id(ldb);
2252 /* merge in the source_dsa vector is available */
2253 for (i=0; (ruv && i < ruv->count); i++) {
2256 if (our_invocation_id &&
2257 GUID_equal(&ruv->cursors[i].source_dsa_invocation_id,
2258 our_invocation_id)) {
2262 for (j=0; j < ni; j++) {
2263 if (!GUID_equal(&ruv->cursors[i].source_dsa_invocation_id,
2264 &nuv.ctr.ctr2.cursors[j].source_dsa_invocation_id)) {
2271 * we update only the highest_usn and not the latest_sync_success time,
2272 * because the last success stands for direct replication
2274 if (ruv->cursors[i].highest_usn > nuv.ctr.ctr2.cursors[j].highest_usn) {
2275 nuv.ctr.ctr2.cursors[j].highest_usn = ruv->cursors[i].highest_usn;
2280 if (found) continue;
2282 /* if it's not there yet, add it */
2283 nuv.ctr.ctr2.cursors[ni] = ruv->cursors[i];
2288 * merge in the current highwatermark for the source_dsa
2291 for (j=0; j < ni; j++) {
2292 if (!GUID_equal(&ar->objs->source_dsa->source_dsa_invocation_id,
2293 &nuv.ctr.ctr2.cursors[j].source_dsa_invocation_id)) {
2300 * here we update the highest_usn and last_sync_success time
2301 * because we're directly replicating from the source_dsa
2303 * and use the tmp_highest_usn because this is what we have just applied
2306 nuv.ctr.ctr2.cursors[j].highest_usn = ar->objs->source_dsa->highwatermark.tmp_highest_usn;
2307 nuv.ctr.ctr2.cursors[j].last_sync_success = now;
2312 * here we update the highest_usn and last_sync_success time
2313 * because we're directly replicating from the source_dsa
2315 * and use the tmp_highest_usn because this is what we have just applied
2318 nuv.ctr.ctr2.cursors[ni].source_dsa_invocation_id= ar->objs->source_dsa->source_dsa_invocation_id;
2319 nuv.ctr.ctr2.cursors[ni].highest_usn = ar->objs->source_dsa->highwatermark.tmp_highest_usn;
2320 nuv.ctr.ctr2.cursors[ni].last_sync_success = now;
2325 * finally correct the size of the cursors array
2327 nuv.ctr.ctr2.count = ni;
2332 qsort(nuv.ctr.ctr2.cursors, nuv.ctr.ctr2.count,
2333 sizeof(struct drsuapi_DsReplicaCursor2),
2334 (comparison_fn_t)drsuapi_DsReplicaCursor2_compare);
2337 * create the change ldb_message
2339 msg = ldb_msg_new(ar);
2340 if (!msg) return replmd_replicated_request_werror(ar, WERR_NOMEM);
2341 msg->dn = ar->search_msg->dn;
2343 ndr_err = ndr_push_struct_blob(&nuv_value, msg,
2344 lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")),
2346 (ndr_push_flags_fn_t)ndr_push_replUpToDateVectorBlob);
2347 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
2348 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
2349 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
2351 ret = ldb_msg_add_value(msg, "replUpToDateVector", &nuv_value, &nuv_el);
2352 if (ret != LDB_SUCCESS) {
2353 return replmd_replicated_request_error(ar, ret);
2355 nuv_el->flags = LDB_FLAG_MOD_REPLACE;
2358 * now create the new repsFrom value from the given repsFromTo1 structure
2362 nrf.ctr.ctr1 = *ar->objs->source_dsa;
2363 /* and fix some values... */
2364 nrf.ctr.ctr1.consecutive_sync_failures = 0;
2365 nrf.ctr.ctr1.last_success = now;
2366 nrf.ctr.ctr1.last_attempt = now;
2367 nrf.ctr.ctr1.result_last_attempt = WERR_OK;
2368 nrf.ctr.ctr1.highwatermark.highest_usn = nrf.ctr.ctr1.highwatermark.tmp_highest_usn;
2371 * first see if we already have a repsFrom value for the current source dsa
2372 * if so we'll later replace this value
2374 orf_el = ldb_msg_find_element(ar->search_msg, "repsFrom");
2376 for (i=0; i < orf_el->num_values; i++) {
2377 struct repsFromToBlob *trf;
2379 trf = talloc(ar, struct repsFromToBlob);
2380 if (!trf) return replmd_replicated_request_werror(ar, WERR_NOMEM);
2382 ndr_err = ndr_pull_struct_blob(&orf_el->values[i], trf, lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")), trf,
2383 (ndr_pull_flags_fn_t)ndr_pull_repsFromToBlob);
2384 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
2385 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
2386 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
2389 if (trf->version != 1) {
2390 return replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
2394 * we compare the source dsa objectGUID not the invocation_id
2395 * because we want only one repsFrom value per source dsa
2396 * and when the invocation_id of the source dsa has changed we don't need
2397 * the old repsFrom with the old invocation_id
2399 if (!GUID_equal(&trf->ctr.ctr1.source_dsa_obj_guid,
2400 &ar->objs->source_dsa->source_dsa_obj_guid)) {
2406 nrf_value = &orf_el->values[i];
2411 * copy over all old values to the new ldb_message
2413 ret = ldb_msg_add_empty(msg, "repsFrom", 0, &nrf_el);
2414 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
2419 * if we haven't found an old repsFrom value for the current source dsa
2420 * we'll add a new value
2423 struct ldb_val zero_value;
2424 ZERO_STRUCT(zero_value);
2425 ret = ldb_msg_add_value(msg, "repsFrom", &zero_value, &nrf_el);
2426 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
2428 nrf_value = &nrf_el->values[nrf_el->num_values - 1];
2431 /* we now fill the value which is already attached to ldb_message */
2432 ndr_err = ndr_push_struct_blob(nrf_value, msg,
2433 lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")),
2435 (ndr_push_flags_fn_t)ndr_push_repsFromToBlob);
2436 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
2437 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
2438 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
2442 * the ldb_message_element for the attribute, has all the old values and the new one
2443 * so we'll replace the whole attribute with all values
2445 nrf_el->flags = LDB_FLAG_MOD_REPLACE;
2448 char *s = ldb_ldif_message_string(ldb, ar, LDB_CHANGETYPE_MODIFY, msg);
2449 DEBUG(4, ("DRS replication uptodate modify message:\n%s\n", s));
2453 /* prepare the ldb_modify() request */
2454 ret = ldb_build_mod_req(&change_req,
2460 replmd_replicated_uptodate_modify_callback,
2462 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
2464 return ldb_next_request(ar->module, change_req);
2467 static int replmd_replicated_uptodate_search_callback(struct ldb_request *req,
2468 struct ldb_reply *ares)
2470 struct replmd_replicated_request *ar = talloc_get_type(req->context,
2471 struct replmd_replicated_request);
2475 return ldb_module_done(ar->req, NULL, NULL,
2476 LDB_ERR_OPERATIONS_ERROR);
2478 if (ares->error != LDB_SUCCESS &&
2479 ares->error != LDB_ERR_NO_SUCH_OBJECT) {
2480 return ldb_module_done(ar->req, ares->controls,
2481 ares->response, ares->error);
2484 switch (ares->type) {
2485 case LDB_REPLY_ENTRY:
2486 ar->search_msg = talloc_steal(ar, ares->message);
2489 case LDB_REPLY_REFERRAL:
2490 /* we ignore referrals */
2493 case LDB_REPLY_DONE:
2494 if (ar->search_msg == NULL) {
2495 ret = replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
2497 ret = replmd_replicated_uptodate_modify(ar);
2499 if (ret != LDB_SUCCESS) {
2500 return ldb_module_done(ar->req, NULL, NULL, ret);
2509 static int replmd_replicated_uptodate_vector(struct replmd_replicated_request *ar)
2511 struct ldb_context *ldb;
2513 static const char *attrs[] = {
2514 "replUpToDateVector",
2518 struct ldb_request *search_req;
2520 ldb = ldb_module_get_ctx(ar->module);
2521 ar->search_msg = NULL;
2523 ret = ldb_build_search_req(&search_req,
2526 ar->objs->partition_dn,
2532 replmd_replicated_uptodate_search_callback,
2534 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
2536 return ldb_next_request(ar->module, search_req);
2541 static int replmd_extended_replicated_objects(struct ldb_module *module, struct ldb_request *req)
2543 struct ldb_context *ldb;
2544 struct dsdb_extended_replicated_objects *objs;
2545 struct replmd_replicated_request *ar;
2546 struct ldb_control **ctrls;
2548 struct replmd_private *replmd_private =
2549 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
2551 ldb = ldb_module_get_ctx(module);
2553 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_extended_replicated_objects\n");
2555 objs = talloc_get_type(req->op.extended.data, struct dsdb_extended_replicated_objects);
2557 ldb_debug(ldb, LDB_DEBUG_FATAL, "replmd_extended_replicated_objects: invalid extended data\n");
2558 return LDB_ERR_PROTOCOL_ERROR;
2561 if (objs->version != DSDB_EXTENDED_REPLICATED_OBJECTS_VERSION) {
2562 ldb_debug(ldb, LDB_DEBUG_FATAL, "replmd_extended_replicated_objects: extended data invalid version [%u != %u]\n",
2563 objs->version, DSDB_EXTENDED_REPLICATED_OBJECTS_VERSION);
2564 return LDB_ERR_PROTOCOL_ERROR;
2567 ar = replmd_ctx_init(module, req);
2569 return LDB_ERR_OPERATIONS_ERROR;
2571 /* Set the flags to have the replmd_op_callback run over the full set of objects */
2572 ar->apply_mode = true;
2574 ar->schema = dsdb_get_schema(ldb);
2576 ldb_debug_set(ldb, LDB_DEBUG_FATAL, "replmd_ctx_init: no loaded schema found\n");
2578 DEBUG(0,(__location__ ": %s\n", ldb_errstring(ldb)));
2579 return LDB_ERR_CONSTRAINT_VIOLATION;
2582 ctrls = req->controls;
2584 if (req->controls) {
2585 req->controls = talloc_memdup(ar, req->controls,
2586 talloc_get_size(req->controls));
2587 if (!req->controls) return replmd_replicated_request_werror(ar, WERR_NOMEM);
2590 ret = ldb_request_add_control(req, DSDB_CONTROL_REPLICATED_UPDATE_OID, false, NULL);
2591 if (ret != LDB_SUCCESS) {
2595 ar->controls = req->controls;
2596 req->controls = ctrls;
2598 DEBUG(4,("linked_attributes_count=%u\n", objs->linked_attributes_count));
2600 /* save away the linked attributes for the end of the
2602 for (i=0; i<ar->objs->linked_attributes_count; i++) {
2603 struct la_entry *la_entry;
2605 if (replmd_private->la_ctx == NULL) {
2606 replmd_private->la_ctx = talloc_new(replmd_private);
2608 la_entry = talloc(replmd_private->la_ctx, struct la_entry);
2609 if (la_entry == NULL) {
2611 return LDB_ERR_OPERATIONS_ERROR;
2613 la_entry->la = talloc(la_entry, struct drsuapi_DsReplicaLinkedAttribute);
2614 if (la_entry->la == NULL) {
2615 talloc_free(la_entry);
2617 return LDB_ERR_OPERATIONS_ERROR;
2619 *la_entry->la = ar->objs->linked_attributes[i];
2621 /* we need to steal the non-scalars so they stay
2622 around until the end of the transaction */
2623 talloc_steal(la_entry->la, la_entry->la->identifier);
2624 talloc_steal(la_entry->la, la_entry->la->value.blob);
2626 DLIST_ADD(replmd_private->la_list, la_entry);
2629 return replmd_replicated_apply_next(ar);
2633 process one linked attribute structure
2635 static int replmd_process_linked_attribute(struct ldb_module *module,
2636 struct la_entry *la_entry)
2638 struct drsuapi_DsReplicaLinkedAttribute *la = la_entry->la;
2639 struct ldb_context *ldb = ldb_module_get_ctx(module);
2640 struct dsdb_schema *schema = dsdb_get_schema(ldb);
2641 struct drsuapi_DsReplicaObjectIdentifier3 target;
2642 struct ldb_message *msg;
2643 TALLOC_CTX *tmp_ctx = talloc_new(la_entry);
2644 struct ldb_request *mod_req;
2646 const struct dsdb_attribute *attr;
2647 struct ldb_dn *target_dn;
2648 struct dsdb_dn *dsdb_dn;
2649 uint64_t seq_num = 0;
2650 struct drsuapi_DsReplicaAttribute drs;
2651 struct drsuapi_DsAttributeValue val;
2652 struct ldb_message_element el;
2653 const struct ldb_val *guid;
2655 time_t t = time(NULL);
2657 drs.value_ctr.num_values = 1;
2658 drs.value_ctr.values = &val;
2659 val.blob = la->value.blob;
2662 linked_attributes[0]:
2663 &objs->linked_attributes[i]: struct drsuapi_DsReplicaLinkedAttribute
2665 identifier: struct drsuapi_DsReplicaObjectIdentifier
2666 __ndr_size : 0x0000003a (58)
2667 __ndr_size_sid : 0x00000000 (0)
2668 guid : 8e95b6a9-13dd-4158-89db-3220a5be5cc7
2670 __ndr_size_dn : 0x00000000 (0)
2672 attid : DRSUAPI_ATTRIBUTE_member (0x1F)
2673 value: struct drsuapi_DsAttributeValue
2674 __ndr_size : 0x0000007e (126)
2676 blob : DATA_BLOB length=126
2677 flags : 0x00000001 (1)
2678 1: DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE
2679 originating_add_time : Wed Sep 2 22:20:01 2009 EST
2680 meta_data: struct drsuapi_DsReplicaMetaData
2681 version : 0x00000015 (21)
2682 originating_change_time : Wed Sep 2 23:39:07 2009 EST
2683 originating_invocation_id: 794640f3-18cf-40ee-a211-a93992b67a64
2684 originating_usn : 0x000000000001e19c (123292)
2686 (for cases where the link is to a normal DN)
2687 &target: struct drsuapi_DsReplicaObjectIdentifier3
2688 __ndr_size : 0x0000007e (126)
2689 __ndr_size_sid : 0x0000001c (28)
2690 guid : 7639e594-db75-4086-b0d4-67890ae46031
2691 sid : S-1-5-21-2848215498-2472035911-1947525656-19924
2692 __ndr_size_dn : 0x00000022 (34)
2693 dn : 'CN=UOne,OU=TestOU,DC=vsofs8,DC=com'
2696 /* find the attribute being modified */
2697 attr = dsdb_attribute_by_attributeID_id(schema, la->attid);
2699 DEBUG(0, (__location__ ": Unable to find attributeID 0x%x\n", la->attid));
2700 talloc_free(tmp_ctx);
2701 return LDB_ERR_OPERATIONS_ERROR;
2704 status = attr->syntax->drsuapi_to_ldb(ldb, schema, attr, &drs, tmp_ctx, &el);
2706 /* construct a modify request for this attribute change */
2707 msg = ldb_msg_new(tmp_ctx);
2710 talloc_free(tmp_ctx);
2711 return LDB_ERR_OPERATIONS_ERROR;
2714 ret = dsdb_find_dn_by_guid(ldb, tmp_ctx,
2715 GUID_string(tmp_ctx, &la->identifier->guid), &msg->dn);
2716 if (ret != LDB_SUCCESS) {
2717 talloc_free(tmp_ctx);
2721 el.name = attr->lDAPDisplayName;
2722 if (la->flags & DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE) {
2723 ret = ldb_msg_add(msg, &el, LDB_FLAG_MOD_ADD);
2725 ret = ldb_msg_add(msg, &el, LDB_FLAG_MOD_DELETE);
2727 if (ret != LDB_SUCCESS) {
2728 talloc_free(tmp_ctx);
2732 dsdb_dn = dsdb_dn_parse(tmp_ctx, ldb, &el.values[0], attr->syntax->ldap_oid);
2734 DEBUG(0,(__location__ ": Failed to parse just-generated DN\n"));
2735 talloc_free(tmp_ctx);
2736 return LDB_ERR_INVALID_DN_SYNTAX;
2739 guid = ldb_dn_get_extended_component(dsdb_dn->dn, "GUID");
2741 DEBUG(0,(__location__ ": Failed to parse GUID from just-generated DN\n"));
2742 talloc_free(tmp_ctx);
2743 return LDB_ERR_INVALID_DN_SYNTAX;
2746 ret = dsdb_find_dn_by_guid(ldb, tmp_ctx, ldb_binary_encode(tmp_ctx, *guid), &target_dn);
2747 if (ret != LDB_SUCCESS) {
2748 /* If this proves to be a problem in the future, then
2749 * just remove the return - perhaps we can just use
2750 * the details the replication peer supplied */
2752 DEBUG(0,(__location__ ": Failed to map GUID %s to DN\n", GUID_string(tmp_ctx, &target.guid)));
2753 talloc_free(tmp_ctx);
2754 return LDB_ERR_OPERATIONS_ERROR;
2757 /* Now update with full DN we just found in the DB (including extended components) */
2758 dsdb_dn->dn = target_dn;
2759 /* Now make a linearized version, using the original binary components (if any) */
2760 el.values[0] = data_blob_string_const(dsdb_dn_get_extended_linearized(tmp_ctx, dsdb_dn, 1));
2763 ret = replmd_update_rpmd(module, schema, msg, &seq_num, t);
2764 if (ret != LDB_SUCCESS) {
2765 talloc_free(tmp_ctx);
2769 /* we only change whenChanged and uSNChanged if the seq_num
2772 if (add_time_element(msg, "whenChanged", t) != LDB_SUCCESS) {
2773 talloc_free(tmp_ctx);
2774 return LDB_ERR_OPERATIONS_ERROR;
2777 if (add_uint64_element(msg, "uSNChanged", seq_num) != LDB_SUCCESS) {
2778 talloc_free(tmp_ctx);
2779 return LDB_ERR_OPERATIONS_ERROR;
2783 ret = ldb_build_mod_req(&mod_req, ldb, tmp_ctx,
2787 ldb_op_default_callback,
2789 if (ret != LDB_SUCCESS) {
2790 talloc_free(tmp_ctx);
2793 talloc_steal(mod_req, msg);
2796 DEBUG(4,("Applying DRS linked attribute change:\n%s\n",
2797 ldb_ldif_message_string(ldb, tmp_ctx, LDB_CHANGETYPE_MODIFY, msg)));
2800 /* Run the new request */
2801 ret = ldb_next_request(module, mod_req);
2803 /* we need to wait for this to finish, as we are being called
2804 from the synchronous end_transaction hook of this module */
2805 if (ret == LDB_SUCCESS) {
2806 ret = ldb_wait(mod_req->handle, LDB_WAIT_ALL);
2809 if (ret == LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS) {
2810 /* the link destination exists, we need to update it
2811 * by deleting the old one for the same DN then adding
2813 msg->elements = talloc_realloc(msg, msg->elements,
2814 struct ldb_message_element,
2815 msg->num_elements+1);
2816 if (msg->elements == NULL) {
2818 talloc_free(tmp_ctx);
2819 return LDB_ERR_OPERATIONS_ERROR;
2821 /* this relies on the backend matching the old entry
2822 only by the DN portion of the extended DN */
2823 msg->elements[1] = msg->elements[0];
2824 msg->elements[0].flags = LDB_FLAG_MOD_DELETE;
2825 msg->num_elements++;
2827 ret = ldb_build_mod_req(&mod_req, ldb, tmp_ctx,
2831 ldb_op_default_callback,
2833 if (ret != LDB_SUCCESS) {
2834 talloc_free(tmp_ctx);
2838 /* Run the new request */
2839 ret = ldb_next_request(module, mod_req);
2841 if (ret == LDB_SUCCESS) {
2842 ret = ldb_wait(mod_req->handle, LDB_WAIT_ALL);
2846 if (ret != LDB_SUCCESS) {
2847 ldb_debug(ldb, LDB_DEBUG_WARNING, "Failed to apply linked attribute change '%s' %s\n",
2849 ldb_ldif_message_string(ldb, tmp_ctx, LDB_CHANGETYPE_MODIFY, msg));
2853 talloc_free(tmp_ctx);
2858 static int replmd_extended(struct ldb_module *module, struct ldb_request *req)
2860 if (strcmp(req->op.extended.oid, DSDB_EXTENDED_REPLICATED_OBJECTS_OID) == 0) {
2861 return replmd_extended_replicated_objects(module, req);
2864 return ldb_next_request(module, req);
2869 we hook into the transaction operations to allow us to
2870 perform the linked attribute updates at the end of the whole
2871 transaction. This allows a forward linked attribute to be created
2872 before the object is created. During a vampire, w2k8 sends us linked
2873 attributes before the objects they are part of.
2875 static int replmd_start_transaction(struct ldb_module *module)
2877 /* create our private structure for this transaction */
2878 struct replmd_private *replmd_private = talloc_get_type(ldb_module_get_private(module),
2879 struct replmd_private);
2880 talloc_free(replmd_private->la_ctx);
2881 replmd_private->la_list = NULL;
2882 replmd_private->la_ctx = NULL;
2884 /* free any leftover mod_usn records from cancelled
2886 while (replmd_private->ncs) {
2887 struct nc_entry *e = replmd_private->ncs;
2888 DLIST_REMOVE(replmd_private->ncs, e);
2892 return ldb_next_start_trans(module);
2896 on prepare commit we loop over our queued la_context structures and
2899 static int replmd_prepare_commit(struct ldb_module *module)
2901 struct replmd_private *replmd_private =
2902 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
2903 struct la_entry *la, *prev;
2906 /* walk the list backwards, to do the first entry first, as we
2907 * added the entries with DLIST_ADD() which puts them at the
2908 * start of the list */
2909 for (la = replmd_private->la_list; la && la->next; la=la->next) ;
2911 for (; la; la=prev) {
2913 DLIST_REMOVE(replmd_private->la_list, la);
2914 ret = replmd_process_linked_attribute(module, la);
2915 if (ret != LDB_SUCCESS) {
2916 talloc_free(replmd_private->la_ctx);
2917 replmd_private->la_list = NULL;
2918 replmd_private->la_ctx = NULL;
2923 talloc_free(replmd_private->la_ctx);
2924 replmd_private->la_list = NULL;
2925 replmd_private->la_ctx = NULL;
2927 /* possibly change @REPLCHANGED */
2928 ret = replmd_notify_store(module);
2929 if (ret != LDB_SUCCESS) {
2933 return ldb_next_prepare_commit(module);
2936 static int replmd_del_transaction(struct ldb_module *module)
2938 struct replmd_private *replmd_private =
2939 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
2940 talloc_free(replmd_private->la_ctx);
2941 replmd_private->la_list = NULL;
2942 replmd_private->la_ctx = NULL;
2943 return ldb_next_del_trans(module);
2947 _PUBLIC_ const struct ldb_module_ops ldb_repl_meta_data_module_ops = {
2948 .name = "repl_meta_data",
2949 .init_context = replmd_init,
2951 .modify = replmd_modify,
2952 .rename = replmd_rename,
2953 .extended = replmd_extended,
2954 .start_transaction = replmd_start_transaction,
2955 .prepare_commit = replmd_prepare_commit,
2956 .del_transaction = replmd_del_transaction,