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 la_backlink *la_backlinks;
59 struct nc_entry *prev, *next;
66 struct la_entry *next, *prev;
67 struct drsuapi_DsReplicaLinkedAttribute *la;
70 struct replmd_replicated_request {
71 struct ldb_module *module;
72 struct ldb_request *req;
74 const struct dsdb_schema *schema;
76 /* the controls we pass down */
77 struct ldb_control **controls;
79 /* details for the mode where we apply a bunch of inbound replication meessages */
81 uint32_t index_current;
82 struct dsdb_extended_replicated_objects *objs;
84 struct ldb_message *search_msg;
90 static int replmd_replicated_apply_next(struct replmd_replicated_request *ar);
95 allocate the private structure and build the list
96 of partition DNs for use by replmd_notify()
98 static int replmd_init(struct ldb_module *module)
100 struct replmd_private *replmd_private;
101 struct ldb_context *ldb = ldb_module_get_ctx(module);
103 replmd_private = talloc_zero(module, struct replmd_private);
104 if (replmd_private == NULL) {
106 return LDB_ERR_OPERATIONS_ERROR;
108 ldb_module_set_private(module, replmd_private);
110 return ldb_next_init(module);
114 cleanup our per-transaction contexts
116 static void replmd_txn_cleanup(struct replmd_private *replmd_private)
118 talloc_free(replmd_private->la_ctx);
119 replmd_private->la_list = NULL;
120 replmd_private->la_ctx = NULL;
122 talloc_free(replmd_private->bl_ctx);
123 replmd_private->la_backlinks = NULL;
124 replmd_private->bl_ctx = NULL;
129 struct la_backlink *next, *prev;
130 const char *attr_name;
131 struct GUID forward_guid, target_guid;
136 process a backlinks we accumulated during a transaction, adding and
137 deleting the backlinks from the target objects
139 static int replmd_process_backlink(struct ldb_module *module, struct la_backlink *bl)
141 struct ldb_dn *target_dn, *source_dn;
143 struct ldb_context *ldb = ldb_module_get_ctx(module);
144 struct ldb_message *msg;
145 TALLOC_CTX *tmp_ctx = talloc_new(bl);
151 - construct ldb_message
152 - either an add or a delete
154 ret = dsdb_module_dn_by_guid(module, tmp_ctx, &bl->target_guid, &target_dn);
155 if (ret != LDB_SUCCESS) {
156 ldb_asprintf_errstring(ldb, "Failed to find target DN for linked attribute with GUID %s\n",
157 GUID_string(bl, &bl->target_guid));
158 talloc_free(tmp_ctx);
162 ret = dsdb_module_dn_by_guid(module, tmp_ctx, &bl->forward_guid, &source_dn);
163 if (ret != LDB_SUCCESS) {
164 ldb_asprintf_errstring(ldb, "Failed to find source DN for linked attribute with GUID %s\n",
165 GUID_string(bl, &bl->forward_guid));
166 talloc_free(tmp_ctx);
170 msg = ldb_msg_new(tmp_ctx);
172 ldb_module_oom(module);
173 talloc_free(tmp_ctx);
174 return LDB_ERR_OPERATIONS_ERROR;
177 /* construct a ldb_message for adding/deleting the backlink */
179 dn_string = ldb_dn_get_extended_linearized(tmp_ctx, source_dn, 1);
181 ldb_module_oom(module);
182 talloc_free(tmp_ctx);
183 return LDB_ERR_OPERATIONS_ERROR;
185 ret = ldb_msg_add_steal_string(msg, bl->attr_name, dn_string);
186 if (ret != LDB_SUCCESS) {
187 talloc_free(tmp_ctx);
190 msg->elements[0].flags = bl->active?LDB_FLAG_MOD_ADD:LDB_FLAG_MOD_DELETE;
192 ret = dsdb_module_modify(module, msg, 0);
193 if (ret != LDB_SUCCESS) {
194 ldb_asprintf_errstring(ldb, "Failed to %s backlink from %s to %s - %s",
195 bl->active?"add":"remove",
196 ldb_dn_get_linearized(source_dn),
197 ldb_dn_get_linearized(target_dn),
199 talloc_free(tmp_ctx);
202 talloc_free(tmp_ctx);
207 add a backlink to the list of backlinks to add/delete in the prepare
210 static int replmd_add_backlink(struct ldb_module *module, const struct dsdb_schema *schema,
211 struct GUID *forward_guid, struct GUID *target_guid,
212 bool active, const struct dsdb_attribute *schema_attr, bool immediate)
214 const struct dsdb_attribute *target_attr;
215 struct la_backlink *bl;
216 struct replmd_private *replmd_private =
217 talloc_get_type_abort(ldb_module_get_private(module), struct replmd_private);
219 target_attr = dsdb_attribute_by_linkID(schema, schema_attr->linkID + 1);
222 * windows 2003 has a broken schema where the
223 * definition of msDS-IsDomainFor is missing (which is
224 * supposed to be the backlink of the
225 * msDS-HasDomainNCs attribute
230 /* see if its already in the list */
231 for (bl=replmd_private->la_backlinks; bl; bl=bl->next) {
232 if (GUID_equal(forward_guid, &bl->forward_guid) &&
233 GUID_equal(target_guid, &bl->target_guid) &&
234 (target_attr->lDAPDisplayName == bl->attr_name ||
235 strcmp(target_attr->lDAPDisplayName, bl->attr_name) == 0)) {
241 /* we found an existing one */
242 if (bl->active == active) {
245 DLIST_REMOVE(replmd_private->la_backlinks, bl);
250 if (replmd_private->bl_ctx == NULL) {
251 replmd_private->bl_ctx = talloc_new(replmd_private);
252 if (replmd_private->bl_ctx == NULL) {
253 ldb_module_oom(module);
254 return LDB_ERR_OPERATIONS_ERROR;
259 bl = talloc(replmd_private->bl_ctx, struct la_backlink);
261 ldb_module_oom(module);
262 return LDB_ERR_OPERATIONS_ERROR;
265 bl->attr_name = target_attr->lDAPDisplayName;
266 bl->forward_guid = *forward_guid;
267 bl->target_guid = *target_guid;
270 /* the caller may ask for this backlink to be processed
273 int ret = replmd_process_backlink(module, bl);
278 DLIST_ADD(replmd_private->la_backlinks, bl);
285 * Callback for most write operations in this module:
287 * notify the repl task that a object has changed. The notifies are
288 * gathered up in the replmd_private structure then written to the
289 * @REPLCHANGED object in each partition during the prepare_commit
291 static int replmd_op_callback(struct ldb_request *req, struct ldb_reply *ares)
294 struct replmd_replicated_request *ac =
295 talloc_get_type_abort(req->context, struct replmd_replicated_request);
296 struct replmd_private *replmd_private =
297 talloc_get_type_abort(ldb_module_get_private(ac->module), struct replmd_private);
298 struct nc_entry *modified_partition;
299 struct ldb_control *partition_ctrl;
300 const struct dsdb_control_current_partition *partition;
302 struct ldb_control **controls;
304 partition_ctrl = ldb_reply_get_control(ares, DSDB_CONTROL_CURRENT_PARTITION_OID);
306 /* Remove the 'partition' control from what we pass up the chain */
307 controls = controls_except_specified(ares->controls, ares, partition_ctrl);
309 if (ares->error != LDB_SUCCESS) {
310 return ldb_module_done(ac->req, controls,
311 ares->response, ares->error);
314 if (ares->type != LDB_REPLY_DONE) {
315 ldb_set_errstring(ldb_module_get_ctx(ac->module), "Invalid reply type for notify\n!");
316 return ldb_module_done(ac->req, NULL,
317 NULL, LDB_ERR_OPERATIONS_ERROR);
320 if (!partition_ctrl) {
321 return ldb_module_done(ac->req, NULL,
322 NULL, LDB_ERR_OPERATIONS_ERROR);
325 partition = talloc_get_type_abort(partition_ctrl->data,
326 struct dsdb_control_current_partition);
328 if (ac->seq_num > 0) {
329 for (modified_partition = replmd_private->ncs; modified_partition;
330 modified_partition = modified_partition->next) {
331 if (ldb_dn_compare(modified_partition->dn, partition->dn) == 0) {
336 if (modified_partition == NULL) {
337 modified_partition = talloc_zero(replmd_private, struct nc_entry);
338 if (!modified_partition) {
339 ldb_oom(ldb_module_get_ctx(ac->module));
340 return ldb_module_done(ac->req, NULL,
341 NULL, LDB_ERR_OPERATIONS_ERROR);
343 modified_partition->dn = ldb_dn_copy(modified_partition, partition->dn);
344 if (!modified_partition->dn) {
345 ldb_oom(ldb_module_get_ctx(ac->module));
346 return ldb_module_done(ac->req, NULL,
347 NULL, LDB_ERR_OPERATIONS_ERROR);
349 DLIST_ADD(replmd_private->ncs, modified_partition);
352 if (ac->seq_num > modified_partition->mod_usn) {
353 modified_partition->mod_usn = ac->seq_num;
357 if (ac->apply_mode) {
361 ret = replmd_replicated_apply_next(ac);
362 if (ret != LDB_SUCCESS) {
363 return ldb_module_done(ac->req, NULL, NULL, ret);
367 /* free the partition control container here, for the
368 * common path. Other cases will have it cleaned up
369 * eventually with the ares */
370 talloc_free(partition_ctrl);
371 return ldb_module_done(ac->req,
372 controls_except_specified(controls, ares, partition_ctrl),
373 ares->response, LDB_SUCCESS);
379 * update a @REPLCHANGED record in each partition if there have been
380 * any writes of replicated data in the partition
382 static int replmd_notify_store(struct ldb_module *module)
384 struct replmd_private *replmd_private =
385 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
386 struct ldb_context *ldb = ldb_module_get_ctx(module);
388 while (replmd_private->ncs) {
390 struct nc_entry *modified_partition = replmd_private->ncs;
392 ret = dsdb_save_partition_usn(ldb, modified_partition->dn, modified_partition->mod_usn);
393 if (ret != LDB_SUCCESS) {
394 DEBUG(0,(__location__ ": Failed to save partition uSN for %s\n",
395 ldb_dn_get_linearized(modified_partition->dn)));
398 DLIST_REMOVE(replmd_private->ncs, modified_partition);
399 talloc_free(modified_partition);
407 created a replmd_replicated_request context
409 static struct replmd_replicated_request *replmd_ctx_init(struct ldb_module *module,
410 struct ldb_request *req)
412 struct ldb_context *ldb;
413 struct replmd_replicated_request *ac;
415 ldb = ldb_module_get_ctx(module);
417 ac = talloc_zero(req, struct replmd_replicated_request);
426 ac->schema = dsdb_get_schema(ldb);
428 ldb_debug_set(ldb, LDB_DEBUG_FATAL,
429 "replmd_modify: no dsdb_schema loaded");
430 DEBUG(0,(__location__ ": %s\n", ldb_errstring(ldb)));
438 add a time element to a record
440 static int add_time_element(struct ldb_message *msg, const char *attr, time_t t)
442 struct ldb_message_element *el;
445 if (ldb_msg_find_element(msg, attr) != NULL) {
449 s = ldb_timestring(msg, t);
451 return LDB_ERR_OPERATIONS_ERROR;
454 if (ldb_msg_add_string(msg, attr, s) != LDB_SUCCESS) {
455 return LDB_ERR_OPERATIONS_ERROR;
458 el = ldb_msg_find_element(msg, attr);
459 /* always set as replace. This works because on add ops, the flag
461 el->flags = LDB_FLAG_MOD_REPLACE;
467 add a uint64_t element to a record
469 static int add_uint64_element(struct ldb_message *msg, const char *attr, uint64_t v)
471 struct ldb_message_element *el;
473 if (ldb_msg_find_element(msg, attr) != NULL) {
477 if (ldb_msg_add_fmt(msg, attr, "%llu", (unsigned long long)v) != LDB_SUCCESS) {
478 return LDB_ERR_OPERATIONS_ERROR;
481 el = ldb_msg_find_element(msg, attr);
482 /* always set as replace. This works because on add ops, the flag
484 el->flags = LDB_FLAG_MOD_REPLACE;
489 static int replmd_replPropertyMetaData1_attid_sort(const struct replPropertyMetaData1 *m1,
490 const struct replPropertyMetaData1 *m2,
491 const uint32_t *rdn_attid)
493 if (m1->attid == m2->attid) {
498 * the rdn attribute should be at the end!
499 * so we need to return a value greater than zero
500 * which means m1 is greater than m2
502 if (m1->attid == *rdn_attid) {
507 * the rdn attribute should be at the end!
508 * so we need to return a value less than zero
509 * which means m2 is greater than m1
511 if (m2->attid == *rdn_attid) {
515 return m1->attid > m2->attid ? 1 : -1;
518 static int replmd_replPropertyMetaDataCtr1_sort(struct replPropertyMetaDataCtr1 *ctr1,
519 const struct dsdb_schema *schema,
522 const char *rdn_name;
523 const struct dsdb_attribute *rdn_sa;
525 rdn_name = ldb_dn_get_rdn_name(dn);
527 DEBUG(0,(__location__ ": No rDN for %s?\n", ldb_dn_get_linearized(dn)));
528 return LDB_ERR_OPERATIONS_ERROR;
531 rdn_sa = dsdb_attribute_by_lDAPDisplayName(schema, rdn_name);
532 if (rdn_sa == NULL) {
533 DEBUG(0,(__location__ ": No sa found for rDN %s for %s\n", rdn_name, ldb_dn_get_linearized(dn)));
534 return LDB_ERR_OPERATIONS_ERROR;
537 DEBUG(6,("Sorting rpmd with attid exception %u rDN=%s DN=%s\n",
538 rdn_sa->attributeID_id, rdn_name, ldb_dn_get_linearized(dn)));
540 ldb_qsort(ctr1->array, ctr1->count, sizeof(struct replPropertyMetaData1),
541 discard_const_p(void, &rdn_sa->attributeID_id),
542 (ldb_qsort_cmp_fn_t)replmd_replPropertyMetaData1_attid_sort);
547 static int replmd_ldb_message_element_attid_sort(const struct ldb_message_element *e1,
548 const struct ldb_message_element *e2,
549 const struct dsdb_schema *schema)
551 const struct dsdb_attribute *a1;
552 const struct dsdb_attribute *a2;
555 * TODO: make this faster by caching the dsdb_attribute pointer
556 * on the ldb_messag_element
559 a1 = dsdb_attribute_by_lDAPDisplayName(schema, e1->name);
560 a2 = dsdb_attribute_by_lDAPDisplayName(schema, e2->name);
563 * TODO: remove this check, we should rely on e1 and e2 having valid attribute names
567 return strcasecmp(e1->name, e2->name);
569 if (a1->attributeID_id == a2->attributeID_id) {
572 return a1->attributeID_id > a2->attributeID_id ? 1 : -1;
575 static void replmd_ldb_message_sort(struct ldb_message *msg,
576 const struct dsdb_schema *schema)
578 ldb_qsort(msg->elements, msg->num_elements, sizeof(struct ldb_message_element),
579 discard_const_p(void, schema), (ldb_qsort_cmp_fn_t)replmd_ldb_message_element_attid_sort);
582 static int replmd_build_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct dsdb_dn *dsdb_dn,
583 const struct GUID *invocation_id, uint64_t seq_num,
584 uint64_t local_usn, NTTIME nttime, bool deleted);
588 fix up linked attributes in replmd_add.
589 This involves setting up the right meta-data in extended DN
590 components, and creating backlinks to the object
592 static int replmd_add_fix_la(struct ldb_module *module, struct ldb_message_element *el,
593 uint64_t seq_num, const struct GUID *invocationId, time_t t,
594 struct GUID *guid, const struct dsdb_attribute *sa)
597 TALLOC_CTX *tmp_ctx = talloc_new(el->values);
598 struct ldb_context *ldb = ldb_module_get_ctx(module);
599 struct dsdb_schema *schema = dsdb_get_schema(ldb);
602 unix_to_nt_time(&now, t);
604 for (i=0; i<el->num_values; i++) {
605 struct ldb_val *v = &el->values[i];
606 struct dsdb_dn *dsdb_dn = dsdb_dn_parse(tmp_ctx, ldb, v, sa->syntax->ldap_oid);
607 struct GUID target_guid;
611 ret = replmd_build_la_val(el->values, v, dsdb_dn, invocationId,
612 seq_num, seq_num, now, false);
613 if (ret != LDB_SUCCESS) {
614 talloc_free(tmp_ctx);
618 /* note that the DN already has the extended
619 components from the extended_dn_store module */
620 status = dsdb_get_extended_dn_guid(dsdb_dn->dn, &target_guid, "GUID");
621 if (!NT_STATUS_IS_OK(status)) {
622 talloc_free(tmp_ctx);
623 return LDB_ERR_OPERATIONS_ERROR;
626 ret = replmd_add_backlink(module, schema, guid, &target_guid, true, sa, false);
627 if (ret != LDB_SUCCESS) {
628 talloc_free(tmp_ctx);
633 talloc_free(tmp_ctx);
639 intercept add requests
641 static int replmd_add(struct ldb_module *module, struct ldb_request *req)
643 struct ldb_context *ldb;
644 struct ldb_control *control;
645 struct replmd_replicated_request *ac;
646 enum ndr_err_code ndr_err;
647 struct ldb_request *down_req;
648 struct ldb_message *msg;
649 const DATA_BLOB *guid_blob;
651 struct replPropertyMetaDataBlob nmd;
652 struct ldb_val nmd_value;
653 const struct GUID *our_invocation_id;
654 time_t t = time(NULL);
659 bool allow_add_guid = false;
660 bool remove_current_guid = false;
662 /* check if there's a show relax control (used by provision to say 'I know what I'm doing') */
663 control = ldb_request_get_control(req, LDB_CONTROL_RELAX_OID);
668 /* do not manipulate our control entries */
669 if (ldb_dn_is_special(req->op.add.message->dn)) {
670 return ldb_next_request(module, req);
673 ldb = ldb_module_get_ctx(module);
675 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_add\n");
677 ac = replmd_ctx_init(module, req);
679 return LDB_ERR_OPERATIONS_ERROR;
682 guid_blob = ldb_msg_find_ldb_val(req->op.add.message, "objectGUID");
683 if ( guid_blob != NULL ) {
684 if( !allow_add_guid ) {
685 ldb_debug_set(ldb, LDB_DEBUG_ERROR,
686 "replmd_add: it's not allowed to add an object with objectGUID\n");
688 return LDB_ERR_UNWILLING_TO_PERFORM;
690 NTSTATUS status = GUID_from_data_blob(guid_blob,&guid);
691 if ( !NT_STATUS_IS_OK(status)) {
692 ldb_debug_set(ldb, LDB_DEBUG_ERROR,
693 "replmd_add: Unable to parse as a GUID the attribute objectGUID\n");
695 return LDB_ERR_UNWILLING_TO_PERFORM;
697 /* we remove this attribute as it can be a string and will not be treated
698 correctly and then we will readd it latter on in the good format*/
699 remove_current_guid = true;
703 guid = GUID_random();
706 /* Get a sequence number from the backend */
707 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &ac->seq_num);
708 if (ret != LDB_SUCCESS) {
713 /* get our invocationId */
714 our_invocation_id = samdb_ntds_invocation_id(ldb);
715 if (!our_invocation_id) {
716 ldb_debug_set(ldb, LDB_DEBUG_ERROR,
717 "replmd_add: unable to find invocationId\n");
719 return LDB_ERR_OPERATIONS_ERROR;
722 /* we have to copy the message as the caller might have it as a const */
723 msg = ldb_msg_copy_shallow(ac, req->op.add.message);
727 return LDB_ERR_OPERATIONS_ERROR;
730 /* generated times */
731 unix_to_nt_time(&now, t);
732 time_str = ldb_timestring(msg, t);
736 return LDB_ERR_OPERATIONS_ERROR;
738 if (remove_current_guid) {
739 ldb_msg_remove_attr(msg,"objectGUID");
743 * remove autogenerated attributes
745 ldb_msg_remove_attr(msg, "whenCreated");
746 ldb_msg_remove_attr(msg, "whenChanged");
747 ldb_msg_remove_attr(msg, "uSNCreated");
748 ldb_msg_remove_attr(msg, "uSNChanged");
749 ldb_msg_remove_attr(msg, "replPropertyMetaData");
752 * readd replicated attributes
754 ret = ldb_msg_add_string(msg, "whenCreated", time_str);
755 if (ret != LDB_SUCCESS) {
761 /* build the replication meta_data */
764 nmd.ctr.ctr1.count = msg->num_elements;
765 nmd.ctr.ctr1.array = talloc_array(msg,
766 struct replPropertyMetaData1,
768 if (!nmd.ctr.ctr1.array) {
771 return LDB_ERR_OPERATIONS_ERROR;
774 for (i=0; i < msg->num_elements; i++) {
775 struct ldb_message_element *e = &msg->elements[i];
776 struct replPropertyMetaData1 *m = &nmd.ctr.ctr1.array[ni];
777 const struct dsdb_attribute *sa;
779 if (e->name[0] == '@') continue;
781 sa = dsdb_attribute_by_lDAPDisplayName(ac->schema, e->name);
783 ldb_debug_set(ldb, LDB_DEBUG_ERROR,
784 "replmd_add: attribute '%s' not defined in schema\n",
787 return LDB_ERR_NO_SUCH_ATTRIBUTE;
790 if ((sa->systemFlags & DS_FLAG_ATTR_NOT_REPLICATED) || (sa->systemFlags & DS_FLAG_ATTR_IS_CONSTRUCTED)) {
791 /* if the attribute is not replicated (0x00000001)
792 * or constructed (0x00000004) it has no metadata
797 #if W2K3_LINKED_ATTRIBUTES
798 if (sa->linkID != 0 && dsdb_functional_level(ldb) > DS_DOMAIN_FUNCTION_2000) {
799 ret = replmd_add_fix_la(module, e, ac->seq_num, our_invocation_id, t, &guid, sa);
800 if (ret != LDB_SUCCESS) {
804 /* linked attributes are not stored in
805 replPropertyMetaData in FL above w2k */
810 m->attid = sa->attributeID_id;
812 m->originating_change_time = now;
813 m->originating_invocation_id = *our_invocation_id;
814 m->originating_usn = ac->seq_num;
815 m->local_usn = ac->seq_num;
819 /* fix meta data count */
820 nmd.ctr.ctr1.count = ni;
823 * sort meta data array, and move the rdn attribute entry to the end
825 ret = replmd_replPropertyMetaDataCtr1_sort(&nmd.ctr.ctr1, ac->schema, msg->dn);
826 if (ret != LDB_SUCCESS) {
831 /* generated NDR encoded values */
832 ndr_err = ndr_push_struct_blob(&nmd_value, msg,
833 lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")),
835 (ndr_push_flags_fn_t)ndr_push_replPropertyMetaDataBlob);
836 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
839 return LDB_ERR_OPERATIONS_ERROR;
843 * add the autogenerated values
845 ret = dsdb_msg_add_guid(msg, &guid, "objectGUID");
846 if (ret != LDB_SUCCESS) {
851 ret = ldb_msg_add_string(msg, "whenChanged", time_str);
852 if (ret != LDB_SUCCESS) {
857 ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNCreated", ac->seq_num);
858 if (ret != LDB_SUCCESS) {
863 ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNChanged", ac->seq_num);
864 if (ret != LDB_SUCCESS) {
869 ret = ldb_msg_add_value(msg, "replPropertyMetaData", &nmd_value, NULL);
870 if (ret != LDB_SUCCESS) {
877 * sort the attributes by attid before storing the object
879 replmd_ldb_message_sort(msg, ac->schema);
881 ret = ldb_build_add_req(&down_req, ldb, ac,
884 ac, replmd_op_callback,
886 if (ret != LDB_SUCCESS) {
891 /* mark the control done */
893 control->critical = 0;
896 /* go on with the call chain */
897 return ldb_next_request(module, down_req);
902 * update the replPropertyMetaData for one element
904 static int replmd_update_rpmd_element(struct ldb_context *ldb,
905 struct ldb_message *msg,
906 struct ldb_message_element *el,
907 struct replPropertyMetaDataBlob *omd,
908 const struct dsdb_schema *schema,
910 const struct GUID *our_invocation_id,
914 const struct dsdb_attribute *a;
915 struct replPropertyMetaData1 *md1;
917 a = dsdb_attribute_by_lDAPDisplayName(schema, el->name);
919 DEBUG(0,(__location__ ": Unable to find attribute %s in schema\n",
921 return LDB_ERR_OPERATIONS_ERROR;
924 if ((a->systemFlags & DS_FLAG_ATTR_NOT_REPLICATED) || (a->systemFlags & DS_FLAG_ATTR_IS_CONSTRUCTED)) {
928 for (i=0; i<omd->ctr.ctr1.count; i++) {
929 if (a->attributeID_id == omd->ctr.ctr1.array[i].attid) break;
932 #if W2K3_LINKED_ATTRIBUTES
933 if (a->linkID != 0 && dsdb_functional_level(ldb) > DS_DOMAIN_FUNCTION_2000) {
934 /* linked attributes are not stored in
935 replPropertyMetaData in FL above w2k, but we do
936 raise the seqnum for the object */
938 ldb_sequence_number(ldb, LDB_SEQ_NEXT, seq_num) != LDB_SUCCESS) {
939 return LDB_ERR_OPERATIONS_ERROR;
945 if (i == omd->ctr.ctr1.count) {
946 /* we need to add a new one */
947 omd->ctr.ctr1.array = talloc_realloc(msg, omd->ctr.ctr1.array,
948 struct replPropertyMetaData1, omd->ctr.ctr1.count+1);
949 if (omd->ctr.ctr1.array == NULL) {
951 return LDB_ERR_OPERATIONS_ERROR;
953 omd->ctr.ctr1.count++;
954 ZERO_STRUCT(omd->ctr.ctr1.array[i]);
957 /* Get a new sequence number from the backend. We only do this
958 * if we have a change that requires a new
959 * replPropertyMetaData element
962 int ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, seq_num);
963 if (ret != LDB_SUCCESS) {
964 return LDB_ERR_OPERATIONS_ERROR;
968 md1 = &omd->ctr.ctr1.array[i];
970 md1->attid = a->attributeID_id;
971 md1->originating_change_time = now;
972 md1->originating_invocation_id = *our_invocation_id;
973 md1->originating_usn = *seq_num;
974 md1->local_usn = *seq_num;
980 * update the replPropertyMetaData object each time we modify an
981 * object. This is needed for DRS replication, as the merge on the
982 * client is based on this object
984 static int replmd_update_rpmd(struct ldb_module *module,
985 const struct dsdb_schema *schema,
986 struct ldb_message *msg, uint64_t *seq_num,
989 const struct ldb_val *omd_value;
990 enum ndr_err_code ndr_err;
991 struct replPropertyMetaDataBlob omd;
994 const struct GUID *our_invocation_id;
996 const char *attrs[] = { "replPropertyMetaData" , NULL };
997 struct ldb_result *res;
998 struct ldb_context *ldb;
1000 ldb = ldb_module_get_ctx(module);
1002 our_invocation_id = samdb_ntds_invocation_id(ldb);
1003 if (!our_invocation_id) {
1004 /* this happens during an initial vampire while
1005 updating the schema */
1006 DEBUG(5,("No invocationID - skipping replPropertyMetaData update\n"));
1010 unix_to_nt_time(&now, t);
1012 /* search for the existing replPropertyMetaDataBlob */
1013 ret = dsdb_search_dn_with_deleted(ldb, msg, &res, msg->dn, attrs);
1014 if (ret != LDB_SUCCESS || res->count != 1) {
1015 DEBUG(0,(__location__ ": Object %s failed to find replPropertyMetaData\n",
1016 ldb_dn_get_linearized(msg->dn)));
1017 return LDB_ERR_OPERATIONS_ERROR;
1021 omd_value = ldb_msg_find_ldb_val(res->msgs[0], "replPropertyMetaData");
1023 DEBUG(0,(__location__ ": Object %s does not have a replPropertyMetaData attribute\n",
1024 ldb_dn_get_linearized(msg->dn)));
1025 return LDB_ERR_OPERATIONS_ERROR;
1028 ndr_err = ndr_pull_struct_blob(omd_value, msg,
1029 lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")), &omd,
1030 (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
1031 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1032 DEBUG(0,(__location__ ": Failed to parse replPropertyMetaData for %s\n",
1033 ldb_dn_get_linearized(msg->dn)));
1034 return LDB_ERR_OPERATIONS_ERROR;
1037 if (omd.version != 1) {
1038 DEBUG(0,(__location__ ": bad version %u in replPropertyMetaData for %s\n",
1039 omd.version, ldb_dn_get_linearized(msg->dn)));
1040 return LDB_ERR_OPERATIONS_ERROR;
1043 for (i=0; i<msg->num_elements; i++) {
1044 ret = replmd_update_rpmd_element(ldb, msg, &msg->elements[i], &omd, schema, seq_num,
1045 our_invocation_id, now);
1046 if (ret != LDB_SUCCESS) {
1052 * replmd_update_rpmd_element has done an update if the
1055 if (*seq_num != 0) {
1056 struct ldb_val *md_value;
1057 struct ldb_message_element *el;
1059 md_value = talloc(msg, struct ldb_val);
1060 if (md_value == NULL) {
1062 return LDB_ERR_OPERATIONS_ERROR;
1065 ret = replmd_replPropertyMetaDataCtr1_sort(&omd.ctr.ctr1, schema, msg->dn);
1066 if (ret != LDB_SUCCESS) {
1070 ndr_err = ndr_push_struct_blob(md_value, msg,
1071 lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")),
1073 (ndr_push_flags_fn_t)ndr_push_replPropertyMetaDataBlob);
1074 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1075 DEBUG(0,(__location__ ": Failed to marshall replPropertyMetaData for %s\n",
1076 ldb_dn_get_linearized(msg->dn)));
1077 return LDB_ERR_OPERATIONS_ERROR;
1080 ret = ldb_msg_add_empty(msg, "replPropertyMetaData", LDB_FLAG_MOD_REPLACE, &el);
1081 if (ret != LDB_SUCCESS) {
1082 DEBUG(0,(__location__ ": Failed to add updated replPropertyMetaData %s\n",
1083 ldb_dn_get_linearized(msg->dn)));
1088 el->values = md_value;
1096 struct dsdb_dn *dsdb_dn;
1101 static int parsed_dn_compare(struct parsed_dn *pdn1, struct parsed_dn *pdn2)
1103 return GUID_compare(pdn1->guid, pdn2->guid);
1106 static struct parsed_dn *parsed_dn_find(struct parsed_dn *pdn, int count, struct GUID *guid)
1108 struct parsed_dn *ret;
1109 BINARY_ARRAY_SEARCH(pdn, count, guid, guid, GUID_compare, ret);
1114 get a series of message element values as an array of DNs and GUIDs
1115 the result is sorted by GUID
1117 static int get_parsed_dns(struct ldb_module *module, TALLOC_CTX *mem_ctx,
1118 struct ldb_message_element *el, struct parsed_dn **pdn,
1119 const char *ldap_oid)
1122 struct ldb_context *ldb = ldb_module_get_ctx(module);
1129 (*pdn) = talloc_array(mem_ctx, struct parsed_dn, el->num_values);
1131 ldb_module_oom(module);
1132 return LDB_ERR_OPERATIONS_ERROR;
1135 for (i=0; i<el->num_values; i++) {
1136 struct ldb_val *v = &el->values[i];
1139 struct parsed_dn *p;
1143 p->dsdb_dn = dsdb_dn_parse(*pdn, ldb, v, ldap_oid);
1144 if (p->dsdb_dn == NULL) {
1145 return LDB_ERR_INVALID_DN_SYNTAX;
1148 dn = p->dsdb_dn->dn;
1150 p->guid = talloc(*pdn, struct GUID);
1151 if (p->guid == NULL) {
1152 ldb_module_oom(module);
1153 return LDB_ERR_OPERATIONS_ERROR;
1156 status = dsdb_get_extended_dn_guid(dn, p->guid, "GUID");
1157 if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
1158 /* we got a DN without a GUID - go find the GUID */
1159 int ret = dsdb_find_guid_by_dn(ldb, dn, p->guid);
1160 if (ret != LDB_SUCCESS) {
1161 ldb_asprintf_errstring(ldb, "Unable to find GUID for DN %s\n",
1162 ldb_dn_get_linearized(dn));
1165 } else if (!NT_STATUS_IS_OK(status)) {
1166 return LDB_ERR_OPERATIONS_ERROR;
1169 /* keep a pointer to the original ldb_val */
1173 qsort(*pdn, el->num_values, sizeof((*pdn)[0]), (comparison_fn_t)parsed_dn_compare);
1179 build a new extended DN, including all meta data fields
1181 DELETED = 1 or missing
1182 RMD_ADDTIME = originating_add_time
1183 RMD_INVOCID = originating_invocation_id
1184 RMD_CHANGETIME = originating_change_time
1185 RMD_ORIGINATING_USN = originating_usn
1186 RMD_LOCAL_USN = local_usn
1187 RMD_VERSION = version
1189 static int replmd_build_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct dsdb_dn *dsdb_dn,
1190 const struct GUID *invocation_id, uint64_t seq_num,
1191 uint64_t local_usn, NTTIME nttime, bool deleted)
1193 struct ldb_dn *dn = dsdb_dn->dn;
1194 const char *tstring, *usn_string;
1195 struct ldb_val tval;
1197 struct ldb_val usnv, local_usnv;
1198 struct ldb_val vers;
1201 const char *dnstring;
1203 tstring = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)nttime);
1205 return LDB_ERR_OPERATIONS_ERROR;
1207 tval = data_blob_string_const(tstring);
1209 usn_string = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)seq_num);
1211 return LDB_ERR_OPERATIONS_ERROR;
1213 usnv = data_blob_string_const(usn_string);
1215 usn_string = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)local_usn);
1217 return LDB_ERR_OPERATIONS_ERROR;
1219 local_usnv = data_blob_string_const(usn_string);
1221 vers = data_blob_string_const("0");
1223 status = GUID_to_ndr_blob(invocation_id, dn, &iid);
1224 if (!NT_STATUS_IS_OK(status)) {
1225 return LDB_ERR_OPERATIONS_ERROR;
1230 dv = data_blob_string_const("1");
1231 ret = ldb_dn_set_extended_component(dn, "DELETED", &dv);
1233 ret = ldb_dn_set_extended_component(dn, "DELETED", NULL);
1235 if (ret != LDB_SUCCESS) return ret;
1236 ret = ldb_dn_set_extended_component(dn, "RMD_ADDTIME", &tval);
1237 if (ret != LDB_SUCCESS) return ret;
1238 ret = ldb_dn_set_extended_component(dn, "RMD_INVOCID", &iid);
1239 if (ret != LDB_SUCCESS) return ret;
1240 ret = ldb_dn_set_extended_component(dn, "RMD_CHANGETIME", &tval);
1241 if (ret != LDB_SUCCESS) return ret;
1242 ret = ldb_dn_set_extended_component(dn, "RMD_LOCAL_USN", &local_usnv);
1243 if (ret != LDB_SUCCESS) return ret;
1244 ret = ldb_dn_set_extended_component(dn, "RMD_ORIGINATING_USN", &usnv);
1245 if (ret != LDB_SUCCESS) return ret;
1246 ret = ldb_dn_set_extended_component(dn, "RMD_VERSION", &vers);
1247 if (ret != LDB_SUCCESS) return ret;
1249 dnstring = dsdb_dn_get_extended_linearized(mem_ctx, dsdb_dn, 1);
1250 if (dnstring == NULL) {
1251 return LDB_ERR_OPERATIONS_ERROR;
1253 *v = data_blob_string_const(dnstring);
1258 static int replmd_update_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct dsdb_dn *dsdb_dn,
1259 struct dsdb_dn *old_dsdb_dn, const struct GUID *invocation_id,
1260 uint64_t seq_num, uint64_t local_usn, NTTIME nttime, bool deleted);
1263 check if any links need upgrading from w2k format
1265 static int replmd_check_upgrade_links(struct parsed_dn *dns, uint32_t count, const struct GUID *invocation_id)
1268 for (i=0; i<count; i++) {
1273 status = dsdb_get_extended_dn_uint32(dns[i].dsdb_dn->dn, &version, "RMD_VERSION");
1274 if (!NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
1278 /* it's an old one that needs upgrading */
1279 ret = replmd_update_la_val(dns, dns[i].v, dns[i].dsdb_dn, dns[i].dsdb_dn, invocation_id,
1281 if (ret != LDB_SUCCESS) {
1289 update an extended DN, including all meta data fields
1291 see replmd_build_la_val for value names
1293 static int replmd_update_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct dsdb_dn *dsdb_dn,
1294 struct dsdb_dn *old_dsdb_dn, const struct GUID *invocation_id,
1295 uint64_t seq_num, uint64_t local_usn, NTTIME nttime, bool deleted)
1297 struct ldb_dn *dn = dsdb_dn->dn;
1298 const char *tstring, *usn_string;
1299 struct ldb_val tval;
1301 struct ldb_val usnv, local_usnv;
1302 struct ldb_val vers;
1303 const struct ldb_val *old_addtime, *old_version;
1306 const char *dnstring;
1308 tstring = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)nttime);
1310 return LDB_ERR_OPERATIONS_ERROR;
1312 tval = data_blob_string_const(tstring);
1314 usn_string = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)seq_num);
1316 return LDB_ERR_OPERATIONS_ERROR;
1318 usnv = data_blob_string_const(usn_string);
1320 usn_string = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)local_usn);
1322 return LDB_ERR_OPERATIONS_ERROR;
1324 local_usnv = data_blob_string_const(usn_string);
1326 status = GUID_to_ndr_blob(invocation_id, dn, &iid);
1327 if (!NT_STATUS_IS_OK(status)) {
1328 return LDB_ERR_OPERATIONS_ERROR;
1333 dv = data_blob_string_const("1");
1334 ret = ldb_dn_set_extended_component(dn, "DELETED", &dv);
1336 ret = ldb_dn_set_extended_component(dn, "DELETED", NULL);
1338 if (ret != LDB_SUCCESS) return ret;
1340 /* get the ADDTIME from the original */
1341 old_addtime = ldb_dn_get_extended_component(old_dsdb_dn->dn, "RMD_ADDTIME");
1342 if (old_addtime == NULL) {
1343 old_addtime = &tval;
1345 if (dsdb_dn != old_dsdb_dn) {
1346 ret = ldb_dn_set_extended_component(dn, "RMD_ADDTIME", old_addtime);
1347 if (ret != LDB_SUCCESS) return ret;
1350 /* use our invocation id */
1351 ret = ldb_dn_set_extended_component(dn, "RMD_INVOCID", &iid);
1352 if (ret != LDB_SUCCESS) return ret;
1354 /* changetime is the current time */
1355 ret = ldb_dn_set_extended_component(dn, "RMD_CHANGETIME", &tval);
1356 if (ret != LDB_SUCCESS) return ret;
1358 /* update the USN */
1359 ret = ldb_dn_set_extended_component(dn, "RMD_ORIGINATING_USN", &usnv);
1360 if (ret != LDB_SUCCESS) return ret;
1362 ret = ldb_dn_set_extended_component(dn, "RMD_LOCAL_USN", &local_usnv);
1363 if (ret != LDB_SUCCESS) return ret;
1365 /* increase the version by 1 */
1366 old_version = ldb_dn_get_extended_component(old_dsdb_dn->dn, "RMD_VERSION");
1367 if (old_version == NULL) {
1368 vers = data_blob_string_const("0");
1371 vstring = talloc_strndup(dn, (const char *)old_version->data, old_version->length);
1373 return LDB_ERR_OPERATIONS_ERROR;
1375 vstring = talloc_asprintf(dn, "%lu",
1376 (unsigned long)strtoul(vstring, NULL, 0)+1);
1377 vers = data_blob_string_const(vstring);
1379 ret = ldb_dn_set_extended_component(dn, "RMD_VERSION", &vers);
1380 if (ret != LDB_SUCCESS) return ret;
1382 dnstring = dsdb_dn_get_extended_linearized(mem_ctx, dsdb_dn, 1);
1383 if (dnstring == NULL) {
1384 return LDB_ERR_OPERATIONS_ERROR;
1386 *v = data_blob_string_const(dnstring);
1392 handle adding a linked attribute
1394 static int replmd_modify_la_add(struct ldb_module *module,
1395 struct dsdb_schema *schema,
1396 struct ldb_message *msg,
1397 struct ldb_message_element *el,
1398 struct ldb_message_element *old_el,
1399 const struct dsdb_attribute *schema_attr,
1402 struct GUID *msg_guid)
1405 struct parsed_dn *dns, *old_dns;
1406 TALLOC_CTX *tmp_ctx = talloc_new(msg);
1408 struct ldb_val *new_values = NULL;
1409 unsigned int num_new_values = 0;
1410 unsigned old_num_values = old_el?old_el->num_values:0;
1411 const struct GUID *invocation_id;
1412 struct ldb_context *ldb = ldb_module_get_ctx(module);
1415 unix_to_nt_time(&now, t);
1417 ret = get_parsed_dns(module, tmp_ctx, el, &dns, schema_attr->syntax->ldap_oid);
1418 if (ret != LDB_SUCCESS) {
1419 talloc_free(tmp_ctx);
1423 ret = get_parsed_dns(module, tmp_ctx, old_el, &old_dns, schema_attr->syntax->ldap_oid);
1424 if (ret != LDB_SUCCESS) {
1425 talloc_free(tmp_ctx);
1429 invocation_id = samdb_ntds_invocation_id(ldb);
1430 if (!invocation_id) {
1431 talloc_free(tmp_ctx);
1432 return LDB_ERR_OPERATIONS_ERROR;
1435 ret = replmd_check_upgrade_links(old_dns, old_num_values, invocation_id);
1436 if (ret != LDB_SUCCESS) {
1437 talloc_free(tmp_ctx);
1441 /* for each new value, see if it exists already with the same GUID */
1442 for (i=0; i<el->num_values; i++) {
1443 struct parsed_dn *p = parsed_dn_find(old_dns, old_num_values, dns[i].guid);
1445 /* this is a new linked attribute value */
1446 new_values = talloc_realloc(tmp_ctx, new_values, struct ldb_val, num_new_values+1);
1447 if (new_values == NULL) {
1448 ldb_module_oom(module);
1449 talloc_free(tmp_ctx);
1450 return LDB_ERR_OPERATIONS_ERROR;
1452 ret = replmd_build_la_val(new_values, &new_values[num_new_values], dns[i].dsdb_dn,
1453 invocation_id, seq_num, seq_num, now, false);
1454 if (ret != LDB_SUCCESS) {
1455 talloc_free(tmp_ctx);
1460 /* this is only allowed if the GUID was
1461 previously deleted. */
1462 const struct ldb_val *v;
1463 v = ldb_dn_get_extended_component(p->dsdb_dn->dn, "DELETED");
1465 ldb_asprintf_errstring(ldb, "Attribute %s already exists for target GUID %s",
1466 el->name, GUID_string(tmp_ctx, p->guid));
1467 talloc_free(tmp_ctx);
1468 return LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS;
1470 ret = replmd_update_la_val(old_el->values, p->v, dns[i].dsdb_dn, p->dsdb_dn,
1471 invocation_id, seq_num, seq_num, now, false);
1472 if (ret != LDB_SUCCESS) {
1473 talloc_free(tmp_ctx);
1478 ret = replmd_add_backlink(module, schema, msg_guid, dns[i].guid, true, schema_attr, true);
1479 if (ret != LDB_SUCCESS) {
1480 talloc_free(tmp_ctx);
1485 /* add the new ones on to the end of the old values, constructing a new el->values */
1486 el->values = talloc_realloc(msg->elements, old_el?old_el->values:NULL,
1488 old_num_values+num_new_values);
1489 if (el->values == NULL) {
1490 ldb_module_oom(module);
1491 return LDB_ERR_OPERATIONS_ERROR;
1494 memcpy(&el->values[old_num_values], new_values, num_new_values*sizeof(struct ldb_val));
1495 el->num_values = old_num_values + num_new_values;
1497 talloc_steal(msg->elements, el->values);
1498 talloc_steal(el->values, new_values);
1500 talloc_free(tmp_ctx);
1502 /* we now tell the backend to replace all existing values
1503 with the one we have constructed */
1504 el->flags = LDB_FLAG_MOD_REPLACE;
1511 handle deleting all active linked attributes
1513 static int replmd_modify_la_delete(struct ldb_module *module,
1514 struct dsdb_schema *schema,
1515 struct ldb_message *msg,
1516 struct ldb_message_element *el,
1517 struct ldb_message_element *old_el,
1518 const struct dsdb_attribute *schema_attr,
1521 struct GUID *msg_guid)
1524 struct parsed_dn *dns, *old_dns;
1525 TALLOC_CTX *tmp_ctx = talloc_new(msg);
1527 const struct GUID *invocation_id;
1528 struct ldb_context *ldb = ldb_module_get_ctx(module);
1531 unix_to_nt_time(&now, t);
1533 /* check if there is nothing to delete */
1534 if ((!old_el || old_el->num_values == 0) &&
1535 el->num_values == 0) {
1539 if (!old_el || old_el->num_values == 0) {
1540 return LDB_ERR_NO_SUCH_ATTRIBUTE;
1543 ret = get_parsed_dns(module, tmp_ctx, el, &dns, schema_attr->syntax->ldap_oid);
1544 if (ret != LDB_SUCCESS) {
1545 talloc_free(tmp_ctx);
1549 ret = get_parsed_dns(module, tmp_ctx, old_el, &old_dns, schema_attr->syntax->ldap_oid);
1550 if (ret != LDB_SUCCESS) {
1551 talloc_free(tmp_ctx);
1555 invocation_id = samdb_ntds_invocation_id(ldb);
1556 if (!invocation_id) {
1557 return LDB_ERR_OPERATIONS_ERROR;
1560 ret = replmd_check_upgrade_links(old_dns, old_el->num_values, invocation_id);
1561 if (ret != LDB_SUCCESS) {
1562 talloc_free(tmp_ctx);
1568 /* see if we are being asked to delete any links that
1569 don't exist or are already deleted */
1570 for (i=0; i<el->num_values; i++) {
1571 struct parsed_dn *p = &dns[i];
1572 struct parsed_dn *p2;
1573 const struct ldb_val *v;
1575 p2 = parsed_dn_find(old_dns, old_el->num_values, p->guid);
1577 ldb_asprintf_errstring(ldb, "Attribute %s doesn't exist for target GUID %s",
1578 el->name, GUID_string(tmp_ctx, p->guid));
1579 return LDB_ERR_NO_SUCH_ATTRIBUTE;
1581 v = ldb_dn_get_extended_component(p2->dsdb_dn->dn, "DELETED");
1583 ldb_asprintf_errstring(ldb, "Attribute %s already deleted for target GUID %s",
1584 el->name, GUID_string(tmp_ctx, p->guid));
1585 return LDB_ERR_NO_SUCH_ATTRIBUTE;
1589 /* for each new value, see if it exists already with the same GUID
1590 if it is not already deleted and matches the delete list then delete it
1592 for (i=0; i<old_el->num_values; i++) {
1593 struct parsed_dn *p = &old_dns[i];
1594 const struct ldb_val *v;
1596 if (dns && parsed_dn_find(dns, el->num_values, p->guid) == NULL) {
1600 v = ldb_dn_get_extended_component(p->dsdb_dn->dn, "DELETED");
1601 if (v != NULL) continue;
1603 ret = replmd_update_la_val(old_el->values, p->v, p->dsdb_dn, p->dsdb_dn,
1604 invocation_id, seq_num, seq_num, now, true);
1605 if (ret != LDB_SUCCESS) {
1606 talloc_free(tmp_ctx);
1610 ret = replmd_add_backlink(module, schema, msg_guid, old_dns[i].guid, false, schema_attr, true);
1611 if (ret != LDB_SUCCESS) {
1612 talloc_free(tmp_ctx);
1617 el->values = talloc_steal(msg->elements, old_el->values);
1618 el->num_values = old_el->num_values;
1620 talloc_free(tmp_ctx);
1622 /* we now tell the backend to replace all existing values
1623 with the one we have constructed */
1624 el->flags = LDB_FLAG_MOD_REPLACE;
1630 handle replacing a linked attribute
1632 static int replmd_modify_la_replace(struct ldb_module *module,
1633 struct dsdb_schema *schema,
1634 struct ldb_message *msg,
1635 struct ldb_message_element *el,
1636 struct ldb_message_element *old_el,
1637 const struct dsdb_attribute *schema_attr,
1640 struct GUID *msg_guid)
1643 struct parsed_dn *dns, *old_dns;
1644 TALLOC_CTX *tmp_ctx = talloc_new(msg);
1646 const struct GUID *invocation_id;
1647 struct ldb_context *ldb = ldb_module_get_ctx(module);
1648 struct ldb_val *new_values = NULL;
1649 uint32_t num_new_values = 0;
1650 unsigned old_num_values = old_el?old_el->num_values:0;
1653 unix_to_nt_time(&now, t);
1655 /* check if there is nothing to replace */
1656 if ((!old_el || old_el->num_values == 0) &&
1657 el->num_values == 0) {
1661 ret = get_parsed_dns(module, tmp_ctx, el, &dns, schema_attr->syntax->ldap_oid);
1662 if (ret != LDB_SUCCESS) {
1663 talloc_free(tmp_ctx);
1667 ret = get_parsed_dns(module, tmp_ctx, old_el, &old_dns, schema_attr->syntax->ldap_oid);
1668 if (ret != LDB_SUCCESS) {
1669 talloc_free(tmp_ctx);
1673 invocation_id = samdb_ntds_invocation_id(ldb);
1674 if (!invocation_id) {
1675 return LDB_ERR_OPERATIONS_ERROR;
1678 ret = replmd_check_upgrade_links(old_dns, old_num_values, invocation_id);
1679 if (ret != LDB_SUCCESS) {
1680 talloc_free(tmp_ctx);
1684 /* mark all the old ones as deleted */
1685 for (i=0; i<old_num_values; i++) {
1686 struct parsed_dn *old_p = &old_dns[i];
1687 struct parsed_dn *p;
1688 const struct ldb_val *v;
1690 v = ldb_dn_get_extended_component(old_p->dsdb_dn->dn, "DELETED");
1693 ret = replmd_add_backlink(module, schema, msg_guid, old_dns[i].guid, false, schema_attr, false);
1694 if (ret != LDB_SUCCESS) {
1695 talloc_free(tmp_ctx);
1699 p = parsed_dn_find(dns, el->num_values, old_p->guid);
1701 /* we don't delete it if we are re-adding it */
1705 ret = replmd_update_la_val(old_el->values, old_p->v, old_p->dsdb_dn, old_p->dsdb_dn,
1706 invocation_id, seq_num, seq_num, now, true);
1707 if (ret != LDB_SUCCESS) {
1708 talloc_free(tmp_ctx);
1713 /* for each new value, either update its meta-data, or add it
1716 for (i=0; i<el->num_values; i++) {
1717 struct parsed_dn *p = &dns[i], *old_p;
1720 (old_p = parsed_dn_find(old_dns,
1721 old_num_values, p->guid)) != NULL) {
1722 /* update in place */
1723 ret = replmd_update_la_val(old_el->values, old_p->v, old_p->dsdb_dn,
1724 old_p->dsdb_dn, invocation_id,
1725 seq_num, seq_num, now, false);
1726 if (ret != LDB_SUCCESS) {
1727 talloc_free(tmp_ctx);
1732 new_values = talloc_realloc(tmp_ctx, new_values, struct ldb_val,
1734 if (new_values == NULL) {
1735 ldb_module_oom(module);
1736 talloc_free(tmp_ctx);
1737 return LDB_ERR_OPERATIONS_ERROR;
1739 ret = replmd_build_la_val(new_values, &new_values[num_new_values], dns[i].dsdb_dn,
1740 invocation_id, seq_num, seq_num, now, false);
1741 if (ret != LDB_SUCCESS) {
1742 talloc_free(tmp_ctx);
1748 ret = replmd_add_backlink(module, schema, msg_guid, dns[i].guid, true, schema_attr, false);
1749 if (ret != LDB_SUCCESS) {
1750 talloc_free(tmp_ctx);
1755 /* add the new values to the end of old_el */
1756 if (num_new_values != 0) {
1757 el->values = talloc_realloc(msg->elements, old_el?old_el->values:NULL,
1758 struct ldb_val, old_num_values+num_new_values);
1759 if (el->values == NULL) {
1760 ldb_module_oom(module);
1761 return LDB_ERR_OPERATIONS_ERROR;
1763 memcpy(&el->values[old_num_values], &new_values[0],
1764 sizeof(struct ldb_val)*num_new_values);
1765 el->num_values = old_num_values + num_new_values;
1766 talloc_steal(msg->elements, new_values);
1768 el->values = old_el->values;
1769 el->num_values = old_el->num_values;
1770 talloc_steal(msg->elements, el->values);
1773 talloc_free(tmp_ctx);
1775 /* we now tell the backend to replace all existing values
1776 with the one we have constructed */
1777 el->flags = LDB_FLAG_MOD_REPLACE;
1784 handle linked attributes in modify requests
1786 static int replmd_modify_handle_linked_attribs(struct ldb_module *module,
1787 struct ldb_message *msg,
1788 uint64_t seq_num, time_t t)
1790 struct ldb_result *res;
1792 struct ldb_context *ldb = ldb_module_get_ctx(module);
1793 struct ldb_message *old_msg;
1794 struct dsdb_schema *schema = dsdb_get_schema(ldb);
1795 struct GUID old_guid;
1798 /* there the replmd_update_rpmd code has already
1799 * checked and saw that there are no linked
1804 #if !W2K3_LINKED_ATTRIBUTES
1808 if (dsdb_functional_level(ldb) == DS_DOMAIN_FUNCTION_2000) {
1809 /* don't do anything special for linked attributes */
1813 ret = dsdb_module_search_dn(module, msg, &res, msg->dn, NULL,
1814 DSDB_SEARCH_SHOW_DELETED |
1815 DSDB_SEARCH_REVEAL_INTERNALS |
1816 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT);
1817 if (ret != LDB_SUCCESS) {
1820 old_msg = res->msgs[0];
1822 old_guid = samdb_result_guid(old_msg, "objectGUID");
1824 for (i=0; i<msg->num_elements; i++) {
1825 struct ldb_message_element *el = &msg->elements[i];
1826 struct ldb_message_element *old_el, *new_el;
1827 const struct dsdb_attribute *schema_attr
1828 = dsdb_attribute_by_lDAPDisplayName(schema, el->name);
1830 ldb_asprintf_errstring(ldb,
1831 "attribute %s is not a valid attribute in schema", el->name);
1832 return LDB_ERR_OBJECT_CLASS_VIOLATION;
1834 if (schema_attr->linkID == 0) {
1837 if ((schema_attr->linkID & 1) == 1) {
1838 /* Odd is for the target. Illegal to modify */
1839 ldb_asprintf_errstring(ldb,
1840 "attribute %s must not be modified directly, it is a linked attribute", el->name);
1841 return LDB_ERR_UNWILLING_TO_PERFORM;
1843 old_el = ldb_msg_find_element(old_msg, el->name);
1844 switch (el->flags & LDB_FLAG_MOD_MASK) {
1845 case LDB_FLAG_MOD_REPLACE:
1846 ret = replmd_modify_la_replace(module, schema, msg, el, old_el, schema_attr, seq_num, t, &old_guid);
1848 case LDB_FLAG_MOD_DELETE:
1849 ret = replmd_modify_la_delete(module, schema, msg, el, old_el, schema_attr, seq_num, t, &old_guid);
1851 case LDB_FLAG_MOD_ADD:
1852 ret = replmd_modify_la_add(module, schema, msg, el, old_el, schema_attr, seq_num, t, &old_guid);
1855 ldb_asprintf_errstring(ldb,
1856 "invalid flags 0x%x for %s linked attribute",
1857 el->flags, el->name);
1858 return LDB_ERR_UNWILLING_TO_PERFORM;
1860 if (ret != LDB_SUCCESS) {
1864 ldb_msg_remove_attr(old_msg, el->name);
1866 ldb_msg_add_empty(old_msg, el->name, 0, &new_el);
1867 new_el->num_values = el->num_values;
1868 new_el->values = el->values;
1870 /* TODO: this relises a bit too heavily on the exact
1871 behaviour of ldb_msg_find_element and
1872 ldb_msg_remove_element */
1873 old_el = ldb_msg_find_element(msg, el->name);
1875 ldb_msg_remove_element(msg, old_el);
1886 static int replmd_modify(struct ldb_module *module, struct ldb_request *req)
1888 struct ldb_context *ldb;
1889 struct replmd_replicated_request *ac;
1890 struct ldb_request *down_req;
1891 struct ldb_message *msg;
1892 time_t t = time(NULL);
1895 /* do not manipulate our control entries */
1896 if (ldb_dn_is_special(req->op.mod.message->dn)) {
1897 return ldb_next_request(module, req);
1900 ldb = ldb_module_get_ctx(module);
1902 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_modify\n");
1904 ac = replmd_ctx_init(module, req);
1906 return LDB_ERR_OPERATIONS_ERROR;
1909 /* we have to copy the message as the caller might have it as a const */
1910 msg = ldb_msg_copy_shallow(ac, req->op.mod.message);
1914 return LDB_ERR_OPERATIONS_ERROR;
1917 ret = replmd_update_rpmd(module, ac->schema, msg, &ac->seq_num, t);
1918 if (ret != LDB_SUCCESS) {
1923 ret = replmd_modify_handle_linked_attribs(module, msg, ac->seq_num, t);
1924 if (ret != LDB_SUCCESS) {
1930 * - replace the old object with the newly constructed one
1933 ret = ldb_build_mod_req(&down_req, ldb, ac,
1936 ac, replmd_op_callback,
1938 if (ret != LDB_SUCCESS) {
1942 talloc_steal(down_req, msg);
1944 /* we only change whenChanged and uSNChanged if the seq_num
1946 if (ac->seq_num != 0) {
1947 if (add_time_element(msg, "whenChanged", t) != LDB_SUCCESS) {
1952 if (add_uint64_element(msg, "uSNChanged", ac->seq_num) != LDB_SUCCESS) {
1958 /* go on with the call chain */
1959 return ldb_next_request(module, down_req);
1962 static int replmd_rename_callback(struct ldb_request *req, struct ldb_reply *ares);
1965 handle a rename request
1967 On a rename we need to do an extra ldb_modify which sets the
1968 whenChanged and uSNChanged attributes. We do this in a callback after the success.
1970 static int replmd_rename(struct ldb_module *module, struct ldb_request *req)
1972 struct ldb_context *ldb;
1973 struct replmd_replicated_request *ac;
1975 struct ldb_request *down_req;
1977 /* do not manipulate our control entries */
1978 if (ldb_dn_is_special(req->op.mod.message->dn)) {
1979 return ldb_next_request(module, req);
1982 ldb = ldb_module_get_ctx(module);
1984 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_rename\n");
1986 ac = replmd_ctx_init(module, req);
1988 return LDB_ERR_OPERATIONS_ERROR;
1990 ret = ldb_build_rename_req(&down_req, ldb, ac,
1991 ac->req->op.rename.olddn,
1992 ac->req->op.rename.newdn,
1994 ac, replmd_rename_callback,
1997 if (ret != LDB_SUCCESS) {
2002 /* go on with the call chain */
2003 return ldb_next_request(module, down_req);
2006 /* After the rename is compleated, update the whenchanged etc */
2007 static int replmd_rename_callback(struct ldb_request *req, struct ldb_reply *ares)
2009 struct ldb_context *ldb;
2010 struct replmd_replicated_request *ac;
2011 struct ldb_request *down_req;
2012 struct ldb_message *msg;
2013 time_t t = time(NULL);
2016 ac = talloc_get_type(req->context, struct replmd_replicated_request);
2017 ldb = ldb_module_get_ctx(ac->module);
2019 if (ares->error != LDB_SUCCESS) {
2020 return ldb_module_done(ac->req, ares->controls,
2021 ares->response, ares->error);
2024 if (ares->type != LDB_REPLY_DONE) {
2025 ldb_set_errstring(ldb,
2026 "invalid ldb_reply_type in callback");
2028 return ldb_module_done(ac->req, NULL, NULL,
2029 LDB_ERR_OPERATIONS_ERROR);
2032 /* Get a sequence number from the backend */
2033 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &ac->seq_num);
2034 if (ret != LDB_SUCCESS) {
2039 * - replace the old object with the newly constructed one
2042 msg = ldb_msg_new(ac);
2045 return LDB_ERR_OPERATIONS_ERROR;
2048 msg->dn = ac->req->op.rename.newdn;
2050 ret = ldb_build_mod_req(&down_req, ldb, ac,
2053 ac, replmd_op_callback,
2056 if (ret != LDB_SUCCESS) {
2060 talloc_steal(down_req, msg);
2062 if (add_time_element(msg, "whenChanged", t) != LDB_SUCCESS) {
2067 if (add_uint64_element(msg, "uSNChanged", ac->seq_num) != LDB_SUCCESS) {
2072 /* go on with the call chain - do the modify after the rename */
2073 return ldb_next_request(ac->module, down_req);
2076 /* remove forwards and backlinks as needed when an object
2078 static int replmd_delete_remove_link(struct ldb_module *module,
2079 struct dsdb_schema *schema,
2081 struct ldb_message_element *el,
2082 const struct dsdb_attribute *sa)
2085 TALLOC_CTX *tmp_ctx = talloc_new(module);
2086 struct ldb_context *ldb = ldb_module_get_ctx(module);
2088 for (i=0; i<el->num_values; i++) {
2089 struct dsdb_dn *dsdb_dn;
2093 struct ldb_message *msg;
2094 const struct dsdb_attribute *target_attr;
2095 struct ldb_message_element *el2;
2096 struct ldb_val dn_val;
2098 if (dsdb_dn_is_deleted_val(&el->values[i])) {
2102 dsdb_dn = dsdb_dn_parse(tmp_ctx, ldb, &el->values[i], sa->syntax->ldap_oid);
2104 talloc_free(tmp_ctx);
2105 return LDB_ERR_OPERATIONS_ERROR;
2108 status = dsdb_get_extended_dn_guid(dsdb_dn->dn, &guid2, "GUID");
2109 if (!NT_STATUS_IS_OK(status)) {
2110 talloc_free(tmp_ctx);
2111 return LDB_ERR_OPERATIONS_ERROR;
2114 /* remove the link */
2115 msg = ldb_msg_new(tmp_ctx);
2117 ldb_module_oom(module);
2118 talloc_free(tmp_ctx);
2119 return LDB_ERR_OPERATIONS_ERROR;
2123 msg->dn = dsdb_dn->dn;
2125 target_attr = dsdb_attribute_by_linkID(schema, sa->linkID ^ 1);
2126 if (target_attr == NULL) {
2130 ret = ldb_msg_add_empty(msg, target_attr->lDAPDisplayName, LDB_FLAG_MOD_DELETE, &el2);
2131 if (ret != LDB_SUCCESS) {
2132 ldb_module_oom(module);
2133 talloc_free(tmp_ctx);
2134 return LDB_ERR_OPERATIONS_ERROR;
2136 dn_val = data_blob_string_const(ldb_dn_get_linearized(dn));
2137 el2->values = &dn_val;
2138 el2->num_values = 1;
2140 ret = dsdb_module_modify(module, msg, 0);
2141 if (ret != LDB_SUCCESS) {
2142 talloc_free(tmp_ctx);
2146 talloc_free(tmp_ctx);
2152 handle update of replication meta data for deletion of objects
2154 This also handles the mapping of delete to a rename operation
2155 to allow deletes to be replicated.
2157 static int replmd_delete(struct ldb_module *module, struct ldb_request *req)
2159 int ret = LDB_ERR_OTHER;
2161 struct ldb_dn *old_dn, *new_dn;
2162 const char *rdn_name;
2163 const struct ldb_val *rdn_value, *new_rdn_value;
2165 struct ldb_context *ldb = ldb_module_get_ctx(module);
2166 struct dsdb_schema *schema = dsdb_get_schema(ldb);
2167 struct ldb_message *msg, *old_msg;
2168 struct ldb_message_element *el;
2169 TALLOC_CTX *tmp_ctx;
2170 struct ldb_result *res, *parent_res;
2171 const char *preserved_attrs[] = {
2172 /* yes, this really is a hard coded list. See MS-ADTS
2173 section 3.1.1.5.5.1.1 */
2174 "nTSecurityDescriptor", "attributeID", "attributeSyntax", "dNReferenceUpdate", "dNSHostName",
2175 "flatName", "governsID", "groupType", "instanceType", "lDAPDisplayName", "legacyExchangeDN",
2176 "isDeleted", "isRecycled", "lastKnownParent", "msDS-LastKnownRDN", "mS-DS-CreatorSID",
2177 "mSMQOwnerID", "nCName", "objectClass", "distinguishedName", "objectGUID", "objectSid",
2178 "oMSyntax", "proxiedObjectName", "name", "replPropertyMetaData", "sAMAccountName",
2179 "securityIdentifier", "sIDHistory", "subClassOf", "systemFlags", "trustPartner", "trustDirection",
2180 "trustType", "trustAttributes", "userAccountControl", "uSNChanged", "uSNCreated", "whenCreate",
2182 uint32_t el_count = 0;
2185 tmp_ctx = talloc_new(ldb);
2187 old_dn = ldb_dn_copy(tmp_ctx, req->op.del.dn);
2189 /* we need the complete msg off disk, so we can work out which
2190 attributes need to be removed */
2191 ret = dsdb_module_search_dn(module, tmp_ctx, &res, old_dn, NULL,
2192 DSDB_SEARCH_SHOW_DELETED |
2193 DSDB_SEARCH_REVEAL_INTERNALS |
2194 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT);
2195 if (ret != LDB_SUCCESS) {
2196 talloc_free(tmp_ctx);
2199 old_msg = res->msgs[0];
2201 /* work out where we will be renaming this object to */
2202 ret = dsdb_get_deleted_objects_dn(ldb, tmp_ctx, old_dn, &new_dn);
2203 if (ret != LDB_SUCCESS) {
2204 /* this is probably an attempted delete on a partition
2205 * that doesn't allow delete operations, such as the
2206 * schema partition */
2207 ldb_asprintf_errstring(ldb, "No Deleted Objects container for DN %s",
2208 ldb_dn_get_linearized(old_dn));
2209 talloc_free(tmp_ctx);
2210 return LDB_ERR_UNWILLING_TO_PERFORM;
2213 rdn_name = ldb_dn_get_rdn_name(old_dn);
2214 rdn_value = ldb_dn_get_rdn_val(old_dn);
2216 /* get the objects GUID from the search we just did */
2217 guid = samdb_result_guid(old_msg, "objectGUID");
2219 /* Add a formatted child */
2220 retb = ldb_dn_add_child_fmt(new_dn, "%s=%s\\0ADEL:%s",
2223 GUID_string(tmp_ctx, &guid));
2225 DEBUG(0,(__location__ ": Unable to add a formatted child to dn: %s",
2226 ldb_dn_get_linearized(new_dn)));
2227 talloc_free(tmp_ctx);
2228 return LDB_ERR_OPERATIONS_ERROR;
2232 now we need to modify the object in the following ways:
2234 - add isDeleted=TRUE
2235 - update rDN and name, with new rDN
2236 - remove linked attributes
2237 - remove objectCategory and sAMAccountType
2238 - remove attribs not on the preserved list
2239 - preserved if in above list, or is rDN
2240 - remove all linked attribs from this object
2241 - remove all links from other objects to this object
2242 - add lastKnownParent
2243 - update replPropertyMetaData?
2245 see MS-ADTS "Tombstone Requirements" section 3.1.1.5.5.1.1
2248 msg = ldb_msg_new(tmp_ctx);
2250 ldb_module_oom(module);
2251 talloc_free(tmp_ctx);
2252 return LDB_ERR_OPERATIONS_ERROR;
2257 ret = ldb_msg_add_string(msg, "isDeleted", "TRUE");
2258 if (ret != LDB_SUCCESS) {
2259 DEBUG(0,(__location__ ": Failed to add isDeleted string to the msg\n"));
2260 ldb_module_oom(module);
2261 talloc_free(tmp_ctx);
2264 msg->elements[el_count++].flags = LDB_FLAG_MOD_ADD;
2266 /* we need the storage form of the parent GUID */
2267 ret = dsdb_module_search_dn(module, tmp_ctx, &parent_res,
2268 ldb_dn_get_parent(tmp_ctx, old_dn), NULL,
2269 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT |
2270 DSDB_SEARCH_REVEAL_INTERNALS);
2271 if (ret != LDB_SUCCESS) {
2272 talloc_free(tmp_ctx);
2276 ret = ldb_msg_add_steal_string(msg, "lastKnownParent",
2277 ldb_dn_get_extended_linearized(tmp_ctx, parent_res->msgs[0]->dn, 1));
2278 if (ret != LDB_SUCCESS) {
2279 DEBUG(0,(__location__ ": Failed to add lastKnownParent string to the msg\n"));
2280 ldb_module_oom(module);
2281 talloc_free(tmp_ctx);
2284 msg->elements[el_count++].flags = LDB_FLAG_MOD_ADD;
2286 /* work out which of the old attributes we will be removing */
2287 for (i=0; i<old_msg->num_elements; i++) {
2288 const struct dsdb_attribute *sa;
2289 el = &old_msg->elements[i];
2290 sa = dsdb_attribute_by_lDAPDisplayName(schema, el->name);
2292 talloc_free(tmp_ctx);
2293 return LDB_ERR_OPERATIONS_ERROR;
2295 if (ldb_attr_cmp(el->name, rdn_name) == 0) {
2296 /* don't remove the rDN */
2301 ret = replmd_delete_remove_link(module, schema, old_dn, el, sa);
2302 if (ret != LDB_SUCCESS) {
2303 talloc_free(tmp_ctx);
2304 return LDB_ERR_OPERATIONS_ERROR;
2308 if (!sa->linkID && ldb_attr_in_list(preserved_attrs, el->name)) {
2312 ret = ldb_msg_add_empty(msg, el->name, LDB_FLAG_MOD_DELETE, &el);
2313 if (ret != LDB_SUCCESS) {
2314 talloc_free(tmp_ctx);
2315 ldb_module_oom(module);
2320 /* work out what the new rdn value is, for updating the
2321 rDN and name fields */
2322 new_rdn_value = ldb_dn_get_rdn_val(new_dn);
2323 ret = ldb_msg_add_value(msg, rdn_name, new_rdn_value, &el);
2324 if (ret != LDB_SUCCESS) {
2325 talloc_free(tmp_ctx);
2328 el->flags = LDB_FLAG_MOD_REPLACE;
2330 el = ldb_msg_find_element(old_msg, "name");
2332 ret = ldb_msg_add_value(msg, "name", new_rdn_value, &el);
2333 if (ret != LDB_SUCCESS) {
2334 talloc_free(tmp_ctx);
2337 el->flags = LDB_FLAG_MOD_REPLACE;
2340 ret = dsdb_module_modify(module, msg, 0);
2341 if (ret != LDB_SUCCESS){
2342 ldb_asprintf_errstring(ldb, "replmd_delete: Failed to modify object %s in delete - %s",
2343 ldb_dn_get_linearized(old_dn), ldb_errstring(ldb));
2344 talloc_free(tmp_ctx);
2348 /* now rename onto the new DN */
2349 ret = dsdb_module_rename(module, old_dn, new_dn, 0);
2350 if (ret != LDB_SUCCESS){
2351 DEBUG(0,(__location__ ": Failed to rename object from '%s' to '%s' - %s\n",
2352 ldb_dn_get_linearized(old_dn),
2353 ldb_dn_get_linearized(new_dn),
2354 ldb_errstring(ldb)));
2355 talloc_free(tmp_ctx);
2359 talloc_free(tmp_ctx);
2361 return ldb_module_done(req, NULL, NULL, LDB_SUCCESS);
2366 static int replmd_replicated_request_error(struct replmd_replicated_request *ar, int ret)
2371 static int replmd_replicated_request_werror(struct replmd_replicated_request *ar, WERROR status)
2373 int ret = LDB_ERR_OTHER;
2374 /* TODO: do some error mapping */
2378 static int replmd_replicated_apply_add(struct replmd_replicated_request *ar)
2380 struct ldb_context *ldb;
2381 struct ldb_request *change_req;
2382 enum ndr_err_code ndr_err;
2383 struct ldb_message *msg;
2384 struct replPropertyMetaDataBlob *md;
2385 struct ldb_val md_value;
2390 * TODO: check if the parent object exist
2394 * TODO: handle the conflict case where an object with the
2398 ldb = ldb_module_get_ctx(ar->module);
2399 msg = ar->objs->objects[ar->index_current].msg;
2400 md = ar->objs->objects[ar->index_current].meta_data;
2402 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &ar->seq_num);
2403 if (ret != LDB_SUCCESS) {
2404 return replmd_replicated_request_error(ar, ret);
2407 ret = ldb_msg_add_value(msg, "objectGUID", &ar->objs->objects[ar->index_current].guid_value, NULL);
2408 if (ret != LDB_SUCCESS) {
2409 return replmd_replicated_request_error(ar, ret);
2412 ret = ldb_msg_add_string(msg, "whenChanged", ar->objs->objects[ar->index_current].when_changed);
2413 if (ret != LDB_SUCCESS) {
2414 return replmd_replicated_request_error(ar, ret);
2417 ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNCreated", ar->seq_num);
2418 if (ret != LDB_SUCCESS) {
2419 return replmd_replicated_request_error(ar, ret);
2422 ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNChanged", ar->seq_num);
2423 if (ret != LDB_SUCCESS) {
2424 return replmd_replicated_request_error(ar, ret);
2427 /* remove any message elements that have zero values */
2428 for (i=0; i<msg->num_elements; i++) {
2429 struct ldb_message_element *el = &msg->elements[i];
2431 if (el->num_values == 0) {
2432 DEBUG(4,(__location__ ": Removing attribute %s with num_values==0\n",
2434 memmove(el, el+1, sizeof(*el)*(msg->num_elements - (i+1)));
2435 msg->num_elements--;
2442 * the meta data array is already sorted by the caller
2444 for (i=0; i < md->ctr.ctr1.count; i++) {
2445 md->ctr.ctr1.array[i].local_usn = ar->seq_num;
2447 ndr_err = ndr_push_struct_blob(&md_value, msg,
2448 lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")),
2450 (ndr_push_flags_fn_t)ndr_push_replPropertyMetaDataBlob);
2451 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
2452 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
2453 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
2455 ret = ldb_msg_add_value(msg, "replPropertyMetaData", &md_value, NULL);
2456 if (ret != LDB_SUCCESS) {
2457 return replmd_replicated_request_error(ar, ret);
2460 replmd_ldb_message_sort(msg, ar->schema);
2463 char *s = ldb_ldif_message_string(ldb, ar, LDB_CHANGETYPE_ADD, msg);
2464 DEBUG(4, ("DRS replication add message:\n%s\n", s));
2468 ret = ldb_build_add_req(&change_req,
2476 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
2478 return ldb_next_request(ar->module, change_req);
2482 return true if an update is newer than an existing entry
2483 see section 5.11 of MS-ADTS
2485 static bool replmd_update_is_newer(const struct GUID *current_invocation_id,
2486 const struct GUID *update_invocation_id,
2487 uint32_t current_version,
2488 uint32_t update_version,
2489 NTTIME current_change_time,
2490 NTTIME update_change_time)
2492 if (update_version != current_version) {
2493 return update_version > current_version;
2495 if (update_change_time > current_change_time) {
2498 if (update_change_time == current_change_time) {
2499 return GUID_compare(update_invocation_id, current_invocation_id) > 0;
2504 static bool replmd_replPropertyMetaData1_is_newer(struct replPropertyMetaData1 *cur_m,
2505 struct replPropertyMetaData1 *new_m)
2507 return replmd_update_is_newer(&cur_m->originating_invocation_id,
2508 &new_m->originating_invocation_id,
2511 cur_m->originating_change_time,
2512 new_m->originating_change_time);
2515 static int replmd_replicated_apply_merge(struct replmd_replicated_request *ar)
2517 struct ldb_context *ldb;
2518 struct ldb_request *change_req;
2519 enum ndr_err_code ndr_err;
2520 struct ldb_message *msg;
2521 struct replPropertyMetaDataBlob *rmd;
2522 struct replPropertyMetaDataBlob omd;
2523 const struct ldb_val *omd_value;
2524 struct replPropertyMetaDataBlob nmd;
2525 struct ldb_val nmd_value;
2527 uint32_t removed_attrs = 0;
2530 ldb = ldb_module_get_ctx(ar->module);
2531 msg = ar->objs->objects[ar->index_current].msg;
2532 rmd = ar->objs->objects[ar->index_current].meta_data;
2537 * TODO: check repl data is correct after a rename
2539 if (ldb_dn_compare(msg->dn, ar->search_msg->dn) != 0) {
2540 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_replicated_request rename %s => %s\n",
2541 ldb_dn_get_linearized(ar->search_msg->dn),
2542 ldb_dn_get_linearized(msg->dn));
2543 /* we can't use dsdb_module_rename() here as we need
2544 the rename call to be intercepted by this module, to
2545 allow it to process linked attribute changes */
2546 if (ldb_rename(ldb, ar->search_msg->dn, msg->dn) != LDB_SUCCESS) {
2547 ldb_debug(ldb, LDB_DEBUG_FATAL, "replmd_replicated_request rename %s => %s failed - %s\n",
2548 ldb_dn_get_linearized(ar->search_msg->dn),
2549 ldb_dn_get_linearized(msg->dn),
2550 ldb_errstring(ldb));
2551 return replmd_replicated_request_werror(ar, WERR_DS_DRA_DB_ERROR);
2555 /* find existing meta data */
2556 omd_value = ldb_msg_find_ldb_val(ar->search_msg, "replPropertyMetaData");
2558 ndr_err = ndr_pull_struct_blob(omd_value, ar,
2559 lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")), &omd,
2560 (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
2561 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
2562 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
2563 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
2566 if (omd.version != 1) {
2567 return replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
2573 nmd.ctr.ctr1.count = omd.ctr.ctr1.count + rmd->ctr.ctr1.count;
2574 nmd.ctr.ctr1.array = talloc_array(ar,
2575 struct replPropertyMetaData1,
2576 nmd.ctr.ctr1.count);
2577 if (!nmd.ctr.ctr1.array) return replmd_replicated_request_werror(ar, WERR_NOMEM);
2579 /* first copy the old meta data */
2580 for (i=0; i < omd.ctr.ctr1.count; i++) {
2581 nmd.ctr.ctr1.array[ni] = omd.ctr.ctr1.array[i];
2585 /* now merge in the new meta data */
2586 for (i=0; i < rmd->ctr.ctr1.count; i++) {
2589 for (j=0; j < ni; j++) {
2592 if (rmd->ctr.ctr1.array[i].attid != nmd.ctr.ctr1.array[j].attid) {
2596 cmp = replmd_replPropertyMetaData1_is_newer(&nmd.ctr.ctr1.array[j],
2597 &rmd->ctr.ctr1.array[i]);
2599 /* replace the entry */
2600 nmd.ctr.ctr1.array[j] = rmd->ctr.ctr1.array[i];
2605 DEBUG(1,("Discarding older DRS attribute update to %s on %s from %s\n",
2606 msg->elements[i-removed_attrs].name,
2607 ldb_dn_get_linearized(msg->dn),
2608 GUID_string(ar, &rmd->ctr.ctr1.array[i].originating_invocation_id)));
2610 /* we don't want to apply this change so remove the attribute */
2611 ldb_msg_remove_element(msg, &msg->elements[i-removed_attrs]);
2618 if (found) continue;
2620 nmd.ctr.ctr1.array[ni] = rmd->ctr.ctr1.array[i];
2625 * finally correct the size of the meta_data array
2627 nmd.ctr.ctr1.count = ni;
2630 * the rdn attribute (the alias for the name attribute),
2631 * 'cn' for most objects is the last entry in the meta data array
2634 * sort the new meta data array
2636 ret = replmd_replPropertyMetaDataCtr1_sort(&nmd.ctr.ctr1, ar->schema, msg->dn);
2637 if (ret != LDB_SUCCESS) {
2642 * check if some replicated attributes left, otherwise skip the ldb_modify() call
2644 if (msg->num_elements == 0) {
2645 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_replicated_apply_merge[%u]: skip replace\n",
2648 ar->index_current++;
2649 return replmd_replicated_apply_next(ar);
2652 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_replicated_apply_merge[%u]: replace %u attributes\n",
2653 ar->index_current, msg->num_elements);
2655 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &ar->seq_num);
2656 if (ret != LDB_SUCCESS) {
2657 return replmd_replicated_request_error(ar, ret);
2660 for (i=0; i<ni; i++) {
2661 nmd.ctr.ctr1.array[i].local_usn = ar->seq_num;
2664 /* create the meta data value */
2665 ndr_err = ndr_push_struct_blob(&nmd_value, msg,
2666 lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")),
2668 (ndr_push_flags_fn_t)ndr_push_replPropertyMetaDataBlob);
2669 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
2670 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
2671 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
2675 * when we know that we'll modify the record, add the whenChanged, uSNChanged
2676 * and replPopertyMetaData attributes
2678 ret = ldb_msg_add_string(msg, "whenChanged", ar->objs->objects[ar->index_current].when_changed);
2679 if (ret != LDB_SUCCESS) {
2680 return replmd_replicated_request_error(ar, ret);
2682 ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNChanged", ar->seq_num);
2683 if (ret != LDB_SUCCESS) {
2684 return replmd_replicated_request_error(ar, ret);
2686 ret = ldb_msg_add_value(msg, "replPropertyMetaData", &nmd_value, NULL);
2687 if (ret != LDB_SUCCESS) {
2688 return replmd_replicated_request_error(ar, ret);
2691 replmd_ldb_message_sort(msg, ar->schema);
2693 /* we want to replace the old values */
2694 for (i=0; i < msg->num_elements; i++) {
2695 msg->elements[i].flags = LDB_FLAG_MOD_REPLACE;
2699 char *s = ldb_ldif_message_string(ldb, ar, LDB_CHANGETYPE_MODIFY, msg);
2700 DEBUG(4, ("DRS replication modify message:\n%s\n", s));
2704 ret = ldb_build_mod_req(&change_req,
2712 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
2714 return ldb_next_request(ar->module, change_req);
2717 static int replmd_replicated_apply_search_callback(struct ldb_request *req,
2718 struct ldb_reply *ares)
2720 struct replmd_replicated_request *ar = talloc_get_type(req->context,
2721 struct replmd_replicated_request);
2725 return ldb_module_done(ar->req, NULL, NULL,
2726 LDB_ERR_OPERATIONS_ERROR);
2728 if (ares->error != LDB_SUCCESS &&
2729 ares->error != LDB_ERR_NO_SUCH_OBJECT) {
2730 return ldb_module_done(ar->req, ares->controls,
2731 ares->response, ares->error);
2734 switch (ares->type) {
2735 case LDB_REPLY_ENTRY:
2736 ar->search_msg = talloc_steal(ar, ares->message);
2739 case LDB_REPLY_REFERRAL:
2740 /* we ignore referrals */
2743 case LDB_REPLY_DONE:
2744 if (ar->search_msg != NULL) {
2745 ret = replmd_replicated_apply_merge(ar);
2747 ret = replmd_replicated_apply_add(ar);
2749 if (ret != LDB_SUCCESS) {
2750 return ldb_module_done(ar->req, NULL, NULL, ret);
2758 static int replmd_replicated_uptodate_vector(struct replmd_replicated_request *ar);
2760 static int replmd_replicated_apply_next(struct replmd_replicated_request *ar)
2762 struct ldb_context *ldb;
2766 struct ldb_request *search_req;
2767 struct ldb_search_options_control *options;
2769 if (ar->index_current >= ar->objs->num_objects) {
2770 /* done with it, go to next stage */
2771 return replmd_replicated_uptodate_vector(ar);
2774 ldb = ldb_module_get_ctx(ar->module);
2775 ar->search_msg = NULL;
2777 tmp_str = ldb_binary_encode(ar, ar->objs->objects[ar->index_current].guid_value);
2778 if (!tmp_str) return replmd_replicated_request_werror(ar, WERR_NOMEM);
2780 filter = talloc_asprintf(ar, "(objectGUID=%s)", tmp_str);
2781 if (!filter) return replmd_replicated_request_werror(ar, WERR_NOMEM);
2782 talloc_free(tmp_str);
2784 ret = ldb_build_search_req(&search_req,
2793 replmd_replicated_apply_search_callback,
2796 ret = ldb_request_add_control(search_req, LDB_CONTROL_SHOW_DELETED_OID, true, NULL);
2797 if (ret != LDB_SUCCESS) {
2801 /* we need to cope with cross-partition links, so search for
2802 the GUID over all partitions */
2803 options = talloc(search_req, struct ldb_search_options_control);
2804 if (options == NULL) {
2805 DEBUG(0, (__location__ ": out of memory\n"));
2806 return LDB_ERR_OPERATIONS_ERROR;
2808 options->search_options = LDB_SEARCH_OPTION_PHANTOM_ROOT;
2810 ret = ldb_request_add_control(search_req,
2811 LDB_CONTROL_SEARCH_OPTIONS_OID,
2813 if (ret != LDB_SUCCESS) {
2817 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
2819 return ldb_next_request(ar->module, search_req);
2822 static int replmd_replicated_uptodate_modify_callback(struct ldb_request *req,
2823 struct ldb_reply *ares)
2825 struct ldb_context *ldb;
2826 struct replmd_replicated_request *ar = talloc_get_type(req->context,
2827 struct replmd_replicated_request);
2828 ldb = ldb_module_get_ctx(ar->module);
2831 return ldb_module_done(ar->req, NULL, NULL,
2832 LDB_ERR_OPERATIONS_ERROR);
2834 if (ares->error != LDB_SUCCESS) {
2835 return ldb_module_done(ar->req, ares->controls,
2836 ares->response, ares->error);
2839 if (ares->type != LDB_REPLY_DONE) {
2840 ldb_set_errstring(ldb, "Invalid reply type\n!");
2841 return ldb_module_done(ar->req, NULL, NULL,
2842 LDB_ERR_OPERATIONS_ERROR);
2847 return ldb_module_done(ar->req, NULL, NULL, LDB_SUCCESS);
2850 static int replmd_replicated_uptodate_modify(struct replmd_replicated_request *ar)
2852 struct ldb_context *ldb;
2853 struct ldb_request *change_req;
2854 enum ndr_err_code ndr_err;
2855 struct ldb_message *msg;
2856 struct replUpToDateVectorBlob ouv;
2857 const struct ldb_val *ouv_value;
2858 const struct drsuapi_DsReplicaCursor2CtrEx *ruv;
2859 struct replUpToDateVectorBlob nuv;
2860 struct ldb_val nuv_value;
2861 struct ldb_message_element *nuv_el = NULL;
2862 const struct GUID *our_invocation_id;
2863 struct ldb_message_element *orf_el = NULL;
2864 struct repsFromToBlob nrf;
2865 struct ldb_val *nrf_value = NULL;
2866 struct ldb_message_element *nrf_el = NULL;
2869 time_t t = time(NULL);
2873 ldb = ldb_module_get_ctx(ar->module);
2874 ruv = ar->objs->uptodateness_vector;
2880 unix_to_nt_time(&now, t);
2883 * first create the new replUpToDateVector
2885 ouv_value = ldb_msg_find_ldb_val(ar->search_msg, "replUpToDateVector");
2887 ndr_err = ndr_pull_struct_blob(ouv_value, ar,
2888 lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")), &ouv,
2889 (ndr_pull_flags_fn_t)ndr_pull_replUpToDateVectorBlob);
2890 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
2891 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
2892 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
2895 if (ouv.version != 2) {
2896 return replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
2901 * the new uptodateness vector will at least
2902 * contain 1 entry, one for the source_dsa
2904 * plus optional values from our old vector and the one from the source_dsa
2906 nuv.ctr.ctr2.count = 1 + ouv.ctr.ctr2.count;
2907 if (ruv) nuv.ctr.ctr2.count += ruv->count;
2908 nuv.ctr.ctr2.cursors = talloc_array(ar,
2909 struct drsuapi_DsReplicaCursor2,
2910 nuv.ctr.ctr2.count);
2911 if (!nuv.ctr.ctr2.cursors) return replmd_replicated_request_werror(ar, WERR_NOMEM);
2913 /* first copy the old vector */
2914 for (i=0; i < ouv.ctr.ctr2.count; i++) {
2915 nuv.ctr.ctr2.cursors[ni] = ouv.ctr.ctr2.cursors[i];
2919 /* get our invocation_id if we have one already attached to the ldb */
2920 our_invocation_id = samdb_ntds_invocation_id(ldb);
2922 /* merge in the source_dsa vector is available */
2923 for (i=0; (ruv && i < ruv->count); i++) {
2926 if (our_invocation_id &&
2927 GUID_equal(&ruv->cursors[i].source_dsa_invocation_id,
2928 our_invocation_id)) {
2932 for (j=0; j < ni; j++) {
2933 if (!GUID_equal(&ruv->cursors[i].source_dsa_invocation_id,
2934 &nuv.ctr.ctr2.cursors[j].source_dsa_invocation_id)) {
2941 * we update only the highest_usn and not the latest_sync_success time,
2942 * because the last success stands for direct replication
2944 if (ruv->cursors[i].highest_usn > nuv.ctr.ctr2.cursors[j].highest_usn) {
2945 nuv.ctr.ctr2.cursors[j].highest_usn = ruv->cursors[i].highest_usn;
2950 if (found) continue;
2952 /* if it's not there yet, add it */
2953 nuv.ctr.ctr2.cursors[ni] = ruv->cursors[i];
2958 * merge in the current highwatermark for the source_dsa
2961 for (j=0; j < ni; j++) {
2962 if (!GUID_equal(&ar->objs->source_dsa->source_dsa_invocation_id,
2963 &nuv.ctr.ctr2.cursors[j].source_dsa_invocation_id)) {
2970 * here we update the highest_usn and last_sync_success time
2971 * because we're directly replicating from the source_dsa
2973 * and use the tmp_highest_usn because this is what we have just applied
2976 nuv.ctr.ctr2.cursors[j].highest_usn = ar->objs->source_dsa->highwatermark.tmp_highest_usn;
2977 nuv.ctr.ctr2.cursors[j].last_sync_success = now;
2982 * here we update the highest_usn and last_sync_success time
2983 * because we're directly replicating from the source_dsa
2985 * and use the tmp_highest_usn because this is what we have just applied
2988 nuv.ctr.ctr2.cursors[ni].source_dsa_invocation_id= ar->objs->source_dsa->source_dsa_invocation_id;
2989 nuv.ctr.ctr2.cursors[ni].highest_usn = ar->objs->source_dsa->highwatermark.tmp_highest_usn;
2990 nuv.ctr.ctr2.cursors[ni].last_sync_success = now;
2995 * finally correct the size of the cursors array
2997 nuv.ctr.ctr2.count = ni;
3002 qsort(nuv.ctr.ctr2.cursors, nuv.ctr.ctr2.count,
3003 sizeof(struct drsuapi_DsReplicaCursor2),
3004 (comparison_fn_t)drsuapi_DsReplicaCursor2_compare);
3007 * create the change ldb_message
3009 msg = ldb_msg_new(ar);
3010 if (!msg) return replmd_replicated_request_werror(ar, WERR_NOMEM);
3011 msg->dn = ar->search_msg->dn;
3013 ndr_err = ndr_push_struct_blob(&nuv_value, msg,
3014 lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")),
3016 (ndr_push_flags_fn_t)ndr_push_replUpToDateVectorBlob);
3017 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
3018 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
3019 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
3021 ret = ldb_msg_add_value(msg, "replUpToDateVector", &nuv_value, &nuv_el);
3022 if (ret != LDB_SUCCESS) {
3023 return replmd_replicated_request_error(ar, ret);
3025 nuv_el->flags = LDB_FLAG_MOD_REPLACE;
3028 * now create the new repsFrom value from the given repsFromTo1 structure
3032 nrf.ctr.ctr1 = *ar->objs->source_dsa;
3033 /* and fix some values... */
3034 nrf.ctr.ctr1.consecutive_sync_failures = 0;
3035 nrf.ctr.ctr1.last_success = now;
3036 nrf.ctr.ctr1.last_attempt = now;
3037 nrf.ctr.ctr1.result_last_attempt = WERR_OK;
3038 nrf.ctr.ctr1.highwatermark.highest_usn = nrf.ctr.ctr1.highwatermark.tmp_highest_usn;
3041 * first see if we already have a repsFrom value for the current source dsa
3042 * if so we'll later replace this value
3044 orf_el = ldb_msg_find_element(ar->search_msg, "repsFrom");
3046 for (i=0; i < orf_el->num_values; i++) {
3047 struct repsFromToBlob *trf;
3049 trf = talloc(ar, struct repsFromToBlob);
3050 if (!trf) return replmd_replicated_request_werror(ar, WERR_NOMEM);
3052 ndr_err = ndr_pull_struct_blob(&orf_el->values[i], trf, lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")), trf,
3053 (ndr_pull_flags_fn_t)ndr_pull_repsFromToBlob);
3054 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
3055 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
3056 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
3059 if (trf->version != 1) {
3060 return replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
3064 * we compare the source dsa objectGUID not the invocation_id
3065 * because we want only one repsFrom value per source dsa
3066 * and when the invocation_id of the source dsa has changed we don't need
3067 * the old repsFrom with the old invocation_id
3069 if (!GUID_equal(&trf->ctr.ctr1.source_dsa_obj_guid,
3070 &ar->objs->source_dsa->source_dsa_obj_guid)) {
3076 nrf_value = &orf_el->values[i];
3081 * copy over all old values to the new ldb_message
3083 ret = ldb_msg_add_empty(msg, "repsFrom", 0, &nrf_el);
3084 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
3089 * if we haven't found an old repsFrom value for the current source dsa
3090 * we'll add a new value
3093 struct ldb_val zero_value;
3094 ZERO_STRUCT(zero_value);
3095 ret = ldb_msg_add_value(msg, "repsFrom", &zero_value, &nrf_el);
3096 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
3098 nrf_value = &nrf_el->values[nrf_el->num_values - 1];
3101 /* we now fill the value which is already attached to ldb_message */
3102 ndr_err = ndr_push_struct_blob(nrf_value, msg,
3103 lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")),
3105 (ndr_push_flags_fn_t)ndr_push_repsFromToBlob);
3106 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
3107 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
3108 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
3112 * the ldb_message_element for the attribute, has all the old values and the new one
3113 * so we'll replace the whole attribute with all values
3115 nrf_el->flags = LDB_FLAG_MOD_REPLACE;
3118 char *s = ldb_ldif_message_string(ldb, ar, LDB_CHANGETYPE_MODIFY, msg);
3119 DEBUG(4, ("DRS replication uptodate modify message:\n%s\n", s));
3123 /* prepare the ldb_modify() request */
3124 ret = ldb_build_mod_req(&change_req,
3130 replmd_replicated_uptodate_modify_callback,
3132 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
3134 return ldb_next_request(ar->module, change_req);
3137 static int replmd_replicated_uptodate_search_callback(struct ldb_request *req,
3138 struct ldb_reply *ares)
3140 struct replmd_replicated_request *ar = talloc_get_type(req->context,
3141 struct replmd_replicated_request);
3145 return ldb_module_done(ar->req, NULL, NULL,
3146 LDB_ERR_OPERATIONS_ERROR);
3148 if (ares->error != LDB_SUCCESS &&
3149 ares->error != LDB_ERR_NO_SUCH_OBJECT) {
3150 return ldb_module_done(ar->req, ares->controls,
3151 ares->response, ares->error);
3154 switch (ares->type) {
3155 case LDB_REPLY_ENTRY:
3156 ar->search_msg = talloc_steal(ar, ares->message);
3159 case LDB_REPLY_REFERRAL:
3160 /* we ignore referrals */
3163 case LDB_REPLY_DONE:
3164 if (ar->search_msg == NULL) {
3165 ret = replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
3167 ret = replmd_replicated_uptodate_modify(ar);
3169 if (ret != LDB_SUCCESS) {
3170 return ldb_module_done(ar->req, NULL, NULL, ret);
3179 static int replmd_replicated_uptodate_vector(struct replmd_replicated_request *ar)
3181 struct ldb_context *ldb;
3183 static const char *attrs[] = {
3184 "replUpToDateVector",
3188 struct ldb_request *search_req;
3190 ldb = ldb_module_get_ctx(ar->module);
3191 ar->search_msg = NULL;
3193 ret = ldb_build_search_req(&search_req,
3196 ar->objs->partition_dn,
3202 replmd_replicated_uptodate_search_callback,
3204 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
3206 return ldb_next_request(ar->module, search_req);
3211 static int replmd_extended_replicated_objects(struct ldb_module *module, struct ldb_request *req)
3213 struct ldb_context *ldb;
3214 struct dsdb_extended_replicated_objects *objs;
3215 struct replmd_replicated_request *ar;
3216 struct ldb_control **ctrls;
3218 struct replmd_private *replmd_private =
3219 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
3221 ldb = ldb_module_get_ctx(module);
3223 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_extended_replicated_objects\n");
3225 objs = talloc_get_type(req->op.extended.data, struct dsdb_extended_replicated_objects);
3227 ldb_debug(ldb, LDB_DEBUG_FATAL, "replmd_extended_replicated_objects: invalid extended data\n");
3228 return LDB_ERR_PROTOCOL_ERROR;
3231 if (objs->version != DSDB_EXTENDED_REPLICATED_OBJECTS_VERSION) {
3232 ldb_debug(ldb, LDB_DEBUG_FATAL, "replmd_extended_replicated_objects: extended data invalid version [%u != %u]\n",
3233 objs->version, DSDB_EXTENDED_REPLICATED_OBJECTS_VERSION);
3234 return LDB_ERR_PROTOCOL_ERROR;
3237 ar = replmd_ctx_init(module, req);
3239 return LDB_ERR_OPERATIONS_ERROR;
3241 /* Set the flags to have the replmd_op_callback run over the full set of objects */
3242 ar->apply_mode = true;
3244 ar->schema = dsdb_get_schema(ldb);
3246 ldb_debug_set(ldb, LDB_DEBUG_FATAL, "replmd_ctx_init: no loaded schema found\n");
3248 DEBUG(0,(__location__ ": %s\n", ldb_errstring(ldb)));
3249 return LDB_ERR_CONSTRAINT_VIOLATION;
3252 ctrls = req->controls;
3254 if (req->controls) {
3255 req->controls = talloc_memdup(ar, req->controls,
3256 talloc_get_size(req->controls));
3257 if (!req->controls) return replmd_replicated_request_werror(ar, WERR_NOMEM);
3260 ret = ldb_request_add_control(req, DSDB_CONTROL_REPLICATED_UPDATE_OID, false, NULL);
3261 if (ret != LDB_SUCCESS) {
3265 ar->controls = req->controls;
3266 req->controls = ctrls;
3268 DEBUG(4,("linked_attributes_count=%u\n", objs->linked_attributes_count));
3270 /* save away the linked attributes for the end of the
3272 for (i=0; i<ar->objs->linked_attributes_count; i++) {
3273 struct la_entry *la_entry;
3275 if (replmd_private->la_ctx == NULL) {
3276 replmd_private->la_ctx = talloc_new(replmd_private);
3278 la_entry = talloc(replmd_private->la_ctx, struct la_entry);
3279 if (la_entry == NULL) {
3281 return LDB_ERR_OPERATIONS_ERROR;
3283 la_entry->la = talloc(la_entry, struct drsuapi_DsReplicaLinkedAttribute);
3284 if (la_entry->la == NULL) {
3285 talloc_free(la_entry);
3287 return LDB_ERR_OPERATIONS_ERROR;
3289 *la_entry->la = ar->objs->linked_attributes[i];
3291 /* we need to steal the non-scalars so they stay
3292 around until the end of the transaction */
3293 talloc_steal(la_entry->la, la_entry->la->identifier);
3294 talloc_steal(la_entry->la, la_entry->la->value.blob);
3296 DLIST_ADD(replmd_private->la_list, la_entry);
3299 return replmd_replicated_apply_next(ar);
3303 process one linked attribute structure
3305 static int replmd_process_linked_attribute(struct ldb_module *module,
3306 struct la_entry *la_entry)
3308 struct drsuapi_DsReplicaLinkedAttribute *la = la_entry->la;
3309 struct ldb_context *ldb = ldb_module_get_ctx(module);
3310 struct dsdb_schema *schema = dsdb_get_schema(ldb);
3311 struct ldb_message *msg;
3312 TALLOC_CTX *tmp_ctx = talloc_new(la_entry);
3314 const struct dsdb_attribute *attr;
3315 struct dsdb_dn *dsdb_dn;
3316 uint64_t seq_num = 0;
3317 struct drsuapi_DsReplicaAttribute drs;
3318 struct drsuapi_DsAttributeValue val;
3319 struct ldb_message_element new_el, *old_el;
3321 time_t t = time(NULL);
3322 struct ldb_result *res;
3323 const char *attrs[2];
3324 struct parsed_dn *pdn_list, *pdn;
3327 bool active = (la->flags & DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE)?true:false;
3328 const struct GUID *our_invocation_id;
3330 drs.value_ctr.num_values = 1;
3331 drs.value_ctr.values = &val;
3332 val.blob = la->value.blob;
3335 linked_attributes[0]:
3336 &objs->linked_attributes[i]: struct drsuapi_DsReplicaLinkedAttribute
3338 identifier: struct drsuapi_DsReplicaObjectIdentifier
3339 __ndr_size : 0x0000003a (58)
3340 __ndr_size_sid : 0x00000000 (0)
3341 guid : 8e95b6a9-13dd-4158-89db-3220a5be5cc7
3343 __ndr_size_dn : 0x00000000 (0)
3345 attid : DRSUAPI_ATTRIBUTE_member (0x1F)
3346 value: struct drsuapi_DsAttributeValue
3347 __ndr_size : 0x0000007e (126)
3349 blob : DATA_BLOB length=126
3350 flags : 0x00000001 (1)
3351 1: DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE
3352 originating_add_time : Wed Sep 2 22:20:01 2009 EST
3353 meta_data: struct drsuapi_DsReplicaMetaData
3354 version : 0x00000015 (21)
3355 originating_change_time : Wed Sep 2 23:39:07 2009 EST
3356 originating_invocation_id: 794640f3-18cf-40ee-a211-a93992b67a64
3357 originating_usn : 0x000000000001e19c (123292)
3359 (for cases where the link is to a normal DN)
3360 &target: struct drsuapi_DsReplicaObjectIdentifier3
3361 __ndr_size : 0x0000007e (126)
3362 __ndr_size_sid : 0x0000001c (28)
3363 guid : 7639e594-db75-4086-b0d4-67890ae46031
3364 sid : S-1-5-21-2848215498-2472035911-1947525656-19924
3365 __ndr_size_dn : 0x00000022 (34)
3366 dn : 'CN=UOne,OU=TestOU,DC=vsofs8,DC=com'
3369 /* find the attribute being modified */
3370 attr = dsdb_attribute_by_attributeID_id(schema, la->attid);
3372 DEBUG(0, (__location__ ": Unable to find attributeID 0x%x\n", la->attid));
3373 talloc_free(tmp_ctx);
3374 return LDB_ERR_OPERATIONS_ERROR;
3377 attrs[0] = attr->lDAPDisplayName;
3380 /* get the existing message from the db for the object with
3381 this GUID, returning attribute being modified. We will then
3382 use this msg as the basis for a modify call */
3383 ret = dsdb_module_search(module, tmp_ctx, &res, NULL, LDB_SCOPE_SUBTREE, attrs,
3384 DSDB_SEARCH_SEARCH_ALL_PARTITIONS |
3385 DSDB_SEARCH_SHOW_DELETED |
3386 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT |
3387 DSDB_SEARCH_REVEAL_INTERNALS,
3388 "objectGUID=%s", GUID_string(tmp_ctx, &la->identifier->guid));
3389 if (ret != LDB_SUCCESS) {
3390 talloc_free(tmp_ctx);
3393 if (res->count != 1) {
3394 ldb_asprintf_errstring(ldb, "DRS linked attribute for GUID %s - DN not found",
3395 GUID_string(tmp_ctx, &la->identifier->guid));
3396 talloc_free(tmp_ctx);
3397 return LDB_ERR_NO_SUCH_OBJECT;
3401 if (msg->num_elements == 0) {
3402 ret = ldb_msg_add_empty(msg, attr->lDAPDisplayName, LDB_FLAG_MOD_REPLACE, &old_el);
3403 if (ret != LDB_SUCCESS) {
3404 ldb_module_oom(module);
3405 talloc_free(tmp_ctx);
3406 return LDB_ERR_OPERATIONS_ERROR;
3409 old_el = &msg->elements[0];
3410 old_el->flags = LDB_FLAG_MOD_REPLACE;
3413 /* parse the existing links */
3414 ret = get_parsed_dns(module, tmp_ctx, old_el, &pdn_list, attr->syntax->ldap_oid);
3415 if (ret != LDB_SUCCESS) {
3416 talloc_free(tmp_ctx);
3420 /* get our invocationId */
3421 our_invocation_id = samdb_ntds_invocation_id(ldb);
3422 if (!our_invocation_id) {
3423 ldb_debug_set(ldb, LDB_DEBUG_ERROR, __location__ ": unable to find invocationId\n");
3424 talloc_free(tmp_ctx);
3425 return LDB_ERR_OPERATIONS_ERROR;
3428 ret = replmd_check_upgrade_links(pdn_list, old_el->num_values, our_invocation_id);
3429 if (ret != LDB_SUCCESS) {
3430 talloc_free(tmp_ctx);
3434 status = attr->syntax->drsuapi_to_ldb(ldb, schema, attr, &drs, tmp_ctx, &new_el);
3435 if (!W_ERROR_IS_OK(status)) {
3436 ldb_asprintf_errstring(ldb, "Failed to parsed linked attribute blob for %s on %s\n",
3437 old_el->name, ldb_dn_get_linearized(msg->dn));
3438 return LDB_ERR_OPERATIONS_ERROR;
3441 if (new_el.num_values != 1) {
3442 ldb_asprintf_errstring(ldb, "Failed to find value in linked attribute blob for %s on %s\n",
3443 old_el->name, ldb_dn_get_linearized(msg->dn));
3444 return LDB_ERR_OPERATIONS_ERROR;
3447 dsdb_dn = dsdb_dn_parse(tmp_ctx, ldb, &new_el.values[0], attr->syntax->ldap_oid);
3449 ldb_asprintf_errstring(ldb, "Failed to parse DN in linked attribute blob for %s on %s\n",
3450 old_el->name, ldb_dn_get_linearized(msg->dn));
3451 return LDB_ERR_OPERATIONS_ERROR;
3454 ntstatus = dsdb_get_extended_dn_guid(dsdb_dn->dn, &guid, "GUID");
3455 if (!NT_STATUS_IS_OK(ntstatus)) {
3456 ldb_asprintf_errstring(ldb, "Failed to find GUID in linked attribute blob for %s on %s\n",
3457 old_el->name, ldb_dn_get_linearized(msg->dn));
3458 return LDB_ERR_OPERATIONS_ERROR;
3461 /* see if this link already exists */
3462 pdn = parsed_dn_find(pdn_list, old_el->num_values, &guid);
3464 /* see if this update is newer than what we have already */
3465 struct GUID invocation_id = GUID_zero();
3466 uint32_t version = 0;
3467 NTTIME change_time = 0;
3468 bool was_active = ldb_dn_get_extended_component(pdn->dsdb_dn->dn, "DELETED") == NULL;
3470 dsdb_get_extended_dn_guid(pdn->dsdb_dn->dn, &invocation_id, "RMD_INVOCID");
3471 dsdb_get_extended_dn_uint32(pdn->dsdb_dn->dn, &version, "RMD_VERSION");
3472 dsdb_get_extended_dn_nttime(pdn->dsdb_dn->dn, &change_time, "RMD_CHANGETIME");
3474 if (!replmd_update_is_newer(&invocation_id,
3475 &la->meta_data.originating_invocation_id,
3477 la->meta_data.version,
3479 la->meta_data.originating_change_time)) {
3480 DEBUG(1,("Discarding older DRS linked attribute update to %s on %s from %s\n",
3481 old_el->name, ldb_dn_get_linearized(msg->dn),
3482 GUID_string(tmp_ctx, &la->meta_data.originating_invocation_id)));
3483 talloc_free(tmp_ctx);
3487 /* get a seq_num for this change */
3488 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &seq_num);
3489 if (ret != LDB_SUCCESS) {
3490 talloc_free(tmp_ctx);
3495 /* remove the existing backlink */
3496 ret = replmd_add_backlink(module, schema, &la->identifier->guid, &guid, false, attr, false);
3497 if (ret != LDB_SUCCESS) {
3498 talloc_free(tmp_ctx);
3503 ret = replmd_update_la_val(tmp_ctx, pdn->v, dsdb_dn, pdn->dsdb_dn,
3504 &la->meta_data.originating_invocation_id,
3505 la->meta_data.originating_usn, seq_num,
3506 la->meta_data.originating_change_time,
3508 if (ret != LDB_SUCCESS) {
3509 talloc_free(tmp_ctx);
3514 /* add the new backlink */
3515 ret = replmd_add_backlink(module, schema, &la->identifier->guid, &guid, true, attr, false);
3516 if (ret != LDB_SUCCESS) {
3517 talloc_free(tmp_ctx);
3522 /* get a seq_num for this change */
3523 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &seq_num);
3524 if (ret != LDB_SUCCESS) {
3525 talloc_free(tmp_ctx);
3529 old_el->values = talloc_realloc(msg->elements, old_el->values,
3530 struct ldb_val, old_el->num_values+1);
3531 if (!old_el->values) {
3532 ldb_module_oom(module);
3533 return LDB_ERR_OPERATIONS_ERROR;
3535 old_el->num_values++;
3537 ret = replmd_build_la_val(tmp_ctx, &old_el->values[old_el->num_values-1], dsdb_dn,
3538 &la->meta_data.originating_invocation_id,
3539 la->meta_data.originating_usn, seq_num,
3540 la->meta_data.originating_change_time,
3541 (la->flags & DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE)?false:true);
3542 if (ret != LDB_SUCCESS) {
3543 talloc_free(tmp_ctx);
3548 ret = replmd_add_backlink(module, schema, &la->identifier->guid, &guid,
3550 if (ret != LDB_SUCCESS) {
3551 talloc_free(tmp_ctx);
3557 /* we only change whenChanged and uSNChanged if the seq_num
3559 if (add_time_element(msg, "whenChanged", t) != LDB_SUCCESS) {
3560 talloc_free(tmp_ctx);
3561 return LDB_ERR_OPERATIONS_ERROR;
3564 if (add_uint64_element(msg, "uSNChanged", seq_num) != LDB_SUCCESS) {
3565 talloc_free(tmp_ctx);
3566 return LDB_ERR_OPERATIONS_ERROR;
3569 ret = dsdb_module_modify(module, msg, 0);
3570 if (ret != LDB_SUCCESS) {
3571 ldb_debug(ldb, LDB_DEBUG_WARNING, "Failed to apply linked attribute change '%s' %s\n",
3573 ldb_ldif_message_string(ldb, tmp_ctx, LDB_CHANGETYPE_MODIFY, msg));
3574 talloc_free(tmp_ctx);
3578 talloc_free(tmp_ctx);
3583 static int replmd_extended(struct ldb_module *module, struct ldb_request *req)
3585 if (strcmp(req->op.extended.oid, DSDB_EXTENDED_REPLICATED_OBJECTS_OID) == 0) {
3586 return replmd_extended_replicated_objects(module, req);
3589 return ldb_next_request(module, req);
3594 we hook into the transaction operations to allow us to
3595 perform the linked attribute updates at the end of the whole
3596 transaction. This allows a forward linked attribute to be created
3597 before the object is created. During a vampire, w2k8 sends us linked
3598 attributes before the objects they are part of.
3600 static int replmd_start_transaction(struct ldb_module *module)
3602 /* create our private structure for this transaction */
3603 struct replmd_private *replmd_private = talloc_get_type(ldb_module_get_private(module),
3604 struct replmd_private);
3605 replmd_txn_cleanup(replmd_private);
3607 /* free any leftover mod_usn records from cancelled
3609 while (replmd_private->ncs) {
3610 struct nc_entry *e = replmd_private->ncs;
3611 DLIST_REMOVE(replmd_private->ncs, e);
3615 return ldb_next_start_trans(module);
3619 on prepare commit we loop over our queued la_context structures and
3622 static int replmd_prepare_commit(struct ldb_module *module)
3624 struct replmd_private *replmd_private =
3625 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
3626 struct la_entry *la, *prev;
3627 struct la_backlink *bl;
3630 /* walk the list backwards, to do the first entry first, as we
3631 * added the entries with DLIST_ADD() which puts them at the
3632 * start of the list */
3633 for (la = replmd_private->la_list; la && la->next; la=la->next) ;
3635 for (; la; la=prev) {
3637 DLIST_REMOVE(replmd_private->la_list, la);
3638 ret = replmd_process_linked_attribute(module, la);
3639 if (ret != LDB_SUCCESS) {
3640 replmd_txn_cleanup(replmd_private);
3645 /* process our backlink list, creating and deleting backlinks
3647 for (bl=replmd_private->la_backlinks; bl; bl=bl->next) {
3648 ret = replmd_process_backlink(module, bl);
3649 if (ret != LDB_SUCCESS) {
3650 replmd_txn_cleanup(replmd_private);
3655 replmd_txn_cleanup(replmd_private);
3657 /* possibly change @REPLCHANGED */
3658 ret = replmd_notify_store(module);
3659 if (ret != LDB_SUCCESS) {
3663 return ldb_next_prepare_commit(module);
3666 static int replmd_del_transaction(struct ldb_module *module)
3668 struct replmd_private *replmd_private =
3669 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
3670 replmd_txn_cleanup(replmd_private);
3672 return ldb_next_del_trans(module);
3676 _PUBLIC_ const struct ldb_module_ops ldb_repl_meta_data_module_ops = {
3677 .name = "repl_meta_data",
3678 .init_context = replmd_init,
3680 .modify = replmd_modify,
3681 .rename = replmd_rename,
3682 .del = replmd_delete,
3683 .extended = replmd_extended,
3684 .start_transaction = replmd_start_transaction,
3685 .prepare_commit = replmd_prepare_commit,
3686 .del_transaction = replmd_del_transaction,