4 Copyright (C) Simo Sorce 2004-2008
5 Copyright (C) Andrew Bartlett <abartlet@samba.org> 2005-2013
6 Copyright (C) Andrew Tridgell 2005-2009
7 Copyright (C) Stefan Metzmacher <metze@samba.org> 2007
8 Copyright (C) Matthieu Patou <mat@samba.org> 2010-2011
10 This program is free software; you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation; either version 3 of the License, or
13 (at your option) any later version.
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
20 You should have received a copy of the GNU General Public License
21 along with this program. If not, see <http://www.gnu.org/licenses/>.
27 * Component: ldb repl_meta_data module
29 * Description: - add a unique objectGUID onto every new record,
30 * - handle whenCreated, whenChanged timestamps
31 * - handle uSNCreated, uSNChanged numbers
32 * - handle replPropertyMetaData attribute
35 * Author: Stefan Metzmacher
39 #include "ldb_module.h"
40 #include "dsdb/samdb/samdb.h"
41 #include "dsdb/common/proto.h"
42 #include "../libds/common/flags.h"
43 #include "librpc/gen_ndr/ndr_misc.h"
44 #include "librpc/gen_ndr/ndr_drsuapi.h"
45 #include "librpc/gen_ndr/ndr_drsblobs.h"
46 #include "param/param.h"
47 #include "libcli/security/security.h"
48 #include "lib/util/dlinklist.h"
49 #include "dsdb/samdb/ldb_modules/util.h"
50 #include "lib/util/binsearch.h"
51 #include "lib/util/tsort.h"
54 * It's 29/12/9999 at 23:59:59 UTC as specified in MS-ADTS 7.1.1.4.2
55 * Deleted Objects Container
57 static const NTTIME DELETED_OBJECT_CONTAINER_CHANGE_TIME = 2650466015990000000ULL;
59 struct replmd_private {
61 struct la_entry *la_list;
63 struct la_backlink *la_backlinks;
65 struct nc_entry *prev, *next;
68 uint64_t mod_usn_urgent;
70 struct ldb_dn *schema_dn;
74 struct la_entry *next, *prev;
75 struct drsuapi_DsReplicaLinkedAttribute *la;
78 struct replmd_replicated_request {
79 struct ldb_module *module;
80 struct ldb_request *req;
82 const struct dsdb_schema *schema;
83 struct GUID our_invocation_id;
85 /* the controls we pass down */
86 struct ldb_control **controls;
88 /* details for the mode where we apply a bunch of inbound replication meessages */
90 uint32_t index_current;
91 struct dsdb_extended_replicated_objects *objs;
93 struct ldb_message *search_msg;
94 struct GUID local_parent_guid;
102 static int replmd_replicated_apply_merge(struct replmd_replicated_request *ar);
103 static int replmd_delete_internals(struct ldb_module *module, struct ldb_request *req, bool re_delete);
105 enum urgent_situation {
106 REPL_URGENT_ON_CREATE = 1,
107 REPL_URGENT_ON_UPDATE = 2,
108 REPL_URGENT_ON_DELETE = 4
111 enum deletion_state {
112 OBJECT_NOT_DELETED=1,
119 static void replmd_deletion_state(struct ldb_module *module,
120 const struct ldb_message *msg,
121 enum deletion_state *current_state,
122 enum deletion_state *next_state)
125 bool enabled = false;
128 *current_state = OBJECT_REMOVED;
129 if (next_state != NULL) {
130 *next_state = OBJECT_REMOVED;
135 ret = dsdb_recyclebin_enabled(module, &enabled);
136 if (ret != LDB_SUCCESS) {
140 if (ldb_msg_check_string_attribute(msg, "isDeleted", "TRUE")) {
142 *current_state = OBJECT_TOMBSTONE;
143 if (next_state != NULL) {
144 *next_state = OBJECT_REMOVED;
149 if (ldb_msg_check_string_attribute(msg, "isRecycled", "TRUE")) {
150 *current_state = OBJECT_RECYCLED;
151 if (next_state != NULL) {
152 *next_state = OBJECT_REMOVED;
157 *current_state = OBJECT_DELETED;
158 if (next_state != NULL) {
159 *next_state = OBJECT_RECYCLED;
164 *current_state = OBJECT_NOT_DELETED;
165 if (next_state == NULL) {
170 *next_state = OBJECT_DELETED;
172 *next_state = OBJECT_TOMBSTONE;
176 static const struct {
177 const char *update_name;
178 enum urgent_situation repl_situation;
179 } urgent_objects[] = {
180 {"nTDSDSA", (REPL_URGENT_ON_CREATE | REPL_URGENT_ON_DELETE)},
181 {"crossRef", (REPL_URGENT_ON_CREATE | REPL_URGENT_ON_DELETE)},
182 {"attributeSchema", (REPL_URGENT_ON_CREATE | REPL_URGENT_ON_UPDATE)},
183 {"classSchema", (REPL_URGENT_ON_CREATE | REPL_URGENT_ON_UPDATE)},
184 {"secret", (REPL_URGENT_ON_CREATE | REPL_URGENT_ON_UPDATE)},
185 {"rIDManager", (REPL_URGENT_ON_CREATE | REPL_URGENT_ON_UPDATE)},
189 /* Attributes looked for when updating or deleting, to check for a urgent replication needed */
190 static const char *urgent_attrs[] = {
193 "userAccountControl",
198 static bool replmd_check_urgent_objectclass(const struct ldb_message_element *objectclass_el,
199 enum urgent_situation situation)
202 for (i=0; urgent_objects[i].update_name; i++) {
204 if ((situation & urgent_objects[i].repl_situation) == 0) {
208 for (j=0; j<objectclass_el->num_values; j++) {
209 const struct ldb_val *v = &objectclass_el->values[j];
210 if (ldb_attr_cmp((const char *)v->data, urgent_objects[i].update_name) == 0) {
218 static bool replmd_check_urgent_attribute(const struct ldb_message_element *el)
220 if (ldb_attr_in_list(urgent_attrs, el->name)) {
227 static int replmd_replicated_apply_isDeleted(struct replmd_replicated_request *ar);
230 initialise the module
231 allocate the private structure and build the list
232 of partition DNs for use by replmd_notify()
234 static int replmd_init(struct ldb_module *module)
236 struct replmd_private *replmd_private;
237 struct ldb_context *ldb = ldb_module_get_ctx(module);
239 replmd_private = talloc_zero(module, struct replmd_private);
240 if (replmd_private == NULL) {
242 return LDB_ERR_OPERATIONS_ERROR;
244 ldb_module_set_private(module, replmd_private);
246 replmd_private->schema_dn = ldb_get_schema_basedn(ldb);
248 return ldb_next_init(module);
252 cleanup our per-transaction contexts
254 static void replmd_txn_cleanup(struct replmd_private *replmd_private)
256 talloc_free(replmd_private->la_ctx);
257 replmd_private->la_list = NULL;
258 replmd_private->la_ctx = NULL;
260 talloc_free(replmd_private->bl_ctx);
261 replmd_private->la_backlinks = NULL;
262 replmd_private->bl_ctx = NULL;
267 struct la_backlink *next, *prev;
268 const char *attr_name;
269 struct GUID forward_guid, target_guid;
274 process a backlinks we accumulated during a transaction, adding and
275 deleting the backlinks from the target objects
277 static int replmd_process_backlink(struct ldb_module *module, struct la_backlink *bl, struct ldb_request *parent)
279 struct ldb_dn *target_dn, *source_dn;
281 struct ldb_context *ldb = ldb_module_get_ctx(module);
282 struct ldb_message *msg;
283 TALLOC_CTX *tmp_ctx = talloc_new(bl);
289 - construct ldb_message
290 - either an add or a delete
292 ret = dsdb_module_dn_by_guid(module, tmp_ctx, &bl->target_guid, &target_dn, parent);
293 if (ret != LDB_SUCCESS) {
294 DEBUG(2,(__location__ ": WARNING: Failed to find target DN for linked attribute with GUID %s\n",
295 GUID_string(bl, &bl->target_guid)));
299 ret = dsdb_module_dn_by_guid(module, tmp_ctx, &bl->forward_guid, &source_dn, parent);
300 if (ret != LDB_SUCCESS) {
301 ldb_asprintf_errstring(ldb, "Failed to find source DN for linked attribute with GUID %s\n",
302 GUID_string(bl, &bl->forward_guid));
303 talloc_free(tmp_ctx);
307 msg = ldb_msg_new(tmp_ctx);
309 ldb_module_oom(module);
310 talloc_free(tmp_ctx);
311 return LDB_ERR_OPERATIONS_ERROR;
314 /* construct a ldb_message for adding/deleting the backlink */
316 dn_string = ldb_dn_get_extended_linearized(tmp_ctx, source_dn, 1);
318 ldb_module_oom(module);
319 talloc_free(tmp_ctx);
320 return LDB_ERR_OPERATIONS_ERROR;
322 ret = ldb_msg_add_steal_string(msg, bl->attr_name, dn_string);
323 if (ret != LDB_SUCCESS) {
324 talloc_free(tmp_ctx);
327 msg->elements[0].flags = bl->active?LDB_FLAG_MOD_ADD:LDB_FLAG_MOD_DELETE;
329 /* a backlink should never be single valued. Unfortunately the
330 exchange schema has a attribute
331 msExchBridgeheadedLocalConnectorsDNBL which is single
332 valued and a backlink. We need to cope with that by
333 ignoring the single value flag */
334 msg->elements[0].flags |= LDB_FLAG_INTERNAL_DISABLE_SINGLE_VALUE_CHECK;
336 ret = dsdb_module_modify(module, msg, DSDB_FLAG_NEXT_MODULE, parent);
337 if (ret == LDB_ERR_NO_SUCH_ATTRIBUTE && !bl->active) {
338 /* we allow LDB_ERR_NO_SUCH_ATTRIBUTE as success to
339 cope with possible corruption where the backlink has
340 already been removed */
341 DEBUG(3,("WARNING: backlink from %s already removed from %s - %s\n",
342 ldb_dn_get_linearized(target_dn),
343 ldb_dn_get_linearized(source_dn),
344 ldb_errstring(ldb)));
346 } else if (ret != LDB_SUCCESS) {
347 ldb_asprintf_errstring(ldb, "Failed to %s backlink from %s to %s - %s",
348 bl->active?"add":"remove",
349 ldb_dn_get_linearized(source_dn),
350 ldb_dn_get_linearized(target_dn),
352 talloc_free(tmp_ctx);
355 talloc_free(tmp_ctx);
360 add a backlink to the list of backlinks to add/delete in the prepare
363 static int replmd_add_backlink(struct ldb_module *module, const struct dsdb_schema *schema,
364 struct GUID *forward_guid, struct GUID *target_guid,
365 bool active, const struct dsdb_attribute *schema_attr, bool immediate)
367 const struct dsdb_attribute *target_attr;
368 struct la_backlink *bl;
369 struct replmd_private *replmd_private =
370 talloc_get_type_abort(ldb_module_get_private(module), struct replmd_private);
372 target_attr = dsdb_attribute_by_linkID(schema, schema_attr->linkID ^ 1);
375 * windows 2003 has a broken schema where the
376 * definition of msDS-IsDomainFor is missing (which is
377 * supposed to be the backlink of the
378 * msDS-HasDomainNCs attribute
383 /* see if its already in the list */
384 for (bl=replmd_private->la_backlinks; bl; bl=bl->next) {
385 if (GUID_equal(forward_guid, &bl->forward_guid) &&
386 GUID_equal(target_guid, &bl->target_guid) &&
387 (target_attr->lDAPDisplayName == bl->attr_name ||
388 strcmp(target_attr->lDAPDisplayName, bl->attr_name) == 0)) {
394 /* we found an existing one */
395 if (bl->active == active) {
398 DLIST_REMOVE(replmd_private->la_backlinks, bl);
403 if (replmd_private->bl_ctx == NULL) {
404 replmd_private->bl_ctx = talloc_new(replmd_private);
405 if (replmd_private->bl_ctx == NULL) {
406 ldb_module_oom(module);
407 return LDB_ERR_OPERATIONS_ERROR;
412 bl = talloc(replmd_private->bl_ctx, struct la_backlink);
414 ldb_module_oom(module);
415 return LDB_ERR_OPERATIONS_ERROR;
418 /* Ensure the schema does not go away before the bl->attr_name is used */
419 if (!talloc_reference(bl, schema)) {
421 ldb_module_oom(module);
422 return LDB_ERR_OPERATIONS_ERROR;
425 bl->attr_name = target_attr->lDAPDisplayName;
426 bl->forward_guid = *forward_guid;
427 bl->target_guid = *target_guid;
430 /* the caller may ask for this backlink to be processed
433 int ret = replmd_process_backlink(module, bl, NULL);
438 DLIST_ADD(replmd_private->la_backlinks, bl);
445 * Callback for most write operations in this module:
447 * notify the repl task that a object has changed. The notifies are
448 * gathered up in the replmd_private structure then written to the
449 * @REPLCHANGED object in each partition during the prepare_commit
451 static int replmd_op_callback(struct ldb_request *req, struct ldb_reply *ares)
454 struct replmd_replicated_request *ac =
455 talloc_get_type_abort(req->context, struct replmd_replicated_request);
456 struct replmd_private *replmd_private =
457 talloc_get_type_abort(ldb_module_get_private(ac->module), struct replmd_private);
458 struct nc_entry *modified_partition;
459 struct ldb_control *partition_ctrl;
460 const struct dsdb_control_current_partition *partition;
462 struct ldb_control **controls;
464 partition_ctrl = ldb_reply_get_control(ares, DSDB_CONTROL_CURRENT_PARTITION_OID);
466 controls = ares->controls;
467 if (ldb_request_get_control(ac->req,
468 DSDB_CONTROL_CURRENT_PARTITION_OID) == NULL) {
470 * Remove the current partition control from what we pass up
471 * the chain if it hasn't been requested manually.
473 controls = ldb_controls_except_specified(ares->controls, ares,
477 if (ares->error != LDB_SUCCESS) {
478 DEBUG(5,("%s failure. Error is: %s\n", __FUNCTION__, ldb_strerror(ares->error)));
479 return ldb_module_done(ac->req, controls,
480 ares->response, ares->error);
483 if (ares->type != LDB_REPLY_DONE) {
484 ldb_set_errstring(ldb_module_get_ctx(ac->module), "Invalid reply type for notify\n!");
485 return ldb_module_done(ac->req, NULL,
486 NULL, LDB_ERR_OPERATIONS_ERROR);
489 if (!partition_ctrl) {
490 ldb_set_errstring(ldb_module_get_ctx(ac->module),"No partition control on reply");
491 return ldb_module_done(ac->req, NULL,
492 NULL, LDB_ERR_OPERATIONS_ERROR);
495 partition = talloc_get_type_abort(partition_ctrl->data,
496 struct dsdb_control_current_partition);
498 if (ac->seq_num > 0) {
499 for (modified_partition = replmd_private->ncs; modified_partition;
500 modified_partition = modified_partition->next) {
501 if (ldb_dn_compare(modified_partition->dn, partition->dn) == 0) {
506 if (modified_partition == NULL) {
507 modified_partition = talloc_zero(replmd_private, struct nc_entry);
508 if (!modified_partition) {
509 ldb_oom(ldb_module_get_ctx(ac->module));
510 return ldb_module_done(ac->req, NULL,
511 NULL, LDB_ERR_OPERATIONS_ERROR);
513 modified_partition->dn = ldb_dn_copy(modified_partition, partition->dn);
514 if (!modified_partition->dn) {
515 ldb_oom(ldb_module_get_ctx(ac->module));
516 return ldb_module_done(ac->req, NULL,
517 NULL, LDB_ERR_OPERATIONS_ERROR);
519 DLIST_ADD(replmd_private->ncs, modified_partition);
522 if (ac->seq_num > modified_partition->mod_usn) {
523 modified_partition->mod_usn = ac->seq_num;
525 modified_partition->mod_usn_urgent = ac->seq_num;
530 if (ac->apply_mode) {
531 ret = replmd_replicated_apply_isDeleted(ac);
532 if (ret != LDB_SUCCESS) {
533 return ldb_module_done(ac->req, NULL, NULL, ret);
537 /* free the partition control container here, for the
538 * common path. Other cases will have it cleaned up
539 * eventually with the ares */
540 talloc_free(partition_ctrl);
541 return ldb_module_done(ac->req, controls,
542 ares->response, LDB_SUCCESS);
548 * update a @REPLCHANGED record in each partition if there have been
549 * any writes of replicated data in the partition
551 static int replmd_notify_store(struct ldb_module *module, struct ldb_request *parent)
553 struct replmd_private *replmd_private =
554 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
556 while (replmd_private->ncs) {
558 struct nc_entry *modified_partition = replmd_private->ncs;
560 ret = dsdb_module_save_partition_usn(module, modified_partition->dn,
561 modified_partition->mod_usn,
562 modified_partition->mod_usn_urgent, parent);
563 if (ret != LDB_SUCCESS) {
564 DEBUG(0,(__location__ ": Failed to save partition uSN for %s\n",
565 ldb_dn_get_linearized(modified_partition->dn)));
569 if (ldb_dn_compare(modified_partition->dn,
570 replmd_private->schema_dn) == 0) {
571 struct ldb_result *ext_res;
572 ret = dsdb_module_extended(module,
573 replmd_private->schema_dn,
575 DSDB_EXTENDED_SCHEMA_UPDATE_NOW_OID,
577 DSDB_FLAG_NEXT_MODULE,
579 if (ret != LDB_SUCCESS) {
582 talloc_free(ext_res);
585 DLIST_REMOVE(replmd_private->ncs, modified_partition);
586 talloc_free(modified_partition);
594 created a replmd_replicated_request context
596 static struct replmd_replicated_request *replmd_ctx_init(struct ldb_module *module,
597 struct ldb_request *req)
599 struct ldb_context *ldb;
600 struct replmd_replicated_request *ac;
601 const struct GUID *our_invocation_id;
603 ldb = ldb_module_get_ctx(module);
605 ac = talloc_zero(req, struct replmd_replicated_request);
614 ac->schema = dsdb_get_schema(ldb, ac);
616 ldb_debug_set(ldb, LDB_DEBUG_FATAL,
617 "replmd_modify: no dsdb_schema loaded");
618 DEBUG(0,(__location__ ": %s\n", ldb_errstring(ldb)));
623 /* get our invocationId */
624 our_invocation_id = samdb_ntds_invocation_id(ldb);
625 if (!our_invocation_id) {
626 ldb_debug_set(ldb, LDB_DEBUG_FATAL,
627 "replmd_add: unable to find invocationId\n");
631 ac->our_invocation_id = *our_invocation_id;
637 add a time element to a record
639 static int add_time_element(struct ldb_message *msg, const char *attr, time_t t)
641 struct ldb_message_element *el;
645 if (ldb_msg_find_element(msg, attr) != NULL) {
649 s = ldb_timestring(msg, t);
651 return LDB_ERR_OPERATIONS_ERROR;
654 ret = ldb_msg_add_string(msg, attr, s);
655 if (ret != LDB_SUCCESS) {
659 el = ldb_msg_find_element(msg, attr);
660 /* always set as replace. This works because on add ops, the flag
662 el->flags = LDB_FLAG_MOD_REPLACE;
668 add a uint64_t element to a record
670 static int add_uint64_element(struct ldb_context *ldb, struct ldb_message *msg,
671 const char *attr, uint64_t v)
673 struct ldb_message_element *el;
676 if (ldb_msg_find_element(msg, attr) != NULL) {
680 ret = samdb_msg_add_uint64(ldb, msg, msg, attr, v);
681 if (ret != LDB_SUCCESS) {
685 el = ldb_msg_find_element(msg, attr);
686 /* always set as replace. This works because on add ops, the flag
688 el->flags = LDB_FLAG_MOD_REPLACE;
693 static int replmd_replPropertyMetaData1_attid_sort(const struct replPropertyMetaData1 *m1,
694 const struct replPropertyMetaData1 *m2,
695 const uint32_t *rdn_attid)
698 * This assignment seems inoccous, but it is critical for the
699 * system, as we need to do the comparisons as a unsigned
700 * quantity, not signed (enums are signed integers)
702 uint32_t attid_1 = m1->attid;
703 uint32_t attid_2 = m2->attid;
705 if (attid_1 == attid_2) {
710 * See above regarding this being an unsigned comparison.
711 * Otherwise when the high bit is set on non-standard
712 * attributes, they would end up first, before objectClass
715 return attid_1 > attid_2 ? 1 : -1;
718 static int replmd_replPropertyMetaDataCtr1_verify(struct ldb_context *ldb,
719 struct replPropertyMetaDataCtr1 *ctr1,
722 if (ctr1->count == 0) {
723 ldb_debug_set(ldb, LDB_DEBUG_FATAL,
724 "No elements found in replPropertyMetaData for %s!\n",
725 ldb_dn_get_linearized(dn));
726 return LDB_ERR_CONSTRAINT_VIOLATION;
729 /* the objectClass attribute is value 0x00000000, so must be first */
730 if (ctr1->array[0].attid != DRSUAPI_ATTID_objectClass) {
731 ldb_debug_set(ldb, LDB_DEBUG_FATAL,
732 "No objectClass found in replPropertyMetaData for %s!\n",
733 ldb_dn_get_linearized(dn));
734 return LDB_ERR_OBJECT_CLASS_VIOLATION;
740 static int replmd_replPropertyMetaDataCtr1_sort_and_verify(struct ldb_context *ldb,
741 struct replPropertyMetaDataCtr1 *ctr1,
744 /* Note this is O(n^2) for the almost-sorted case, which this is */
745 LDB_TYPESAFE_QSORT(ctr1->array, ctr1->count, NULL,
746 replmd_replPropertyMetaData1_attid_sort);
747 return replmd_replPropertyMetaDataCtr1_verify(ldb, ctr1, dn);
750 static int replmd_ldb_message_element_attid_sort(const struct ldb_message_element *e1,
751 const struct ldb_message_element *e2,
752 const struct dsdb_schema *schema)
754 const struct dsdb_attribute *a1;
755 const struct dsdb_attribute *a2;
758 * TODO: make this faster by caching the dsdb_attribute pointer
759 * on the ldb_messag_element
762 a1 = dsdb_attribute_by_lDAPDisplayName(schema, e1->name);
763 a2 = dsdb_attribute_by_lDAPDisplayName(schema, e2->name);
766 * TODO: remove this check, we should rely on e1 and e2 having valid attribute names
770 return strcasecmp(e1->name, e2->name);
772 if (a1->attributeID_id == a2->attributeID_id) {
775 return a1->attributeID_id > a2->attributeID_id ? 1 : -1;
778 static void replmd_ldb_message_sort(struct ldb_message *msg,
779 const struct dsdb_schema *schema)
781 LDB_TYPESAFE_QSORT(msg->elements, msg->num_elements, schema, replmd_ldb_message_element_attid_sort);
784 static int replmd_build_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct dsdb_dn *dsdb_dn,
785 const struct GUID *invocation_id, uint64_t seq_num,
786 uint64_t local_usn, NTTIME nttime, uint32_t version, bool deleted);
790 fix up linked attributes in replmd_add.
791 This involves setting up the right meta-data in extended DN
792 components, and creating backlinks to the object
794 static int replmd_add_fix_la(struct ldb_module *module, struct ldb_message_element *el,
795 uint64_t seq_num, const struct GUID *invocationId, NTTIME now,
796 struct GUID *guid, const struct dsdb_attribute *sa, struct ldb_request *parent)
799 TALLOC_CTX *tmp_ctx = talloc_new(el->values);
800 struct ldb_context *ldb = ldb_module_get_ctx(module);
802 /* We will take a reference to the schema in replmd_add_backlink */
803 const struct dsdb_schema *schema = dsdb_get_schema(ldb, NULL);
805 for (i=0; i<el->num_values; i++) {
806 struct ldb_val *v = &el->values[i];
807 struct dsdb_dn *dsdb_dn = dsdb_dn_parse(tmp_ctx, ldb, v, sa->syntax->ldap_oid);
808 struct GUID target_guid;
812 /* note that the DN already has the extended
813 components from the extended_dn_store module */
814 status = dsdb_get_extended_dn_guid(dsdb_dn->dn, &target_guid, "GUID");
815 if (!NT_STATUS_IS_OK(status) || GUID_all_zero(&target_guid)) {
816 ret = dsdb_module_guid_by_dn(module, dsdb_dn->dn, &target_guid, parent);
817 if (ret != LDB_SUCCESS) {
818 talloc_free(tmp_ctx);
821 ret = dsdb_set_extended_dn_guid(dsdb_dn->dn, &target_guid, "GUID");
822 if (ret != LDB_SUCCESS) {
823 talloc_free(tmp_ctx);
828 ret = replmd_build_la_val(el->values, v, dsdb_dn, invocationId,
829 seq_num, seq_num, now, 0, false);
830 if (ret != LDB_SUCCESS) {
831 talloc_free(tmp_ctx);
835 ret = replmd_add_backlink(module, schema, guid, &target_guid, true, sa, false);
836 if (ret != LDB_SUCCESS) {
837 talloc_free(tmp_ctx);
842 talloc_free(tmp_ctx);
848 intercept add requests
850 static int replmd_add(struct ldb_module *module, struct ldb_request *req)
852 struct ldb_context *ldb;
853 struct ldb_control *control;
854 struct replmd_replicated_request *ac;
855 enum ndr_err_code ndr_err;
856 struct ldb_request *down_req;
857 struct ldb_message *msg;
858 const DATA_BLOB *guid_blob;
860 struct replPropertyMetaDataBlob nmd;
861 struct ldb_val nmd_value;
864 * The use of a time_t here seems odd, but as the NTTIME
865 * elements are actually declared as NTTIME_1sec in the IDL,
866 * getting a higher resolution timestamp is not required.
868 time_t t = time(NULL);
873 unsigned int functional_level;
875 bool allow_add_guid = false;
876 bool remove_current_guid = false;
877 bool is_urgent = false;
878 bool is_schema_nc = false;
879 struct ldb_message_element *objectclass_el;
880 struct replmd_private *replmd_private =
881 talloc_get_type_abort(ldb_module_get_private(module), struct replmd_private);
883 /* check if there's a show relax control (used by provision to say 'I know what I'm doing') */
884 control = ldb_request_get_control(req, LDB_CONTROL_RELAX_OID);
886 allow_add_guid = true;
889 /* do not manipulate our control entries */
890 if (ldb_dn_is_special(req->op.add.message->dn)) {
891 return ldb_next_request(module, req);
894 ldb = ldb_module_get_ctx(module);
896 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_add\n");
898 guid_blob = ldb_msg_find_ldb_val(req->op.add.message, "objectGUID");
899 if (guid_blob != NULL) {
900 if (!allow_add_guid) {
901 ldb_set_errstring(ldb,
902 "replmd_add: it's not allowed to add an object with objectGUID!");
903 return LDB_ERR_UNWILLING_TO_PERFORM;
905 NTSTATUS status = GUID_from_data_blob(guid_blob,&guid);
906 if (!NT_STATUS_IS_OK(status)) {
907 ldb_set_errstring(ldb,
908 "replmd_add: Unable to parse the 'objectGUID' as a GUID!");
909 return LDB_ERR_UNWILLING_TO_PERFORM;
911 /* we remove this attribute as it can be a string and
912 * will not be treated correctly and then we will re-add
913 * it later on in the good format */
914 remove_current_guid = true;
918 guid = GUID_random();
921 ac = replmd_ctx_init(module, req);
923 return ldb_module_oom(module);
926 functional_level = dsdb_functional_level(ldb);
928 /* Get a sequence number from the backend */
929 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &ac->seq_num);
930 if (ret != LDB_SUCCESS) {
935 /* we have to copy the message as the caller might have it as a const */
936 msg = ldb_msg_copy_shallow(ac, req->op.add.message);
940 return LDB_ERR_OPERATIONS_ERROR;
943 /* generated times */
944 unix_to_nt_time(&now, t);
945 time_str = ldb_timestring(msg, t);
949 return LDB_ERR_OPERATIONS_ERROR;
951 if (remove_current_guid) {
952 ldb_msg_remove_attr(msg,"objectGUID");
956 * remove autogenerated attributes
958 ldb_msg_remove_attr(msg, "whenCreated");
959 ldb_msg_remove_attr(msg, "whenChanged");
960 ldb_msg_remove_attr(msg, "uSNCreated");
961 ldb_msg_remove_attr(msg, "uSNChanged");
962 ldb_msg_remove_attr(msg, "replPropertyMetaData");
965 * readd replicated attributes
967 ret = ldb_msg_add_string(msg, "whenCreated", time_str);
968 if (ret != LDB_SUCCESS) {
974 /* build the replication meta_data */
977 nmd.ctr.ctr1.count = msg->num_elements;
978 nmd.ctr.ctr1.array = talloc_array(msg,
979 struct replPropertyMetaData1,
981 if (!nmd.ctr.ctr1.array) {
984 return LDB_ERR_OPERATIONS_ERROR;
987 is_schema_nc = ldb_dn_compare_base(replmd_private->schema_dn, msg->dn) == 0;
989 for (i=0; i < msg->num_elements; i++) {
990 struct ldb_message_element *e = &msg->elements[i];
991 struct replPropertyMetaData1 *m = &nmd.ctr.ctr1.array[ni];
992 const struct dsdb_attribute *sa;
994 if (e->name[0] == '@') continue;
996 sa = dsdb_attribute_by_lDAPDisplayName(ac->schema, e->name);
998 ldb_debug_set(ldb, LDB_DEBUG_ERROR,
999 "replmd_add: attribute '%s' not defined in schema\n",
1002 return LDB_ERR_NO_SUCH_ATTRIBUTE;
1005 if ((sa->systemFlags & DS_FLAG_ATTR_NOT_REPLICATED) || (sa->systemFlags & DS_FLAG_ATTR_IS_CONSTRUCTED)) {
1006 /* if the attribute is not replicated (0x00000001)
1007 * or constructed (0x00000004) it has no metadata
1012 if (sa->linkID != 0 && functional_level > DS_DOMAIN_FUNCTION_2000) {
1013 ret = replmd_add_fix_la(module, e, ac->seq_num,
1014 &ac->our_invocation_id, now,
1016 if (ret != LDB_SUCCESS) {
1020 /* linked attributes are not stored in
1021 replPropertyMetaData in FL above w2k */
1025 m->attid = dsdb_attribute_get_attid(sa, is_schema_nc);
1027 if (m->attid == DRSUAPI_ATTID_isDeleted) {
1028 const struct ldb_val *rdn_val = ldb_dn_get_rdn_val(msg->dn);
1031 if (rdn_val == NULL) {
1034 return LDB_ERR_OPERATIONS_ERROR;
1037 rdn = (const char*)rdn_val->data;
1038 if (strcmp(rdn, "Deleted Objects") == 0) {
1040 * Set the originating_change_time to 29/12/9999 at 23:59:59
1041 * as specified in MS-ADTS 7.1.1.4.2 Deleted Objects Container
1043 m->originating_change_time = DELETED_OBJECT_CONTAINER_CHANGE_TIME;
1045 m->originating_change_time = now;
1048 m->originating_change_time = now;
1050 m->originating_invocation_id = ac->our_invocation_id;
1051 m->originating_usn = ac->seq_num;
1052 m->local_usn = ac->seq_num;
1056 /* fix meta data count */
1057 nmd.ctr.ctr1.count = ni;
1060 * sort meta data array
1062 ret = replmd_replPropertyMetaDataCtr1_sort_and_verify(ldb, &nmd.ctr.ctr1, msg->dn);
1063 if (ret != LDB_SUCCESS) {
1064 ldb_asprintf_errstring(ldb, "%s: error during direct ADD: %s", __func__, ldb_errstring(ldb));
1069 /* generated NDR encoded values */
1070 ndr_err = ndr_push_struct_blob(&nmd_value, msg,
1072 (ndr_push_flags_fn_t)ndr_push_replPropertyMetaDataBlob);
1073 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1076 return LDB_ERR_OPERATIONS_ERROR;
1080 * add the autogenerated values
1082 ret = dsdb_msg_add_guid(msg, &guid, "objectGUID");
1083 if (ret != LDB_SUCCESS) {
1088 ret = ldb_msg_add_string(msg, "whenChanged", time_str);
1089 if (ret != LDB_SUCCESS) {
1094 ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNCreated", ac->seq_num);
1095 if (ret != LDB_SUCCESS) {
1100 ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNChanged", ac->seq_num);
1101 if (ret != LDB_SUCCESS) {
1106 ret = ldb_msg_add_value(msg, "replPropertyMetaData", &nmd_value, NULL);
1107 if (ret != LDB_SUCCESS) {
1114 * sort the attributes by attid before storing the object
1116 replmd_ldb_message_sort(msg, ac->schema);
1119 * Assert that we do have an objectClass
1121 objectclass_el = ldb_msg_find_element(msg, "objectClass");
1122 if (objectclass_el == NULL) {
1123 ldb_asprintf_errstring(ldb, __location__
1124 ": objectClass missing on %s\n",
1125 ldb_dn_get_linearized(msg->dn));
1127 return LDB_ERR_OBJECT_CLASS_VIOLATION;
1129 is_urgent = replmd_check_urgent_objectclass(objectclass_el,
1130 REPL_URGENT_ON_CREATE);
1132 ac->is_urgent = is_urgent;
1133 ret = ldb_build_add_req(&down_req, ldb, ac,
1136 ac, replmd_op_callback,
1139 LDB_REQ_SET_LOCATION(down_req);
1140 if (ret != LDB_SUCCESS) {
1145 /* current partition control is needed by "replmd_op_callback" */
1146 if (ldb_request_get_control(req, DSDB_CONTROL_CURRENT_PARTITION_OID) == NULL) {
1147 ret = ldb_request_add_control(down_req,
1148 DSDB_CONTROL_CURRENT_PARTITION_OID,
1150 if (ret != LDB_SUCCESS) {
1156 if (functional_level == DS_DOMAIN_FUNCTION_2000) {
1157 ret = ldb_request_add_control(down_req, DSDB_CONTROL_APPLY_LINKS, false, NULL);
1158 if (ret != LDB_SUCCESS) {
1164 /* mark the control done */
1166 control->critical = 0;
1168 /* go on with the call chain */
1169 return ldb_next_request(module, down_req);
1174 * update the replPropertyMetaData for one element
1176 static int replmd_update_rpmd_element(struct ldb_context *ldb,
1177 struct ldb_message *msg,
1178 struct ldb_message_element *el,
1179 struct ldb_message_element *old_el,
1180 struct replPropertyMetaDataBlob *omd,
1181 const struct dsdb_schema *schema,
1183 const struct GUID *our_invocation_id,
1186 struct ldb_request *req)
1189 const struct dsdb_attribute *a;
1190 struct replPropertyMetaData1 *md1;
1191 bool may_skip = false;
1194 a = dsdb_attribute_by_lDAPDisplayName(schema, el->name);
1196 if (ldb_request_get_control(req, LDB_CONTROL_RELAX_OID)) {
1197 /* allow this to make it possible for dbcheck
1198 to remove bad attributes */
1202 DEBUG(0,(__location__ ": Unable to find attribute %s in schema\n",
1204 return LDB_ERR_OPERATIONS_ERROR;
1207 attid = dsdb_attribute_get_attid(a, is_schema_nc);
1209 if ((a->systemFlags & DS_FLAG_ATTR_NOT_REPLICATED) || (a->systemFlags & DS_FLAG_ATTR_IS_CONSTRUCTED)) {
1214 * if the attribute's value haven't changed, and this isn't
1215 * just a delete of everything then return LDB_SUCCESS Unless
1216 * we have the provision control or if the attribute is
1217 * interSiteTopologyGenerator as this page explain:
1218 * http://support.microsoft.com/kb/224815 this attribute is
1219 * periodicaly written by the DC responsible for the intersite
1220 * generation in a given site
1222 * Unchanged could be deleting or replacing an already-gone
1223 * thing with an unconstrained delete/empty replace or a
1224 * replace with the same value, but not an add with the same
1225 * value because that could be about adding a duplicate (which
1226 * is for someone else to error out on).
1228 if (old_el != NULL && ldb_msg_element_equal_ordered(el, old_el)) {
1229 if (LDB_FLAG_MOD_TYPE(el->flags) == LDB_FLAG_MOD_REPLACE) {
1232 } else if (old_el == NULL && el->num_values == 0) {
1233 if (LDB_FLAG_MOD_TYPE(el->flags) == LDB_FLAG_MOD_REPLACE) {
1235 } else if (LDB_FLAG_MOD_TYPE(el->flags) == LDB_FLAG_MOD_DELETE) {
1241 if (strcmp(el->name, "interSiteTopologyGenerator") != 0 &&
1242 !ldb_request_get_control(req, LDB_CONTROL_PROVISION_OID)) {
1244 * allow this to make it possible for dbcheck
1245 * to rebuild broken metadata
1251 for (i=0; i<omd->ctr.ctr1.count; i++) {
1253 * First check if we find it under the msDS-IntID,
1254 * then check if we find it under the OID and
1257 * This allows the administrator to simply re-write
1258 * the attributes and so restore replication, which is
1259 * likely what they will try to do.
1261 if (attid == omd->ctr.ctr1.array[i].attid) {
1265 if (a->attributeID_id == omd->ctr.ctr1.array[i].attid) {
1270 if (a->linkID != 0 && dsdb_functional_level(ldb) > DS_DOMAIN_FUNCTION_2000) {
1271 /* linked attributes are not stored in
1272 replPropertyMetaData in FL above w2k, but we do
1273 raise the seqnum for the object */
1274 if (*seq_num == 0 &&
1275 ldb_sequence_number(ldb, LDB_SEQ_NEXT, seq_num) != LDB_SUCCESS) {
1276 return LDB_ERR_OPERATIONS_ERROR;
1281 if (i == omd->ctr.ctr1.count) {
1282 /* we need to add a new one */
1283 omd->ctr.ctr1.array = talloc_realloc(msg, omd->ctr.ctr1.array,
1284 struct replPropertyMetaData1, omd->ctr.ctr1.count+1);
1285 if (omd->ctr.ctr1.array == NULL) {
1287 return LDB_ERR_OPERATIONS_ERROR;
1289 omd->ctr.ctr1.count++;
1290 ZERO_STRUCT(omd->ctr.ctr1.array[i]);
1293 /* Get a new sequence number from the backend. We only do this
1294 * if we have a change that requires a new
1295 * replPropertyMetaData element
1297 if (*seq_num == 0) {
1298 int ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, seq_num);
1299 if (ret != LDB_SUCCESS) {
1300 return LDB_ERR_OPERATIONS_ERROR;
1304 md1 = &omd->ctr.ctr1.array[i];
1307 if (md1->attid == DRSUAPI_ATTID_isDeleted) {
1308 const struct ldb_val *rdn_val = ldb_dn_get_rdn_val(msg->dn);
1311 if (rdn_val == NULL) {
1313 return LDB_ERR_OPERATIONS_ERROR;
1316 rdn = (const char*)rdn_val->data;
1317 if (strcmp(rdn, "Deleted Objects") == 0) {
1319 * Set the originating_change_time to 29/12/9999 at 23:59:59
1320 * as specified in MS-ADTS 7.1.1.4.2 Deleted Objects Container
1322 md1->originating_change_time = DELETED_OBJECT_CONTAINER_CHANGE_TIME;
1324 md1->originating_change_time = now;
1327 md1->originating_change_time = now;
1329 md1->originating_invocation_id = *our_invocation_id;
1330 md1->originating_usn = *seq_num;
1331 md1->local_usn = *seq_num;
1337 * Bump the replPropertyMetaData version on an attribute, and if it
1338 * has changed (or forced by leaving rdn_old NULL), update the value
1341 * This is important, as calling a modify operation may not change the
1342 * version number if the values appear unchanged, but a rename between
1343 * parents bumps this value.
1346 static int replmd_update_rpmd_rdn_attr(struct ldb_context *ldb,
1347 struct ldb_message *msg,
1348 const struct ldb_val *rdn_new,
1349 const struct ldb_val *rdn_old,
1350 struct replPropertyMetaDataBlob *omd,
1351 struct replmd_replicated_request *ar,
1355 struct ldb_message_element new_el = {
1356 .flags = LDB_FLAG_MOD_REPLACE,
1357 .name = ldb_dn_get_rdn_name(msg->dn),
1359 .values = discard_const_p(struct ldb_val, rdn_new)
1361 struct ldb_message_element old_el = {
1362 .flags = LDB_FLAG_MOD_REPLACE,
1363 .name = ldb_dn_get_rdn_name(msg->dn),
1364 .num_values = rdn_old ? 1 : 0,
1365 .values = discard_const_p(struct ldb_val, rdn_old)
1368 if (ldb_msg_element_equal_ordered(&new_el, &old_el) == false) {
1369 int ret = ldb_msg_add(msg, &new_el, LDB_FLAG_MOD_REPLACE);
1370 if (ret != LDB_SUCCESS) {
1371 return ldb_oom(ldb);
1375 return replmd_update_rpmd_element(ldb, msg, &new_el, NULL,
1376 omd, ar->schema, &ar->seq_num,
1377 &ar->our_invocation_id,
1378 now, is_schema_nc, ar->req);
1382 static uint64_t find_max_local_usn(struct replPropertyMetaDataBlob omd)
1384 uint32_t count = omd.ctr.ctr1.count;
1387 for (i=0; i < count; i++) {
1388 struct replPropertyMetaData1 m = omd.ctr.ctr1.array[i];
1389 if (max < m.local_usn) {
1397 * update the replPropertyMetaData object each time we modify an
1398 * object. This is needed for DRS replication, as the merge on the
1399 * client is based on this object
1401 static int replmd_update_rpmd(struct ldb_module *module,
1402 const struct dsdb_schema *schema,
1403 struct ldb_request *req,
1404 const char * const *rename_attrs,
1405 struct ldb_message *msg, uint64_t *seq_num,
1406 time_t t, bool is_schema_nc,
1407 bool *is_urgent, bool *rodc)
1409 const struct ldb_val *omd_value;
1410 enum ndr_err_code ndr_err;
1411 struct replPropertyMetaDataBlob omd;
1414 const struct GUID *our_invocation_id;
1416 const char * const *attrs = NULL;
1417 const char * const attrs2[] = { "uSNChanged", "objectClass", "instanceType", NULL };
1418 struct ldb_result *res;
1419 struct ldb_context *ldb;
1420 struct ldb_message_element *objectclass_el;
1421 enum urgent_situation situation;
1422 bool rmd_is_provided;
1423 bool rmd_is_just_resorted = false;
1424 const char *not_rename_attrs[4 + msg->num_elements];
1427 attrs = rename_attrs;
1429 for (i = 0; i < msg->num_elements; i++) {
1430 not_rename_attrs[i] = msg->elements[i].name;
1432 not_rename_attrs[i] = "replPropertyMetaData";
1433 not_rename_attrs[i+1] = "objectClass";
1434 not_rename_attrs[i+2] = "instanceType";
1435 not_rename_attrs[i+3] = NULL;
1436 attrs = not_rename_attrs;
1439 ldb = ldb_module_get_ctx(module);
1441 our_invocation_id = samdb_ntds_invocation_id(ldb);
1442 if (!our_invocation_id) {
1443 /* this happens during an initial vampire while
1444 updating the schema */
1445 DEBUG(5,("No invocationID - skipping replPropertyMetaData update\n"));
1449 unix_to_nt_time(&now, t);
1451 if (ldb_request_get_control(req, DSDB_CONTROL_CHANGEREPLMETADATA_OID)) {
1452 rmd_is_provided = true;
1453 if (ldb_request_get_control(req, DSDB_CONTROL_CHANGEREPLMETADATA_RESORT_OID)) {
1454 rmd_is_just_resorted = true;
1457 rmd_is_provided = false;
1460 /* if isDeleted is present and is TRUE, then we consider we are deleting,
1461 * otherwise we consider we are updating */
1462 if (ldb_msg_check_string_attribute(msg, "isDeleted", "TRUE")) {
1463 situation = REPL_URGENT_ON_DELETE;
1464 } else if (rename_attrs) {
1465 situation = REPL_URGENT_ON_CREATE | REPL_URGENT_ON_DELETE;
1467 situation = REPL_URGENT_ON_UPDATE;
1470 if (rmd_is_provided) {
1471 /* In this case the change_replmetadata control was supplied */
1472 /* We check that it's the only attribute that is provided
1473 * (it's a rare case so it's better to keep the code simplier)
1474 * We also check that the highest local_usn is bigger or the same as
1477 if( msg->num_elements != 1 ||
1478 strncmp(msg->elements[0].name,
1479 "replPropertyMetaData", 20) ) {
1480 DEBUG(0,(__location__ ": changereplmetada control called without "\
1481 "a specified replPropertyMetaData attribute or with others\n"));
1482 return LDB_ERR_OPERATIONS_ERROR;
1484 if (situation != REPL_URGENT_ON_UPDATE) {
1485 DEBUG(0,(__location__ ": changereplmetada control can't be called when deleting an object\n"));
1486 return LDB_ERR_OPERATIONS_ERROR;
1488 omd_value = ldb_msg_find_ldb_val(msg, "replPropertyMetaData");
1490 DEBUG(0,(__location__ ": replPropertyMetaData was not specified for Object %s\n",
1491 ldb_dn_get_linearized(msg->dn)));
1492 return LDB_ERR_OPERATIONS_ERROR;
1494 ndr_err = ndr_pull_struct_blob(omd_value, msg, &omd,
1495 (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
1496 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1497 DEBUG(0,(__location__ ": Failed to parse replPropertyMetaData for %s\n",
1498 ldb_dn_get_linearized(msg->dn)));
1499 return LDB_ERR_OPERATIONS_ERROR;
1502 ret = dsdb_module_search_dn(module, msg, &res, msg->dn, attrs2,
1503 DSDB_FLAG_NEXT_MODULE |
1504 DSDB_SEARCH_SHOW_RECYCLED |
1505 DSDB_SEARCH_SHOW_EXTENDED_DN |
1506 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT |
1507 DSDB_SEARCH_REVEAL_INTERNALS, req);
1509 if (ret != LDB_SUCCESS) {
1513 if (rmd_is_just_resorted == false) {
1514 *seq_num = find_max_local_usn(omd);
1516 db_seq = ldb_msg_find_attr_as_uint64(res->msgs[0], "uSNChanged", 0);
1519 * The test here now allows for a new
1520 * replPropertyMetaData with no change, if was
1521 * just dbcheck re-sorting the values.
1523 if (*seq_num <= db_seq) {
1524 DEBUG(0,(__location__ ": changereplmetada control provided but max(local_usn)" \
1525 " is less than uSNChanged (max = %lld uSNChanged = %lld)\n",
1526 (long long)*seq_num, (long long)db_seq));
1527 return LDB_ERR_OPERATIONS_ERROR;
1532 /* search for the existing replPropertyMetaDataBlob. We need
1533 * to use REVEAL and ask for DNs in storage format to support
1534 * the check for values being the same in
1535 * replmd_update_rpmd_element()
1537 ret = dsdb_module_search_dn(module, msg, &res, msg->dn, attrs,
1538 DSDB_FLAG_NEXT_MODULE |
1539 DSDB_SEARCH_SHOW_RECYCLED |
1540 DSDB_SEARCH_SHOW_EXTENDED_DN |
1541 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT |
1542 DSDB_SEARCH_REVEAL_INTERNALS, req);
1543 if (ret != LDB_SUCCESS) {
1547 omd_value = ldb_msg_find_ldb_val(res->msgs[0], "replPropertyMetaData");
1549 DEBUG(0,(__location__ ": Object %s does not have a replPropertyMetaData attribute\n",
1550 ldb_dn_get_linearized(msg->dn)));
1551 return LDB_ERR_OPERATIONS_ERROR;
1554 ndr_err = ndr_pull_struct_blob(omd_value, msg, &omd,
1555 (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
1556 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1557 DEBUG(0,(__location__ ": Failed to parse replPropertyMetaData for %s\n",
1558 ldb_dn_get_linearized(msg->dn)));
1559 return LDB_ERR_OPERATIONS_ERROR;
1562 if (omd.version != 1) {
1563 DEBUG(0,(__location__ ": bad version %u in replPropertyMetaData for %s\n",
1564 omd.version, ldb_dn_get_linearized(msg->dn)));
1565 return LDB_ERR_OPERATIONS_ERROR;
1568 for (i=0; i<msg->num_elements; i++) {
1569 struct ldb_message_element *old_el;
1570 old_el = ldb_msg_find_element(res->msgs[0], msg->elements[i].name);
1571 ret = replmd_update_rpmd_element(ldb, msg, &msg->elements[i], old_el, &omd, schema, seq_num,
1575 if (ret != LDB_SUCCESS) {
1579 if (!*is_urgent && (situation == REPL_URGENT_ON_UPDATE)) {
1580 *is_urgent = replmd_check_urgent_attribute(&msg->elements[i]);
1587 * Assert that we have an objectClass attribute - this is major
1588 * corruption if we don't have this!
1590 objectclass_el = ldb_msg_find_element(res->msgs[0], "objectClass");
1591 if (objectclass_el != NULL) {
1593 * Now check if this objectClass means we need to do urgent replication
1595 if (!*is_urgent && replmd_check_urgent_objectclass(objectclass_el,
1599 } else if (!ldb_request_get_control(req, DSDB_CONTROL_DBCHECK)) {
1600 ldb_asprintf_errstring(ldb, __location__
1601 ": objectClass missing on %s\n",
1602 ldb_dn_get_linearized(msg->dn));
1603 return LDB_ERR_OBJECT_CLASS_VIOLATION;
1607 * replmd_update_rpmd_element has done an update if the
1610 if (*seq_num != 0 || rmd_is_just_resorted == true) {
1611 struct ldb_val *md_value;
1612 struct ldb_message_element *el;
1614 /*if we are RODC and this is a DRSR update then its ok*/
1615 if (!ldb_request_get_control(req, DSDB_CONTROL_REPLICATED_UPDATE_OID)
1616 && !ldb_request_get_control(req, DSDB_CONTROL_DBCHECK_MODIFY_RO_REPLICA)) {
1617 unsigned instanceType;
1619 ret = samdb_rodc(ldb, rodc);
1620 if (ret != LDB_SUCCESS) {
1621 DEBUG(4, (__location__ ": unable to tell if we are an RODC\n"));
1623 ldb_set_errstring(ldb, "RODC modify is forbidden!");
1624 return LDB_ERR_REFERRAL;
1627 instanceType = ldb_msg_find_attr_as_uint(res->msgs[0], "instanceType", INSTANCE_TYPE_WRITE);
1628 if (!(instanceType & INSTANCE_TYPE_WRITE)) {
1629 return ldb_error(ldb, LDB_ERR_UNWILLING_TO_PERFORM,
1630 "cannot change replicated attribute on partial replica");
1634 md_value = talloc(msg, struct ldb_val);
1635 if (md_value == NULL) {
1637 return LDB_ERR_OPERATIONS_ERROR;
1640 ret = replmd_replPropertyMetaDataCtr1_sort_and_verify(ldb, &omd.ctr.ctr1, msg->dn);
1641 if (ret != LDB_SUCCESS) {
1642 ldb_asprintf_errstring(ldb, "%s: %s", __func__, ldb_errstring(ldb));
1646 ndr_err = ndr_push_struct_blob(md_value, msg, &omd,
1647 (ndr_push_flags_fn_t)ndr_push_replPropertyMetaDataBlob);
1648 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1649 DEBUG(0,(__location__ ": Failed to marshall replPropertyMetaData for %s\n",
1650 ldb_dn_get_linearized(msg->dn)));
1651 return LDB_ERR_OPERATIONS_ERROR;
1654 ret = ldb_msg_add_empty(msg, "replPropertyMetaData", LDB_FLAG_MOD_REPLACE, &el);
1655 if (ret != LDB_SUCCESS) {
1656 DEBUG(0,(__location__ ": Failed to add updated replPropertyMetaData %s\n",
1657 ldb_dn_get_linearized(msg->dn)));
1662 el->values = md_value;
1669 struct dsdb_dn *dsdb_dn;
1674 static int parsed_dn_compare(struct parsed_dn *pdn1, struct parsed_dn *pdn2)
1676 return GUID_compare(&pdn1->guid, &pdn2->guid);
1679 static int GUID_compare_struct(struct GUID *g1, struct GUID g2)
1681 return GUID_compare(g1, &g2);
1684 static struct parsed_dn *parsed_dn_find(struct parsed_dn *pdn,
1685 unsigned int count, struct GUID *guid,
1688 struct parsed_dn *ret;
1690 if (dn && GUID_all_zero(guid)) {
1691 /* when updating a link using DRS, we sometimes get a
1692 NULL GUID. We then need to try and match by DN */
1693 for (i=0; i<count; i++) {
1694 if (ldb_dn_compare(pdn[i].dsdb_dn->dn, dn) == 0) {
1695 dsdb_get_extended_dn_guid(pdn[i].dsdb_dn->dn, guid, "GUID");
1701 BINARY_ARRAY_SEARCH(pdn, count, guid, guid, GUID_compare_struct, ret);
1706 get a series of message element values as an array of DNs and GUIDs
1707 the result is sorted by GUID
1709 static int get_parsed_dns(struct ldb_module *module, TALLOC_CTX *mem_ctx,
1710 struct ldb_message_element *el, struct parsed_dn **pdn,
1711 const char *ldap_oid, struct ldb_request *parent)
1714 struct ldb_context *ldb = ldb_module_get_ctx(module);
1721 (*pdn) = talloc_array(mem_ctx, struct parsed_dn, el->num_values);
1723 ldb_module_oom(module);
1724 return LDB_ERR_OPERATIONS_ERROR;
1727 for (i=0; i<el->num_values; i++) {
1728 struct ldb_val *v = &el->values[i];
1731 struct parsed_dn *p;
1735 p->dsdb_dn = dsdb_dn_parse(*pdn, ldb, v, ldap_oid);
1736 if (p->dsdb_dn == NULL) {
1737 return LDB_ERR_INVALID_DN_SYNTAX;
1740 dn = p->dsdb_dn->dn;
1742 status = dsdb_get_extended_dn_guid(dn, &p->guid, "GUID");
1743 if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
1744 /* we got a DN without a GUID - go find the GUID */
1745 int ret = dsdb_module_guid_by_dn(module, dn, &p->guid, parent);
1746 if (ret != LDB_SUCCESS) {
1747 ldb_asprintf_errstring(ldb, "Unable to find GUID for DN %s\n",
1748 ldb_dn_get_linearized(dn));
1749 if (ret == LDB_ERR_NO_SUCH_OBJECT &&
1750 LDB_FLAG_MOD_TYPE(el->flags) == LDB_FLAG_MOD_DELETE &&
1751 ldb_attr_cmp(el->name, "member") == 0) {
1752 return LDB_ERR_UNWILLING_TO_PERFORM;
1756 ret = dsdb_set_extended_dn_guid(dn, &p->guid, "GUID");
1757 if (ret != LDB_SUCCESS) {
1760 } else if (!NT_STATUS_IS_OK(status)) {
1761 return LDB_ERR_OPERATIONS_ERROR;
1764 /* keep a pointer to the original ldb_val */
1768 TYPESAFE_QSORT(*pdn, el->num_values, parsed_dn_compare);
1774 build a new extended DN, including all meta data fields
1776 RMD_FLAGS = DSDB_RMD_FLAG_* bits
1777 RMD_ADDTIME = originating_add_time
1778 RMD_INVOCID = originating_invocation_id
1779 RMD_CHANGETIME = originating_change_time
1780 RMD_ORIGINATING_USN = originating_usn
1781 RMD_LOCAL_USN = local_usn
1782 RMD_VERSION = version
1784 static int replmd_build_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct dsdb_dn *dsdb_dn,
1785 const struct GUID *invocation_id, uint64_t seq_num,
1786 uint64_t local_usn, NTTIME nttime, uint32_t version, bool deleted)
1788 struct ldb_dn *dn = dsdb_dn->dn;
1789 const char *tstring, *usn_string, *flags_string;
1790 struct ldb_val tval;
1792 struct ldb_val usnv, local_usnv;
1793 struct ldb_val vers, flagsv;
1796 const char *dnstring;
1798 uint32_t rmd_flags = deleted?DSDB_RMD_FLAG_DELETED:0;
1800 tstring = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)nttime);
1802 return LDB_ERR_OPERATIONS_ERROR;
1804 tval = data_blob_string_const(tstring);
1806 usn_string = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)seq_num);
1808 return LDB_ERR_OPERATIONS_ERROR;
1810 usnv = data_blob_string_const(usn_string);
1812 usn_string = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)local_usn);
1814 return LDB_ERR_OPERATIONS_ERROR;
1816 local_usnv = data_blob_string_const(usn_string);
1818 vstring = talloc_asprintf(mem_ctx, "%lu", (unsigned long)version);
1820 return LDB_ERR_OPERATIONS_ERROR;
1822 vers = data_blob_string_const(vstring);
1824 status = GUID_to_ndr_blob(invocation_id, dn, &iid);
1825 if (!NT_STATUS_IS_OK(status)) {
1826 return LDB_ERR_OPERATIONS_ERROR;
1829 flags_string = talloc_asprintf(mem_ctx, "%u", rmd_flags);
1830 if (!flags_string) {
1831 return LDB_ERR_OPERATIONS_ERROR;
1833 flagsv = data_blob_string_const(flags_string);
1835 ret = ldb_dn_set_extended_component(dn, "RMD_FLAGS", &flagsv);
1836 if (ret != LDB_SUCCESS) return ret;
1837 ret = ldb_dn_set_extended_component(dn, "RMD_ADDTIME", &tval);
1838 if (ret != LDB_SUCCESS) return ret;
1839 ret = ldb_dn_set_extended_component(dn, "RMD_INVOCID", &iid);
1840 if (ret != LDB_SUCCESS) return ret;
1841 ret = ldb_dn_set_extended_component(dn, "RMD_CHANGETIME", &tval);
1842 if (ret != LDB_SUCCESS) return ret;
1843 ret = ldb_dn_set_extended_component(dn, "RMD_LOCAL_USN", &local_usnv);
1844 if (ret != LDB_SUCCESS) return ret;
1845 ret = ldb_dn_set_extended_component(dn, "RMD_ORIGINATING_USN", &usnv);
1846 if (ret != LDB_SUCCESS) return ret;
1847 ret = ldb_dn_set_extended_component(dn, "RMD_VERSION", &vers);
1848 if (ret != LDB_SUCCESS) return ret;
1850 dnstring = dsdb_dn_get_extended_linearized(mem_ctx, dsdb_dn, 1);
1851 if (dnstring == NULL) {
1852 return LDB_ERR_OPERATIONS_ERROR;
1854 *v = data_blob_string_const(dnstring);
1859 static int replmd_update_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct dsdb_dn *dsdb_dn,
1860 struct dsdb_dn *old_dsdb_dn, const struct GUID *invocation_id,
1861 uint64_t seq_num, uint64_t local_usn, NTTIME nttime,
1862 uint32_t version, bool deleted);
1865 check if any links need upgrading from w2k format
1867 The parent_ctx is the ldb_message_element which contains the values array that dns[i].v points at, and which should be used for allocating any new value.
1869 static int replmd_check_upgrade_links(struct parsed_dn *dns, uint32_t count, struct ldb_message_element *parent_ctx, const struct GUID *invocation_id)
1872 for (i=0; i<count; i++) {
1877 status = dsdb_get_extended_dn_uint32(dns[i].dsdb_dn->dn, &version, "RMD_VERSION");
1878 if (!NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
1882 /* it's an old one that needs upgrading */
1883 ret = replmd_update_la_val(parent_ctx->values, dns[i].v, dns[i].dsdb_dn, dns[i].dsdb_dn, invocation_id,
1885 if (ret != LDB_SUCCESS) {
1893 update an extended DN, including all meta data fields
1895 see replmd_build_la_val for value names
1897 static int replmd_update_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct dsdb_dn *dsdb_dn,
1898 struct dsdb_dn *old_dsdb_dn, const struct GUID *invocation_id,
1899 uint64_t usn, uint64_t local_usn, NTTIME nttime,
1900 uint32_t version, bool deleted)
1902 struct ldb_dn *dn = dsdb_dn->dn;
1903 const char *tstring, *usn_string, *flags_string;
1904 struct ldb_val tval;
1906 struct ldb_val usnv, local_usnv;
1907 struct ldb_val vers, flagsv;
1908 const struct ldb_val *old_addtime;
1909 uint32_t old_version;
1912 const char *dnstring;
1914 uint32_t rmd_flags = deleted?DSDB_RMD_FLAG_DELETED:0;
1916 tstring = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)nttime);
1918 return LDB_ERR_OPERATIONS_ERROR;
1920 tval = data_blob_string_const(tstring);
1922 usn_string = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)usn);
1924 return LDB_ERR_OPERATIONS_ERROR;
1926 usnv = data_blob_string_const(usn_string);
1928 usn_string = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)local_usn);
1930 return LDB_ERR_OPERATIONS_ERROR;
1932 local_usnv = data_blob_string_const(usn_string);
1934 status = GUID_to_ndr_blob(invocation_id, dn, &iid);
1935 if (!NT_STATUS_IS_OK(status)) {
1936 return LDB_ERR_OPERATIONS_ERROR;
1939 flags_string = talloc_asprintf(mem_ctx, "%u", rmd_flags);
1940 if (!flags_string) {
1941 return LDB_ERR_OPERATIONS_ERROR;
1943 flagsv = data_blob_string_const(flags_string);
1945 ret = ldb_dn_set_extended_component(dn, "RMD_FLAGS", &flagsv);
1946 if (ret != LDB_SUCCESS) return ret;
1948 /* get the ADDTIME from the original */
1949 old_addtime = ldb_dn_get_extended_component(old_dsdb_dn->dn, "RMD_ADDTIME");
1950 if (old_addtime == NULL) {
1951 old_addtime = &tval;
1953 if (dsdb_dn != old_dsdb_dn ||
1954 ldb_dn_get_extended_component(dn, "RMD_ADDTIME") == NULL) {
1955 ret = ldb_dn_set_extended_component(dn, "RMD_ADDTIME", old_addtime);
1956 if (ret != LDB_SUCCESS) return ret;
1959 /* use our invocation id */
1960 ret = ldb_dn_set_extended_component(dn, "RMD_INVOCID", &iid);
1961 if (ret != LDB_SUCCESS) return ret;
1963 /* changetime is the current time */
1964 ret = ldb_dn_set_extended_component(dn, "RMD_CHANGETIME", &tval);
1965 if (ret != LDB_SUCCESS) return ret;
1967 /* update the USN */
1968 ret = ldb_dn_set_extended_component(dn, "RMD_ORIGINATING_USN", &usnv);
1969 if (ret != LDB_SUCCESS) return ret;
1971 ret = ldb_dn_set_extended_component(dn, "RMD_LOCAL_USN", &local_usnv);
1972 if (ret != LDB_SUCCESS) return ret;
1974 /* increase the version by 1 */
1975 status = dsdb_get_extended_dn_uint32(old_dsdb_dn->dn, &old_version, "RMD_VERSION");
1976 if (NT_STATUS_IS_OK(status) && old_version >= version) {
1977 version = old_version+1;
1979 vstring = talloc_asprintf(dn, "%lu", (unsigned long)version);
1980 vers = data_blob_string_const(vstring);
1981 ret = ldb_dn_set_extended_component(dn, "RMD_VERSION", &vers);
1982 if (ret != LDB_SUCCESS) return ret;
1984 dnstring = dsdb_dn_get_extended_linearized(mem_ctx, dsdb_dn, 1);
1985 if (dnstring == NULL) {
1986 return LDB_ERR_OPERATIONS_ERROR;
1988 *v = data_blob_string_const(dnstring);
1994 handle adding a linked attribute
1996 static int replmd_modify_la_add(struct ldb_module *module,
1997 const struct dsdb_schema *schema,
1998 struct ldb_message *msg,
1999 struct ldb_message_element *el,
2000 struct ldb_message_element *old_el,
2001 const struct dsdb_attribute *schema_attr,
2004 struct GUID *msg_guid,
2005 struct ldb_request *parent)
2008 struct parsed_dn *dns, *old_dns;
2009 TALLOC_CTX *tmp_ctx = talloc_new(msg);
2011 struct ldb_val *new_values = NULL;
2012 unsigned int num_new_values = 0;
2013 unsigned old_num_values = old_el?old_el->num_values:0;
2014 const struct GUID *invocation_id;
2015 struct ldb_context *ldb = ldb_module_get_ctx(module);
2018 unix_to_nt_time(&now, t);
2020 ret = get_parsed_dns(module, tmp_ctx, el, &dns, schema_attr->syntax->ldap_oid, parent);
2021 if (ret != LDB_SUCCESS) {
2022 talloc_free(tmp_ctx);
2026 ret = get_parsed_dns(module, tmp_ctx, old_el, &old_dns, schema_attr->syntax->ldap_oid, parent);
2027 if (ret != LDB_SUCCESS) {
2028 talloc_free(tmp_ctx);
2032 invocation_id = samdb_ntds_invocation_id(ldb);
2033 if (!invocation_id) {
2034 talloc_free(tmp_ctx);
2035 return LDB_ERR_OPERATIONS_ERROR;
2038 ret = replmd_check_upgrade_links(old_dns, old_num_values, old_el, invocation_id);
2039 if (ret != LDB_SUCCESS) {
2040 talloc_free(tmp_ctx);
2044 /* for each new value, see if it exists already with the same GUID */
2045 for (i=0; i<el->num_values; i++) {
2046 struct parsed_dn *p = parsed_dn_find(old_dns, old_num_values, &dns[i].guid, NULL);
2048 /* this is a new linked attribute value */
2049 new_values = talloc_realloc(tmp_ctx, new_values, struct ldb_val, num_new_values+1);
2050 if (new_values == NULL) {
2051 ldb_module_oom(module);
2052 talloc_free(tmp_ctx);
2053 return LDB_ERR_OPERATIONS_ERROR;
2055 ret = replmd_build_la_val(new_values, &new_values[num_new_values], dns[i].dsdb_dn,
2056 invocation_id, seq_num, seq_num, now, 0, false);
2057 if (ret != LDB_SUCCESS) {
2058 talloc_free(tmp_ctx);
2063 /* this is only allowed if the GUID was
2064 previously deleted. */
2065 uint32_t rmd_flags = dsdb_dn_rmd_flags(p->dsdb_dn->dn);
2067 if (!(rmd_flags & DSDB_RMD_FLAG_DELETED)) {
2068 struct GUID_txt_buf guid_str;
2069 ldb_asprintf_errstring(ldb, "Attribute %s already exists for target GUID %s",
2070 el->name, GUID_buf_string(&p->guid, &guid_str));
2071 talloc_free(tmp_ctx);
2072 /* error codes for 'member' need to be
2074 if (ldb_attr_cmp(el->name, "member") == 0) {
2075 return LDB_ERR_ENTRY_ALREADY_EXISTS;
2077 return LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS;
2080 ret = replmd_update_la_val(old_el->values, p->v, dns[i].dsdb_dn, p->dsdb_dn,
2081 invocation_id, seq_num, seq_num, now, 0, false);
2082 if (ret != LDB_SUCCESS) {
2083 talloc_free(tmp_ctx);
2088 ret = replmd_add_backlink(module, schema, msg_guid, &dns[i].guid, true, schema_attr, true);
2089 if (ret != LDB_SUCCESS) {
2090 talloc_free(tmp_ctx);
2095 /* add the new ones on to the end of the old values, constructing a new el->values */
2096 el->values = talloc_realloc(msg->elements, old_el?old_el->values:NULL,
2098 old_num_values+num_new_values);
2099 if (el->values == NULL) {
2100 ldb_module_oom(module);
2101 return LDB_ERR_OPERATIONS_ERROR;
2104 memcpy(&el->values[old_num_values], new_values, num_new_values*sizeof(struct ldb_val));
2105 el->num_values = old_num_values + num_new_values;
2107 talloc_steal(msg->elements, el->values);
2108 talloc_steal(el->values, new_values);
2110 talloc_free(tmp_ctx);
2112 /* we now tell the backend to replace all existing values
2113 with the one we have constructed */
2114 el->flags = LDB_FLAG_MOD_REPLACE;
2121 handle deleting all active linked attributes
2123 static int replmd_modify_la_delete(struct ldb_module *module,
2124 const struct dsdb_schema *schema,
2125 struct ldb_message *msg,
2126 struct ldb_message_element *el,
2127 struct ldb_message_element *old_el,
2128 const struct dsdb_attribute *schema_attr,
2131 struct GUID *msg_guid,
2132 struct ldb_request *parent)
2135 struct parsed_dn *dns, *old_dns;
2136 TALLOC_CTX *tmp_ctx = talloc_new(msg);
2138 const struct GUID *invocation_id;
2139 struct ldb_context *ldb = ldb_module_get_ctx(module);
2142 unix_to_nt_time(&now, t);
2144 /* check if there is nothing to delete */
2145 if ((!old_el || old_el->num_values == 0) &&
2146 el->num_values == 0) {
2150 if (!old_el || old_el->num_values == 0) {
2151 return LDB_ERR_NO_SUCH_ATTRIBUTE;
2154 ret = get_parsed_dns(module, tmp_ctx, el, &dns, schema_attr->syntax->ldap_oid, parent);
2155 if (ret != LDB_SUCCESS) {
2156 talloc_free(tmp_ctx);
2160 ret = get_parsed_dns(module, tmp_ctx, old_el, &old_dns, schema_attr->syntax->ldap_oid, parent);
2161 if (ret != LDB_SUCCESS) {
2162 talloc_free(tmp_ctx);
2166 invocation_id = samdb_ntds_invocation_id(ldb);
2167 if (!invocation_id) {
2168 return LDB_ERR_OPERATIONS_ERROR;
2171 ret = replmd_check_upgrade_links(old_dns, old_el->num_values, old_el, invocation_id);
2172 if (ret != LDB_SUCCESS) {
2173 talloc_free(tmp_ctx);
2179 /* see if we are being asked to delete any links that
2180 don't exist or are already deleted */
2181 for (i=0; i<el->num_values; i++) {
2182 struct parsed_dn *p = &dns[i];
2183 struct parsed_dn *p2;
2186 p2 = parsed_dn_find(old_dns, old_el->num_values, &p->guid, NULL);
2188 struct GUID_txt_buf buf;
2189 ldb_asprintf_errstring(ldb, "Attribute %s doesn't exist for target GUID %s",
2190 el->name, GUID_buf_string(&p->guid, &buf));
2191 if (ldb_attr_cmp(el->name, "member") == 0) {
2192 return LDB_ERR_UNWILLING_TO_PERFORM;
2194 return LDB_ERR_NO_SUCH_ATTRIBUTE;
2197 rmd_flags = dsdb_dn_rmd_flags(p2->dsdb_dn->dn);
2198 if (rmd_flags & DSDB_RMD_FLAG_DELETED) {
2199 struct GUID_txt_buf buf;
2200 ldb_asprintf_errstring(ldb, "Attribute %s already deleted for target GUID %s",
2201 el->name, GUID_buf_string(&p->guid, &buf));
2202 if (ldb_attr_cmp(el->name, "member") == 0) {
2203 return LDB_ERR_UNWILLING_TO_PERFORM;
2205 return LDB_ERR_NO_SUCH_ATTRIBUTE;
2210 /* for each new value, see if it exists already with the same GUID
2211 if it is not already deleted and matches the delete list then delete it
2213 for (i=0; i<old_el->num_values; i++) {
2214 struct parsed_dn *p = &old_dns[i];
2217 if (el->num_values && parsed_dn_find(dns, el->num_values, &p->guid, NULL) == NULL) {
2221 rmd_flags = dsdb_dn_rmd_flags(p->dsdb_dn->dn);
2222 if (rmd_flags & DSDB_RMD_FLAG_DELETED) continue;
2224 ret = replmd_update_la_val(old_el->values, p->v, p->dsdb_dn, p->dsdb_dn,
2225 invocation_id, seq_num, seq_num, now, 0, true);
2226 if (ret != LDB_SUCCESS) {
2227 talloc_free(tmp_ctx);
2231 ret = replmd_add_backlink(module, schema, msg_guid, &old_dns[i].guid, false, schema_attr, true);
2232 if (ret != LDB_SUCCESS) {
2233 talloc_free(tmp_ctx);
2238 el->values = talloc_steal(msg->elements, old_el->values);
2239 el->num_values = old_el->num_values;
2241 talloc_free(tmp_ctx);
2243 /* we now tell the backend to replace all existing values
2244 with the one we have constructed */
2245 el->flags = LDB_FLAG_MOD_REPLACE;
2251 handle replacing a linked attribute
2253 static int replmd_modify_la_replace(struct ldb_module *module,
2254 const struct dsdb_schema *schema,
2255 struct ldb_message *msg,
2256 struct ldb_message_element *el,
2257 struct ldb_message_element *old_el,
2258 const struct dsdb_attribute *schema_attr,
2261 struct GUID *msg_guid,
2262 struct ldb_request *parent)
2265 struct parsed_dn *dns, *old_dns;
2266 TALLOC_CTX *tmp_ctx = talloc_new(msg);
2268 const struct GUID *invocation_id;
2269 struct ldb_context *ldb = ldb_module_get_ctx(module);
2270 struct ldb_val *new_values = NULL;
2271 unsigned int num_new_values = 0;
2272 unsigned int old_num_values = old_el?old_el->num_values:0;
2275 unix_to_nt_time(&now, t);
2277 /* check if there is nothing to replace */
2278 if ((!old_el || old_el->num_values == 0) &&
2279 el->num_values == 0) {
2283 ret = get_parsed_dns(module, tmp_ctx, el, &dns, schema_attr->syntax->ldap_oid, parent);
2284 if (ret != LDB_SUCCESS) {
2285 talloc_free(tmp_ctx);
2289 ret = get_parsed_dns(module, tmp_ctx, old_el, &old_dns, schema_attr->syntax->ldap_oid, parent);
2290 if (ret != LDB_SUCCESS) {
2291 talloc_free(tmp_ctx);
2295 invocation_id = samdb_ntds_invocation_id(ldb);
2296 if (!invocation_id) {
2297 return LDB_ERR_OPERATIONS_ERROR;
2300 ret = replmd_check_upgrade_links(old_dns, old_num_values, old_el, invocation_id);
2301 if (ret != LDB_SUCCESS) {
2302 talloc_free(tmp_ctx);
2306 /* mark all the old ones as deleted */
2307 for (i=0; i<old_num_values; i++) {
2308 struct parsed_dn *old_p = &old_dns[i];
2309 struct parsed_dn *p;
2310 uint32_t rmd_flags = dsdb_dn_rmd_flags(old_p->dsdb_dn->dn);
2312 if (rmd_flags & DSDB_RMD_FLAG_DELETED) continue;
2314 ret = replmd_add_backlink(module, schema, msg_guid, &old_dns[i].guid, false, schema_attr, false);
2315 if (ret != LDB_SUCCESS) {
2316 talloc_free(tmp_ctx);
2320 p = parsed_dn_find(dns, el->num_values, &old_p->guid, NULL);
2322 /* we don't delete it if we are re-adding it */
2326 ret = replmd_update_la_val(old_el->values, old_p->v, old_p->dsdb_dn, old_p->dsdb_dn,
2327 invocation_id, seq_num, seq_num, now, 0, true);
2328 if (ret != LDB_SUCCESS) {
2329 talloc_free(tmp_ctx);
2334 /* for each new value, either update its meta-data, or add it
2337 for (i=0; i<el->num_values; i++) {
2338 struct parsed_dn *p = &dns[i], *old_p;
2341 (old_p = parsed_dn_find(old_dns,
2342 old_num_values, &p->guid, NULL)) != NULL) {
2343 /* update in place */
2344 ret = replmd_update_la_val(old_el->values, old_p->v, p->dsdb_dn,
2345 old_p->dsdb_dn, invocation_id,
2346 seq_num, seq_num, now, 0, false);
2347 if (ret != LDB_SUCCESS) {
2348 talloc_free(tmp_ctx);
2353 new_values = talloc_realloc(tmp_ctx, new_values, struct ldb_val,
2355 if (new_values == NULL) {
2356 ldb_module_oom(module);
2357 talloc_free(tmp_ctx);
2358 return LDB_ERR_OPERATIONS_ERROR;
2360 ret = replmd_build_la_val(new_values, &new_values[num_new_values], dns[i].dsdb_dn,
2361 invocation_id, seq_num, seq_num, now, 0, false);
2362 if (ret != LDB_SUCCESS) {
2363 talloc_free(tmp_ctx);
2369 ret = replmd_add_backlink(module, schema, msg_guid, &dns[i].guid, true, schema_attr, false);
2370 if (ret != LDB_SUCCESS) {
2371 talloc_free(tmp_ctx);
2376 /* add the new values to the end of old_el */
2377 if (num_new_values != 0) {
2378 el->values = talloc_realloc(msg->elements, old_el?old_el->values:NULL,
2379 struct ldb_val, old_num_values+num_new_values);
2380 if (el->values == NULL) {
2381 ldb_module_oom(module);
2382 return LDB_ERR_OPERATIONS_ERROR;
2384 memcpy(&el->values[old_num_values], &new_values[0],
2385 sizeof(struct ldb_val)*num_new_values);
2386 el->num_values = old_num_values + num_new_values;
2387 talloc_steal(msg->elements, new_values);
2389 el->values = old_el->values;
2390 el->num_values = old_el->num_values;
2391 talloc_steal(msg->elements, el->values);
2394 talloc_free(tmp_ctx);
2396 /* we now tell the backend to replace all existing values
2397 with the one we have constructed */
2398 el->flags = LDB_FLAG_MOD_REPLACE;
2405 handle linked attributes in modify requests
2407 static int replmd_modify_handle_linked_attribs(struct ldb_module *module,
2408 struct ldb_message *msg,
2409 uint64_t seq_num, time_t t,
2410 struct ldb_request *parent)
2412 struct ldb_result *res;
2415 struct ldb_context *ldb = ldb_module_get_ctx(module);
2416 struct ldb_message *old_msg;
2418 const struct dsdb_schema *schema;
2419 struct GUID old_guid;
2422 /* there the replmd_update_rpmd code has already
2423 * checked and saw that there are no linked
2428 if (dsdb_functional_level(ldb) == DS_DOMAIN_FUNCTION_2000) {
2429 /* don't do anything special for linked attributes */
2433 ret = dsdb_module_search_dn(module, msg, &res, msg->dn, NULL,
2434 DSDB_FLAG_NEXT_MODULE |
2435 DSDB_SEARCH_SHOW_RECYCLED |
2436 DSDB_SEARCH_REVEAL_INTERNALS |
2437 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT,
2439 if (ret != LDB_SUCCESS) {
2442 schema = dsdb_get_schema(ldb, res);
2444 return LDB_ERR_OPERATIONS_ERROR;
2447 old_msg = res->msgs[0];
2449 old_guid = samdb_result_guid(old_msg, "objectGUID");
2451 for (i=0; i<msg->num_elements; i++) {
2452 struct ldb_message_element *el = &msg->elements[i];
2453 struct ldb_message_element *old_el, *new_el;
2454 const struct dsdb_attribute *schema_attr
2455 = dsdb_attribute_by_lDAPDisplayName(schema, el->name);
2457 ldb_asprintf_errstring(ldb,
2458 "%s: attribute %s is not a valid attribute in schema",
2459 __FUNCTION__, el->name);
2460 return LDB_ERR_OBJECT_CLASS_VIOLATION;
2462 if (schema_attr->linkID == 0) {
2465 if ((schema_attr->linkID & 1) == 1) {
2466 if (parent && ldb_request_get_control(parent, DSDB_CONTROL_DBCHECK)) {
2469 /* Odd is for the target. Illegal to modify */
2470 ldb_asprintf_errstring(ldb,
2471 "attribute %s must not be modified directly, it is a linked attribute", el->name);
2472 return LDB_ERR_UNWILLING_TO_PERFORM;
2474 old_el = ldb_msg_find_element(old_msg, el->name);
2475 switch (el->flags & LDB_FLAG_MOD_MASK) {
2476 case LDB_FLAG_MOD_REPLACE:
2477 ret = replmd_modify_la_replace(module, schema, msg, el, old_el, schema_attr, seq_num, t, &old_guid, parent);
2479 case LDB_FLAG_MOD_DELETE:
2480 ret = replmd_modify_la_delete(module, schema, msg, el, old_el, schema_attr, seq_num, t, &old_guid, parent);
2482 case LDB_FLAG_MOD_ADD:
2483 ret = replmd_modify_la_add(module, schema, msg, el, old_el, schema_attr, seq_num, t, &old_guid, parent);
2486 ldb_asprintf_errstring(ldb,
2487 "invalid flags 0x%x for %s linked attribute",
2488 el->flags, el->name);
2489 return LDB_ERR_UNWILLING_TO_PERFORM;
2491 if (dsdb_check_single_valued_link(schema_attr, el) != LDB_SUCCESS) {
2492 ldb_asprintf_errstring(ldb,
2493 "Attribute %s is single valued but more than one value has been supplied",
2495 return LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS;
2497 el->flags |= LDB_FLAG_INTERNAL_DISABLE_SINGLE_VALUE_CHECK;
2502 if (ret != LDB_SUCCESS) {
2506 ldb_msg_remove_attr(old_msg, el->name);
2508 ldb_msg_add_empty(old_msg, el->name, 0, &new_el);
2509 new_el->num_values = el->num_values;
2510 new_el->values = talloc_steal(msg->elements, el->values);
2512 /* TODO: this relises a bit too heavily on the exact
2513 behaviour of ldb_msg_find_element and
2514 ldb_msg_remove_element */
2515 old_el = ldb_msg_find_element(msg, el->name);
2517 ldb_msg_remove_element(msg, old_el);
2528 static int replmd_modify(struct ldb_module *module, struct ldb_request *req)
2530 struct ldb_context *ldb;
2531 struct replmd_replicated_request *ac;
2532 struct ldb_request *down_req;
2533 struct ldb_message *msg;
2534 time_t t = time(NULL);
2536 bool is_urgent = false, rodc = false;
2537 bool is_schema_nc = false;
2538 unsigned int functional_level;
2539 const struct ldb_message_element *guid_el = NULL;
2540 struct ldb_control *sd_propagation_control;
2541 struct replmd_private *replmd_private =
2542 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
2544 /* do not manipulate our control entries */
2545 if (ldb_dn_is_special(req->op.mod.message->dn)) {
2546 return ldb_next_request(module, req);
2549 sd_propagation_control = ldb_request_get_control(req,
2550 DSDB_CONTROL_SEC_DESC_PROPAGATION_OID);
2551 if (sd_propagation_control != NULL) {
2552 if (req->op.mod.message->num_elements != 1) {
2553 return ldb_module_operr(module);
2555 ret = strcmp(req->op.mod.message->elements[0].name,
2556 "nTSecurityDescriptor");
2558 return ldb_module_operr(module);
2561 return ldb_next_request(module, req);
2564 ldb = ldb_module_get_ctx(module);
2566 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_modify\n");
2568 guid_el = ldb_msg_find_element(req->op.mod.message, "objectGUID");
2569 if (guid_el != NULL) {
2570 ldb_set_errstring(ldb,
2571 "replmd_modify: it's not allowed to change the objectGUID!");
2572 return LDB_ERR_CONSTRAINT_VIOLATION;
2575 ac = replmd_ctx_init(module, req);
2577 return ldb_module_oom(module);
2580 functional_level = dsdb_functional_level(ldb);
2582 /* we have to copy the message as the caller might have it as a const */
2583 msg = ldb_msg_copy_shallow(ac, req->op.mod.message);
2587 return LDB_ERR_OPERATIONS_ERROR;
2590 ldb_msg_remove_attr(msg, "whenChanged");
2591 ldb_msg_remove_attr(msg, "uSNChanged");
2593 is_schema_nc = ldb_dn_compare_base(replmd_private->schema_dn, msg->dn) == 0;
2595 ret = replmd_update_rpmd(module, ac->schema, req, NULL,
2596 msg, &ac->seq_num, t, is_schema_nc,
2598 if (rodc && (ret == LDB_ERR_REFERRAL)) {
2599 struct loadparm_context *lp_ctx;
2602 lp_ctx = talloc_get_type(ldb_get_opaque(ldb, "loadparm"),
2603 struct loadparm_context);
2605 referral = talloc_asprintf(req,
2607 lpcfg_dnsdomain(lp_ctx),
2608 ldb_dn_get_linearized(msg->dn));
2609 ret = ldb_module_send_referral(req, referral);
2614 if (ret != LDB_SUCCESS) {
2619 ret = replmd_modify_handle_linked_attribs(module, msg, ac->seq_num, t, req);
2620 if (ret != LDB_SUCCESS) {
2626 * - replace the old object with the newly constructed one
2629 ac->is_urgent = is_urgent;
2631 ret = ldb_build_mod_req(&down_req, ldb, ac,
2634 ac, replmd_op_callback,
2636 LDB_REQ_SET_LOCATION(down_req);
2637 if (ret != LDB_SUCCESS) {
2642 /* current partition control is needed by "replmd_op_callback" */
2643 if (ldb_request_get_control(req, DSDB_CONTROL_CURRENT_PARTITION_OID) == NULL) {
2644 ret = ldb_request_add_control(down_req,
2645 DSDB_CONTROL_CURRENT_PARTITION_OID,
2647 if (ret != LDB_SUCCESS) {
2653 /* If we are in functional level 2000, then
2654 * replmd_modify_handle_linked_attribs will have done
2656 if (functional_level == DS_DOMAIN_FUNCTION_2000) {
2657 ret = ldb_request_add_control(down_req, DSDB_CONTROL_APPLY_LINKS, false, NULL);
2658 if (ret != LDB_SUCCESS) {
2664 talloc_steal(down_req, msg);
2666 /* we only change whenChanged and uSNChanged if the seq_num
2668 if (ac->seq_num != 0) {
2669 ret = add_time_element(msg, "whenChanged", t);
2670 if (ret != LDB_SUCCESS) {
2676 ret = add_uint64_element(ldb, msg, "uSNChanged", ac->seq_num);
2677 if (ret != LDB_SUCCESS) {
2684 /* go on with the call chain */
2685 return ldb_next_request(module, down_req);
2688 static int replmd_rename_callback(struct ldb_request *req, struct ldb_reply *ares);
2691 handle a rename request
2693 On a rename we need to do an extra ldb_modify which sets the
2694 whenChanged and uSNChanged attributes. We do this in a callback after the success.
2696 static int replmd_rename(struct ldb_module *module, struct ldb_request *req)
2698 struct ldb_context *ldb;
2699 struct replmd_replicated_request *ac;
2701 struct ldb_request *down_req;
2703 /* do not manipulate our control entries */
2704 if (ldb_dn_is_special(req->op.mod.message->dn)) {
2705 return ldb_next_request(module, req);
2708 ldb = ldb_module_get_ctx(module);
2710 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_rename\n");
2712 ac = replmd_ctx_init(module, req);
2714 return ldb_module_oom(module);
2717 ret = ldb_build_rename_req(&down_req, ldb, ac,
2718 ac->req->op.rename.olddn,
2719 ac->req->op.rename.newdn,
2721 ac, replmd_rename_callback,
2723 LDB_REQ_SET_LOCATION(down_req);
2724 if (ret != LDB_SUCCESS) {
2729 /* go on with the call chain */
2730 return ldb_next_request(module, down_req);
2733 /* After the rename is compleated, update the whenchanged etc */
2734 static int replmd_rename_callback(struct ldb_request *req, struct ldb_reply *ares)
2736 struct ldb_context *ldb;
2737 struct ldb_request *down_req;
2738 struct ldb_message *msg;
2739 const struct dsdb_attribute *rdn_attr;
2740 const char *rdn_name;
2741 const struct ldb_val *rdn_val;
2742 const char *attrs[5] = { NULL, };
2743 time_t t = time(NULL);
2745 bool is_urgent = false, rodc = false;
2747 struct replmd_replicated_request *ac =
2748 talloc_get_type(req->context, struct replmd_replicated_request);
2749 struct replmd_private *replmd_private =
2750 talloc_get_type(ldb_module_get_private(ac->module),
2751 struct replmd_private);
2753 ldb = ldb_module_get_ctx(ac->module);
2755 if (ares->error != LDB_SUCCESS) {
2756 return ldb_module_done(ac->req, ares->controls,
2757 ares->response, ares->error);
2760 if (ares->type != LDB_REPLY_DONE) {
2761 ldb_set_errstring(ldb,
2762 "invalid ldb_reply_type in callback");
2764 return ldb_module_done(ac->req, NULL, NULL,
2765 LDB_ERR_OPERATIONS_ERROR);
2769 * - replace the old object with the newly constructed one
2772 msg = ldb_msg_new(ac);
2775 return LDB_ERR_OPERATIONS_ERROR;
2778 msg->dn = ac->req->op.rename.newdn;
2780 is_schema_nc = ldb_dn_compare_base(replmd_private->schema_dn, msg->dn) == 0;
2782 rdn_name = ldb_dn_get_rdn_name(msg->dn);
2783 if (rdn_name == NULL) {
2785 return ldb_module_done(ac->req, NULL, NULL,
2789 /* normalize the rdn attribute name */
2790 rdn_attr = dsdb_attribute_by_lDAPDisplayName(ac->schema, rdn_name);
2791 if (rdn_attr == NULL) {
2793 return ldb_module_done(ac->req, NULL, NULL,
2796 rdn_name = rdn_attr->lDAPDisplayName;
2798 rdn_val = ldb_dn_get_rdn_val(msg->dn);
2799 if (rdn_val == NULL) {
2801 return ldb_module_done(ac->req, NULL, NULL,
2805 if (ldb_msg_add_empty(msg, rdn_name, LDB_FLAG_MOD_REPLACE, NULL) != 0) {
2807 return ldb_module_done(ac->req, NULL, NULL,
2810 if (ldb_msg_add_value(msg, rdn_name, rdn_val, NULL) != 0) {
2812 return ldb_module_done(ac->req, NULL, NULL,
2815 if (ldb_msg_add_empty(msg, "name", LDB_FLAG_MOD_REPLACE, NULL) != 0) {
2817 return ldb_module_done(ac->req, NULL, NULL,
2820 if (ldb_msg_add_value(msg, "name", rdn_val, NULL) != 0) {
2822 return ldb_module_done(ac->req, NULL, NULL,
2827 * here we let replmd_update_rpmd() only search for
2828 * the existing "replPropertyMetaData" and rdn_name attributes.
2830 * We do not want the existing "name" attribute as
2831 * the "name" attribute needs to get the version
2832 * updated on rename even if the rdn value hasn't changed.
2834 * This is the diff of the meta data, for a moved user
2835 * on a w2k8r2 server:
2838 * -dn: CN=sdf df,CN=Users,DC=bla,DC=base
2839 * +dn: CN=sdf df,OU=TestOU,DC=bla,DC=base
2840 * replPropertyMetaData: NDR: struct replPropertyMetaDataBlob
2841 * version : 0x00000001 (1)
2842 * reserved : 0x00000000 (0)
2843 * @@ -66,11 +66,11 @@ replPropertyMetaData: NDR: struct re
2844 * local_usn : 0x00000000000037a5 (14245)
2845 * array: struct replPropertyMetaData1
2846 * attid : DRSUAPI_ATTID_name (0x90001)
2847 * - version : 0x00000001 (1)
2848 * - originating_change_time : Wed Feb 9 17:20:49 2011 CET
2849 * + version : 0x00000002 (2)
2850 * + originating_change_time : Wed Apr 6 15:21:01 2011 CEST
2851 * originating_invocation_id: 0d36ca05-5507-4e62-aca3-354bab0d39e1
2852 * - originating_usn : 0x00000000000037a5 (14245)
2853 * - local_usn : 0x00000000000037a5 (14245)
2854 * + originating_usn : 0x0000000000003834 (14388)
2855 * + local_usn : 0x0000000000003834 (14388)
2856 * array: struct replPropertyMetaData1
2857 * attid : DRSUAPI_ATTID_userAccountControl (0x90008)
2858 * version : 0x00000004 (4)
2860 attrs[0] = "replPropertyMetaData";
2861 attrs[1] = "objectClass";
2862 attrs[2] = "instanceType";
2863 attrs[3] = rdn_name;
2866 ret = replmd_update_rpmd(ac->module, ac->schema, req, attrs,
2867 msg, &ac->seq_num, t,
2868 is_schema_nc, &is_urgent, &rodc);
2869 if (rodc && (ret == LDB_ERR_REFERRAL)) {
2870 struct ldb_dn *olddn = ac->req->op.rename.olddn;
2871 struct loadparm_context *lp_ctx;
2874 lp_ctx = talloc_get_type(ldb_get_opaque(ldb, "loadparm"),
2875 struct loadparm_context);
2877 referral = talloc_asprintf(req,
2879 lpcfg_dnsdomain(lp_ctx),
2880 ldb_dn_get_linearized(olddn));
2881 ret = ldb_module_send_referral(req, referral);
2883 return ldb_module_done(req, NULL, NULL, ret);
2886 if (ret != LDB_SUCCESS) {
2888 return ldb_module_done(ac->req, NULL, NULL, ret);
2891 if (ac->seq_num == 0) {
2893 return ldb_module_done(ac->req, NULL, NULL,
2895 "internal error seq_num == 0"));
2897 ac->is_urgent = is_urgent;
2899 ret = ldb_build_mod_req(&down_req, ldb, ac,
2902 ac, replmd_op_callback,
2904 LDB_REQ_SET_LOCATION(down_req);
2905 if (ret != LDB_SUCCESS) {
2910 /* current partition control is needed by "replmd_op_callback" */
2911 if (ldb_request_get_control(req, DSDB_CONTROL_CURRENT_PARTITION_OID) == NULL) {
2912 ret = ldb_request_add_control(down_req,
2913 DSDB_CONTROL_CURRENT_PARTITION_OID,
2915 if (ret != LDB_SUCCESS) {
2921 talloc_steal(down_req, msg);
2923 ret = add_time_element(msg, "whenChanged", t);
2924 if (ret != LDB_SUCCESS) {
2930 ret = add_uint64_element(ldb, msg, "uSNChanged", ac->seq_num);
2931 if (ret != LDB_SUCCESS) {
2937 /* go on with the call chain - do the modify after the rename */
2938 return ldb_next_request(ac->module, down_req);
2942 * remove links from objects that point at this object when an object
2943 * is deleted. We remove it from the NEXT module per MS-DRSR 5.160
2944 * RemoveObj which states that link removal due to the object being
2945 * deleted is NOT an originating update - they just go away!
2948 static int replmd_delete_remove_link(struct ldb_module *module,
2949 const struct dsdb_schema *schema,
2951 struct ldb_message_element *el,
2952 const struct dsdb_attribute *sa,
2953 struct ldb_request *parent)
2956 TALLOC_CTX *tmp_ctx = talloc_new(module);
2957 struct ldb_context *ldb = ldb_module_get_ctx(module);
2959 for (i=0; i<el->num_values; i++) {
2960 struct dsdb_dn *dsdb_dn;
2964 struct ldb_message *msg;
2965 const struct dsdb_attribute *target_attr;
2966 struct ldb_message_element *el2;
2967 struct ldb_val dn_val;
2969 if (dsdb_dn_is_deleted_val(&el->values[i])) {
2973 dsdb_dn = dsdb_dn_parse(tmp_ctx, ldb, &el->values[i], sa->syntax->ldap_oid);
2975 talloc_free(tmp_ctx);
2976 return LDB_ERR_OPERATIONS_ERROR;
2979 status = dsdb_get_extended_dn_guid(dsdb_dn->dn, &guid2, "GUID");
2980 if (!NT_STATUS_IS_OK(status)) {
2981 talloc_free(tmp_ctx);
2982 return LDB_ERR_OPERATIONS_ERROR;
2985 /* remove the link */
2986 msg = ldb_msg_new(tmp_ctx);
2988 ldb_module_oom(module);
2989 talloc_free(tmp_ctx);
2990 return LDB_ERR_OPERATIONS_ERROR;
2994 msg->dn = dsdb_dn->dn;
2996 target_attr = dsdb_attribute_by_linkID(schema, sa->linkID ^ 1);
2997 if (target_attr == NULL) {
3001 ret = ldb_msg_add_empty(msg, target_attr->lDAPDisplayName, LDB_FLAG_MOD_DELETE, &el2);
3002 if (ret != LDB_SUCCESS) {
3003 ldb_module_oom(module);
3004 talloc_free(tmp_ctx);
3005 return LDB_ERR_OPERATIONS_ERROR;
3007 dn_val = data_blob_string_const(ldb_dn_get_linearized(dn));
3008 el2->values = &dn_val;
3009 el2->num_values = 1;
3011 ret = dsdb_module_modify(module, msg, DSDB_FLAG_OWN_MODULE, parent);
3012 if (ret != LDB_SUCCESS) {
3013 talloc_free(tmp_ctx);
3017 talloc_free(tmp_ctx);
3023 handle update of replication meta data for deletion of objects
3025 This also handles the mapping of delete to a rename operation
3026 to allow deletes to be replicated.
3028 It also handles the incoming deleted objects, to ensure they are
3029 fully deleted here. In that case re_delete is true, and we do not
3030 use this as a signal to change the deleted state, just reinforce it.
3033 static int replmd_delete_internals(struct ldb_module *module, struct ldb_request *req, bool re_delete)
3035 int ret = LDB_ERR_OTHER;
3036 bool retb, disallow_move_on_delete;
3037 struct ldb_dn *old_dn, *new_dn;
3038 const char *rdn_name;
3039 const struct ldb_val *rdn_value, *new_rdn_value;
3041 struct ldb_context *ldb = ldb_module_get_ctx(module);
3042 const struct dsdb_schema *schema;
3043 struct ldb_message *msg, *old_msg;
3044 struct ldb_message_element *el;
3045 TALLOC_CTX *tmp_ctx;
3046 struct ldb_result *res, *parent_res;
3047 const char *preserved_attrs[] = {
3048 /* yes, this really is a hard coded list. See MS-ADTS
3049 section 3.1.1.5.5.1.1 */
3050 "nTSecurityDescriptor", "attributeID", "attributeSyntax", "dNReferenceUpdate", "dNSHostName",
3051 "flatName", "governsID", "groupType", "instanceType", "lDAPDisplayName", "legacyExchangeDN",
3052 "isDeleted", "isRecycled", "lastKnownParent", "msDS-LastKnownRDN", "mS-DS-CreatorSID",
3053 "mSMQOwnerID", "nCName", "objectClass", "distinguishedName", "objectGUID", "objectSid",
3054 "oMSyntax", "proxiedObjectName", "name", "replPropertyMetaData", "sAMAccountName",
3055 "securityIdentifier", "sIDHistory", "subClassOf", "systemFlags", "trustPartner", "trustDirection",
3056 "trustType", "trustAttributes", "userAccountControl", "uSNChanged", "uSNCreated", "whenCreated",
3057 "whenChanged", NULL};
3058 unsigned int i, el_count = 0;
3059 enum deletion_state deletion_state, next_deletion_state;
3061 if (ldb_dn_is_special(req->op.del.dn)) {
3062 return ldb_next_request(module, req);
3066 * We have to allow dbcheck to remove an object that
3067 * is beyond repair, and to do so totally. This could
3068 * mean we we can get a partial object from the other
3069 * DC, causing havoc, so dbcheck suggests
3070 * re-replication first. dbcheck sets both DBCHECK
3071 * and RELAX in this situation.
3073 if (ldb_request_get_control(req, LDB_CONTROL_RELAX_OID)
3074 && ldb_request_get_control(req, DSDB_CONTROL_DBCHECK)) {
3075 /* really, really remove it */
3076 return ldb_next_request(module, req);
3079 tmp_ctx = talloc_new(ldb);
3082 return LDB_ERR_OPERATIONS_ERROR;
3085 schema = dsdb_get_schema(ldb, tmp_ctx);
3087 talloc_free(tmp_ctx);
3088 return LDB_ERR_OPERATIONS_ERROR;
3091 old_dn = ldb_dn_copy(tmp_ctx, req->op.del.dn);
3093 /* we need the complete msg off disk, so we can work out which
3094 attributes need to be removed */
3095 ret = dsdb_module_search_dn(module, tmp_ctx, &res, old_dn, NULL,
3096 DSDB_FLAG_NEXT_MODULE |
3097 DSDB_SEARCH_SHOW_RECYCLED |
3098 DSDB_SEARCH_REVEAL_INTERNALS |
3099 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT, req);
3100 if (ret != LDB_SUCCESS) {
3101 ldb_asprintf_errstring(ldb_module_get_ctx(module),
3102 "repmd_delete: Failed to %s %s, because we failed to find it: %s",
3103 re_delete ? "re-delete" : "delete",
3104 ldb_dn_get_linearized(old_dn),
3105 ldb_errstring(ldb_module_get_ctx(module)));
3106 talloc_free(tmp_ctx);
3109 old_msg = res->msgs[0];
3111 replmd_deletion_state(module, old_msg,
3113 &next_deletion_state);
3115 /* This supports us noticing an incoming isDeleted and acting on it */
3117 SMB_ASSERT(deletion_state > OBJECT_NOT_DELETED);
3118 next_deletion_state = deletion_state;
3121 if (next_deletion_state == OBJECT_REMOVED) {
3123 * We have to prevent objects being deleted, even if
3124 * the administrator really wants them gone, as
3125 * without the tombstone, we can get a partial object
3126 * from the other DC, causing havoc.
3128 * The only other valid case is when the 180 day
3129 * timeout has expired, when relax is specified.
3131 if (ldb_request_get_control(req, LDB_CONTROL_RELAX_OID)) {
3132 /* it is already deleted - really remove it this time */
3133 talloc_free(tmp_ctx);
3134 return ldb_next_request(module, req);
3137 ldb_asprintf_errstring(ldb, "Refusing to delete tombstone object %s. "
3138 "This check is to prevent corruption of the replicated state.",
3139 ldb_dn_get_linearized(old_msg->dn));
3140 return LDB_ERR_UNWILLING_TO_PERFORM;
3143 rdn_name = ldb_dn_get_rdn_name(old_dn);
3144 rdn_value = ldb_dn_get_rdn_val(old_dn);
3145 if ((rdn_name == NULL) || (rdn_value == NULL)) {
3146 talloc_free(tmp_ctx);
3147 return ldb_operr(ldb);
3150 msg = ldb_msg_new(tmp_ctx);
3152 ldb_module_oom(module);
3153 talloc_free(tmp_ctx);
3154 return LDB_ERR_OPERATIONS_ERROR;
3159 /* consider the SYSTEM_FLAG_DISALLOW_MOVE_ON_DELETE flag */
3160 disallow_move_on_delete =
3161 (ldb_msg_find_attr_as_int(old_msg, "systemFlags", 0)
3162 & SYSTEM_FLAG_DISALLOW_MOVE_ON_DELETE);
3164 /* work out where we will be renaming this object to */
3165 if (!disallow_move_on_delete) {
3166 struct ldb_dn *deleted_objects_dn;
3167 ret = dsdb_get_deleted_objects_dn(ldb, tmp_ctx, old_dn,
3168 &deleted_objects_dn);
3171 * We should not move objects if we can't find the
3172 * deleted objects DN. Not moving (or otherwise
3173 * harming) the Deleted Objects DN itself is handled
3176 if (re_delete && (ret != LDB_SUCCESS)) {
3177 new_dn = ldb_dn_get_parent(tmp_ctx, old_dn);
3178 if (new_dn == NULL) {
3179 ldb_module_oom(module);
3180 talloc_free(tmp_ctx);
3181 return LDB_ERR_OPERATIONS_ERROR;
3183 } else if (ret != LDB_SUCCESS) {
3184 /* this is probably an attempted delete on a partition
3185 * that doesn't allow delete operations, such as the
3186 * schema partition */
3187 ldb_asprintf_errstring(ldb, "No Deleted Objects container for DN %s",
3188 ldb_dn_get_linearized(old_dn));
3189 talloc_free(tmp_ctx);
3190 return LDB_ERR_UNWILLING_TO_PERFORM;
3192 new_dn = deleted_objects_dn;
3195 new_dn = ldb_dn_get_parent(tmp_ctx, old_dn);
3196 if (new_dn == NULL) {
3197 ldb_module_oom(module);
3198 talloc_free(tmp_ctx);
3199 return LDB_ERR_OPERATIONS_ERROR;
3203 if (deletion_state == OBJECT_NOT_DELETED) {
3204 /* get the objects GUID from the search we just did */
3205 guid = samdb_result_guid(old_msg, "objectGUID");
3207 /* Add a formatted child */
3208 retb = ldb_dn_add_child_fmt(new_dn, "%s=%s\\0ADEL:%s",
3210 ldb_dn_escape_value(tmp_ctx, *rdn_value),
3211 GUID_string(tmp_ctx, &guid));
3213 ldb_asprintf_errstring(ldb, __location__
3214 ": Unable to add a formatted child to dn: %s",
3215 ldb_dn_get_linearized(new_dn));
3216 talloc_free(tmp_ctx);
3217 return LDB_ERR_OPERATIONS_ERROR;
3220 ret = ldb_msg_add_string(msg, "isDeleted", "TRUE");
3221 if (ret != LDB_SUCCESS) {
3222 ldb_asprintf_errstring(ldb, __location__
3223 ": Failed to add isDeleted string to the msg");
3224 talloc_free(tmp_ctx);
3227 msg->elements[el_count++].flags = LDB_FLAG_MOD_REPLACE;
3230 * No matter what has happened with other renames etc, try again to
3231 * get this to be under the deleted DN. See MS-DRSR 5.160 RemoveObj
3234 struct ldb_dn *rdn = ldb_dn_copy(tmp_ctx, old_dn);
3235 retb = ldb_dn_remove_base_components(rdn, ldb_dn_get_comp_num(rdn) - 1);
3237 ldb_asprintf_errstring(ldb, __location__
3238 ": Unable to add a prepare rdn of %s",
3239 ldb_dn_get_linearized(rdn));
3240 talloc_free(tmp_ctx);
3241 return LDB_ERR_OPERATIONS_ERROR;
3243 SMB_ASSERT(ldb_dn_get_comp_num(rdn) == 1);
3245 retb = ldb_dn_add_child(new_dn, rdn);
3247 ldb_asprintf_errstring(ldb, __location__
3248 ": Unable to add rdn %s to base dn: %s",
3249 ldb_dn_get_linearized(rdn),
3250 ldb_dn_get_linearized(new_dn));
3251 talloc_free(tmp_ctx);
3252 return LDB_ERR_OPERATIONS_ERROR;
3257 now we need to modify the object in the following ways:
3259 - add isDeleted=TRUE
3260 - update rDN and name, with new rDN
3261 - remove linked attributes
3262 - remove objectCategory and sAMAccountType
3263 - remove attribs not on the preserved list
3264 - preserved if in above list, or is rDN
3265 - remove all linked attribs from this object
3266 - remove all links from other objects to this object
3267 - add lastKnownParent
3268 - update replPropertyMetaData?
3270 see MS-ADTS "Tombstone Requirements" section 3.1.1.5.5.1.1
3273 if (deletion_state == OBJECT_NOT_DELETED) {
3274 struct ldb_dn *parent_dn = ldb_dn_get_parent(tmp_ctx, old_dn);
3275 char *parent_dn_str = NULL;
3277 /* we need the storage form of the parent GUID */
3278 ret = dsdb_module_search_dn(module, tmp_ctx, &parent_res,
3280 DSDB_FLAG_NEXT_MODULE |
3281 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT |
3282 DSDB_SEARCH_REVEAL_INTERNALS|
3283 DSDB_SEARCH_SHOW_RECYCLED, req);
3284 if (ret != LDB_SUCCESS) {
3285 ldb_asprintf_errstring(ldb_module_get_ctx(module),
3286 "repmd_delete: Failed to %s %s, "
3287 "because we failed to find it's parent (%s): %s",
3288 re_delete ? "re-delete" : "delete",
3289 ldb_dn_get_linearized(old_dn),
3290 ldb_dn_get_linearized(parent_dn),
3291 ldb_errstring(ldb_module_get_ctx(module)));
3292 talloc_free(tmp_ctx);
3297 * Now we can use the DB version,
3298 * it will have the extended DN info in it
3300 parent_dn = parent_res->msgs[0]->dn;
3301 parent_dn_str = ldb_dn_get_extended_linearized(tmp_ctx,
3304 if (parent_dn_str == NULL) {
3305 talloc_free(tmp_ctx);
3306 return ldb_module_oom(module);
3309 ret = ldb_msg_add_steal_string(msg, "lastKnownParent",
3311 if (ret != LDB_SUCCESS) {
3312 ldb_asprintf_errstring(ldb, __location__
3313 ": Failed to add lastKnownParent "
3314 "string when deleting %s",
3315 ldb_dn_get_linearized(old_dn));
3316 talloc_free(tmp_ctx);
3319 msg->elements[el_count++].flags = LDB_FLAG_MOD_REPLACE;
3321 if (next_deletion_state == OBJECT_DELETED) {
3322 ret = ldb_msg_add_value(msg, "msDS-LastKnownRDN", rdn_value, NULL);
3323 if (ret != LDB_SUCCESS) {
3324 ldb_asprintf_errstring(ldb, __location__
3325 ": Failed to add msDS-LastKnownRDN "
3326 "string when deleting %s",
3327 ldb_dn_get_linearized(old_dn));
3328 talloc_free(tmp_ctx);
3331 msg->elements[el_count++].flags = LDB_FLAG_MOD_ADD;
3335 switch (next_deletion_state) {
3337 case OBJECT_RECYCLED:
3338 case OBJECT_TOMBSTONE:
3341 * MS-ADTS 3.1.1.5.5.1.1 Tombstone Requirements
3342 * describes what must be removed from a tombstone
3345 * MS-ADTS 3.1.1.5.5.1.3 Recycled-Object Requirements
3346 * describes what must be removed from a recycled
3352 * we also mark it as recycled, meaning this object can't be
3353 * recovered (we are stripping its attributes).
3354 * This is done only if we have this schema object of course ...
3355 * This behavior is identical to the one of Windows 2008R2 which
3356 * always set the isRecycled attribute, even if the recycle-bin is
3357 * not activated and what ever the forest level is.
3359 if (dsdb_attribute_by_lDAPDisplayName(schema, "isRecycled") != NULL) {
3360 ret = ldb_msg_add_string(msg, "isRecycled", "TRUE");
3361 if (ret != LDB_SUCCESS) {
3362 DEBUG(0,(__location__ ": Failed to add isRecycled string to the msg\n"));
3363 ldb_module_oom(module);
3364 talloc_free(tmp_ctx);
3367 msg->elements[el_count++].flags = LDB_FLAG_MOD_REPLACE;
3370 /* work out which of the old attributes we will be removing */
3371 for (i=0; i<old_msg->num_elements; i++) {
3372 const struct dsdb_attribute *sa;
3373 el = &old_msg->elements[i];
3374 sa = dsdb_attribute_by_lDAPDisplayName(schema, el->name);
3376 talloc_free(tmp_ctx);
3377 return LDB_ERR_OPERATIONS_ERROR;
3379 if (ldb_attr_cmp(el->name, rdn_name) == 0) {
3380 /* don't remove the rDN */
3383 if (sa->linkID && (sa->linkID & 1)) {
3385 we have a backlink in this object
3386 that needs to be removed. We're not
3387 allowed to remove it directly
3388 however, so we instead setup a
3389 modify to delete the corresponding
3392 ret = replmd_delete_remove_link(module, schema, old_dn, el, sa, req);
3393 if (ret != LDB_SUCCESS) {
3394 const char *old_dn_str
3395 = ldb_dn_get_linearized(old_dn);
3396 ldb_asprintf_errstring(ldb,
3398 ": Failed to remove backlink of "
3399 "%s when deleting %s",
3402 talloc_free(tmp_ctx);
3403 return LDB_ERR_OPERATIONS_ERROR;
3405 /* now we continue, which means we
3406 won't remove this backlink
3412 if (ldb_attr_in_list(preserved_attrs, el->name)) {
3415 if (sa->searchFlags & SEARCH_FLAG_PRESERVEONDELETE) {
3419 ret = ldb_msg_add_empty(msg, el->name, LDB_FLAG_MOD_DELETE, &el);
3420 if (ret != LDB_SUCCESS) {
3421 talloc_free(tmp_ctx);
3422 ldb_module_oom(module);
3429 case OBJECT_DELETED:
3431 * MS-ADTS 3.1.1.5.5.1.2 Deleted-Object Requirements
3432 * describes what must be removed from a deleted
3436 ret = ldb_msg_add_empty(msg, "objectCategory", LDB_FLAG_MOD_REPLACE, NULL);
3437 if (ret != LDB_SUCCESS) {
3438 talloc_free(tmp_ctx);
3439 ldb_module_oom(module);
3443 ret = ldb_msg_add_empty(msg, "sAMAccountType", LDB_FLAG_MOD_REPLACE, NULL);
3444 if (ret != LDB_SUCCESS) {
3445 talloc_free(tmp_ctx);
3446 ldb_module_oom(module);
3456 if (deletion_state == OBJECT_NOT_DELETED) {
3457 const struct dsdb_attribute *sa;
3459 /* work out what the new rdn value is, for updating the
3460 rDN and name fields */
3461 new_rdn_value = ldb_dn_get_rdn_val(new_dn);
3462 if (new_rdn_value == NULL) {
3463 talloc_free(tmp_ctx);
3464 return ldb_operr(ldb);
3467 sa = dsdb_attribute_by_lDAPDisplayName(schema, rdn_name);
3469 talloc_free(tmp_ctx);
3470 return LDB_ERR_OPERATIONS_ERROR;
3473 ret = ldb_msg_add_value(msg, sa->lDAPDisplayName, new_rdn_value,
3475 if (ret != LDB_SUCCESS) {
3476 talloc_free(tmp_ctx);
3479 el->flags = LDB_FLAG_MOD_REPLACE;
3481 el = ldb_msg_find_element(old_msg, "name");
3483 ret = ldb_msg_add_value(msg, "name", new_rdn_value, &el);
3484 if (ret != LDB_SUCCESS) {
3485 talloc_free(tmp_ctx);
3488 el->flags = LDB_FLAG_MOD_REPLACE;
3493 * TODO: Per MS-DRSR 5.160 RemoveObj we should remove links directly, not as an originating update!
3498 * No matter what has happned with other renames, try again to
3499 * get this to be under the deleted DN.
3501 if (strcmp(ldb_dn_get_linearized(old_dn), ldb_dn_get_linearized(new_dn)) != 0) {
3502 /* now rename onto the new DN */
3503 ret = dsdb_module_rename(module, old_dn, new_dn, DSDB_FLAG_NEXT_MODULE, req);
3504 if (ret != LDB_SUCCESS){
3505 DEBUG(0,(__location__ ": Failed to rename object from '%s' to '%s' - %s\n",
3506 ldb_dn_get_linearized(old_dn),
3507 ldb_dn_get_linearized(new_dn),
3508 ldb_errstring(ldb)));
3509 talloc_free(tmp_ctx);
3515 ret = dsdb_module_modify(module, msg, DSDB_FLAG_OWN_MODULE, req);
3516 if (ret != LDB_SUCCESS) {
3517 ldb_asprintf_errstring(ldb, "replmd_delete: Failed to modify object %s in delete - %s",
3518 ldb_dn_get_linearized(old_dn), ldb_errstring(ldb));
3519 talloc_free(tmp_ctx);
3523 talloc_free(tmp_ctx);
3525 return ldb_module_done(req, NULL, NULL, LDB_SUCCESS);
3528 static int replmd_delete(struct ldb_module *module, struct ldb_request *req)
3530 return replmd_delete_internals(module, req, false);
3534 static int replmd_replicated_request_error(struct replmd_replicated_request *ar, int ret)
3539 static int replmd_replicated_request_werror(struct replmd_replicated_request *ar, WERROR status)
3541 int ret = LDB_ERR_OTHER;
3542 /* TODO: do some error mapping */
3544 /* Let the caller know the full WERROR */
3545 ar->objs->error = status;
3551 static struct replPropertyMetaData1 *
3552 replmd_replPropertyMetaData1_find_attid(struct replPropertyMetaDataBlob *md_blob,
3553 enum drsuapi_DsAttributeId attid)
3556 struct replPropertyMetaDataCtr1 *rpmd_ctr = &md_blob->ctr.ctr1;
3558 for (i = 0; i < rpmd_ctr->count; i++) {
3559 if (rpmd_ctr->array[i].attid == attid) {
3560 return &rpmd_ctr->array[i];
3568 return true if an update is newer than an existing entry
3569 see section 5.11 of MS-ADTS
3571 static bool replmd_update_is_newer(const struct GUID *current_invocation_id,
3572 const struct GUID *update_invocation_id,
3573 uint32_t current_version,
3574 uint32_t update_version,
3575 NTTIME current_change_time,
3576 NTTIME update_change_time)
3578 if (update_version != current_version) {
3579 return update_version > current_version;
3581 if (update_change_time != current_change_time) {
3582 return update_change_time > current_change_time;
3584 return GUID_compare(update_invocation_id, current_invocation_id) > 0;
3587 static bool replmd_replPropertyMetaData1_is_newer(struct replPropertyMetaData1 *cur_m,
3588 struct replPropertyMetaData1 *new_m)
3590 return replmd_update_is_newer(&cur_m->originating_invocation_id,
3591 &new_m->originating_invocation_id,
3594 cur_m->originating_change_time,
3595 new_m->originating_change_time);
3598 static bool replmd_replPropertyMetaData1_new_should_be_taken(uint32_t dsdb_repl_flags,
3599 struct replPropertyMetaData1 *cur_m,
3600 struct replPropertyMetaData1 *new_m)
3605 * If the new replPropertyMetaData entry for this attribute is
3606 * not provided (this happens in the case where we look for
3607 * ATTID_name, but the name was not changed), then the local
3608 * state is clearly still current, as the remote
3609 * server didn't send it due to being older the high watermark
3612 if (new_m == NULL) {
3616 if (dsdb_repl_flags & DSDB_REPL_FLAG_PRIORITISE_INCOMING) {
3618 * if we compare equal then do an
3619 * update. This is used when a client
3620 * asks for a FULL_SYNC, and can be
3621 * used to recover a corrupt
3624 * This call is a bit tricky, what we
3625 * are doing it turning the 'is_newer'
3626 * call into a 'not is older' by
3627 * swapping cur_m and new_m, and negating the
3630 cmp = !replmd_replPropertyMetaData1_is_newer(new_m,
3633 cmp = replmd_replPropertyMetaData1_is_newer(cur_m,
3643 static struct ldb_dn *replmd_conflict_dn(TALLOC_CTX *mem_ctx, struct ldb_dn *dn, struct GUID *guid)
3645 const struct ldb_val *rdn_val;
3646 const char *rdn_name;
3647 struct ldb_dn *new_dn;
3649 rdn_val = ldb_dn_get_rdn_val(dn);
3650 rdn_name = ldb_dn_get_rdn_name(dn);
3651 if (!rdn_val || !rdn_name) {
3655 new_dn = ldb_dn_copy(mem_ctx, dn);
3660 if (!ldb_dn_remove_child_components(new_dn, 1)) {
3664 if (!ldb_dn_add_child_fmt(new_dn, "%s=%s\\0ACNF:%s",
3666 ldb_dn_escape_value(new_dn, *rdn_val),
3667 GUID_string(new_dn, guid))) {
3676 perform a modify operation which sets the rDN and name attributes to
3677 their current values. This has the effect of changing these
3678 attributes to have been last updated by the current DC. This is
3679 needed to ensure that renames performed as part of conflict
3680 resolution are propogated to other DCs
3682 static int replmd_name_modify(struct replmd_replicated_request *ar,
3683 struct ldb_request *req, struct ldb_dn *dn)
3685 struct ldb_message *msg;
3686 const char *rdn_name;
3687 const struct ldb_val *rdn_val;
3688 const struct dsdb_attribute *rdn_attr;
3691 msg = ldb_msg_new(req);
3697 rdn_name = ldb_dn_get_rdn_name(dn);
3698 if (rdn_name == NULL) {
3702 /* normalize the rdn attribute name */
3703 rdn_attr = dsdb_attribute_by_lDAPDisplayName(ar->schema, rdn_name);
3704 if (rdn_attr == NULL) {
3707 rdn_name = rdn_attr->lDAPDisplayName;
3709 rdn_val = ldb_dn_get_rdn_val(dn);
3710 if (rdn_val == NULL) {
3714 if (ldb_msg_add_empty(msg, rdn_name, LDB_FLAG_MOD_REPLACE, NULL) != 0) {
3717 if (ldb_msg_add_value(msg, rdn_name, rdn_val, NULL) != 0) {
3720 if (ldb_msg_add_empty(msg, "name", LDB_FLAG_MOD_REPLACE, NULL) != 0) {
3723 if (ldb_msg_add_value(msg, "name", rdn_val, NULL) != 0) {
3727 ret = dsdb_module_modify(ar->module, msg, DSDB_FLAG_OWN_MODULE, req);
3728 if (ret != LDB_SUCCESS) {
3729 DEBUG(0,(__location__ ": Failed to modify rDN/name of conflict DN '%s' - %s",
3730 ldb_dn_get_linearized(dn),
3731 ldb_errstring(ldb_module_get_ctx(ar->module))));
3741 DEBUG(0,(__location__ ": Failed to setup modify rDN/name of conflict DN '%s'",
3742 ldb_dn_get_linearized(dn)));
3743 return LDB_ERR_OPERATIONS_ERROR;
3748 callback for conflict DN handling where we have renamed the incoming
3749 record. After renaming it, we need to ensure the change of name and
3750 rDN for the incoming record is seen as an originating update by this DC.
3752 This also handles updating lastKnownParent for entries sent to lostAndFound
3754 static int replmd_op_name_modify_callback(struct ldb_request *req, struct ldb_reply *ares)
3756 struct replmd_replicated_request *ar =
3757 talloc_get_type_abort(req->context, struct replmd_replicated_request);
3758 struct ldb_dn *conflict_dn = NULL;
3761 if (ares->error != LDB_SUCCESS) {
3762 /* call the normal callback for everything except success */
3763 return replmd_op_callback(req, ares);
3766 switch (req->operation) {
3768 conflict_dn = req->op.add.message->dn;
3771 conflict_dn = req->op.mod.message->dn;
3774 smb_panic("replmd_op_name_modify_callback called in unknown circumstances");
3777 /* perform a modify of the rDN and name of the record */
3778 ret = replmd_name_modify(ar, req, conflict_dn);
3779 if (ret != LDB_SUCCESS) {
3781 return replmd_op_callback(req, ares);
3784 if (ar->objs->objects[ar->index_current].last_known_parent) {
3785 struct ldb_message *msg = ldb_msg_new(req);
3787 ldb_module_oom(ar->module);
3788 return LDB_ERR_OPERATIONS_ERROR;
3791 msg->dn = req->op.add.message->dn;
3793 ret = ldb_msg_add_steal_string(msg, "lastKnownParent",
3794 ldb_dn_get_extended_linearized(msg, ar->objs->objects[ar->index_current].last_known_parent, 1));
3795 if (ret != LDB_SUCCESS) {
3796 DEBUG(0,(__location__ ": Failed to add lastKnownParent string to the msg\n"));
3797 ldb_module_oom(ar->module);
3800 msg->elements[0].flags = LDB_FLAG_MOD_REPLACE;
3802 ret = dsdb_module_modify(ar->module, msg, DSDB_FLAG_OWN_MODULE, req);
3803 if (ret != LDB_SUCCESS) {
3804 DEBUG(0,(__location__ ": Failed to modify lastKnownParent of lostAndFound DN '%s' - %s",
3805 ldb_dn_get_linearized(msg->dn),
3806 ldb_errstring(ldb_module_get_ctx(ar->module))));
3812 return replmd_op_callback(req, ares);
3816 callback for replmd_replicated_apply_add()
3817 This copes with the creation of conflict records in the case where
3818 the DN exists, but with a different objectGUID
3820 static int replmd_op_possible_conflict_callback(struct ldb_request *req, struct ldb_reply *ares, int (*callback)(struct ldb_request *req, struct ldb_reply *ares))
3822 struct ldb_dn *conflict_dn;
3823 struct replmd_replicated_request *ar =
3824 talloc_get_type_abort(req->context, struct replmd_replicated_request);
3825 struct ldb_result *res;
3826 const char *attrs[] = { "replPropertyMetaData", "objectGUID", NULL };
3828 const struct ldb_val *omd_value;
3829 struct replPropertyMetaDataBlob omd, *rmd;
3830 enum ndr_err_code ndr_err;
3831 bool rename_incoming_record, rodc;
3832 struct replPropertyMetaData1 *rmd_name, *omd_name;
3833 struct ldb_message *msg;
3834 struct ldb_request *down_req = NULL;
3836 /* call the normal callback for success */
3837 if (ares->error == LDB_SUCCESS) {
3838 return callback(req, ares);
3842 * we have a conflict, and need to decide if we will keep the
3843 * new record or the old record
3846 msg = ar->objs->objects[ar->index_current].msg;
3847 conflict_dn = msg->dn;
3849 /* For failures other than conflicts, fail the whole operation here */
3850 if (ares->error != LDB_ERR_ENTRY_ALREADY_EXISTS) {
3851 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module), "Failed to locally apply remote add of %s: %s",
3852 ldb_dn_get_linearized(conflict_dn),
3853 ldb_errstring(ldb_module_get_ctx(ar->module)));
3855 return ldb_module_done(ar->req, NULL, NULL,
3856 LDB_ERR_OPERATIONS_ERROR);
3859 ret = samdb_rodc(ldb_module_get_ctx(ar->module), &rodc);
3860 if (ret != LDB_SUCCESS) {
3861 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module), "Failed to determine if we are an RODC when attempting to form conflict DN: %s", ldb_errstring(ldb_module_get_ctx(ar->module)));
3862 return ldb_module_done(ar->req, NULL, NULL,
3863 LDB_ERR_OPERATIONS_ERROR);
3869 * We are on an RODC, or were a GC for this
3870 * partition, so we have to fail this until
3871 * someone who owns the partition sorts it
3874 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
3875 "Conflict adding object '%s' from incoming replication as we are read only for the partition. \n"
3876 " - We must fail the operation until a master for this partition resolves the conflict",
3877 ldb_dn_get_linearized(conflict_dn));
3882 * first we need the replPropertyMetaData attribute from the
3883 * local, conflicting record
3885 ret = dsdb_module_search_dn(ar->module, req, &res, conflict_dn,
3887 DSDB_FLAG_NEXT_MODULE |
3888 DSDB_SEARCH_SHOW_DELETED |
3889 DSDB_SEARCH_SHOW_RECYCLED, req);
3890 if (ret != LDB_SUCCESS) {
3891 DEBUG(0,(__location__ ": Unable to find object for conflicting record '%s'\n",
3892 ldb_dn_get_linearized(conflict_dn)));
3896 omd_value = ldb_msg_find_ldb_val(res->msgs[0], "replPropertyMetaData");
3897 if (omd_value == NULL) {
3898 DEBUG(0,(__location__ ": Unable to find replPropertyMetaData for conflicting record '%s'\n",
3899 ldb_dn_get_linearized(conflict_dn)));
3903 ndr_err = ndr_pull_struct_blob(omd_value, res->msgs[0], &omd,
3904 (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
3905 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
3906 DEBUG(0,(__location__ ": Failed to parse old replPropertyMetaData for %s\n",
3907 ldb_dn_get_linearized(conflict_dn)));
3911 rmd = ar->objs->objects[ar->index_current].meta_data;
3914 * we decide which is newer based on the RPMD on the name
3915 * attribute. See [MS-DRSR] ResolveNameConflict.
3917 * We expect omd_name to be present, as this is from a local
3918 * search, but while rmd_name should have been given to us by
3919 * the remote server, if it is missing we just prefer the
3921 * replmd_replPropertyMetaData1_new_should_be_taken()
3923 rmd_name = replmd_replPropertyMetaData1_find_attid(rmd, DRSUAPI_ATTID_name);
3924 omd_name = replmd_replPropertyMetaData1_find_attid(&omd, DRSUAPI_ATTID_name);
3926 DEBUG(0,(__location__ ": Failed to find name attribute in local LDB replPropertyMetaData for %s\n",
3927 ldb_dn_get_linearized(conflict_dn)));
3932 * Should we preserve the current record, and so rename the
3933 * incoming record to be a conflict?
3935 rename_incoming_record
3936 = !replmd_replPropertyMetaData1_new_should_be_taken(ar->objs->dsdb_repl_flags & DSDB_REPL_FLAG_PRIORITISE_INCOMING,
3937 omd_name, rmd_name);
3939 if (rename_incoming_record) {
3941 struct ldb_dn *new_dn;
3943 guid = samdb_result_guid(msg, "objectGUID");
3944 if (GUID_all_zero(&guid)) {
3945 DEBUG(0,(__location__ ": Failed to find objectGUID for conflicting incoming record %s\n",
3946 ldb_dn_get_linearized(conflict_dn)));
3949 new_dn = replmd_conflict_dn(req, conflict_dn, &guid);
3950 if (new_dn == NULL) {
3951 DEBUG(0,(__location__ ": Failed to form conflict DN for %s\n",
3952 ldb_dn_get_linearized(conflict_dn)));
3956 DEBUG(2,(__location__ ": Resolving conflict record via incoming rename '%s' -> '%s'\n",
3957 ldb_dn_get_linearized(conflict_dn), ldb_dn_get_linearized(new_dn)));
3959 /* re-submit the request, but with the new DN */
3960 callback = replmd_op_name_modify_callback;
3963 /* we are renaming the existing record */
3965 struct ldb_dn *new_dn;
3967 guid = samdb_result_guid(res->msgs[0], "objectGUID");
3968 if (GUID_all_zero(&guid)) {
3969 DEBUG(0,(__location__ ": Failed to find objectGUID for existing conflict record %s\n",
3970 ldb_dn_get_linearized(conflict_dn)));
3974 new_dn = replmd_conflict_dn(req, conflict_dn, &guid);
3975 if (new_dn == NULL) {
3976 DEBUG(0,(__location__ ": Failed to form conflict DN for %s\n",
3977 ldb_dn_get_linearized(conflict_dn)));
3981 DEBUG(2,(__location__ ": Resolving conflict record via existing-record rename '%s' -> '%s'\n",
3982 ldb_dn_get_linearized(conflict_dn), ldb_dn_get_linearized(new_dn)));
3984 ret = dsdb_module_rename(ar->module, conflict_dn, new_dn,
3985 DSDB_FLAG_OWN_MODULE, req);
3986 if (ret != LDB_SUCCESS) {
3987 DEBUG(0,(__location__ ": Failed to rename conflict dn '%s' to '%s' - %s\n",
3988 ldb_dn_get_linearized(conflict_dn),
3989 ldb_dn_get_linearized(new_dn),
3990 ldb_errstring(ldb_module_get_ctx(ar->module))));
3995 * now we need to ensure that the rename is seen as an
3996 * originating update. We do that with a modify.
3998 ret = replmd_name_modify(ar, req, new_dn);
3999 if (ret != LDB_SUCCESS) {
4003 DEBUG(2,(__location__ ": With conflicting record renamed, re-apply replicated creation of '%s'\n",
4004 ldb_dn_get_linearized(req->op.add.message->dn)));
4007 ret = ldb_build_add_req(&down_req,
4008 ldb_module_get_ctx(ar->module),
4015 if (ret != LDB_SUCCESS) {
4018 LDB_REQ_SET_LOCATION(down_req);
4020 /* current partition control needed by "repmd_op_callback" */
4021 ret = ldb_request_add_control(down_req,
4022 DSDB_CONTROL_CURRENT_PARTITION_OID,
4024 if (ret != LDB_SUCCESS) {
4025 return replmd_replicated_request_error(ar, ret);
4028 if (ar->objs->dsdb_repl_flags & DSDB_REPL_FLAG_PARTIAL_REPLICA) {
4029 /* this tells the partition module to make it a
4030 partial replica if creating an NC */
4031 ret = ldb_request_add_control(down_req,
4032 DSDB_CONTROL_PARTIAL_REPLICA,
4034 if (ret != LDB_SUCCESS) {
4035 return replmd_replicated_request_error(ar, ret);
4040 * Finally we re-run the add, otherwise the new record won't
4041 * exist, as we are here because of that exact failure!
4043 return ldb_next_request(ar->module, down_req);
4046 /* on failure make the caller get the error. This means
4047 * replication will stop with an error, but there is not much
4050 return ldb_module_done(ar->req, NULL, NULL,
4055 callback for replmd_replicated_apply_add()
4056 This copes with the creation of conflict records in the case where
4057 the DN exists, but with a different objectGUID
4059 static int replmd_op_add_callback(struct ldb_request *req, struct ldb_reply *ares)
4061 struct replmd_replicated_request *ar =
4062 talloc_get_type_abort(req->context, struct replmd_replicated_request);
4064 if (ar->objs->objects[ar->index_current].last_known_parent) {
4065 /* This is like a conflict DN, where we put the object in LostAndFound
4066 see MS-DRSR 4.1.10.6.10 FindBestParentObject */
4067 return replmd_op_possible_conflict_callback(req, ares, replmd_op_name_modify_callback);
4070 return replmd_op_possible_conflict_callback(req, ares, replmd_op_callback);
4074 this is called when a new object comes in over DRS
4076 static int replmd_replicated_apply_add(struct replmd_replicated_request *ar)
4078 struct ldb_context *ldb;
4079 struct ldb_request *change_req;
4080 enum ndr_err_code ndr_err;
4081 struct ldb_message *msg;
4082 struct replPropertyMetaDataBlob *md;
4083 struct ldb_val md_value;
4086 bool remote_isDeleted = false;
4089 time_t t = time(NULL);
4090 const struct ldb_val *rdn_val;
4091 struct replmd_private *replmd_private =
4092 talloc_get_type(ldb_module_get_private(ar->module),
4093 struct replmd_private);
4094 unix_to_nt_time(&now, t);
4096 ldb = ldb_module_get_ctx(ar->module);
4097 msg = ar->objs->objects[ar->index_current].msg;
4098 md = ar->objs->objects[ar->index_current].meta_data;
4099 is_schema_nc = ldb_dn_compare_base(replmd_private->schema_dn, msg->dn) == 0;
4101 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &ar->seq_num);
4102 if (ret != LDB_SUCCESS) {
4103 return replmd_replicated_request_error(ar, ret);
4106 ret = dsdb_msg_add_guid(msg,
4107 &ar->objs->objects[ar->index_current].object_guid,
4109 if (ret != LDB_SUCCESS) {
4110 return replmd_replicated_request_error(ar, ret);
4113 ret = ldb_msg_add_string(msg, "whenChanged", ar->objs->objects[ar->index_current].when_changed);
4114 if (ret != LDB_SUCCESS) {
4115 return replmd_replicated_request_error(ar, ret);
4118 ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNCreated", ar->seq_num);
4119 if (ret != LDB_SUCCESS) {
4120 return replmd_replicated_request_error(ar, ret);
4123 ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNChanged", ar->seq_num);
4124 if (ret != LDB_SUCCESS) {
4125 return replmd_replicated_request_error(ar, ret);
4128 /* remove any message elements that have zero values */
4129 for (i=0; i<msg->num_elements; i++) {
4130 struct ldb_message_element *el = &msg->elements[i];
4132 if (el->num_values == 0) {
4133 if (ldb_attr_cmp(msg->elements[i].name, "objectClass") == 0) {
4134 ldb_asprintf_errstring(ldb, __location__
4135 ": empty objectClass sent on %s, aborting replication\n",
4136 ldb_dn_get_linearized(msg->dn));
4137 return replmd_replicated_request_error(ar, LDB_ERR_OBJECT_CLASS_VIOLATION);
4140 DEBUG(4,(__location__ ": Removing attribute %s with num_values==0\n",
4142 memmove(el, el+1, sizeof(*el)*(msg->num_elements - (i+1)));
4143 msg->num_elements--;
4150 struct GUID_txt_buf guid_txt;
4152 char *s = ldb_ldif_message_string(ldb, ar, LDB_CHANGETYPE_ADD, msg);
4153 DEBUG(4, ("DRS replication add message of %s:\n%s\n",
4154 GUID_buf_string(&ar->objs->objects[ar->index_current].object_guid, &guid_txt),
4159 remote_isDeleted = ldb_msg_find_attr_as_bool(msg,
4160 "isDeleted", false);
4163 * the meta data array is already sorted by the caller, except
4164 * for the RDN, which needs to be added.
4168 rdn_val = ldb_dn_get_rdn_val(msg->dn);
4169 ret = replmd_update_rpmd_rdn_attr(ldb, msg, rdn_val, NULL,
4170 md, ar, now, is_schema_nc);
4171 if (ret != LDB_SUCCESS) {
4172 ldb_asprintf_errstring(ldb, "%s: error during DRS repl ADD: %s", __func__, ldb_errstring(ldb));
4173 return replmd_replicated_request_error(ar, ret);
4176 ret = replmd_replPropertyMetaDataCtr1_sort_and_verify(ldb, &md->ctr.ctr1, msg->dn);
4177 if (ret != LDB_SUCCESS) {
4178 ldb_asprintf_errstring(ldb, "%s: error during DRS repl ADD: %s", __func__, ldb_errstring(ldb));
4179 return replmd_replicated_request_error(ar, ret);
4182 for (i=0; i < md->ctr.ctr1.count; i++) {
4183 md->ctr.ctr1.array[i].local_usn = ar->seq_num;
4185 ndr_err = ndr_push_struct_blob(&md_value, msg, md,
4186 (ndr_push_flags_fn_t)ndr_push_replPropertyMetaDataBlob);
4187 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
4188 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
4189 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
4191 ret = ldb_msg_add_value(msg, "replPropertyMetaData", &md_value, NULL);
4192 if (ret != LDB_SUCCESS) {
4193 return replmd_replicated_request_error(ar, ret);
4196 replmd_ldb_message_sort(msg, ar->schema);
4198 if (!remote_isDeleted) {
4199 ret = dsdb_module_schedule_sd_propagation(ar->module,
4200 ar->objs->partition_dn,
4202 if (ret != LDB_SUCCESS) {
4203 return replmd_replicated_request_error(ar, ret);
4207 ar->isDeleted = remote_isDeleted;
4209 ret = ldb_build_add_req(&change_req,
4215 replmd_op_add_callback,
4217 LDB_REQ_SET_LOCATION(change_req);
4218 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
4220 /* current partition control needed by "repmd_op_callback" */
4221 ret = ldb_request_add_control(change_req,
4222 DSDB_CONTROL_CURRENT_PARTITION_OID,
4224 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
4226 if (ar->objs->dsdb_repl_flags & DSDB_REPL_FLAG_PARTIAL_REPLICA) {
4227 /* this tells the partition module to make it a
4228 partial replica if creating an NC */
4229 ret = ldb_request_add_control(change_req,
4230 DSDB_CONTROL_PARTIAL_REPLICA,
4232 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
4235 return ldb_next_request(ar->module, change_req);
4238 static int replmd_replicated_apply_search_for_parent_callback(struct ldb_request *req,
4239 struct ldb_reply *ares)
4241 struct replmd_replicated_request *ar = talloc_get_type(req->context,
4242 struct replmd_replicated_request);
4246 return ldb_module_done(ar->req, NULL, NULL,
4247 LDB_ERR_OPERATIONS_ERROR);
4251 * The error NO_SUCH_OBJECT is not expected, unless the search
4252 * base is the partition DN, and that case doesn't happen here
4253 * because then we wouldn't get a parent_guid_value in any
4256 if (ares->error != LDB_SUCCESS) {
4257 return ldb_module_done(ar->req, ares->controls,
4258 ares->response, ares->error);
4261 switch (ares->type) {
4262 case LDB_REPLY_ENTRY:
4264 struct ldb_message *parent_msg = ares->message;
4265 struct ldb_message *msg = ar->objs->objects[ar->index_current].msg;
4266 struct ldb_dn *parent_dn;
4269 if (!ldb_msg_check_string_attribute(msg, "isDeleted", "TRUE")
4270 && ldb_msg_check_string_attribute(parent_msg, "isDeleted", "TRUE")) {
4271 /* Per MS-DRSR 4.1.10.6.10
4272 * FindBestParentObject we need to move this
4273 * new object under a deleted object to
4275 struct ldb_dn *nc_root;
4277 ret = dsdb_find_nc_root(ldb_module_get_ctx(ar->module), msg, msg->dn, &nc_root);
4278 if (ret == LDB_ERR_NO_SUCH_OBJECT) {
4279 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
4280 "No suitable NC root found for %s. "
4281 "We need to move this object because parent object %s "
4282 "is deleted, but this object is not.",
4283 ldb_dn_get_linearized(msg->dn),
4284 ldb_dn_get_linearized(parent_msg->dn));
4285 return ldb_module_done(ar->req, NULL, NULL, LDB_ERR_OPERATIONS_ERROR);
4286 } else if (ret != LDB_SUCCESS) {
4287 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
4288 "Unable to find NC root for %s: %s. "
4289 "We need to move this object because parent object %s "
4290 "is deleted, but this object is not.",
4291 ldb_dn_get_linearized(msg->dn),
4292 ldb_errstring(ldb_module_get_ctx(ar->module)),
4293 ldb_dn_get_linearized(parent_msg->dn));
4294 return ldb_module_done(ar->req, NULL, NULL, LDB_ERR_OPERATIONS_ERROR);
4297 ret = dsdb_wellknown_dn(ldb_module_get_ctx(ar->module), msg,
4299 DS_GUID_LOSTANDFOUND_CONTAINER,
4301 if (ret != LDB_SUCCESS) {
4302 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
4303 "Unable to find LostAndFound Container for %s "
4304 "in partition %s: %s. "
4305 "We need to move this object because parent object %s "
4306 "is deleted, but this object is not.",
4307 ldb_dn_get_linearized(msg->dn), ldb_dn_get_linearized(nc_root),
4308 ldb_errstring(ldb_module_get_ctx(ar->module)),
4309 ldb_dn_get_linearized(parent_msg->dn));
4310 return ldb_module_done(ar->req, NULL, NULL, LDB_ERR_OPERATIONS_ERROR);
4312 ar->objs->objects[ar->index_current].last_known_parent
4313 = talloc_steal(ar->objs->objects[ar->index_current].msg, parent_msg->dn);
4317 = talloc_steal(ar->objs->objects[ar->index_current].msg, parent_msg->dn);
4320 ar->objs->objects[ar->index_current].local_parent_dn = parent_dn;
4322 comp_num = ldb_dn_get_comp_num(msg->dn);
4324 if (!ldb_dn_remove_base_components(msg->dn, comp_num - 1)) {
4326 return ldb_module_done(ar->req, NULL, NULL, ldb_module_operr(ar->module));
4329 if (!ldb_dn_add_base(msg->dn, parent_dn)) {
4331 return ldb_module_done(ar->req, NULL, NULL, ldb_module_operr(ar->module));
4335 case LDB_REPLY_REFERRAL:
4336 /* we ignore referrals */
4339 case LDB_REPLY_DONE:
4341 if (ar->objs->objects[ar->index_current].local_parent_dn == NULL) {
4342 struct GUID_txt_buf str_buf;
4343 if (ar->search_msg != NULL) {
4344 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
4345 "No parent with GUID %s found for object locally known as %s",
4346 GUID_buf_string(ar->objs->objects[ar->index_current].parent_guid, &str_buf),
4347 ldb_dn_get_linearized(ar->search_msg->dn));
4349 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
4350 "No parent with GUID %s found for object remotely known as %s",
4351 GUID_buf_string(ar->objs->objects[ar->index_current].parent_guid, &str_buf),
4352 ldb_dn_get_linearized(ar->objs->objects[ar->index_current].msg->dn));
4356 * This error code is really important, as it
4357 * is the flag back to the callers to retry
4358 * this with DRSUAPI_DRS_GET_ANC, and so get
4359 * the parent objects before the child
4362 return ldb_module_done(ar->req, NULL, NULL,
4363 replmd_replicated_request_werror(ar, WERR_DS_DRA_MISSING_PARENT));
4366 if (ar->search_msg != NULL) {
4367 ret = replmd_replicated_apply_merge(ar);
4369 ret = replmd_replicated_apply_add(ar);
4371 if (ret != LDB_SUCCESS) {
4372 return ldb_module_done(ar->req, NULL, NULL, ret);
4381 * Look for the parent object, so we put the new object in the right
4382 * place This is akin to NameObject in MS-DRSR - this routine and the
4383 * callbacks find the right parent name, and correct name for this
4387 static int replmd_replicated_apply_search_for_parent(struct replmd_replicated_request *ar)
4389 struct ldb_context *ldb;
4393 struct ldb_request *search_req;
4394 static const char *attrs[] = {"isDeleted", NULL};
4395 struct GUID_txt_buf guid_str_buf;
4397 ldb = ldb_module_get_ctx(ar->module);
4399 if (ar->objs->objects[ar->index_current].parent_guid == NULL) {
4400 if (ar->search_msg != NULL) {
4401 return replmd_replicated_apply_merge(ar);
4403 return replmd_replicated_apply_add(ar);
4407 tmp_str = GUID_buf_string(ar->objs->objects[ar->index_current].parent_guid,
4410 filter = talloc_asprintf(ar, "(objectGUID=%s)", tmp_str);
4411 if (!filter) return replmd_replicated_request_werror(ar, WERR_NOMEM);
4413 ret = ldb_build_search_req(&search_req,
4416 ar->objs->partition_dn,
4422 replmd_replicated_apply_search_for_parent_callback,
4424 LDB_REQ_SET_LOCATION(search_req);
4426 ret = dsdb_request_add_controls(search_req,
4427 DSDB_SEARCH_SHOW_RECYCLED|
4428 DSDB_SEARCH_SHOW_DELETED|
4429 DSDB_SEARCH_SHOW_EXTENDED_DN);
4430 if (ret != LDB_SUCCESS) {
4434 return ldb_next_request(ar->module, search_req);
4438 handle renames that come in over DRS replication
4440 static int replmd_replicated_handle_rename(struct replmd_replicated_request *ar,
4441 struct ldb_message *msg,
4442 struct ldb_request *parent,
4446 TALLOC_CTX *tmp_ctx = talloc_new(msg);
4447 struct ldb_result *res;
4448 struct ldb_dn *conflict_dn;
4449 const char *attrs[] = { "replPropertyMetaData", "objectGUID", NULL };
4450 const struct ldb_val *omd_value;
4451 struct replPropertyMetaDataBlob omd, *rmd;
4452 enum ndr_err_code ndr_err;
4453 bool rename_incoming_record, rodc;
4454 struct replPropertyMetaData1 *rmd_name, *omd_name;
4455 struct ldb_dn *new_dn;
4458 DEBUG(4,("replmd_replicated_request rename %s => %s\n",
4459 ldb_dn_get_linearized(ar->search_msg->dn),
4460 ldb_dn_get_linearized(msg->dn)));
4463 ret = dsdb_module_rename(ar->module, ar->search_msg->dn, msg->dn,
4464 DSDB_FLAG_NEXT_MODULE, ar->req);
4465 if (ret == LDB_SUCCESS) {
4466 talloc_free(tmp_ctx);
4471 if (ret != LDB_ERR_ENTRY_ALREADY_EXISTS) {
4472 talloc_free(tmp_ctx);
4473 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module), "Failed to locally apply remote rename from %s to %s: %s",
4474 ldb_dn_get_linearized(ar->search_msg->dn),
4475 ldb_dn_get_linearized(msg->dn),
4476 ldb_errstring(ldb_module_get_ctx(ar->module)));
4480 ret = samdb_rodc(ldb_module_get_ctx(ar->module), &rodc);
4481 if (ret != LDB_SUCCESS) {
4482 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
4483 "Failed to determine if we are an RODC when attempting to form conflict DN: %s",
4484 ldb_errstring(ldb_module_get_ctx(ar->module)));
4485 return LDB_ERR_OPERATIONS_ERROR;
4488 * we have a conflict, and need to decide if we will keep the
4489 * new record or the old record
4492 conflict_dn = msg->dn;
4496 * We are on an RODC, or were a GC for this
4497 * partition, so we have to fail this until
4498 * someone who owns the partition sorts it
4501 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
4502 "Conflict adding object '%s' from incoming replication but we are read only for the partition. \n"
4503 " - We must fail the operation until a master for this partition resolves the conflict",
4504 ldb_dn_get_linearized(conflict_dn));
4509 * first we need the replPropertyMetaData attribute from the
4512 ret = dsdb_module_search_dn(ar->module, tmp_ctx, &res, conflict_dn,
4514 DSDB_FLAG_NEXT_MODULE |
4515 DSDB_SEARCH_SHOW_DELETED |
4516 DSDB_SEARCH_SHOW_RECYCLED, ar->req);
4517 if (ret != LDB_SUCCESS) {
4518 DEBUG(0,(__location__ ": Unable to find object for conflicting record '%s'\n",
4519 ldb_dn_get_linearized(conflict_dn)));
4523 omd_value = ldb_msg_find_ldb_val(res->msgs[0], "replPropertyMetaData");
4524 if (omd_value == NULL) {
4525 DEBUG(0,(__location__ ": Unable to find replPropertyMetaData for conflicting record '%s'\n",
4526 ldb_dn_get_linearized(conflict_dn)));
4530 ndr_err = ndr_pull_struct_blob(omd_value, res->msgs[0], &omd,
4531 (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
4532 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
4533 DEBUG(0,(__location__ ": Failed to parse old replPropertyMetaData for %s\n",
4534 ldb_dn_get_linearized(conflict_dn)));
4538 rmd = ar->objs->objects[ar->index_current].meta_data;
4541 * we decide which is newer based on the RPMD on the name
4542 * attribute. See [MS-DRSR] ResolveNameConflict.
4544 * We expect omd_name to be present, as this is from a local
4545 * search, but while rmd_name should have been given to us by
4546 * the remote server, if it is missing we just prefer the
4548 * replmd_replPropertyMetaData1_new_should_be_taken()
4550 rmd_name = replmd_replPropertyMetaData1_find_attid(rmd, DRSUAPI_ATTID_name);
4551 omd_name = replmd_replPropertyMetaData1_find_attid(&omd, DRSUAPI_ATTID_name);
4553 DEBUG(0,(__location__ ": Failed to find name attribute in local LDB replPropertyMetaData for %s\n",
4554 ldb_dn_get_linearized(conflict_dn)));
4559 * Should we preserve the current record, and so rename the
4560 * incoming record to be a conflict?
4562 rename_incoming_record =
4563 !replmd_replPropertyMetaData1_new_should_be_taken(
4564 ar->objs->dsdb_repl_flags & DSDB_REPL_FLAG_PRIORITISE_INCOMING,
4565 omd_name, rmd_name);
4567 if (rename_incoming_record) {
4569 new_dn = replmd_conflict_dn(msg, msg->dn,
4570 &ar->objs->objects[ar->index_current].object_guid);
4571 if (new_dn == NULL) {
4572 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
4573 "Failed to form conflict DN for %s\n",
4574 ldb_dn_get_linearized(msg->dn));
4576 return replmd_replicated_request_werror(ar, WERR_NOMEM);
4579 ret = dsdb_module_rename(ar->module, ar->search_msg->dn, new_dn,
4580 DSDB_FLAG_NEXT_MODULE, ar->req);
4581 if (ret != LDB_SUCCESS) {
4582 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
4583 "Failed to rename incoming conflicting dn '%s' (was '%s') to '%s' - %s\n",
4584 ldb_dn_get_linearized(conflict_dn),
4585 ldb_dn_get_linearized(ar->search_msg->dn),
4586 ldb_dn_get_linearized(new_dn),
4587 ldb_errstring(ldb_module_get_ctx(ar->module)));
4588 return replmd_replicated_request_werror(ar, WERR_DS_DRA_DB_ERROR);
4596 /* we are renaming the existing record */
4598 guid = samdb_result_guid(res->msgs[0], "objectGUID");
4599 if (GUID_all_zero(&guid)) {
4600 DEBUG(0,(__location__ ": Failed to find objectGUID for existing conflict record %s\n",
4601 ldb_dn_get_linearized(conflict_dn)));
4605 new_dn = replmd_conflict_dn(tmp_ctx, conflict_dn, &guid);
4606 if (new_dn == NULL) {
4607 DEBUG(0,(__location__ ": Failed to form conflict DN for %s\n",
4608 ldb_dn_get_linearized(conflict_dn)));
4612 DEBUG(2,(__location__ ": Resolving conflict record via existing-record rename '%s' -> '%s'\n",
4613 ldb_dn_get_linearized(conflict_dn), ldb_dn_get_linearized(new_dn)));
4615 ret = dsdb_module_rename(ar->module, conflict_dn, new_dn,
4616 DSDB_FLAG_OWN_MODULE, ar->req);
4617 if (ret != LDB_SUCCESS) {
4618 DEBUG(0,(__location__ ": Failed to rename conflict dn '%s' to '%s' - %s\n",
4619 ldb_dn_get_linearized(conflict_dn),
4620 ldb_dn_get_linearized(new_dn),
4621 ldb_errstring(ldb_module_get_ctx(ar->module))));
4626 * now we need to ensure that the rename is seen as an
4627 * originating update. We do that with a modify.
4629 ret = replmd_name_modify(ar, ar->req, new_dn);
4630 if (ret != LDB_SUCCESS) {
4634 DEBUG(2,(__location__ ": With conflicting record renamed, re-apply replicated rename '%s' -> '%s'\n",
4635 ldb_dn_get_linearized(ar->search_msg->dn),
4636 ldb_dn_get_linearized(msg->dn)));
4639 ret = dsdb_module_rename(ar->module, ar->search_msg->dn, msg->dn,
4640 DSDB_FLAG_NEXT_MODULE, ar->req);
4641 if (ret != LDB_SUCCESS) {
4642 DEBUG(0,(__location__ ": After conflict resolution, failed to rename dn '%s' to '%s' - %s\n",
4643 ldb_dn_get_linearized(ar->search_msg->dn),
4644 ldb_dn_get_linearized(msg->dn),
4645 ldb_errstring(ldb_module_get_ctx(ar->module))));
4651 * On failure make the caller get the error
4652 * This means replication will stop with an error,
4653 * but there is not much else we can do. In the
4654 * LDB_ERR_ENTRY_ALREADY_EXISTS case this is exactly what is
4658 talloc_free(tmp_ctx);
4663 static int replmd_replicated_apply_merge(struct replmd_replicated_request *ar)
4665 struct ldb_context *ldb;
4666 struct ldb_request *change_req;
4667 enum ndr_err_code ndr_err;
4668 struct ldb_message *msg;
4669 struct replPropertyMetaDataBlob *rmd;
4670 struct replPropertyMetaDataBlob omd;
4671 const struct ldb_val *omd_value;
4672 struct replPropertyMetaDataBlob nmd;
4673 struct ldb_val nmd_value;
4674 struct GUID remote_parent_guid;
4677 unsigned int removed_attrs = 0;
4679 int (*callback)(struct ldb_request *req, struct ldb_reply *ares) = replmd_op_callback;
4680 bool isDeleted = false;
4681 bool local_isDeleted = false;
4682 bool remote_isDeleted = false;
4683 bool take_remote_isDeleted = false;
4684 bool sd_updated = false;
4685 bool renamed = false;
4686 bool is_schema_nc = false;
4688 const struct ldb_val *old_rdn, *new_rdn;
4689 struct replmd_private *replmd_private =
4690 talloc_get_type(ldb_module_get_private(ar->module),
4691 struct replmd_private);
4693 time_t t = time(NULL);
4694 unix_to_nt_time(&now, t);
4696 ldb = ldb_module_get_ctx(ar->module);
4697 msg = ar->objs->objects[ar->index_current].msg;
4699 is_schema_nc = ldb_dn_compare_base(replmd_private->schema_dn, msg->dn) == 0;
4701 rmd = ar->objs->objects[ar->index_current].meta_data;
4705 /* find existing meta data */
4706 omd_value = ldb_msg_find_ldb_val(ar->search_msg, "replPropertyMetaData");
4708 ndr_err = ndr_pull_struct_blob(omd_value, ar, &omd,
4709 (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
4710 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
4711 nt_status = ndr_map_error2ntstatus(ndr_err);
4712 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
4715 if (omd.version != 1) {
4716 return replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
4721 struct GUID_txt_buf guid_txt;
4723 char *s = ldb_ldif_message_string(ldb, ar, LDB_CHANGETYPE_MODIFY, msg);
4724 DEBUG(5, ("Initial DRS replication modify message of %s is:\n%s\n"
4727 GUID_buf_string(&ar->objs->objects[ar->index_current].object_guid, &guid_txt),
4729 ndr_print_struct_string(s,
4730 (ndr_print_fn_t)ndr_print_replPropertyMetaDataBlob,
4731 "existing replPropertyMetaData",
4733 ndr_print_struct_string(s,
4734 (ndr_print_fn_t)ndr_print_replPropertyMetaDataBlob,
4735 "incoming replPropertyMetaData",
4740 local_isDeleted = ldb_msg_find_attr_as_bool(ar->search_msg,
4741 "isDeleted", false);
4742 remote_isDeleted = ldb_msg_find_attr_as_bool(msg,
4743 "isDeleted", false);
4746 * Fill in the remote_parent_guid with the GUID or an all-zero
4749 if (ar->objs->objects[ar->index_current].parent_guid != NULL) {
4750 remote_parent_guid = *ar->objs->objects[ar->index_current].parent_guid;
4752 remote_parent_guid = GUID_zero();
4756 * To ensure we follow a complex rename chain around, we have
4757 * to confirm that the DN is the same (mostly to confirm the
4758 * RDN) and the parentGUID is the same.
4760 * This ensures we keep things under the correct parent, which
4761 * replmd_replicated_handle_rename() will do.
4764 if (strcmp(ldb_dn_get_linearized(msg->dn), ldb_dn_get_linearized(ar->search_msg->dn)) == 0
4765 && GUID_equal(&remote_parent_guid, &ar->local_parent_guid)) {
4769 * handle renames, even just by case that come in over
4770 * DRS. Changes in the parent DN don't hit us here,
4771 * because the search for a parent will clean up those
4774 * We also have already filtered out the case where
4775 * the peer has an older name to what we have (see
4776 * replmd_replicated_apply_search_callback())
4778 ret = replmd_replicated_handle_rename(ar, msg, ar->req, &renamed);
4781 if (ret != LDB_SUCCESS) {
4782 ldb_debug(ldb, LDB_DEBUG_FATAL,
4783 "replmd_replicated_request rename %s => %s failed - %s\n",
4784 ldb_dn_get_linearized(ar->search_msg->dn),
4785 ldb_dn_get_linearized(msg->dn),
4786 ldb_errstring(ldb));
4787 return replmd_replicated_request_werror(ar, WERR_DS_DRA_DB_ERROR);
4790 if (renamed == true) {
4792 * Set the callback to one that will fix up the name
4793 * metadata on the new conflict DN
4795 callback = replmd_op_name_modify_callback;
4800 nmd.ctr.ctr1.count = omd.ctr.ctr1.count + rmd->ctr.ctr1.count;
4801 nmd.ctr.ctr1.array = talloc_array(ar,
4802 struct replPropertyMetaData1,
4803 nmd.ctr.ctr1.count);
4804 if (!nmd.ctr.ctr1.array) return replmd_replicated_request_werror(ar, WERR_NOMEM);
4806 /* first copy the old meta data */
4807 for (i=0; i < omd.ctr.ctr1.count; i++) {
4808 nmd.ctr.ctr1.array[ni] = omd.ctr.ctr1.array[i];
4813 /* now merge in the new meta data */
4814 for (i=0; i < rmd->ctr.ctr1.count; i++) {
4817 for (j=0; j < ni; j++) {
4820 if (rmd->ctr.ctr1.array[i].attid != nmd.ctr.ctr1.array[j].attid) {
4824 cmp = replmd_replPropertyMetaData1_new_should_be_taken(
4825 ar->objs->dsdb_repl_flags,
4826 &nmd.ctr.ctr1.array[j],
4827 &rmd->ctr.ctr1.array[i]);
4829 /* replace the entry */
4830 nmd.ctr.ctr1.array[j] = rmd->ctr.ctr1.array[i];
4831 if (ar->seq_num == 0) {
4832 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &ar->seq_num);
4833 if (ret != LDB_SUCCESS) {
4834 return replmd_replicated_request_error(ar, ret);
4837 nmd.ctr.ctr1.array[j].local_usn = ar->seq_num;
4838 switch (nmd.ctr.ctr1.array[j].attid) {
4839 case DRSUAPI_ATTID_ntSecurityDescriptor:
4842 case DRSUAPI_ATTID_isDeleted:
4843 take_remote_isDeleted = true;
4852 if (rmd->ctr.ctr1.array[i].attid != DRSUAPI_ATTID_instanceType) {
4853 DEBUG(3,("Discarding older DRS attribute update to %s on %s from %s\n",
4854 msg->elements[i-removed_attrs].name,
4855 ldb_dn_get_linearized(msg->dn),
4856 GUID_string(ar, &rmd->ctr.ctr1.array[i].originating_invocation_id)));
4859 /* we don't want to apply this change so remove the attribute */
4860 ldb_msg_remove_element(msg, &msg->elements[i-removed_attrs]);
4867 if (found) continue;
4869 nmd.ctr.ctr1.array[ni] = rmd->ctr.ctr1.array[i];
4870 if (ar->seq_num == 0) {
4871 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &ar->seq_num);
4872 if (ret != LDB_SUCCESS) {
4873 return replmd_replicated_request_error(ar, ret);
4876 nmd.ctr.ctr1.array[ni].local_usn = ar->seq_num;
4877 switch (nmd.ctr.ctr1.array[ni].attid) {
4878 case DRSUAPI_ATTID_ntSecurityDescriptor:
4881 case DRSUAPI_ATTID_isDeleted:
4882 take_remote_isDeleted = true;
4891 * finally correct the size of the meta_data array
4893 nmd.ctr.ctr1.count = ni;
4895 new_rdn = ldb_dn_get_rdn_val(msg->dn);
4896 old_rdn = ldb_dn_get_rdn_val(ar->search_msg->dn);
4899 ret = replmd_update_rpmd_rdn_attr(ldb, msg, new_rdn, old_rdn,
4900 &nmd, ar, now, is_schema_nc);
4901 if (ret != LDB_SUCCESS) {
4902 ldb_asprintf_errstring(ldb, "%s: error during DRS repl merge: %s", __func__, ldb_errstring(ldb));
4903 return replmd_replicated_request_error(ar, ret);
4907 * sort the new meta data array
4909 ret = replmd_replPropertyMetaDataCtr1_sort_and_verify(ldb, &nmd.ctr.ctr1, msg->dn);
4910 if (ret != LDB_SUCCESS) {
4911 ldb_asprintf_errstring(ldb, "%s: error during DRS repl merge: %s", __func__, ldb_errstring(ldb));
4916 * Work out if this object is deleted, so we can prune any extra attributes. See MS-DRSR 4.1.10.6.9
4919 * This also controls SD propagation below
4921 if (take_remote_isDeleted) {
4922 isDeleted = remote_isDeleted;
4924 isDeleted = local_isDeleted;
4927 ar->isDeleted = isDeleted;
4930 * check if some replicated attributes left, otherwise skip the ldb_modify() call
4932 if (msg->num_elements == 0) {
4933 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_replicated_apply_merge[%u]: skip replace\n",
4936 return replmd_replicated_apply_isDeleted(ar);
4939 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_replicated_apply_merge[%u]: replace %u attributes\n",
4940 ar->index_current, msg->num_elements);
4946 if (sd_updated && !isDeleted) {
4947 ret = dsdb_module_schedule_sd_propagation(ar->module,
4948 ar->objs->partition_dn,
4950 if (ret != LDB_SUCCESS) {
4951 return ldb_operr(ldb);
4955 /* create the meta data value */
4956 ndr_err = ndr_push_struct_blob(&nmd_value, msg, &nmd,
4957 (ndr_push_flags_fn_t)ndr_push_replPropertyMetaDataBlob);
4958 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
4959 nt_status = ndr_map_error2ntstatus(ndr_err);
4960 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
4964 * when we know that we'll modify the record, add the whenChanged, uSNChanged
4965 * and replPopertyMetaData attributes
4967 ret = ldb_msg_add_string(msg, "whenChanged", ar->objs->objects[ar->index_current].when_changed);
4968 if (ret != LDB_SUCCESS) {
4969 return replmd_replicated_request_error(ar, ret);
4971 ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNChanged", ar->seq_num);
4972 if (ret != LDB_SUCCESS) {
4973 return replmd_replicated_request_error(ar, ret);
4975 ret = ldb_msg_add_value(msg, "replPropertyMetaData", &nmd_value, NULL);
4976 if (ret != LDB_SUCCESS) {
4977 return replmd_replicated_request_error(ar, ret);
4980 replmd_ldb_message_sort(msg, ar->schema);
4982 /* we want to replace the old values */
4983 for (i=0; i < msg->num_elements; i++) {
4984 msg->elements[i].flags = LDB_FLAG_MOD_REPLACE;
4985 if (ldb_attr_cmp(msg->elements[i].name, "objectClass") == 0) {
4986 if (msg->elements[i].num_values == 0) {
4987 ldb_asprintf_errstring(ldb, __location__
4988 ": objectClass removed on %s, aborting replication\n",
4989 ldb_dn_get_linearized(msg->dn));
4990 return replmd_replicated_request_error(ar, LDB_ERR_OBJECT_CLASS_VIOLATION);
4996 struct GUID_txt_buf guid_txt;
4998 char *s = ldb_ldif_message_string(ldb, ar, LDB_CHANGETYPE_MODIFY, msg);
4999 DEBUG(4, ("Final DRS replication modify message of %s:\n%s\n",
5000 GUID_buf_string(&ar->objs->objects[ar->index_current].object_guid, &guid_txt),
5005 ret = ldb_build_mod_req(&change_req,
5013 LDB_REQ_SET_LOCATION(change_req);
5014 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
5016 /* current partition control needed by "repmd_op_callback" */
5017 ret = ldb_request_add_control(change_req,
5018 DSDB_CONTROL_CURRENT_PARTITION_OID,
5020 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
5022 return ldb_next_request(ar->module, change_req);
5025 static int replmd_replicated_apply_search_callback(struct ldb_request *req,
5026 struct ldb_reply *ares)
5028 struct replmd_replicated_request *ar = talloc_get_type(req->context,
5029 struct replmd_replicated_request);
5033 return ldb_module_done(ar->req, NULL, NULL,
5034 LDB_ERR_OPERATIONS_ERROR);
5036 if (ares->error != LDB_SUCCESS &&
5037 ares->error != LDB_ERR_NO_SUCH_OBJECT) {
5038 return ldb_module_done(ar->req, ares->controls,
5039 ares->response, ares->error);
5042 switch (ares->type) {
5043 case LDB_REPLY_ENTRY:
5044 ar->search_msg = talloc_steal(ar, ares->message);
5047 case LDB_REPLY_REFERRAL:
5048 /* we ignore referrals */
5051 case LDB_REPLY_DONE:
5053 struct replPropertyMetaData1 *md_remote;
5054 struct replPropertyMetaData1 *md_local;
5056 struct replPropertyMetaDataBlob omd;
5057 const struct ldb_val *omd_value;
5058 struct replPropertyMetaDataBlob *rmd;
5059 struct ldb_message *msg;
5061 ar->objs->objects[ar->index_current].local_parent_dn = NULL;
5062 ar->objs->objects[ar->index_current].last_known_parent = NULL;
5065 * This is the ADD case, find the appropriate parent,
5066 * as this object doesn't exist locally:
5068 if (ar->search_msg == NULL) {
5069 ret = replmd_replicated_apply_search_for_parent(ar);
5070 if (ret != LDB_SUCCESS) {
5071 return ldb_module_done(ar->req, NULL, NULL, ret);
5078 * Otherwise, in the MERGE case, work out if we are
5079 * attempting a rename, and if so find the parent the
5080 * newly renamed object wants to belong under (which
5081 * may not be the parent in it's attached string DN
5083 rmd = ar->objs->objects[ar->index_current].meta_data;
5087 /* find existing meta data */
5088 omd_value = ldb_msg_find_ldb_val(ar->search_msg, "replPropertyMetaData");
5090 enum ndr_err_code ndr_err;
5091 ndr_err = ndr_pull_struct_blob(omd_value, ar, &omd,
5092 (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
5093 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
5094 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
5095 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
5098 if (omd.version != 1) {
5099 return replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
5103 ar->local_parent_guid = samdb_result_guid(ar->search_msg, "parentGUID");
5105 instanceType = ldb_msg_find_attr_as_int(ar->search_msg, "instanceType", 0);
5106 if (((instanceType & INSTANCE_TYPE_IS_NC_HEAD) == 0)
5107 && GUID_all_zero(&ar->local_parent_guid)) {
5108 DEBUG(0, ("Refusing to replicate new version of %s "
5109 "as local object has an all-zero parentGUID attribute, "
5110 "despite not being an NC root\n",
5111 ldb_dn_get_linearized(ar->search_msg->dn)));
5112 return replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
5116 * now we need to check for double renames. We could have a
5117 * local rename pending which our replication partner hasn't
5118 * received yet. We choose which one wins by looking at the
5119 * attribute stamps on the two objects, the newer one wins.
5121 * This also simply applies the correct algorithms for
5122 * determining if a change was made to name at all, or
5123 * if the object has just been renamed under the same
5126 md_remote = replmd_replPropertyMetaData1_find_attid(rmd, DRSUAPI_ATTID_name);
5127 md_local = replmd_replPropertyMetaData1_find_attid(&omd, DRSUAPI_ATTID_name);
5129 DEBUG(0,(__location__ ": Failed to find name attribute in local LDB replPropertyMetaData for %s\n",
5130 ldb_dn_get_linearized(ar->search_msg->dn)));
5131 return replmd_replicated_request_werror(ar, WERR_DS_DRA_DB_ERROR);
5135 * if there is no name attribute given then we have to assume the
5136 * object we've received has the older name
5138 if (replmd_replPropertyMetaData1_new_should_be_taken(
5139 ar->objs->dsdb_repl_flags & DSDB_REPL_FLAG_PRIORITISE_INCOMING,
5140 md_local, md_remote)) {
5141 struct GUID_txt_buf p_guid_local;
5142 struct GUID_txt_buf p_guid_remote;
5143 msg = ar->objs->objects[ar->index_current].msg;
5145 /* Merge on the existing object, with rename */
5147 DEBUG(4,(__location__ ": Looking for new parent for object %s currently under %s "
5148 "as incoming object changing to %s under %s\n",
5149 ldb_dn_get_linearized(ar->search_msg->dn),
5150 GUID_buf_string(&ar->local_parent_guid, &p_guid_local),
5151 ldb_dn_get_linearized(msg->dn),
5152 GUID_buf_string(ar->objs->objects[ar->index_current].parent_guid,
5154 ret = replmd_replicated_apply_search_for_parent(ar);
5156 struct GUID_txt_buf p_guid_local;
5157 struct GUID_txt_buf p_guid_remote;
5158 msg = ar->objs->objects[ar->index_current].msg;
5161 * Merge on the existing object, force no
5162 * rename (code below just to explain why in
5166 if (strcmp(ldb_dn_get_linearized(ar->search_msg->dn),
5167 ldb_dn_get_linearized(msg->dn)) == 0) {
5168 if (ar->objs->objects[ar->index_current].parent_guid != NULL &&
5169 GUID_equal(&ar->local_parent_guid,
5170 ar->objs->objects[ar->index_current].parent_guid)
5172 DEBUG(4,(__location__ ": Keeping object %s at under %s "
5173 "despite incoming object changing parent to %s\n",
5174 ldb_dn_get_linearized(ar->search_msg->dn),
5175 GUID_buf_string(&ar->local_parent_guid, &p_guid_local),
5176 GUID_buf_string(ar->objs->objects[ar->index_current].parent_guid,
5180 DEBUG(4,(__location__ ": Keeping object %s at under %s "
5181 " and rejecting older rename to %s under %s\n",
5182 ldb_dn_get_linearized(ar->search_msg->dn),
5183 GUID_buf_string(&ar->local_parent_guid, &p_guid_local),
5184 ldb_dn_get_linearized(msg->dn),
5185 GUID_buf_string(ar->objs->objects[ar->index_current].parent_guid,
5189 * This assignment ensures that the strcmp()
5190 * and GUID_equal() calls in
5191 * replmd_replicated_apply_merge() avoids the
5194 ar->objs->objects[ar->index_current].parent_guid =
5195 &ar->local_parent_guid;
5197 msg->dn = ar->search_msg->dn;
5198 ret = replmd_replicated_apply_merge(ar);
5200 if (ret != LDB_SUCCESS) {
5201 return ldb_module_done(ar->req, NULL, NULL, ret);
5210 static int replmd_replicated_uptodate_vector(struct replmd_replicated_request *ar);
5212 static int replmd_replicated_apply_next(struct replmd_replicated_request *ar)
5214 struct ldb_context *ldb;
5218 struct ldb_request *search_req;
5219 static const char *attrs[] = { "*", "parentGUID", "instanceType",
5220 "replPropertyMetaData", "nTSecurityDescriptor",
5222 struct GUID_txt_buf guid_str_buf;
5224 if (ar->index_current >= ar->objs->num_objects) {
5225 /* done with it, go to next stage */
5226 return replmd_replicated_uptodate_vector(ar);
5229 ldb = ldb_module_get_ctx(ar->module);
5230 ar->search_msg = NULL;
5231 ar->isDeleted = false;
5233 tmp_str = GUID_buf_string(&ar->objs->objects[ar->index_current].object_guid,
5236 filter = talloc_asprintf(ar, "(objectGUID=%s)", tmp_str);
5237 if (!filter) return replmd_replicated_request_werror(ar, WERR_NOMEM);
5239 ret = ldb_build_search_req(&search_req,
5242 ar->objs->partition_dn,
5248 replmd_replicated_apply_search_callback,
5250 LDB_REQ_SET_LOCATION(search_req);
5252 ret = dsdb_request_add_controls(search_req, DSDB_SEARCH_SHOW_RECYCLED);
5254 if (ret != LDB_SUCCESS) {
5258 return ldb_next_request(ar->module, search_req);
5262 * This is essentially a wrapper for replmd_replicated_apply_next()
5264 * This is needed to ensure that both codepaths call this handler.
5266 static int replmd_replicated_apply_isDeleted(struct replmd_replicated_request *ar)
5268 struct ldb_dn *deleted_objects_dn;
5269 struct ldb_message *msg = ar->objs->objects[ar->index_current].msg;
5270 int ret = dsdb_get_deleted_objects_dn(ldb_module_get_ctx(ar->module), msg, msg->dn,
5271 &deleted_objects_dn);
5272 if (ar->isDeleted && (ret != LDB_SUCCESS || ldb_dn_compare(msg->dn, deleted_objects_dn) != 0)) {
5274 * Do a delete here again, so that if there is
5275 * anything local that conflicts with this
5276 * object being deleted, it is removed. This
5277 * includes links. See MS-DRSR 4.1.10.6.9
5280 * If the object is already deleted, and there
5281 * is no more work required, it doesn't do
5285 /* This has been updated to point to the DN we eventually did the modify on */
5287 struct ldb_request *del_req;
5288 struct ldb_result *res;
5290 TALLOC_CTX *tmp_ctx = talloc_new(ar);
5292 ret = ldb_oom(ldb_module_get_ctx(ar->module));
5296 res = talloc_zero(tmp_ctx, struct ldb_result);
5298 ret = ldb_oom(ldb_module_get_ctx(ar->module));
5299 talloc_free(tmp_ctx);
5303 /* Build a delete request, which hopefully will artually turn into nothing */
5304 ret = ldb_build_del_req(&del_req, ldb_module_get_ctx(ar->module), tmp_ctx,
5308 ldb_modify_default_callback,
5310 LDB_REQ_SET_LOCATION(del_req);
5311 if (ret != LDB_SUCCESS) {
5312 talloc_free(tmp_ctx);
5317 * This is the guts of the call, call back
5318 * into our delete code, but setting the
5319 * re_delete flag so we delete anything that
5320 * shouldn't be there on a deleted or recycled
5323 ret = replmd_delete_internals(ar->module, del_req, true);
5324 if (ret == LDB_SUCCESS) {
5325 ret = ldb_wait(del_req->handle, LDB_WAIT_ALL);
5328 talloc_free(tmp_ctx);
5329 if (ret != LDB_SUCCESS) {
5334 ar->index_current++;
5335 return replmd_replicated_apply_next(ar);
5338 static int replmd_replicated_uptodate_modify_callback(struct ldb_request *req,
5339 struct ldb_reply *ares)
5341 struct ldb_context *ldb;
5342 struct replmd_replicated_request *ar = talloc_get_type(req->context,
5343 struct replmd_replicated_request);
5344 ldb = ldb_module_get_ctx(ar->module);
5347 return ldb_module_done(ar->req, NULL, NULL,
5348 LDB_ERR_OPERATIONS_ERROR);
5350 if (ares->error != LDB_SUCCESS) {
5351 return ldb_module_done(ar->req, ares->controls,
5352 ares->response, ares->error);
5355 if (ares->type != LDB_REPLY_DONE) {
5356 ldb_asprintf_errstring(ldb, "Invalid LDB reply type %d", ares->type);
5357 return ldb_module_done(ar->req, NULL, NULL,
5358 LDB_ERR_OPERATIONS_ERROR);
5363 return ldb_module_done(ar->req, NULL, NULL, LDB_SUCCESS);
5366 static int replmd_replicated_uptodate_modify(struct replmd_replicated_request *ar)
5368 struct ldb_context *ldb;
5369 struct ldb_request *change_req;
5370 enum ndr_err_code ndr_err;
5371 struct ldb_message *msg;
5372 struct replUpToDateVectorBlob ouv;
5373 const struct ldb_val *ouv_value;
5374 const struct drsuapi_DsReplicaCursor2CtrEx *ruv;
5375 struct replUpToDateVectorBlob nuv;
5376 struct ldb_val nuv_value;
5377 struct ldb_message_element *nuv_el = NULL;
5378 struct ldb_message_element *orf_el = NULL;
5379 struct repsFromToBlob nrf;
5380 struct ldb_val *nrf_value = NULL;
5381 struct ldb_message_element *nrf_el = NULL;
5385 time_t t = time(NULL);
5388 uint32_t instanceType;
5390 ldb = ldb_module_get_ctx(ar->module);
5391 ruv = ar->objs->uptodateness_vector;
5397 unix_to_nt_time(&now, t);
5399 if (ar->search_msg == NULL) {
5400 /* this happens for a REPL_OBJ call where we are
5401 creating the target object by replicating it. The
5402 subdomain join code does this for the partition DN
5404 DEBUG(4,(__location__ ": Skipping UDV and repsFrom update as no target DN\n"));
5405 return ldb_module_done(ar->req, NULL, NULL, LDB_SUCCESS);
5408 instanceType = ldb_msg_find_attr_as_uint(ar->search_msg, "instanceType", 0);
5409 if (! (instanceType & INSTANCE_TYPE_IS_NC_HEAD)) {
5410 DEBUG(4,(__location__ ": Skipping UDV and repsFrom update as not NC root: %s\n",
5411 ldb_dn_get_linearized(ar->search_msg->dn)));
5412 return ldb_module_done(ar->req, NULL, NULL, LDB_SUCCESS);
5416 * first create the new replUpToDateVector
5418 ouv_value = ldb_msg_find_ldb_val(ar->search_msg, "replUpToDateVector");
5420 ndr_err = ndr_pull_struct_blob(ouv_value, ar, &ouv,
5421 (ndr_pull_flags_fn_t)ndr_pull_replUpToDateVectorBlob);
5422 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
5423 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
5424 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
5427 if (ouv.version != 2) {
5428 return replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
5433 * the new uptodateness vector will at least
5434 * contain 1 entry, one for the source_dsa
5436 * plus optional values from our old vector and the one from the source_dsa
5438 nuv.ctr.ctr2.count = ouv.ctr.ctr2.count;
5439 if (ruv) nuv.ctr.ctr2.count += ruv->count;
5440 nuv.ctr.ctr2.cursors = talloc_array(ar,
5441 struct drsuapi_DsReplicaCursor2,
5442 nuv.ctr.ctr2.count);
5443 if (!nuv.ctr.ctr2.cursors) return replmd_replicated_request_werror(ar, WERR_NOMEM);
5445 /* first copy the old vector */
5446 for (i=0; i < ouv.ctr.ctr2.count; i++) {
5447 nuv.ctr.ctr2.cursors[ni] = ouv.ctr.ctr2.cursors[i];
5451 /* merge in the source_dsa vector is available */
5452 for (i=0; (ruv && i < ruv->count); i++) {
5455 if (GUID_equal(&ruv->cursors[i].source_dsa_invocation_id,
5456 &ar->our_invocation_id)) {
5460 for (j=0; j < ni; j++) {
5461 if (!GUID_equal(&ruv->cursors[i].source_dsa_invocation_id,
5462 &nuv.ctr.ctr2.cursors[j].source_dsa_invocation_id)) {
5468 if (ruv->cursors[i].highest_usn > nuv.ctr.ctr2.cursors[j].highest_usn) {
5469 nuv.ctr.ctr2.cursors[j] = ruv->cursors[i];
5474 if (found) continue;
5476 /* if it's not there yet, add it */
5477 nuv.ctr.ctr2.cursors[ni] = ruv->cursors[i];
5482 * finally correct the size of the cursors array
5484 nuv.ctr.ctr2.count = ni;
5489 TYPESAFE_QSORT(nuv.ctr.ctr2.cursors, nuv.ctr.ctr2.count, drsuapi_DsReplicaCursor2_compare);
5492 * create the change ldb_message
5494 msg = ldb_msg_new(ar);
5495 if (!msg) return replmd_replicated_request_werror(ar, WERR_NOMEM);
5496 msg->dn = ar->search_msg->dn;
5498 ndr_err = ndr_push_struct_blob(&nuv_value, msg, &nuv,
5499 (ndr_push_flags_fn_t)ndr_push_replUpToDateVectorBlob);
5500 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
5501 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
5502 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
5504 ret = ldb_msg_add_value(msg, "replUpToDateVector", &nuv_value, &nuv_el);
5505 if (ret != LDB_SUCCESS) {
5506 return replmd_replicated_request_error(ar, ret);
5508 nuv_el->flags = LDB_FLAG_MOD_REPLACE;
5511 * now create the new repsFrom value from the given repsFromTo1 structure
5515 nrf.ctr.ctr1 = *ar->objs->source_dsa;
5516 nrf.ctr.ctr1.last_attempt = now;
5517 nrf.ctr.ctr1.last_success = now;
5518 nrf.ctr.ctr1.result_last_attempt = WERR_OK;
5521 * first see if we already have a repsFrom value for the current source dsa
5522 * if so we'll later replace this value
5524 orf_el = ldb_msg_find_element(ar->search_msg, "repsFrom");
5526 for (i=0; i < orf_el->num_values; i++) {
5527 struct repsFromToBlob *trf;
5529 trf = talloc(ar, struct repsFromToBlob);
5530 if (!trf) return replmd_replicated_request_werror(ar, WERR_NOMEM);
5532 ndr_err = ndr_pull_struct_blob(&orf_el->values[i], trf, trf,
5533 (ndr_pull_flags_fn_t)ndr_pull_repsFromToBlob);
5534 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
5535 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
5536 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
5539 if (trf->version != 1) {
5540 return replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
5544 * we compare the source dsa objectGUID not the invocation_id
5545 * because we want only one repsFrom value per source dsa
5546 * and when the invocation_id of the source dsa has changed we don't need
5547 * the old repsFrom with the old invocation_id
5549 if (!GUID_equal(&trf->ctr.ctr1.source_dsa_obj_guid,
5550 &ar->objs->source_dsa->source_dsa_obj_guid)) {
5556 nrf_value = &orf_el->values[i];
5561 * copy over all old values to the new ldb_message
5563 ret = ldb_msg_add_empty(msg, "repsFrom", 0, &nrf_el);
5564 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
5569 * if we haven't found an old repsFrom value for the current source dsa
5570 * we'll add a new value
5573 struct ldb_val zero_value;
5574 ZERO_STRUCT(zero_value);
5575 ret = ldb_msg_add_value(msg, "repsFrom", &zero_value, &nrf_el);
5576 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
5578 nrf_value = &nrf_el->values[nrf_el->num_values - 1];
5581 /* we now fill the value which is already attached to ldb_message */
5582 ndr_err = ndr_push_struct_blob(nrf_value, msg,
5584 (ndr_push_flags_fn_t)ndr_push_repsFromToBlob);
5585 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
5586 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
5587 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
5591 * the ldb_message_element for the attribute, has all the old values and the new one
5592 * so we'll replace the whole attribute with all values
5594 nrf_el->flags = LDB_FLAG_MOD_REPLACE;
5596 if (CHECK_DEBUGLVL(4)) {
5597 char *s = ldb_ldif_message_string(ldb, ar, LDB_CHANGETYPE_MODIFY, msg);
5598 DEBUG(4, ("DRS replication uptodate modify message:\n%s\n", s));
5602 /* prepare the ldb_modify() request */
5603 ret = ldb_build_mod_req(&change_req,
5609 replmd_replicated_uptodate_modify_callback,
5611 LDB_REQ_SET_LOCATION(change_req);
5612 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
5614 return ldb_next_request(ar->module, change_req);
5617 static int replmd_replicated_uptodate_search_callback(struct ldb_request *req,
5618 struct ldb_reply *ares)
5620 struct replmd_replicated_request *ar = talloc_get_type(req->context,
5621 struct replmd_replicated_request);
5625 return ldb_module_done(ar->req, NULL, NULL,
5626 LDB_ERR_OPERATIONS_ERROR);
5628 if (ares->error != LDB_SUCCESS &&
5629 ares->error != LDB_ERR_NO_SUCH_OBJECT) {
5630 return ldb_module_done(ar->req, ares->controls,
5631 ares->response, ares->error);
5634 switch (ares->type) {
5635 case LDB_REPLY_ENTRY:
5636 ar->search_msg = talloc_steal(ar, ares->message);
5639 case LDB_REPLY_REFERRAL:
5640 /* we ignore referrals */
5643 case LDB_REPLY_DONE:
5644 ret = replmd_replicated_uptodate_modify(ar);
5645 if (ret != LDB_SUCCESS) {
5646 return ldb_module_done(ar->req, NULL, NULL, ret);
5655 static int replmd_replicated_uptodate_vector(struct replmd_replicated_request *ar)
5657 struct ldb_context *ldb;
5659 static const char *attrs[] = {
5660 "replUpToDateVector",
5665 struct ldb_request *search_req;
5667 ldb = ldb_module_get_ctx(ar->module);
5668 ar->search_msg = NULL;
5670 ret = ldb_build_search_req(&search_req,
5673 ar->objs->partition_dn,
5679 replmd_replicated_uptodate_search_callback,
5681 LDB_REQ_SET_LOCATION(search_req);
5682 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
5684 return ldb_next_request(ar->module, search_req);
5689 static int replmd_extended_replicated_objects(struct ldb_module *module, struct ldb_request *req)
5691 struct ldb_context *ldb;
5692 struct dsdb_extended_replicated_objects *objs;
5693 struct replmd_replicated_request *ar;
5694 struct ldb_control **ctrls;
5697 struct replmd_private *replmd_private =
5698 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
5699 struct dsdb_control_replicated_update *rep_update;
5701 ldb = ldb_module_get_ctx(module);
5703 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_extended_replicated_objects\n");
5705 objs = talloc_get_type(req->op.extended.data, struct dsdb_extended_replicated_objects);
5707 ldb_debug(ldb, LDB_DEBUG_FATAL, "replmd_extended_replicated_objects: invalid extended data\n");
5708 return LDB_ERR_PROTOCOL_ERROR;
5711 if (objs->version != DSDB_EXTENDED_REPLICATED_OBJECTS_VERSION) {
5712 ldb_debug(ldb, LDB_DEBUG_FATAL, "replmd_extended_replicated_objects: extended data invalid version [%u != %u]\n",
5713 objs->version, DSDB_EXTENDED_REPLICATED_OBJECTS_VERSION);
5714 return LDB_ERR_PROTOCOL_ERROR;
5717 ar = replmd_ctx_init(module, req);
5719 return LDB_ERR_OPERATIONS_ERROR;
5721 /* Set the flags to have the replmd_op_callback run over the full set of objects */
5722 ar->apply_mode = true;
5724 ar->schema = dsdb_get_schema(ldb, ar);
5726 ldb_debug_set(ldb, LDB_DEBUG_FATAL, "replmd_ctx_init: no loaded schema found\n");
5728 DEBUG(0,(__location__ ": %s\n", ldb_errstring(ldb)));
5729 return LDB_ERR_CONSTRAINT_VIOLATION;
5732 ctrls = req->controls;
5734 if (req->controls) {
5735 req->controls = talloc_memdup(ar, req->controls,
5736 talloc_get_size(req->controls));
5737 if (!req->controls) return replmd_replicated_request_werror(ar, WERR_NOMEM);
5740 /* This allows layers further down to know if a change came in
5741 over replication and what the replication flags were */
5742 rep_update = talloc_zero(ar, struct dsdb_control_replicated_update);
5743 if (rep_update == NULL) {
5744 return ldb_module_oom(module);
5746 rep_update->dsdb_repl_flags = objs->dsdb_repl_flags;
5748 ret = ldb_request_add_control(req, DSDB_CONTROL_REPLICATED_UPDATE_OID, false, rep_update);
5749 if (ret != LDB_SUCCESS) {
5753 /* If this change contained linked attributes in the body
5754 * (rather than in the links section) we need to update
5755 * backlinks in linked_attributes */
5756 ret = ldb_request_add_control(req, DSDB_CONTROL_APPLY_LINKS, false, NULL);
5757 if (ret != LDB_SUCCESS) {
5761 ar->controls = req->controls;
5762 req->controls = ctrls;
5764 DEBUG(4,("linked_attributes_count=%u\n", objs->linked_attributes_count));
5766 /* save away the linked attributes for the end of the
5768 for (i=0; i<ar->objs->linked_attributes_count; i++) {
5769 struct la_entry *la_entry;
5771 if (replmd_private->la_ctx == NULL) {
5772 replmd_private->la_ctx = talloc_new(replmd_private);
5774 la_entry = talloc(replmd_private->la_ctx, struct la_entry);
5775 if (la_entry == NULL) {
5777 return LDB_ERR_OPERATIONS_ERROR;
5779 la_entry->la = talloc(la_entry, struct drsuapi_DsReplicaLinkedAttribute);
5780 if (la_entry->la == NULL) {
5781 talloc_free(la_entry);
5783 return LDB_ERR_OPERATIONS_ERROR;
5785 *la_entry->la = ar->objs->linked_attributes[i];
5787 /* we need to steal the non-scalars so they stay
5788 around until the end of the transaction */
5789 talloc_steal(la_entry->la, la_entry->la->identifier);
5790 talloc_steal(la_entry->la, la_entry->la->value.blob);
5792 DLIST_ADD(replmd_private->la_list, la_entry);
5795 return replmd_replicated_apply_next(ar);
5799 process one linked attribute structure
5801 static int replmd_process_linked_attribute(struct ldb_module *module,
5802 struct la_entry *la_entry,
5803 struct ldb_request *parent)
5805 struct drsuapi_DsReplicaLinkedAttribute *la = la_entry->la;
5806 struct ldb_context *ldb = ldb_module_get_ctx(module);
5807 struct ldb_message *msg;
5808 struct ldb_message *target_msg = NULL;
5809 TALLOC_CTX *tmp_ctx = talloc_new(la_entry);
5810 const struct dsdb_schema *schema = dsdb_get_schema(ldb, tmp_ctx);
5812 const struct dsdb_attribute *attr;
5813 struct dsdb_dn *dsdb_dn;
5814 uint64_t seq_num = 0;
5815 struct ldb_message_element *old_el;
5817 time_t t = time(NULL);
5818 struct ldb_result *res;
5819 struct ldb_result *target_res;
5820 const char *attrs[4];
5821 const char *attrs2[] = { "isDeleted", "isRecycled", NULL };
5822 struct parsed_dn *pdn_list, *pdn;
5823 struct GUID guid = GUID_zero();
5825 bool active = (la->flags & DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE)?true:false;
5826 const struct GUID *our_invocation_id;
5828 enum deletion_state deletion_state = OBJECT_NOT_DELETED;
5829 enum deletion_state target_deletion_state = OBJECT_NOT_DELETED;
5832 linked_attributes[0]:
5833 &objs->linked_attributes[i]: struct drsuapi_DsReplicaLinkedAttribute
5835 identifier: struct drsuapi_DsReplicaObjectIdentifier
5836 __ndr_size : 0x0000003a (58)
5837 __ndr_size_sid : 0x00000000 (0)
5838 guid : 8e95b6a9-13dd-4158-89db-3220a5be5cc7
5840 __ndr_size_dn : 0x00000000 (0)
5842 attid : DRSUAPI_ATTID_member (0x1F)
5843 value: struct drsuapi_DsAttributeValue
5844 __ndr_size : 0x0000007e (126)
5846 blob : DATA_BLOB length=126
5847 flags : 0x00000001 (1)
5848 1: DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE
5849 originating_add_time : Wed Sep 2 22:20:01 2009 EST
5850 meta_data: struct drsuapi_DsReplicaMetaData
5851 version : 0x00000015 (21)
5852 originating_change_time : Wed Sep 2 23:39:07 2009 EST
5853 originating_invocation_id: 794640f3-18cf-40ee-a211-a93992b67a64
5854 originating_usn : 0x000000000001e19c (123292)
5856 (for cases where the link is to a normal DN)
5857 &target: struct drsuapi_DsReplicaObjectIdentifier3
5858 __ndr_size : 0x0000007e (126)
5859 __ndr_size_sid : 0x0000001c (28)
5860 guid : 7639e594-db75-4086-b0d4-67890ae46031
5861 sid : S-1-5-21-2848215498-2472035911-1947525656-19924
5862 __ndr_size_dn : 0x00000022 (34)
5863 dn : 'CN=UOne,OU=TestOU,DC=vsofs8,DC=com'
5866 /* find the attribute being modified */
5867 attr = dsdb_attribute_by_attributeID_id(schema, la->attid);
5869 DEBUG(0, (__location__ ": Unable to find attributeID 0x%x\n", la->attid));
5870 talloc_free(tmp_ctx);
5871 return LDB_ERR_OPERATIONS_ERROR;
5874 attrs[0] = attr->lDAPDisplayName;
5875 attrs[1] = "isDeleted";
5876 attrs[2] = "isRecycled";
5879 /* get the existing message from the db for the object with
5880 this GUID, returning attribute being modified. We will then
5881 use this msg as the basis for a modify call */
5882 ret = dsdb_module_search(module, tmp_ctx, &res, NULL, LDB_SCOPE_SUBTREE, attrs,
5883 DSDB_FLAG_NEXT_MODULE |
5884 DSDB_SEARCH_SEARCH_ALL_PARTITIONS |
5885 DSDB_SEARCH_SHOW_RECYCLED |
5886 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT |
5887 DSDB_SEARCH_REVEAL_INTERNALS,
5889 "objectGUID=%s", GUID_string(tmp_ctx, &la->identifier->guid));
5890 if (ret != LDB_SUCCESS) {
5891 talloc_free(tmp_ctx);
5894 if (res->count != 1) {
5895 ldb_asprintf_errstring(ldb, "DRS linked attribute for GUID %s - DN not found",
5896 GUID_string(tmp_ctx, &la->identifier->guid));
5897 talloc_free(tmp_ctx);
5898 return LDB_ERR_NO_SUCH_OBJECT;
5903 * Check for deleted objects per MS-DRSR 4.1.10.6.13
5904 * ProcessLinkValue, because link updates are not applied to
5905 * recycled and tombstone objects. We don't have to delete
5906 * any existing link, that should have happened when the
5907 * object deletion was replicated or initiated.
5910 replmd_deletion_state(module, msg, &deletion_state, NULL);
5912 if (deletion_state >= OBJECT_RECYCLED) {
5913 talloc_free(tmp_ctx);
5917 old_el = ldb_msg_find_element(msg, attr->lDAPDisplayName);
5918 if (old_el == NULL) {
5919 ret = ldb_msg_add_empty(msg, attr->lDAPDisplayName, LDB_FLAG_MOD_REPLACE, &old_el);
5920 if (ret != LDB_SUCCESS) {
5921 ldb_module_oom(module);
5922 talloc_free(tmp_ctx);
5923 return LDB_ERR_OPERATIONS_ERROR;
5926 old_el->flags = LDB_FLAG_MOD_REPLACE;
5929 /* parse the existing links */
5930 ret = get_parsed_dns(module, tmp_ctx, old_el, &pdn_list, attr->syntax->ldap_oid, parent);
5931 if (ret != LDB_SUCCESS) {
5932 talloc_free(tmp_ctx);
5936 /* get our invocationId */
5937 our_invocation_id = samdb_ntds_invocation_id(ldb);
5938 if (!our_invocation_id) {
5939 ldb_debug_set(ldb, LDB_DEBUG_ERROR, __location__ ": unable to find invocationId\n");
5940 talloc_free(tmp_ctx);
5941 return LDB_ERR_OPERATIONS_ERROR;
5944 ret = replmd_check_upgrade_links(pdn_list, old_el->num_values, old_el, our_invocation_id);
5945 if (ret != LDB_SUCCESS) {
5946 talloc_free(tmp_ctx);
5950 status = dsdb_dn_la_from_blob(ldb, attr, schema, tmp_ctx, la->value.blob, &dsdb_dn);
5951 if (!W_ERROR_IS_OK(status)) {
5952 ldb_asprintf_errstring(ldb, "Failed to parsed linked attribute blob for %s on %s - %s\n",
5953 old_el->name, ldb_dn_get_linearized(msg->dn), win_errstr(status));
5954 talloc_free(tmp_ctx);
5955 return LDB_ERR_OPERATIONS_ERROR;
5958 ntstatus = dsdb_get_extended_dn_guid(dsdb_dn->dn, &guid, "GUID");
5959 if (!NT_STATUS_IS_OK(ntstatus) && !active) {
5961 * This strange behaviour (allowing a NULL/missing
5962 * GUID) originally comes from:
5964 * commit e3054ce0fe0f8f62d2f5b2a77893e7a1479128bd
5965 * Author: Andrew Tridgell <tridge@samba.org>
5966 * Date: Mon Dec 21 21:21:55 2009 +1100
5968 * s4-drs: cope better with NULL GUIDS from DRS
5970 * It is valid to get a NULL GUID over DRS for a deleted forward link. We
5971 * need to match by DN if possible when seeing if we should update an
5974 * Pair-Programmed-With: Andrew Bartlett <abartlet@samba.org>
5977 ret = dsdb_module_search_dn(module, tmp_ctx, &target_res,
5978 dsdb_dn->dn, attrs2,
5979 DSDB_FLAG_NEXT_MODULE |
5980 DSDB_SEARCH_SHOW_RECYCLED |
5981 DSDB_SEARCH_SEARCH_ALL_PARTITIONS |
5982 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT,
5984 } else if (!NT_STATUS_IS_OK(ntstatus)) {
5985 ldb_asprintf_errstring(ldb, "Failed to find GUID in linked attribute blob for %s on %s from %s",
5987 ldb_dn_get_linearized(dsdb_dn->dn),
5988 ldb_dn_get_linearized(msg->dn));
5989 talloc_free(tmp_ctx);
5990 return LDB_ERR_OPERATIONS_ERROR;
5992 ret = dsdb_module_search(module, tmp_ctx, &target_res,
5993 NULL, LDB_SCOPE_SUBTREE,
5995 DSDB_FLAG_NEXT_MODULE |
5996 DSDB_SEARCH_SHOW_RECYCLED |
5997 DSDB_SEARCH_SEARCH_ALL_PARTITIONS |
5998 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT,
6001 GUID_string(tmp_ctx, &guid));
6004 if (ret != LDB_SUCCESS) {
6005 ldb_asprintf_errstring(ldb_module_get_ctx(module), "Failed to re-resolve GUID %s: %s\n",
6006 GUID_string(tmp_ctx, &guid),
6007 ldb_errstring(ldb_module_get_ctx(module)));
6008 talloc_free(tmp_ctx);
6012 if (target_res->count == 0) {
6013 DEBUG(2,(__location__ ": WARNING: Failed to re-resolve GUID %s - using %s\n",
6014 GUID_string(tmp_ctx, &guid),
6015 ldb_dn_get_linearized(dsdb_dn->dn)));
6016 } else if (target_res->count != 1) {
6017 ldb_asprintf_errstring(ldb_module_get_ctx(module), "More than one object found matching objectGUID %s\n",
6018 GUID_string(tmp_ctx, &guid));
6019 talloc_free(tmp_ctx);
6020 return LDB_ERR_OPERATIONS_ERROR;
6022 target_msg = target_res->msgs[0];
6023 dsdb_dn->dn = talloc_steal(dsdb_dn, target_msg->dn);
6027 * Check for deleted objects per MS-DRSR 4.1.10.6.13
6028 * ProcessLinkValue, because link updates are not applied to
6029 * recycled and tombstone objects. We don't have to delete
6030 * any existing link, that should have happened when the
6031 * object deletion was replicated or initiated.
6033 replmd_deletion_state(module, target_msg,
6034 &target_deletion_state, NULL);
6036 if (target_deletion_state >= OBJECT_RECYCLED) {
6037 talloc_free(tmp_ctx);
6041 /* see if this link already exists */
6042 pdn = parsed_dn_find(pdn_list, old_el->num_values, &guid, dsdb_dn->dn);
6044 /* see if this update is newer than what we have already */
6045 struct GUID invocation_id = GUID_zero();
6046 uint32_t version = 0;
6047 uint32_t originating_usn = 0;
6048 NTTIME change_time = 0;
6049 uint32_t rmd_flags = dsdb_dn_rmd_flags(pdn->dsdb_dn->dn);
6051 dsdb_get_extended_dn_guid(pdn->dsdb_dn->dn, &invocation_id, "RMD_INVOCID");
6052 dsdb_get_extended_dn_uint32(pdn->dsdb_dn->dn, &version, "RMD_VERSION");
6053 dsdb_get_extended_dn_uint32(pdn->dsdb_dn->dn, &originating_usn, "RMD_ORIGINATING_USN");
6054 dsdb_get_extended_dn_nttime(pdn->dsdb_dn->dn, &change_time, "RMD_CHANGETIME");
6056 if (!replmd_update_is_newer(&invocation_id,
6057 &la->meta_data.originating_invocation_id,
6059 la->meta_data.version,
6061 la->meta_data.originating_change_time)) {
6062 DEBUG(3,("Discarding older DRS linked attribute update to %s on %s from %s\n",
6063 old_el->name, ldb_dn_get_linearized(msg->dn),
6064 GUID_string(tmp_ctx, &la->meta_data.originating_invocation_id)));
6065 talloc_free(tmp_ctx);
6069 /* get a seq_num for this change */
6070 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &seq_num);
6071 if (ret != LDB_SUCCESS) {
6072 talloc_free(tmp_ctx);
6076 if (!(rmd_flags & DSDB_RMD_FLAG_DELETED)) {
6077 /* remove the existing backlink */
6078 ret = replmd_add_backlink(module, schema, &la->identifier->guid, &guid, false, attr, true);
6079 if (ret != LDB_SUCCESS) {
6080 talloc_free(tmp_ctx);
6085 ret = replmd_update_la_val(tmp_ctx, pdn->v, dsdb_dn, pdn->dsdb_dn,
6086 &la->meta_data.originating_invocation_id,
6087 la->meta_data.originating_usn, seq_num,
6088 la->meta_data.originating_change_time,
6089 la->meta_data.version,
6091 if (ret != LDB_SUCCESS) {
6092 talloc_free(tmp_ctx);
6097 /* add the new backlink */
6098 ret = replmd_add_backlink(module, schema, &la->identifier->guid, &guid, true, attr, true);
6099 if (ret != LDB_SUCCESS) {
6100 talloc_free(tmp_ctx);
6105 /* get a seq_num for this change */
6106 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &seq_num);
6107 if (ret != LDB_SUCCESS) {
6108 talloc_free(tmp_ctx);
6112 old_el->values = talloc_realloc(msg->elements, old_el->values,
6113 struct ldb_val, old_el->num_values+1);
6114 if (!old_el->values) {
6115 ldb_module_oom(module);
6116 return LDB_ERR_OPERATIONS_ERROR;
6118 old_el->num_values++;
6120 ret = replmd_build_la_val(tmp_ctx, &old_el->values[old_el->num_values-1], dsdb_dn,
6121 &la->meta_data.originating_invocation_id,
6122 la->meta_data.originating_usn, seq_num,
6123 la->meta_data.originating_change_time,
6124 la->meta_data.version,
6125 (la->flags & DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE)?false:true);
6126 if (ret != LDB_SUCCESS) {
6127 talloc_free(tmp_ctx);
6132 ret = replmd_add_backlink(module, schema, &la->identifier->guid, &guid,
6134 if (ret != LDB_SUCCESS) {
6135 talloc_free(tmp_ctx);
6141 /* we only change whenChanged and uSNChanged if the seq_num
6143 ret = add_time_element(msg, "whenChanged", t);
6144 if (ret != LDB_SUCCESS) {
6145 talloc_free(tmp_ctx);
6150 ret = add_uint64_element(ldb, msg, "uSNChanged", seq_num);
6151 if (ret != LDB_SUCCESS) {
6152 talloc_free(tmp_ctx);
6157 old_el = ldb_msg_find_element(msg, attr->lDAPDisplayName);
6158 if (old_el == NULL) {
6159 talloc_free(tmp_ctx);
6160 return ldb_operr(ldb);
6163 ret = dsdb_check_single_valued_link(attr, old_el);
6164 if (ret != LDB_SUCCESS) {
6165 talloc_free(tmp_ctx);
6169 old_el->flags |= LDB_FLAG_INTERNAL_DISABLE_SINGLE_VALUE_CHECK;
6171 ret = dsdb_module_modify(module, msg, DSDB_FLAG_NEXT_MODULE, parent);
6172 if (ret != LDB_SUCCESS) {
6173 ldb_debug(ldb, LDB_DEBUG_WARNING, "Failed to apply linked attribute change '%s'\n%s\n",
6175 ldb_ldif_message_string(ldb, tmp_ctx, LDB_CHANGETYPE_MODIFY, msg));
6176 talloc_free(tmp_ctx);
6180 talloc_free(tmp_ctx);
6185 static int replmd_extended(struct ldb_module *module, struct ldb_request *req)
6187 if (strcmp(req->op.extended.oid, DSDB_EXTENDED_REPLICATED_OBJECTS_OID) == 0) {
6188 return replmd_extended_replicated_objects(module, req);
6191 return ldb_next_request(module, req);
6196 we hook into the transaction operations to allow us to
6197 perform the linked attribute updates at the end of the whole
6198 transaction. This allows a forward linked attribute to be created
6199 before the object is created. During a vampire, w2k8 sends us linked
6200 attributes before the objects they are part of.
6202 static int replmd_start_transaction(struct ldb_module *module)
6204 /* create our private structure for this transaction */
6205 struct replmd_private *replmd_private = talloc_get_type(ldb_module_get_private(module),
6206 struct replmd_private);
6207 replmd_txn_cleanup(replmd_private);
6209 /* free any leftover mod_usn records from cancelled
6211 while (replmd_private->ncs) {
6212 struct nc_entry *e = replmd_private->ncs;
6213 DLIST_REMOVE(replmd_private->ncs, e);
6217 return ldb_next_start_trans(module);
6221 on prepare commit we loop over our queued la_context structures and
6224 static int replmd_prepare_commit(struct ldb_module *module)
6226 struct replmd_private *replmd_private =
6227 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
6228 struct la_entry *la, *prev;
6229 struct la_backlink *bl;
6232 /* walk the list backwards, to do the first entry first, as we
6233 * added the entries with DLIST_ADD() which puts them at the
6234 * start of the list */
6235 for (la = DLIST_TAIL(replmd_private->la_list); la; la=prev) {
6236 prev = DLIST_PREV(la);
6237 DLIST_REMOVE(replmd_private->la_list, la);
6238 ret = replmd_process_linked_attribute(module, la, NULL);
6239 if (ret != LDB_SUCCESS) {
6240 replmd_txn_cleanup(replmd_private);
6245 /* process our backlink list, creating and deleting backlinks
6247 for (bl=replmd_private->la_backlinks; bl; bl=bl->next) {
6248 ret = replmd_process_backlink(module, bl, NULL);
6249 if (ret != LDB_SUCCESS) {
6250 replmd_txn_cleanup(replmd_private);
6255 replmd_txn_cleanup(replmd_private);
6257 /* possibly change @REPLCHANGED */
6258 ret = replmd_notify_store(module, NULL);
6259 if (ret != LDB_SUCCESS) {
6263 return ldb_next_prepare_commit(module);
6266 static int replmd_del_transaction(struct ldb_module *module)
6268 struct replmd_private *replmd_private =
6269 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
6270 replmd_txn_cleanup(replmd_private);
6272 return ldb_next_del_trans(module);
6276 static const struct ldb_module_ops ldb_repl_meta_data_module_ops = {
6277 .name = "repl_meta_data",
6278 .init_context = replmd_init,
6280 .modify = replmd_modify,
6281 .rename = replmd_rename,
6282 .del = replmd_delete,
6283 .extended = replmd_extended,
6284 .start_transaction = replmd_start_transaction,
6285 .prepare_commit = replmd_prepare_commit,
6286 .del_transaction = replmd_del_transaction,
6289 int ldb_repl_meta_data_module_init(const char *version)
6291 LDB_MODULE_CHECK_VERSION(version);
6292 return ldb_register_module(&ldb_repl_meta_data_module_ops);