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)));
568 DLIST_REMOVE(replmd_private->ncs, modified_partition);
569 talloc_free(modified_partition);
577 created a replmd_replicated_request context
579 static struct replmd_replicated_request *replmd_ctx_init(struct ldb_module *module,
580 struct ldb_request *req)
582 struct ldb_context *ldb;
583 struct replmd_replicated_request *ac;
584 const struct GUID *our_invocation_id;
586 ldb = ldb_module_get_ctx(module);
588 ac = talloc_zero(req, struct replmd_replicated_request);
597 ac->schema = dsdb_get_schema(ldb, ac);
599 ldb_debug_set(ldb, LDB_DEBUG_FATAL,
600 "replmd_modify: no dsdb_schema loaded");
601 DEBUG(0,(__location__ ": %s\n", ldb_errstring(ldb)));
606 /* get our invocationId */
607 our_invocation_id = samdb_ntds_invocation_id(ldb);
608 if (!our_invocation_id) {
609 ldb_debug_set(ldb, LDB_DEBUG_FATAL,
610 "replmd_add: unable to find invocationId\n");
614 ac->our_invocation_id = *our_invocation_id;
620 add a time element to a record
622 static int add_time_element(struct ldb_message *msg, const char *attr, time_t t)
624 struct ldb_message_element *el;
628 if (ldb_msg_find_element(msg, attr) != NULL) {
632 s = ldb_timestring(msg, t);
634 return LDB_ERR_OPERATIONS_ERROR;
637 ret = ldb_msg_add_string(msg, attr, s);
638 if (ret != LDB_SUCCESS) {
642 el = ldb_msg_find_element(msg, attr);
643 /* always set as replace. This works because on add ops, the flag
645 el->flags = LDB_FLAG_MOD_REPLACE;
651 add a uint64_t element to a record
653 static int add_uint64_element(struct ldb_context *ldb, struct ldb_message *msg,
654 const char *attr, uint64_t v)
656 struct ldb_message_element *el;
659 if (ldb_msg_find_element(msg, attr) != NULL) {
663 ret = samdb_msg_add_uint64(ldb, msg, msg, attr, v);
664 if (ret != LDB_SUCCESS) {
668 el = ldb_msg_find_element(msg, attr);
669 /* always set as replace. This works because on add ops, the flag
671 el->flags = LDB_FLAG_MOD_REPLACE;
676 static int replmd_replPropertyMetaData1_attid_sort(const struct replPropertyMetaData1 *m1,
677 const struct replPropertyMetaData1 *m2,
678 const uint32_t *rdn_attid)
681 * This assignment seems inoccous, but it is critical for the
682 * system, as we need to do the comparisons as a unsigned
683 * quantity, not signed (enums are signed integers)
685 uint32_t attid_1 = m1->attid;
686 uint32_t attid_2 = m2->attid;
688 if (attid_1 == attid_2) {
693 * See above regarding this being an unsigned comparison.
694 * Otherwise when the high bit is set on non-standard
695 * attributes, they would end up first, before objectClass
698 return attid_1 > attid_2 ? 1 : -1;
701 static int replmd_replPropertyMetaDataCtr1_verify(struct ldb_context *ldb,
702 struct replPropertyMetaDataCtr1 *ctr1,
705 if (ctr1->count == 0) {
706 ldb_debug_set(ldb, LDB_DEBUG_FATAL,
707 "No elements found in replPropertyMetaData for %s!\n",
708 ldb_dn_get_linearized(dn));
709 return LDB_ERR_CONSTRAINT_VIOLATION;
712 /* the objectClass attribute is value 0x00000000, so must be first */
713 if (ctr1->array[0].attid != DRSUAPI_ATTID_objectClass) {
714 ldb_debug_set(ldb, LDB_DEBUG_FATAL,
715 "No objectClass found in replPropertyMetaData for %s!\n",
716 ldb_dn_get_linearized(dn));
717 return LDB_ERR_OBJECT_CLASS_VIOLATION;
723 static int replmd_replPropertyMetaDataCtr1_sort_and_verify(struct ldb_context *ldb,
724 struct replPropertyMetaDataCtr1 *ctr1,
727 /* Note this is O(n^2) for the almost-sorted case, which this is */
728 LDB_TYPESAFE_QSORT(ctr1->array, ctr1->count, NULL,
729 replmd_replPropertyMetaData1_attid_sort);
730 return replmd_replPropertyMetaDataCtr1_verify(ldb, ctr1, dn);
733 static int replmd_ldb_message_element_attid_sort(const struct ldb_message_element *e1,
734 const struct ldb_message_element *e2,
735 const struct dsdb_schema *schema)
737 const struct dsdb_attribute *a1;
738 const struct dsdb_attribute *a2;
741 * TODO: make this faster by caching the dsdb_attribute pointer
742 * on the ldb_messag_element
745 a1 = dsdb_attribute_by_lDAPDisplayName(schema, e1->name);
746 a2 = dsdb_attribute_by_lDAPDisplayName(schema, e2->name);
749 * TODO: remove this check, we should rely on e1 and e2 having valid attribute names
753 return strcasecmp(e1->name, e2->name);
755 if (a1->attributeID_id == a2->attributeID_id) {
758 return a1->attributeID_id > a2->attributeID_id ? 1 : -1;
761 static void replmd_ldb_message_sort(struct ldb_message *msg,
762 const struct dsdb_schema *schema)
764 LDB_TYPESAFE_QSORT(msg->elements, msg->num_elements, schema, replmd_ldb_message_element_attid_sort);
767 static int replmd_build_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct dsdb_dn *dsdb_dn,
768 const struct GUID *invocation_id, uint64_t seq_num,
769 uint64_t local_usn, NTTIME nttime, uint32_t version, bool deleted);
773 fix up linked attributes in replmd_add.
774 This involves setting up the right meta-data in extended DN
775 components, and creating backlinks to the object
777 static int replmd_add_fix_la(struct ldb_module *module, struct ldb_message_element *el,
778 uint64_t seq_num, const struct GUID *invocationId, NTTIME now,
779 struct GUID *guid, const struct dsdb_attribute *sa, struct ldb_request *parent)
782 TALLOC_CTX *tmp_ctx = talloc_new(el->values);
783 struct ldb_context *ldb = ldb_module_get_ctx(module);
785 /* We will take a reference to the schema in replmd_add_backlink */
786 const struct dsdb_schema *schema = dsdb_get_schema(ldb, NULL);
788 for (i=0; i<el->num_values; i++) {
789 struct ldb_val *v = &el->values[i];
790 struct dsdb_dn *dsdb_dn = dsdb_dn_parse(tmp_ctx, ldb, v, sa->syntax->ldap_oid);
791 struct GUID target_guid;
795 /* note that the DN already has the extended
796 components from the extended_dn_store module */
797 status = dsdb_get_extended_dn_guid(dsdb_dn->dn, &target_guid, "GUID");
798 if (!NT_STATUS_IS_OK(status) || GUID_all_zero(&target_guid)) {
799 ret = dsdb_module_guid_by_dn(module, dsdb_dn->dn, &target_guid, parent);
800 if (ret != LDB_SUCCESS) {
801 talloc_free(tmp_ctx);
804 ret = dsdb_set_extended_dn_guid(dsdb_dn->dn, &target_guid, "GUID");
805 if (ret != LDB_SUCCESS) {
806 talloc_free(tmp_ctx);
811 ret = replmd_build_la_val(el->values, v, dsdb_dn, invocationId,
812 seq_num, seq_num, now, 0, false);
813 if (ret != LDB_SUCCESS) {
814 talloc_free(tmp_ctx);
818 ret = replmd_add_backlink(module, schema, guid, &target_guid, true, sa, false);
819 if (ret != LDB_SUCCESS) {
820 talloc_free(tmp_ctx);
825 talloc_free(tmp_ctx);
831 intercept add requests
833 static int replmd_add(struct ldb_module *module, struct ldb_request *req)
835 struct samldb_msds_intid_persistant *msds_intid_struct;
836 struct ldb_context *ldb;
837 struct ldb_control *control;
838 struct replmd_replicated_request *ac;
839 enum ndr_err_code ndr_err;
840 struct ldb_request *down_req;
841 struct ldb_message *msg;
842 const DATA_BLOB *guid_blob;
844 struct replPropertyMetaDataBlob nmd;
845 struct ldb_val nmd_value;
848 * The use of a time_t here seems odd, but as the NTTIME
849 * elements are actually declared as NTTIME_1sec in the IDL,
850 * getting a higher resolution timestamp is not required.
852 time_t t = time(NULL);
857 unsigned int functional_level;
859 bool allow_add_guid = false;
860 bool remove_current_guid = false;
861 bool is_urgent = false;
862 bool is_schema_nc = false;
863 struct ldb_message_element *objectclass_el;
864 struct replmd_private *replmd_private =
865 talloc_get_type_abort(ldb_module_get_private(module), struct replmd_private);
867 /* check if there's a show relax control (used by provision to say 'I know what I'm doing') */
868 control = ldb_request_get_control(req, LDB_CONTROL_RELAX_OID);
870 allow_add_guid = true;
873 /* do not manipulate our control entries */
874 if (ldb_dn_is_special(req->op.add.message->dn)) {
875 return ldb_next_request(module, req);
878 ldb = ldb_module_get_ctx(module);
880 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_add\n");
882 guid_blob = ldb_msg_find_ldb_val(req->op.add.message, "objectGUID");
883 if (guid_blob != NULL) {
884 if (!allow_add_guid) {
885 ldb_set_errstring(ldb,
886 "replmd_add: it's not allowed to add an object with objectGUID!");
887 return LDB_ERR_UNWILLING_TO_PERFORM;
889 NTSTATUS status = GUID_from_data_blob(guid_blob,&guid);
890 if (!NT_STATUS_IS_OK(status)) {
891 ldb_set_errstring(ldb,
892 "replmd_add: Unable to parse the 'objectGUID' as a GUID!");
893 return LDB_ERR_UNWILLING_TO_PERFORM;
895 /* we remove this attribute as it can be a string and
896 * will not be treated correctly and then we will re-add
897 * it later on in the good format */
898 remove_current_guid = true;
902 guid = GUID_random();
905 ac = replmd_ctx_init(module, req);
907 return ldb_module_oom(module);
910 functional_level = dsdb_functional_level(ldb);
912 /* Get a sequence number from the backend */
913 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &ac->seq_num);
914 if (ret != LDB_SUCCESS) {
919 /* we have to copy the message as the caller might have it as a const */
920 msg = ldb_msg_copy_shallow(ac, req->op.add.message);
924 return LDB_ERR_OPERATIONS_ERROR;
927 /* generated times */
928 unix_to_nt_time(&now, t);
929 time_str = ldb_timestring(msg, t);
933 return LDB_ERR_OPERATIONS_ERROR;
935 if (remove_current_guid) {
936 ldb_msg_remove_attr(msg,"objectGUID");
940 * remove autogenerated attributes
942 ldb_msg_remove_attr(msg, "whenCreated");
943 ldb_msg_remove_attr(msg, "whenChanged");
944 ldb_msg_remove_attr(msg, "uSNCreated");
945 ldb_msg_remove_attr(msg, "uSNChanged");
946 ldb_msg_remove_attr(msg, "replPropertyMetaData");
949 * readd replicated attributes
951 ret = ldb_msg_add_string(msg, "whenCreated", time_str);
952 if (ret != LDB_SUCCESS) {
958 /* build the replication meta_data */
961 nmd.ctr.ctr1.count = msg->num_elements;
962 nmd.ctr.ctr1.array = talloc_array(msg,
963 struct replPropertyMetaData1,
965 if (!nmd.ctr.ctr1.array) {
968 return LDB_ERR_OPERATIONS_ERROR;
971 is_schema_nc = ldb_dn_compare_base(replmd_private->schema_dn, msg->dn) == 0;
973 for (i=0; i < msg->num_elements; i++) {
974 struct ldb_message_element *e = &msg->elements[i];
975 struct replPropertyMetaData1 *m = &nmd.ctr.ctr1.array[ni];
976 const struct dsdb_attribute *sa;
978 if (e->name[0] == '@') continue;
980 sa = dsdb_attribute_by_lDAPDisplayName(ac->schema, e->name);
982 ldb_debug_set(ldb, LDB_DEBUG_ERROR,
983 "replmd_add: attribute '%s' not defined in schema\n",
986 return LDB_ERR_NO_SUCH_ATTRIBUTE;
989 if ((sa->systemFlags & DS_FLAG_ATTR_NOT_REPLICATED) || (sa->systemFlags & DS_FLAG_ATTR_IS_CONSTRUCTED)) {
990 /* if the attribute is not replicated (0x00000001)
991 * or constructed (0x00000004) it has no metadata
996 if (sa->linkID != 0 && functional_level > DS_DOMAIN_FUNCTION_2000) {
997 ret = replmd_add_fix_la(module, e, ac->seq_num,
998 &ac->our_invocation_id, now,
1000 if (ret != LDB_SUCCESS) {
1004 /* linked attributes are not stored in
1005 replPropertyMetaData in FL above w2k */
1009 m->attid = dsdb_attribute_get_attid(sa, is_schema_nc);
1011 if (m->attid == DRSUAPI_ATTID_isDeleted) {
1012 const struct ldb_val *rdn_val = ldb_dn_get_rdn_val(msg->dn);
1015 if (rdn_val == NULL) {
1018 return LDB_ERR_OPERATIONS_ERROR;
1021 rdn = (const char*)rdn_val->data;
1022 if (strcmp(rdn, "Deleted Objects") == 0) {
1024 * Set the originating_change_time to 29/12/9999 at 23:59:59
1025 * as specified in MS-ADTS 7.1.1.4.2 Deleted Objects Container
1027 m->originating_change_time = DELETED_OBJECT_CONTAINER_CHANGE_TIME;
1029 m->originating_change_time = now;
1032 m->originating_change_time = now;
1034 m->originating_invocation_id = ac->our_invocation_id;
1035 m->originating_usn = ac->seq_num;
1036 m->local_usn = ac->seq_num;
1040 /* fix meta data count */
1041 nmd.ctr.ctr1.count = ni;
1044 * sort meta data array
1046 ret = replmd_replPropertyMetaDataCtr1_sort_and_verify(ldb, &nmd.ctr.ctr1, msg->dn);
1047 if (ret != LDB_SUCCESS) {
1048 ldb_asprintf_errstring(ldb, "%s: error during direct ADD: %s", __func__, ldb_errstring(ldb));
1053 /* generated NDR encoded values */
1054 ndr_err = ndr_push_struct_blob(&nmd_value, msg,
1056 (ndr_push_flags_fn_t)ndr_push_replPropertyMetaDataBlob);
1057 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1060 return LDB_ERR_OPERATIONS_ERROR;
1064 * add the autogenerated values
1066 ret = dsdb_msg_add_guid(msg, &guid, "objectGUID");
1067 if (ret != LDB_SUCCESS) {
1072 ret = ldb_msg_add_string(msg, "whenChanged", time_str);
1073 if (ret != LDB_SUCCESS) {
1078 ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNCreated", ac->seq_num);
1079 if (ret != LDB_SUCCESS) {
1084 ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNChanged", ac->seq_num);
1085 if (ret != LDB_SUCCESS) {
1090 ret = ldb_msg_add_value(msg, "replPropertyMetaData", &nmd_value, NULL);
1091 if (ret != LDB_SUCCESS) {
1098 * sort the attributes by attid before storing the object
1100 replmd_ldb_message_sort(msg, ac->schema);
1103 * Assert that we do have an objectClass
1105 objectclass_el = ldb_msg_find_element(msg, "objectClass");
1106 if (objectclass_el == NULL) {
1107 ldb_asprintf_errstring(ldb, __location__
1108 ": objectClass missing on %s\n",
1109 ldb_dn_get_linearized(msg->dn));
1111 return LDB_ERR_OBJECT_CLASS_VIOLATION;
1113 is_urgent = replmd_check_urgent_objectclass(objectclass_el,
1114 REPL_URGENT_ON_CREATE);
1116 ac->is_urgent = is_urgent;
1117 ret = ldb_build_add_req(&down_req, ldb, ac,
1120 ac, replmd_op_callback,
1123 LDB_REQ_SET_LOCATION(down_req);
1124 if (ret != LDB_SUCCESS) {
1129 /* current partition control is needed by "replmd_op_callback" */
1130 if (ldb_request_get_control(req, DSDB_CONTROL_CURRENT_PARTITION_OID) == NULL) {
1131 ret = ldb_request_add_control(down_req,
1132 DSDB_CONTROL_CURRENT_PARTITION_OID,
1134 if (ret != LDB_SUCCESS) {
1140 if (functional_level == DS_DOMAIN_FUNCTION_2000) {
1141 ret = ldb_request_add_control(down_req, DSDB_CONTROL_APPLY_LINKS, false, NULL);
1142 if (ret != LDB_SUCCESS) {
1148 /* mark the control done */
1150 control->critical = 0;
1152 if (ldb_dn_compare_base(replmd_private->schema_dn, req->op.add.message->dn) != 0) {
1154 /* Update the usn in the SAMLDB_MSDS_INTID_OPAQUE opaque */
1155 msds_intid_struct = (struct samldb_msds_intid_persistant *) ldb_get_opaque(ldb, SAMLDB_MSDS_INTID_OPAQUE);
1156 if (msds_intid_struct) {
1157 msds_intid_struct->usn = ac->seq_num;
1160 /* go on with the call chain */
1161 return ldb_next_request(module, down_req);
1166 * update the replPropertyMetaData for one element
1168 static int replmd_update_rpmd_element(struct ldb_context *ldb,
1169 struct ldb_message *msg,
1170 struct ldb_message_element *el,
1171 struct ldb_message_element *old_el,
1172 struct replPropertyMetaDataBlob *omd,
1173 const struct dsdb_schema *schema,
1175 const struct GUID *our_invocation_id,
1178 struct ldb_request *req)
1181 const struct dsdb_attribute *a;
1182 struct replPropertyMetaData1 *md1;
1183 bool may_skip = false;
1186 a = dsdb_attribute_by_lDAPDisplayName(schema, el->name);
1188 if (ldb_request_get_control(req, LDB_CONTROL_RELAX_OID)) {
1189 /* allow this to make it possible for dbcheck
1190 to remove bad attributes */
1194 DEBUG(0,(__location__ ": Unable to find attribute %s in schema\n",
1196 return LDB_ERR_OPERATIONS_ERROR;
1199 attid = dsdb_attribute_get_attid(a, is_schema_nc);
1201 if ((a->systemFlags & DS_FLAG_ATTR_NOT_REPLICATED) || (a->systemFlags & DS_FLAG_ATTR_IS_CONSTRUCTED)) {
1206 * if the attribute's value haven't changed, and this isn't
1207 * just a delete of everything then return LDB_SUCCESS Unless
1208 * we have the provision control or if the attribute is
1209 * interSiteTopologyGenerator as this page explain:
1210 * http://support.microsoft.com/kb/224815 this attribute is
1211 * periodicaly written by the DC responsible for the intersite
1212 * generation in a given site
1214 * Unchanged could be deleting or replacing an already-gone
1215 * thing with an unconstrained delete/empty replace or a
1216 * replace with the same value, but not an add with the same
1217 * value because that could be about adding a duplicate (which
1218 * is for someone else to error out on).
1220 if (old_el != NULL && ldb_msg_element_equal_ordered(el, old_el)) {
1221 if (LDB_FLAG_MOD_TYPE(el->flags) == LDB_FLAG_MOD_REPLACE) {
1224 } else if (old_el == NULL && el->num_values == 0) {
1225 if (LDB_FLAG_MOD_TYPE(el->flags) == LDB_FLAG_MOD_REPLACE) {
1227 } else if (LDB_FLAG_MOD_TYPE(el->flags) == LDB_FLAG_MOD_DELETE) {
1233 if (strcmp(el->name, "interSiteTopologyGenerator") != 0 &&
1234 !ldb_request_get_control(req, LDB_CONTROL_PROVISION_OID)) {
1236 * allow this to make it possible for dbcheck
1237 * to rebuild broken metadata
1243 for (i=0; i<omd->ctr.ctr1.count; i++) {
1245 * First check if we find it under the msDS-IntID,
1246 * then check if we find it under the OID and
1249 * This allows the administrator to simply re-write
1250 * the attributes and so restore replication, which is
1251 * likely what they will try to do.
1253 if (attid == omd->ctr.ctr1.array[i].attid) {
1257 if (a->attributeID_id == omd->ctr.ctr1.array[i].attid) {
1262 if (a->linkID != 0 && dsdb_functional_level(ldb) > DS_DOMAIN_FUNCTION_2000) {
1263 /* linked attributes are not stored in
1264 replPropertyMetaData in FL above w2k, but we do
1265 raise the seqnum for the object */
1266 if (*seq_num == 0 &&
1267 ldb_sequence_number(ldb, LDB_SEQ_NEXT, seq_num) != LDB_SUCCESS) {
1268 return LDB_ERR_OPERATIONS_ERROR;
1273 if (i == omd->ctr.ctr1.count) {
1274 /* we need to add a new one */
1275 omd->ctr.ctr1.array = talloc_realloc(msg, omd->ctr.ctr1.array,
1276 struct replPropertyMetaData1, omd->ctr.ctr1.count+1);
1277 if (omd->ctr.ctr1.array == NULL) {
1279 return LDB_ERR_OPERATIONS_ERROR;
1281 omd->ctr.ctr1.count++;
1282 ZERO_STRUCT(omd->ctr.ctr1.array[i]);
1285 /* Get a new sequence number from the backend. We only do this
1286 * if we have a change that requires a new
1287 * replPropertyMetaData element
1289 if (*seq_num == 0) {
1290 int ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, seq_num);
1291 if (ret != LDB_SUCCESS) {
1292 return LDB_ERR_OPERATIONS_ERROR;
1296 md1 = &omd->ctr.ctr1.array[i];
1299 if (md1->attid == DRSUAPI_ATTID_isDeleted) {
1300 const struct ldb_val *rdn_val = ldb_dn_get_rdn_val(msg->dn);
1303 if (rdn_val == NULL) {
1305 return LDB_ERR_OPERATIONS_ERROR;
1308 rdn = (const char*)rdn_val->data;
1309 if (strcmp(rdn, "Deleted Objects") == 0) {
1311 * Set the originating_change_time to 29/12/9999 at 23:59:59
1312 * as specified in MS-ADTS 7.1.1.4.2 Deleted Objects Container
1314 md1->originating_change_time = DELETED_OBJECT_CONTAINER_CHANGE_TIME;
1316 md1->originating_change_time = now;
1319 md1->originating_change_time = now;
1321 md1->originating_invocation_id = *our_invocation_id;
1322 md1->originating_usn = *seq_num;
1323 md1->local_usn = *seq_num;
1329 * Bump the replPropertyMetaData version on an attribute, and if it
1330 * has changed (or forced by leaving rdn_old NULL), update the value
1333 * This is important, as calling a modify operation may not change the
1334 * version number if the values appear unchanged, but a rename between
1335 * parents bumps this value.
1338 static int replmd_update_rpmd_rdn_attr(struct ldb_context *ldb,
1339 struct ldb_message *msg,
1340 const struct ldb_val *rdn_new,
1341 const struct ldb_val *rdn_old,
1342 struct replPropertyMetaDataBlob *omd,
1343 struct replmd_replicated_request *ar,
1347 struct ldb_message_element new_el = {
1348 .flags = LDB_FLAG_MOD_REPLACE,
1349 .name = ldb_dn_get_rdn_name(msg->dn),
1351 .values = discard_const_p(struct ldb_val, rdn_new)
1353 struct ldb_message_element old_el = {
1354 .flags = LDB_FLAG_MOD_REPLACE,
1355 .name = ldb_dn_get_rdn_name(msg->dn),
1356 .num_values = rdn_old ? 1 : 0,
1357 .values = discard_const_p(struct ldb_val, rdn_old)
1360 if (ldb_msg_element_equal_ordered(&new_el, &old_el) == false) {
1361 int ret = ldb_msg_add(msg, &new_el, LDB_FLAG_MOD_REPLACE);
1362 if (ret != LDB_SUCCESS) {
1363 return ldb_oom(ldb);
1367 return replmd_update_rpmd_element(ldb, msg, &new_el, NULL,
1368 omd, ar->schema, &ar->seq_num,
1369 &ar->our_invocation_id,
1370 now, is_schema_nc, ar->req);
1374 static uint64_t find_max_local_usn(struct replPropertyMetaDataBlob omd)
1376 uint32_t count = omd.ctr.ctr1.count;
1379 for (i=0; i < count; i++) {
1380 struct replPropertyMetaData1 m = omd.ctr.ctr1.array[i];
1381 if (max < m.local_usn) {
1389 * update the replPropertyMetaData object each time we modify an
1390 * object. This is needed for DRS replication, as the merge on the
1391 * client is based on this object
1393 static int replmd_update_rpmd(struct ldb_module *module,
1394 const struct dsdb_schema *schema,
1395 struct ldb_request *req,
1396 const char * const *rename_attrs,
1397 struct ldb_message *msg, uint64_t *seq_num,
1398 time_t t, bool is_schema_nc,
1399 bool *is_urgent, bool *rodc)
1401 const struct ldb_val *omd_value;
1402 enum ndr_err_code ndr_err;
1403 struct replPropertyMetaDataBlob omd;
1406 const struct GUID *our_invocation_id;
1408 const char * const *attrs = NULL;
1409 const char * const attrs2[] = { "uSNChanged", "objectClass", "instanceType", NULL };
1410 struct ldb_result *res;
1411 struct ldb_context *ldb;
1412 struct ldb_message_element *objectclass_el;
1413 enum urgent_situation situation;
1414 bool rmd_is_provided;
1415 bool rmd_is_just_resorted = false;
1416 const char *not_rename_attrs[4 + msg->num_elements];
1419 attrs = rename_attrs;
1421 for (i = 0; i < msg->num_elements; i++) {
1422 not_rename_attrs[i] = msg->elements[i].name;
1424 not_rename_attrs[i] = "replPropertyMetaData";
1425 not_rename_attrs[i+1] = "objectClass";
1426 not_rename_attrs[i+2] = "instanceType";
1427 not_rename_attrs[i+3] = NULL;
1428 attrs = not_rename_attrs;
1431 ldb = ldb_module_get_ctx(module);
1433 our_invocation_id = samdb_ntds_invocation_id(ldb);
1434 if (!our_invocation_id) {
1435 /* this happens during an initial vampire while
1436 updating the schema */
1437 DEBUG(5,("No invocationID - skipping replPropertyMetaData update\n"));
1441 unix_to_nt_time(&now, t);
1443 if (ldb_request_get_control(req, DSDB_CONTROL_CHANGEREPLMETADATA_OID)) {
1444 rmd_is_provided = true;
1445 if (ldb_request_get_control(req, DSDB_CONTROL_CHANGEREPLMETADATA_RESORT_OID)) {
1446 rmd_is_just_resorted = true;
1449 rmd_is_provided = false;
1452 /* if isDeleted is present and is TRUE, then we consider we are deleting,
1453 * otherwise we consider we are updating */
1454 if (ldb_msg_check_string_attribute(msg, "isDeleted", "TRUE")) {
1455 situation = REPL_URGENT_ON_DELETE;
1456 } else if (rename_attrs) {
1457 situation = REPL_URGENT_ON_CREATE | REPL_URGENT_ON_DELETE;
1459 situation = REPL_URGENT_ON_UPDATE;
1462 if (rmd_is_provided) {
1463 /* In this case the change_replmetadata control was supplied */
1464 /* We check that it's the only attribute that is provided
1465 * (it's a rare case so it's better to keep the code simplier)
1466 * We also check that the highest local_usn is bigger or the same as
1469 if( msg->num_elements != 1 ||
1470 strncmp(msg->elements[0].name,
1471 "replPropertyMetaData", 20) ) {
1472 DEBUG(0,(__location__ ": changereplmetada control called without "\
1473 "a specified replPropertyMetaData attribute or with others\n"));
1474 return LDB_ERR_OPERATIONS_ERROR;
1476 if (situation != REPL_URGENT_ON_UPDATE) {
1477 DEBUG(0,(__location__ ": changereplmetada control can't be called when deleting an object\n"));
1478 return LDB_ERR_OPERATIONS_ERROR;
1480 omd_value = ldb_msg_find_ldb_val(msg, "replPropertyMetaData");
1482 DEBUG(0,(__location__ ": replPropertyMetaData was not specified for Object %s\n",
1483 ldb_dn_get_linearized(msg->dn)));
1484 return LDB_ERR_OPERATIONS_ERROR;
1486 ndr_err = ndr_pull_struct_blob(omd_value, msg, &omd,
1487 (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
1488 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1489 DEBUG(0,(__location__ ": Failed to parse replPropertyMetaData for %s\n",
1490 ldb_dn_get_linearized(msg->dn)));
1491 return LDB_ERR_OPERATIONS_ERROR;
1494 ret = dsdb_module_search_dn(module, msg, &res, msg->dn, attrs2,
1495 DSDB_FLAG_NEXT_MODULE |
1496 DSDB_SEARCH_SHOW_RECYCLED |
1497 DSDB_SEARCH_SHOW_EXTENDED_DN |
1498 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT |
1499 DSDB_SEARCH_REVEAL_INTERNALS, req);
1501 if (ret != LDB_SUCCESS) {
1505 if (rmd_is_just_resorted == false) {
1506 *seq_num = find_max_local_usn(omd);
1508 db_seq = ldb_msg_find_attr_as_uint64(res->msgs[0], "uSNChanged", 0);
1511 * The test here now allows for a new
1512 * replPropertyMetaData with no change, if was
1513 * just dbcheck re-sorting the values.
1515 if (*seq_num <= db_seq) {
1516 DEBUG(0,(__location__ ": changereplmetada control provided but max(local_usn)" \
1517 " is less than uSNChanged (max = %lld uSNChanged = %lld)\n",
1518 (long long)*seq_num, (long long)db_seq));
1519 return LDB_ERR_OPERATIONS_ERROR;
1524 /* search for the existing replPropertyMetaDataBlob. We need
1525 * to use REVEAL and ask for DNs in storage format to support
1526 * the check for values being the same in
1527 * replmd_update_rpmd_element()
1529 ret = dsdb_module_search_dn(module, msg, &res, msg->dn, attrs,
1530 DSDB_FLAG_NEXT_MODULE |
1531 DSDB_SEARCH_SHOW_RECYCLED |
1532 DSDB_SEARCH_SHOW_EXTENDED_DN |
1533 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT |
1534 DSDB_SEARCH_REVEAL_INTERNALS, req);
1535 if (ret != LDB_SUCCESS) {
1539 omd_value = ldb_msg_find_ldb_val(res->msgs[0], "replPropertyMetaData");
1541 DEBUG(0,(__location__ ": Object %s does not have a replPropertyMetaData attribute\n",
1542 ldb_dn_get_linearized(msg->dn)));
1543 return LDB_ERR_OPERATIONS_ERROR;
1546 ndr_err = ndr_pull_struct_blob(omd_value, msg, &omd,
1547 (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
1548 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1549 DEBUG(0,(__location__ ": Failed to parse replPropertyMetaData for %s\n",
1550 ldb_dn_get_linearized(msg->dn)));
1551 return LDB_ERR_OPERATIONS_ERROR;
1554 if (omd.version != 1) {
1555 DEBUG(0,(__location__ ": bad version %u in replPropertyMetaData for %s\n",
1556 omd.version, ldb_dn_get_linearized(msg->dn)));
1557 return LDB_ERR_OPERATIONS_ERROR;
1560 for (i=0; i<msg->num_elements; i++) {
1561 struct ldb_message_element *old_el;
1562 old_el = ldb_msg_find_element(res->msgs[0], msg->elements[i].name);
1563 ret = replmd_update_rpmd_element(ldb, msg, &msg->elements[i], old_el, &omd, schema, seq_num,
1567 if (ret != LDB_SUCCESS) {
1571 if (!*is_urgent && (situation == REPL_URGENT_ON_UPDATE)) {
1572 *is_urgent = replmd_check_urgent_attribute(&msg->elements[i]);
1579 * Assert that we have an objectClass attribute - this is major
1580 * corruption if we don't have this!
1582 objectclass_el = ldb_msg_find_element(res->msgs[0], "objectClass");
1583 if (objectclass_el != NULL) {
1585 * Now check if this objectClass means we need to do urgent replication
1587 if (!*is_urgent && replmd_check_urgent_objectclass(objectclass_el,
1591 } else if (!ldb_request_get_control(req, DSDB_CONTROL_DBCHECK)) {
1592 ldb_asprintf_errstring(ldb, __location__
1593 ": objectClass missing on %s\n",
1594 ldb_dn_get_linearized(msg->dn));
1595 return LDB_ERR_OBJECT_CLASS_VIOLATION;
1599 * replmd_update_rpmd_element has done an update if the
1602 if (*seq_num != 0 || rmd_is_just_resorted == true) {
1603 struct ldb_val *md_value;
1604 struct ldb_message_element *el;
1606 /*if we are RODC and this is a DRSR update then its ok*/
1607 if (!ldb_request_get_control(req, DSDB_CONTROL_REPLICATED_UPDATE_OID)
1608 && !ldb_request_get_control(req, DSDB_CONTROL_DBCHECK_MODIFY_RO_REPLICA)) {
1609 unsigned instanceType;
1611 ret = samdb_rodc(ldb, rodc);
1612 if (ret != LDB_SUCCESS) {
1613 DEBUG(4, (__location__ ": unable to tell if we are an RODC\n"));
1615 ldb_set_errstring(ldb, "RODC modify is forbidden!");
1616 return LDB_ERR_REFERRAL;
1619 instanceType = ldb_msg_find_attr_as_uint(res->msgs[0], "instanceType", INSTANCE_TYPE_WRITE);
1620 if (!(instanceType & INSTANCE_TYPE_WRITE)) {
1621 return ldb_error(ldb, LDB_ERR_UNWILLING_TO_PERFORM,
1622 "cannot change replicated attribute on partial replica");
1626 md_value = talloc(msg, struct ldb_val);
1627 if (md_value == NULL) {
1629 return LDB_ERR_OPERATIONS_ERROR;
1632 ret = replmd_replPropertyMetaDataCtr1_sort_and_verify(ldb, &omd.ctr.ctr1, msg->dn);
1633 if (ret != LDB_SUCCESS) {
1634 ldb_asprintf_errstring(ldb, "%s: %s", __func__, ldb_errstring(ldb));
1638 ndr_err = ndr_push_struct_blob(md_value, msg, &omd,
1639 (ndr_push_flags_fn_t)ndr_push_replPropertyMetaDataBlob);
1640 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1641 DEBUG(0,(__location__ ": Failed to marshall replPropertyMetaData for %s\n",
1642 ldb_dn_get_linearized(msg->dn)));
1643 return LDB_ERR_OPERATIONS_ERROR;
1646 ret = ldb_msg_add_empty(msg, "replPropertyMetaData", LDB_FLAG_MOD_REPLACE, &el);
1647 if (ret != LDB_SUCCESS) {
1648 DEBUG(0,(__location__ ": Failed to add updated replPropertyMetaData %s\n",
1649 ldb_dn_get_linearized(msg->dn)));
1654 el->values = md_value;
1661 struct dsdb_dn *dsdb_dn;
1666 static int parsed_dn_compare(struct parsed_dn *pdn1, struct parsed_dn *pdn2)
1668 return GUID_compare(&pdn1->guid, &pdn2->guid);
1671 static int GUID_compare_struct(struct GUID *g1, struct GUID g2)
1673 return GUID_compare(g1, &g2);
1676 static struct parsed_dn *parsed_dn_find(struct parsed_dn *pdn,
1677 unsigned int count, struct GUID *guid,
1680 struct parsed_dn *ret;
1682 if (dn && GUID_all_zero(guid)) {
1683 /* when updating a link using DRS, we sometimes get a
1684 NULL GUID. We then need to try and match by DN */
1685 for (i=0; i<count; i++) {
1686 if (ldb_dn_compare(pdn[i].dsdb_dn->dn, dn) == 0) {
1687 dsdb_get_extended_dn_guid(pdn[i].dsdb_dn->dn, guid, "GUID");
1693 BINARY_ARRAY_SEARCH(pdn, count, guid, guid, GUID_compare_struct, ret);
1698 get a series of message element values as an array of DNs and GUIDs
1699 the result is sorted by GUID
1701 static int get_parsed_dns(struct ldb_module *module, TALLOC_CTX *mem_ctx,
1702 struct ldb_message_element *el, struct parsed_dn **pdn,
1703 const char *ldap_oid, struct ldb_request *parent)
1706 struct ldb_context *ldb = ldb_module_get_ctx(module);
1713 (*pdn) = talloc_array(mem_ctx, struct parsed_dn, el->num_values);
1715 ldb_module_oom(module);
1716 return LDB_ERR_OPERATIONS_ERROR;
1719 for (i=0; i<el->num_values; i++) {
1720 struct ldb_val *v = &el->values[i];
1723 struct parsed_dn *p;
1727 p->dsdb_dn = dsdb_dn_parse(*pdn, ldb, v, ldap_oid);
1728 if (p->dsdb_dn == NULL) {
1729 return LDB_ERR_INVALID_DN_SYNTAX;
1732 dn = p->dsdb_dn->dn;
1734 status = dsdb_get_extended_dn_guid(dn, &p->guid, "GUID");
1735 if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
1736 /* we got a DN without a GUID - go find the GUID */
1737 int ret = dsdb_module_guid_by_dn(module, dn, &p->guid, parent);
1738 if (ret != LDB_SUCCESS) {
1739 ldb_asprintf_errstring(ldb, "Unable to find GUID for DN %s\n",
1740 ldb_dn_get_linearized(dn));
1741 if (ret == LDB_ERR_NO_SUCH_OBJECT &&
1742 LDB_FLAG_MOD_TYPE(el->flags) == LDB_FLAG_MOD_DELETE &&
1743 ldb_attr_cmp(el->name, "member") == 0) {
1744 return LDB_ERR_UNWILLING_TO_PERFORM;
1748 ret = dsdb_set_extended_dn_guid(dn, &p->guid, "GUID");
1749 if (ret != LDB_SUCCESS) {
1752 } else if (!NT_STATUS_IS_OK(status)) {
1753 return LDB_ERR_OPERATIONS_ERROR;
1756 /* keep a pointer to the original ldb_val */
1760 TYPESAFE_QSORT(*pdn, el->num_values, parsed_dn_compare);
1766 build a new extended DN, including all meta data fields
1768 RMD_FLAGS = DSDB_RMD_FLAG_* bits
1769 RMD_ADDTIME = originating_add_time
1770 RMD_INVOCID = originating_invocation_id
1771 RMD_CHANGETIME = originating_change_time
1772 RMD_ORIGINATING_USN = originating_usn
1773 RMD_LOCAL_USN = local_usn
1774 RMD_VERSION = version
1776 static int replmd_build_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct dsdb_dn *dsdb_dn,
1777 const struct GUID *invocation_id, uint64_t seq_num,
1778 uint64_t local_usn, NTTIME nttime, uint32_t version, bool deleted)
1780 struct ldb_dn *dn = dsdb_dn->dn;
1781 const char *tstring, *usn_string, *flags_string;
1782 struct ldb_val tval;
1784 struct ldb_val usnv, local_usnv;
1785 struct ldb_val vers, flagsv;
1788 const char *dnstring;
1790 uint32_t rmd_flags = deleted?DSDB_RMD_FLAG_DELETED:0;
1792 tstring = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)nttime);
1794 return LDB_ERR_OPERATIONS_ERROR;
1796 tval = data_blob_string_const(tstring);
1798 usn_string = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)seq_num);
1800 return LDB_ERR_OPERATIONS_ERROR;
1802 usnv = data_blob_string_const(usn_string);
1804 usn_string = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)local_usn);
1806 return LDB_ERR_OPERATIONS_ERROR;
1808 local_usnv = data_blob_string_const(usn_string);
1810 vstring = talloc_asprintf(mem_ctx, "%lu", (unsigned long)version);
1812 return LDB_ERR_OPERATIONS_ERROR;
1814 vers = data_blob_string_const(vstring);
1816 status = GUID_to_ndr_blob(invocation_id, dn, &iid);
1817 if (!NT_STATUS_IS_OK(status)) {
1818 return LDB_ERR_OPERATIONS_ERROR;
1821 flags_string = talloc_asprintf(mem_ctx, "%u", rmd_flags);
1822 if (!flags_string) {
1823 return LDB_ERR_OPERATIONS_ERROR;
1825 flagsv = data_blob_string_const(flags_string);
1827 ret = ldb_dn_set_extended_component(dn, "RMD_FLAGS", &flagsv);
1828 if (ret != LDB_SUCCESS) return ret;
1829 ret = ldb_dn_set_extended_component(dn, "RMD_ADDTIME", &tval);
1830 if (ret != LDB_SUCCESS) return ret;
1831 ret = ldb_dn_set_extended_component(dn, "RMD_INVOCID", &iid);
1832 if (ret != LDB_SUCCESS) return ret;
1833 ret = ldb_dn_set_extended_component(dn, "RMD_CHANGETIME", &tval);
1834 if (ret != LDB_SUCCESS) return ret;
1835 ret = ldb_dn_set_extended_component(dn, "RMD_LOCAL_USN", &local_usnv);
1836 if (ret != LDB_SUCCESS) return ret;
1837 ret = ldb_dn_set_extended_component(dn, "RMD_ORIGINATING_USN", &usnv);
1838 if (ret != LDB_SUCCESS) return ret;
1839 ret = ldb_dn_set_extended_component(dn, "RMD_VERSION", &vers);
1840 if (ret != LDB_SUCCESS) return ret;
1842 dnstring = dsdb_dn_get_extended_linearized(mem_ctx, dsdb_dn, 1);
1843 if (dnstring == NULL) {
1844 return LDB_ERR_OPERATIONS_ERROR;
1846 *v = data_blob_string_const(dnstring);
1851 static int replmd_update_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct dsdb_dn *dsdb_dn,
1852 struct dsdb_dn *old_dsdb_dn, const struct GUID *invocation_id,
1853 uint64_t seq_num, uint64_t local_usn, NTTIME nttime,
1854 uint32_t version, bool deleted);
1857 check if any links need upgrading from w2k format
1859 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.
1861 static int replmd_check_upgrade_links(struct parsed_dn *dns, uint32_t count, struct ldb_message_element *parent_ctx, const struct GUID *invocation_id)
1864 for (i=0; i<count; i++) {
1869 status = dsdb_get_extended_dn_uint32(dns[i].dsdb_dn->dn, &version, "RMD_VERSION");
1870 if (!NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
1874 /* it's an old one that needs upgrading */
1875 ret = replmd_update_la_val(parent_ctx->values, dns[i].v, dns[i].dsdb_dn, dns[i].dsdb_dn, invocation_id,
1877 if (ret != LDB_SUCCESS) {
1885 update an extended DN, including all meta data fields
1887 see replmd_build_la_val for value names
1889 static int replmd_update_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct dsdb_dn *dsdb_dn,
1890 struct dsdb_dn *old_dsdb_dn, const struct GUID *invocation_id,
1891 uint64_t usn, uint64_t local_usn, NTTIME nttime,
1892 uint32_t version, bool deleted)
1894 struct ldb_dn *dn = dsdb_dn->dn;
1895 const char *tstring, *usn_string, *flags_string;
1896 struct ldb_val tval;
1898 struct ldb_val usnv, local_usnv;
1899 struct ldb_val vers, flagsv;
1900 const struct ldb_val *old_addtime;
1901 uint32_t old_version;
1904 const char *dnstring;
1906 uint32_t rmd_flags = deleted?DSDB_RMD_FLAG_DELETED:0;
1908 tstring = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)nttime);
1910 return LDB_ERR_OPERATIONS_ERROR;
1912 tval = data_blob_string_const(tstring);
1914 usn_string = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)usn);
1916 return LDB_ERR_OPERATIONS_ERROR;
1918 usnv = data_blob_string_const(usn_string);
1920 usn_string = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)local_usn);
1922 return LDB_ERR_OPERATIONS_ERROR;
1924 local_usnv = data_blob_string_const(usn_string);
1926 status = GUID_to_ndr_blob(invocation_id, dn, &iid);
1927 if (!NT_STATUS_IS_OK(status)) {
1928 return LDB_ERR_OPERATIONS_ERROR;
1931 flags_string = talloc_asprintf(mem_ctx, "%u", rmd_flags);
1932 if (!flags_string) {
1933 return LDB_ERR_OPERATIONS_ERROR;
1935 flagsv = data_blob_string_const(flags_string);
1937 ret = ldb_dn_set_extended_component(dn, "RMD_FLAGS", &flagsv);
1938 if (ret != LDB_SUCCESS) return ret;
1940 /* get the ADDTIME from the original */
1941 old_addtime = ldb_dn_get_extended_component(old_dsdb_dn->dn, "RMD_ADDTIME");
1942 if (old_addtime == NULL) {
1943 old_addtime = &tval;
1945 if (dsdb_dn != old_dsdb_dn ||
1946 ldb_dn_get_extended_component(dn, "RMD_ADDTIME") == NULL) {
1947 ret = ldb_dn_set_extended_component(dn, "RMD_ADDTIME", old_addtime);
1948 if (ret != LDB_SUCCESS) return ret;
1951 /* use our invocation id */
1952 ret = ldb_dn_set_extended_component(dn, "RMD_INVOCID", &iid);
1953 if (ret != LDB_SUCCESS) return ret;
1955 /* changetime is the current time */
1956 ret = ldb_dn_set_extended_component(dn, "RMD_CHANGETIME", &tval);
1957 if (ret != LDB_SUCCESS) return ret;
1959 /* update the USN */
1960 ret = ldb_dn_set_extended_component(dn, "RMD_ORIGINATING_USN", &usnv);
1961 if (ret != LDB_SUCCESS) return ret;
1963 ret = ldb_dn_set_extended_component(dn, "RMD_LOCAL_USN", &local_usnv);
1964 if (ret != LDB_SUCCESS) return ret;
1966 /* increase the version by 1 */
1967 status = dsdb_get_extended_dn_uint32(old_dsdb_dn->dn, &old_version, "RMD_VERSION");
1968 if (NT_STATUS_IS_OK(status) && old_version >= version) {
1969 version = old_version+1;
1971 vstring = talloc_asprintf(dn, "%lu", (unsigned long)version);
1972 vers = data_blob_string_const(vstring);
1973 ret = ldb_dn_set_extended_component(dn, "RMD_VERSION", &vers);
1974 if (ret != LDB_SUCCESS) return ret;
1976 dnstring = dsdb_dn_get_extended_linearized(mem_ctx, dsdb_dn, 1);
1977 if (dnstring == NULL) {
1978 return LDB_ERR_OPERATIONS_ERROR;
1980 *v = data_blob_string_const(dnstring);
1986 handle adding a linked attribute
1988 static int replmd_modify_la_add(struct ldb_module *module,
1989 const struct dsdb_schema *schema,
1990 struct ldb_message *msg,
1991 struct ldb_message_element *el,
1992 struct ldb_message_element *old_el,
1993 const struct dsdb_attribute *schema_attr,
1996 struct GUID *msg_guid,
1997 struct ldb_request *parent)
2000 struct parsed_dn *dns, *old_dns;
2001 TALLOC_CTX *tmp_ctx = talloc_new(msg);
2003 struct ldb_val *new_values = NULL;
2004 unsigned int num_new_values = 0;
2005 unsigned old_num_values = old_el?old_el->num_values:0;
2006 const struct GUID *invocation_id;
2007 struct ldb_context *ldb = ldb_module_get_ctx(module);
2010 unix_to_nt_time(&now, t);
2012 ret = get_parsed_dns(module, tmp_ctx, el, &dns, schema_attr->syntax->ldap_oid, parent);
2013 if (ret != LDB_SUCCESS) {
2014 talloc_free(tmp_ctx);
2018 ret = get_parsed_dns(module, tmp_ctx, old_el, &old_dns, schema_attr->syntax->ldap_oid, parent);
2019 if (ret != LDB_SUCCESS) {
2020 talloc_free(tmp_ctx);
2024 invocation_id = samdb_ntds_invocation_id(ldb);
2025 if (!invocation_id) {
2026 talloc_free(tmp_ctx);
2027 return LDB_ERR_OPERATIONS_ERROR;
2030 ret = replmd_check_upgrade_links(old_dns, old_num_values, old_el, invocation_id);
2031 if (ret != LDB_SUCCESS) {
2032 talloc_free(tmp_ctx);
2036 /* for each new value, see if it exists already with the same GUID */
2037 for (i=0; i<el->num_values; i++) {
2038 struct parsed_dn *p = parsed_dn_find(old_dns, old_num_values, &dns[i].guid, NULL);
2040 /* this is a new linked attribute value */
2041 new_values = talloc_realloc(tmp_ctx, new_values, struct ldb_val, num_new_values+1);
2042 if (new_values == NULL) {
2043 ldb_module_oom(module);
2044 talloc_free(tmp_ctx);
2045 return LDB_ERR_OPERATIONS_ERROR;
2047 ret = replmd_build_la_val(new_values, &new_values[num_new_values], dns[i].dsdb_dn,
2048 invocation_id, seq_num, seq_num, now, 0, false);
2049 if (ret != LDB_SUCCESS) {
2050 talloc_free(tmp_ctx);
2055 /* this is only allowed if the GUID was
2056 previously deleted. */
2057 uint32_t rmd_flags = dsdb_dn_rmd_flags(p->dsdb_dn->dn);
2059 if (!(rmd_flags & DSDB_RMD_FLAG_DELETED)) {
2060 struct GUID_txt_buf guid_str;
2061 ldb_asprintf_errstring(ldb, "Attribute %s already exists for target GUID %s",
2062 el->name, GUID_buf_string(&p->guid, &guid_str));
2063 talloc_free(tmp_ctx);
2064 /* error codes for 'member' need to be
2066 if (ldb_attr_cmp(el->name, "member") == 0) {
2067 return LDB_ERR_ENTRY_ALREADY_EXISTS;
2069 return LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS;
2072 ret = replmd_update_la_val(old_el->values, p->v, dns[i].dsdb_dn, p->dsdb_dn,
2073 invocation_id, seq_num, seq_num, now, 0, false);
2074 if (ret != LDB_SUCCESS) {
2075 talloc_free(tmp_ctx);
2080 ret = replmd_add_backlink(module, schema, msg_guid, &dns[i].guid, true, schema_attr, true);
2081 if (ret != LDB_SUCCESS) {
2082 talloc_free(tmp_ctx);
2087 /* add the new ones on to the end of the old values, constructing a new el->values */
2088 el->values = talloc_realloc(msg->elements, old_el?old_el->values:NULL,
2090 old_num_values+num_new_values);
2091 if (el->values == NULL) {
2092 ldb_module_oom(module);
2093 return LDB_ERR_OPERATIONS_ERROR;
2096 memcpy(&el->values[old_num_values], new_values, num_new_values*sizeof(struct ldb_val));
2097 el->num_values = old_num_values + num_new_values;
2099 talloc_steal(msg->elements, el->values);
2100 talloc_steal(el->values, new_values);
2102 talloc_free(tmp_ctx);
2104 /* we now tell the backend to replace all existing values
2105 with the one we have constructed */
2106 el->flags = LDB_FLAG_MOD_REPLACE;
2113 handle deleting all active linked attributes
2115 static int replmd_modify_la_delete(struct ldb_module *module,
2116 const struct dsdb_schema *schema,
2117 struct ldb_message *msg,
2118 struct ldb_message_element *el,
2119 struct ldb_message_element *old_el,
2120 const struct dsdb_attribute *schema_attr,
2123 struct GUID *msg_guid,
2124 struct ldb_request *parent)
2127 struct parsed_dn *dns, *old_dns;
2128 TALLOC_CTX *tmp_ctx = talloc_new(msg);
2130 const struct GUID *invocation_id;
2131 struct ldb_context *ldb = ldb_module_get_ctx(module);
2134 unix_to_nt_time(&now, t);
2136 /* check if there is nothing to delete */
2137 if ((!old_el || old_el->num_values == 0) &&
2138 el->num_values == 0) {
2142 if (!old_el || old_el->num_values == 0) {
2143 return LDB_ERR_NO_SUCH_ATTRIBUTE;
2146 ret = get_parsed_dns(module, tmp_ctx, el, &dns, schema_attr->syntax->ldap_oid, parent);
2147 if (ret != LDB_SUCCESS) {
2148 talloc_free(tmp_ctx);
2152 ret = get_parsed_dns(module, tmp_ctx, old_el, &old_dns, schema_attr->syntax->ldap_oid, parent);
2153 if (ret != LDB_SUCCESS) {
2154 talloc_free(tmp_ctx);
2158 invocation_id = samdb_ntds_invocation_id(ldb);
2159 if (!invocation_id) {
2160 return LDB_ERR_OPERATIONS_ERROR;
2163 ret = replmd_check_upgrade_links(old_dns, old_el->num_values, old_el, invocation_id);
2164 if (ret != LDB_SUCCESS) {
2165 talloc_free(tmp_ctx);
2171 /* see if we are being asked to delete any links that
2172 don't exist or are already deleted */
2173 for (i=0; i<el->num_values; i++) {
2174 struct parsed_dn *p = &dns[i];
2175 struct parsed_dn *p2;
2178 p2 = parsed_dn_find(old_dns, old_el->num_values, &p->guid, NULL);
2180 struct GUID_txt_buf buf;
2181 ldb_asprintf_errstring(ldb, "Attribute %s doesn't exist for target GUID %s",
2182 el->name, GUID_buf_string(&p->guid, &buf));
2183 if (ldb_attr_cmp(el->name, "member") == 0) {
2184 return LDB_ERR_UNWILLING_TO_PERFORM;
2186 return LDB_ERR_NO_SUCH_ATTRIBUTE;
2189 rmd_flags = dsdb_dn_rmd_flags(p2->dsdb_dn->dn);
2190 if (rmd_flags & DSDB_RMD_FLAG_DELETED) {
2191 struct GUID_txt_buf buf;
2192 ldb_asprintf_errstring(ldb, "Attribute %s already deleted for target GUID %s",
2193 el->name, GUID_buf_string(&p->guid, &buf));
2194 if (ldb_attr_cmp(el->name, "member") == 0) {
2195 return LDB_ERR_UNWILLING_TO_PERFORM;
2197 return LDB_ERR_NO_SUCH_ATTRIBUTE;
2202 /* for each new value, see if it exists already with the same GUID
2203 if it is not already deleted and matches the delete list then delete it
2205 for (i=0; i<old_el->num_values; i++) {
2206 struct parsed_dn *p = &old_dns[i];
2209 if (el->num_values && parsed_dn_find(dns, el->num_values, &p->guid, NULL) == NULL) {
2213 rmd_flags = dsdb_dn_rmd_flags(p->dsdb_dn->dn);
2214 if (rmd_flags & DSDB_RMD_FLAG_DELETED) continue;
2216 ret = replmd_update_la_val(old_el->values, p->v, p->dsdb_dn, p->dsdb_dn,
2217 invocation_id, seq_num, seq_num, now, 0, true);
2218 if (ret != LDB_SUCCESS) {
2219 talloc_free(tmp_ctx);
2223 ret = replmd_add_backlink(module, schema, msg_guid, &old_dns[i].guid, false, schema_attr, true);
2224 if (ret != LDB_SUCCESS) {
2225 talloc_free(tmp_ctx);
2230 el->values = talloc_steal(msg->elements, old_el->values);
2231 el->num_values = old_el->num_values;
2233 talloc_free(tmp_ctx);
2235 /* we now tell the backend to replace all existing values
2236 with the one we have constructed */
2237 el->flags = LDB_FLAG_MOD_REPLACE;
2243 handle replacing a linked attribute
2245 static int replmd_modify_la_replace(struct ldb_module *module,
2246 const struct dsdb_schema *schema,
2247 struct ldb_message *msg,
2248 struct ldb_message_element *el,
2249 struct ldb_message_element *old_el,
2250 const struct dsdb_attribute *schema_attr,
2253 struct GUID *msg_guid,
2254 struct ldb_request *parent)
2257 struct parsed_dn *dns, *old_dns;
2258 TALLOC_CTX *tmp_ctx = talloc_new(msg);
2260 const struct GUID *invocation_id;
2261 struct ldb_context *ldb = ldb_module_get_ctx(module);
2262 struct ldb_val *new_values = NULL;
2263 unsigned int num_new_values = 0;
2264 unsigned int old_num_values = old_el?old_el->num_values:0;
2267 unix_to_nt_time(&now, t);
2269 /* check if there is nothing to replace */
2270 if ((!old_el || old_el->num_values == 0) &&
2271 el->num_values == 0) {
2275 ret = get_parsed_dns(module, tmp_ctx, el, &dns, schema_attr->syntax->ldap_oid, parent);
2276 if (ret != LDB_SUCCESS) {
2277 talloc_free(tmp_ctx);
2281 ret = get_parsed_dns(module, tmp_ctx, old_el, &old_dns, schema_attr->syntax->ldap_oid, parent);
2282 if (ret != LDB_SUCCESS) {
2283 talloc_free(tmp_ctx);
2287 invocation_id = samdb_ntds_invocation_id(ldb);
2288 if (!invocation_id) {
2289 return LDB_ERR_OPERATIONS_ERROR;
2292 ret = replmd_check_upgrade_links(old_dns, old_num_values, old_el, invocation_id);
2293 if (ret != LDB_SUCCESS) {
2294 talloc_free(tmp_ctx);
2298 /* mark all the old ones as deleted */
2299 for (i=0; i<old_num_values; i++) {
2300 struct parsed_dn *old_p = &old_dns[i];
2301 struct parsed_dn *p;
2302 uint32_t rmd_flags = dsdb_dn_rmd_flags(old_p->dsdb_dn->dn);
2304 if (rmd_flags & DSDB_RMD_FLAG_DELETED) continue;
2306 ret = replmd_add_backlink(module, schema, msg_guid, &old_dns[i].guid, false, schema_attr, false);
2307 if (ret != LDB_SUCCESS) {
2308 talloc_free(tmp_ctx);
2312 p = parsed_dn_find(dns, el->num_values, &old_p->guid, NULL);
2314 /* we don't delete it if we are re-adding it */
2318 ret = replmd_update_la_val(old_el->values, old_p->v, old_p->dsdb_dn, old_p->dsdb_dn,
2319 invocation_id, seq_num, seq_num, now, 0, true);
2320 if (ret != LDB_SUCCESS) {
2321 talloc_free(tmp_ctx);
2326 /* for each new value, either update its meta-data, or add it
2329 for (i=0; i<el->num_values; i++) {
2330 struct parsed_dn *p = &dns[i], *old_p;
2333 (old_p = parsed_dn_find(old_dns,
2334 old_num_values, &p->guid, NULL)) != NULL) {
2335 /* update in place */
2336 ret = replmd_update_la_val(old_el->values, old_p->v, p->dsdb_dn,
2337 old_p->dsdb_dn, invocation_id,
2338 seq_num, seq_num, now, 0, false);
2339 if (ret != LDB_SUCCESS) {
2340 talloc_free(tmp_ctx);
2345 new_values = talloc_realloc(tmp_ctx, new_values, struct ldb_val,
2347 if (new_values == NULL) {
2348 ldb_module_oom(module);
2349 talloc_free(tmp_ctx);
2350 return LDB_ERR_OPERATIONS_ERROR;
2352 ret = replmd_build_la_val(new_values, &new_values[num_new_values], dns[i].dsdb_dn,
2353 invocation_id, seq_num, seq_num, now, 0, false);
2354 if (ret != LDB_SUCCESS) {
2355 talloc_free(tmp_ctx);
2361 ret = replmd_add_backlink(module, schema, msg_guid, &dns[i].guid, true, schema_attr, false);
2362 if (ret != LDB_SUCCESS) {
2363 talloc_free(tmp_ctx);
2368 /* add the new values to the end of old_el */
2369 if (num_new_values != 0) {
2370 el->values = talloc_realloc(msg->elements, old_el?old_el->values:NULL,
2371 struct ldb_val, old_num_values+num_new_values);
2372 if (el->values == NULL) {
2373 ldb_module_oom(module);
2374 return LDB_ERR_OPERATIONS_ERROR;
2376 memcpy(&el->values[old_num_values], &new_values[0],
2377 sizeof(struct ldb_val)*num_new_values);
2378 el->num_values = old_num_values + num_new_values;
2379 talloc_steal(msg->elements, new_values);
2381 el->values = old_el->values;
2382 el->num_values = old_el->num_values;
2383 talloc_steal(msg->elements, el->values);
2386 talloc_free(tmp_ctx);
2388 /* we now tell the backend to replace all existing values
2389 with the one we have constructed */
2390 el->flags = LDB_FLAG_MOD_REPLACE;
2397 handle linked attributes in modify requests
2399 static int replmd_modify_handle_linked_attribs(struct ldb_module *module,
2400 struct ldb_message *msg,
2401 uint64_t seq_num, time_t t,
2402 struct ldb_request *parent)
2404 struct ldb_result *res;
2407 struct ldb_context *ldb = ldb_module_get_ctx(module);
2408 struct ldb_message *old_msg;
2410 const struct dsdb_schema *schema;
2411 struct GUID old_guid;
2414 /* there the replmd_update_rpmd code has already
2415 * checked and saw that there are no linked
2420 if (dsdb_functional_level(ldb) == DS_DOMAIN_FUNCTION_2000) {
2421 /* don't do anything special for linked attributes */
2425 ret = dsdb_module_search_dn(module, msg, &res, msg->dn, NULL,
2426 DSDB_FLAG_NEXT_MODULE |
2427 DSDB_SEARCH_SHOW_RECYCLED |
2428 DSDB_SEARCH_REVEAL_INTERNALS |
2429 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT,
2431 if (ret != LDB_SUCCESS) {
2434 schema = dsdb_get_schema(ldb, res);
2436 return LDB_ERR_OPERATIONS_ERROR;
2439 old_msg = res->msgs[0];
2441 old_guid = samdb_result_guid(old_msg, "objectGUID");
2443 for (i=0; i<msg->num_elements; i++) {
2444 struct ldb_message_element *el = &msg->elements[i];
2445 struct ldb_message_element *old_el, *new_el;
2446 const struct dsdb_attribute *schema_attr
2447 = dsdb_attribute_by_lDAPDisplayName(schema, el->name);
2449 ldb_asprintf_errstring(ldb,
2450 "%s: attribute %s is not a valid attribute in schema",
2451 __FUNCTION__, el->name);
2452 return LDB_ERR_OBJECT_CLASS_VIOLATION;
2454 if (schema_attr->linkID == 0) {
2457 if ((schema_attr->linkID & 1) == 1) {
2458 if (parent && ldb_request_get_control(parent, DSDB_CONTROL_DBCHECK)) {
2461 /* Odd is for the target. Illegal to modify */
2462 ldb_asprintf_errstring(ldb,
2463 "attribute %s must not be modified directly, it is a linked attribute", el->name);
2464 return LDB_ERR_UNWILLING_TO_PERFORM;
2466 old_el = ldb_msg_find_element(old_msg, el->name);
2467 switch (el->flags & LDB_FLAG_MOD_MASK) {
2468 case LDB_FLAG_MOD_REPLACE:
2469 ret = replmd_modify_la_replace(module, schema, msg, el, old_el, schema_attr, seq_num, t, &old_guid, parent);
2471 case LDB_FLAG_MOD_DELETE:
2472 ret = replmd_modify_la_delete(module, schema, msg, el, old_el, schema_attr, seq_num, t, &old_guid, parent);
2474 case LDB_FLAG_MOD_ADD:
2475 ret = replmd_modify_la_add(module, schema, msg, el, old_el, schema_attr, seq_num, t, &old_guid, parent);
2478 ldb_asprintf_errstring(ldb,
2479 "invalid flags 0x%x for %s linked attribute",
2480 el->flags, el->name);
2481 return LDB_ERR_UNWILLING_TO_PERFORM;
2483 if (dsdb_check_single_valued_link(schema_attr, el) != LDB_SUCCESS) {
2484 ldb_asprintf_errstring(ldb,
2485 "Attribute %s is single valued but more than one value has been supplied",
2487 return LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS;
2489 el->flags |= LDB_FLAG_INTERNAL_DISABLE_SINGLE_VALUE_CHECK;
2494 if (ret != LDB_SUCCESS) {
2498 ldb_msg_remove_attr(old_msg, el->name);
2500 ldb_msg_add_empty(old_msg, el->name, 0, &new_el);
2501 new_el->num_values = el->num_values;
2502 new_el->values = talloc_steal(msg->elements, el->values);
2504 /* TODO: this relises a bit too heavily on the exact
2505 behaviour of ldb_msg_find_element and
2506 ldb_msg_remove_element */
2507 old_el = ldb_msg_find_element(msg, el->name);
2509 ldb_msg_remove_element(msg, old_el);
2520 static int replmd_modify(struct ldb_module *module, struct ldb_request *req)
2522 struct samldb_msds_intid_persistant *msds_intid_struct;
2523 struct ldb_context *ldb;
2524 struct replmd_replicated_request *ac;
2525 struct ldb_request *down_req;
2526 struct ldb_message *msg;
2527 time_t t = time(NULL);
2529 bool is_urgent = false, rodc = false;
2530 bool is_schema_nc = false;
2531 unsigned int functional_level;
2532 const struct ldb_message_element *guid_el = NULL;
2533 struct ldb_control *sd_propagation_control;
2534 struct replmd_private *replmd_private =
2535 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
2537 /* do not manipulate our control entries */
2538 if (ldb_dn_is_special(req->op.mod.message->dn)) {
2539 return ldb_next_request(module, req);
2542 sd_propagation_control = ldb_request_get_control(req,
2543 DSDB_CONTROL_SEC_DESC_PROPAGATION_OID);
2544 if (sd_propagation_control != NULL) {
2545 if (req->op.mod.message->num_elements != 1) {
2546 return ldb_module_operr(module);
2548 ret = strcmp(req->op.mod.message->elements[0].name,
2549 "nTSecurityDescriptor");
2551 return ldb_module_operr(module);
2554 return ldb_next_request(module, req);
2557 ldb = ldb_module_get_ctx(module);
2559 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_modify\n");
2561 guid_el = ldb_msg_find_element(req->op.mod.message, "objectGUID");
2562 if (guid_el != NULL) {
2563 ldb_set_errstring(ldb,
2564 "replmd_modify: it's not allowed to change the objectGUID!");
2565 return LDB_ERR_CONSTRAINT_VIOLATION;
2568 ac = replmd_ctx_init(module, req);
2570 return ldb_module_oom(module);
2573 functional_level = dsdb_functional_level(ldb);
2575 /* we have to copy the message as the caller might have it as a const */
2576 msg = ldb_msg_copy_shallow(ac, req->op.mod.message);
2580 return LDB_ERR_OPERATIONS_ERROR;
2583 ldb_msg_remove_attr(msg, "whenChanged");
2584 ldb_msg_remove_attr(msg, "uSNChanged");
2586 is_schema_nc = ldb_dn_compare_base(replmd_private->schema_dn, msg->dn) == 0;
2588 ret = replmd_update_rpmd(module, ac->schema, req, NULL,
2589 msg, &ac->seq_num, t, is_schema_nc,
2591 if (rodc && (ret == LDB_ERR_REFERRAL)) {
2592 struct loadparm_context *lp_ctx;
2595 lp_ctx = talloc_get_type(ldb_get_opaque(ldb, "loadparm"),
2596 struct loadparm_context);
2598 referral = talloc_asprintf(req,
2600 lpcfg_dnsdomain(lp_ctx),
2601 ldb_dn_get_linearized(msg->dn));
2602 ret = ldb_module_send_referral(req, referral);
2607 if (ret != LDB_SUCCESS) {
2612 ret = replmd_modify_handle_linked_attribs(module, msg, ac->seq_num, t, req);
2613 if (ret != LDB_SUCCESS) {
2619 * - replace the old object with the newly constructed one
2622 ac->is_urgent = is_urgent;
2624 ret = ldb_build_mod_req(&down_req, ldb, ac,
2627 ac, replmd_op_callback,
2629 LDB_REQ_SET_LOCATION(down_req);
2630 if (ret != LDB_SUCCESS) {
2635 /* current partition control is needed by "replmd_op_callback" */
2636 if (ldb_request_get_control(req, DSDB_CONTROL_CURRENT_PARTITION_OID) == NULL) {
2637 ret = ldb_request_add_control(down_req,
2638 DSDB_CONTROL_CURRENT_PARTITION_OID,
2640 if (ret != LDB_SUCCESS) {
2646 /* If we are in functional level 2000, then
2647 * replmd_modify_handle_linked_attribs will have done
2649 if (functional_level == DS_DOMAIN_FUNCTION_2000) {
2650 ret = ldb_request_add_control(down_req, DSDB_CONTROL_APPLY_LINKS, false, NULL);
2651 if (ret != LDB_SUCCESS) {
2657 talloc_steal(down_req, msg);
2659 /* we only change whenChanged and uSNChanged if the seq_num
2661 if (ac->seq_num != 0) {
2662 ret = add_time_element(msg, "whenChanged", t);
2663 if (ret != LDB_SUCCESS) {
2669 ret = add_uint64_element(ldb, msg, "uSNChanged", ac->seq_num);
2670 if (ret != LDB_SUCCESS) {
2677 if (!ldb_dn_compare_base(replmd_private->schema_dn, msg->dn)) {
2678 /* Update the usn in the SAMLDB_MSDS_INTID_OPAQUE opaque */
2679 msds_intid_struct = (struct samldb_msds_intid_persistant *) ldb_get_opaque(ldb, SAMLDB_MSDS_INTID_OPAQUE);
2680 if (msds_intid_struct) {
2681 msds_intid_struct->usn = ac->seq_num;
2685 /* go on with the call chain */
2686 return ldb_next_request(module, down_req);
2689 static int replmd_rename_callback(struct ldb_request *req, struct ldb_reply *ares);
2692 handle a rename request
2694 On a rename we need to do an extra ldb_modify which sets the
2695 whenChanged and uSNChanged attributes. We do this in a callback after the success.
2697 static int replmd_rename(struct ldb_module *module, struct ldb_request *req)
2699 struct ldb_context *ldb;
2700 struct replmd_replicated_request *ac;
2702 struct ldb_request *down_req;
2704 /* do not manipulate our control entries */
2705 if (ldb_dn_is_special(req->op.mod.message->dn)) {
2706 return ldb_next_request(module, req);
2709 ldb = ldb_module_get_ctx(module);
2711 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_rename\n");
2713 ac = replmd_ctx_init(module, req);
2715 return ldb_module_oom(module);
2718 ret = ldb_build_rename_req(&down_req, ldb, ac,
2719 ac->req->op.rename.olddn,
2720 ac->req->op.rename.newdn,
2722 ac, replmd_rename_callback,
2724 LDB_REQ_SET_LOCATION(down_req);
2725 if (ret != LDB_SUCCESS) {
2730 /* go on with the call chain */
2731 return ldb_next_request(module, down_req);
2734 /* After the rename is compleated, update the whenchanged etc */
2735 static int replmd_rename_callback(struct ldb_request *req, struct ldb_reply *ares)
2737 struct ldb_context *ldb;
2738 struct ldb_request *down_req;
2739 struct ldb_message *msg;
2740 const struct dsdb_attribute *rdn_attr;
2741 const char *rdn_name;
2742 const struct ldb_val *rdn_val;
2743 const char *attrs[5] = { NULL, };
2744 time_t t = time(NULL);
2746 bool is_urgent = false, rodc = false;
2748 struct replmd_replicated_request *ac =
2749 talloc_get_type(req->context, struct replmd_replicated_request);
2750 struct replmd_private *replmd_private =
2751 talloc_get_type(ldb_module_get_private(ac->module),
2752 struct replmd_private);
2754 ldb = ldb_module_get_ctx(ac->module);
2756 if (ares->error != LDB_SUCCESS) {
2757 return ldb_module_done(ac->req, ares->controls,
2758 ares->response, ares->error);
2761 if (ares->type != LDB_REPLY_DONE) {
2762 ldb_set_errstring(ldb,
2763 "invalid ldb_reply_type in callback");
2765 return ldb_module_done(ac->req, NULL, NULL,
2766 LDB_ERR_OPERATIONS_ERROR);
2770 * - replace the old object with the newly constructed one
2773 msg = ldb_msg_new(ac);
2776 return LDB_ERR_OPERATIONS_ERROR;
2779 msg->dn = ac->req->op.rename.newdn;
2781 is_schema_nc = ldb_dn_compare_base(replmd_private->schema_dn, msg->dn) == 0;
2783 rdn_name = ldb_dn_get_rdn_name(msg->dn);
2784 if (rdn_name == NULL) {
2786 return ldb_module_done(ac->req, NULL, NULL,
2790 /* normalize the rdn attribute name */
2791 rdn_attr = dsdb_attribute_by_lDAPDisplayName(ac->schema, rdn_name);
2792 if (rdn_attr == NULL) {
2794 return ldb_module_done(ac->req, NULL, NULL,
2797 rdn_name = rdn_attr->lDAPDisplayName;
2799 rdn_val = ldb_dn_get_rdn_val(msg->dn);
2800 if (rdn_val == NULL) {
2802 return ldb_module_done(ac->req, NULL, NULL,
2806 if (ldb_msg_add_empty(msg, rdn_name, LDB_FLAG_MOD_REPLACE, NULL) != 0) {
2808 return ldb_module_done(ac->req, NULL, NULL,
2811 if (ldb_msg_add_value(msg, rdn_name, rdn_val, NULL) != 0) {
2813 return ldb_module_done(ac->req, NULL, NULL,
2816 if (ldb_msg_add_empty(msg, "name", LDB_FLAG_MOD_REPLACE, NULL) != 0) {
2818 return ldb_module_done(ac->req, NULL, NULL,
2821 if (ldb_msg_add_value(msg, "name", rdn_val, NULL) != 0) {
2823 return ldb_module_done(ac->req, NULL, NULL,
2828 * here we let replmd_update_rpmd() only search for
2829 * the existing "replPropertyMetaData" and rdn_name attributes.
2831 * We do not want the existing "name" attribute as
2832 * the "name" attribute needs to get the version
2833 * updated on rename even if the rdn value hasn't changed.
2835 * This is the diff of the meta data, for a moved user
2836 * on a w2k8r2 server:
2839 * -dn: CN=sdf df,CN=Users,DC=bla,DC=base
2840 * +dn: CN=sdf df,OU=TestOU,DC=bla,DC=base
2841 * replPropertyMetaData: NDR: struct replPropertyMetaDataBlob
2842 * version : 0x00000001 (1)
2843 * reserved : 0x00000000 (0)
2844 * @@ -66,11 +66,11 @@ replPropertyMetaData: NDR: struct re
2845 * local_usn : 0x00000000000037a5 (14245)
2846 * array: struct replPropertyMetaData1
2847 * attid : DRSUAPI_ATTID_name (0x90001)
2848 * - version : 0x00000001 (1)
2849 * - originating_change_time : Wed Feb 9 17:20:49 2011 CET
2850 * + version : 0x00000002 (2)
2851 * + originating_change_time : Wed Apr 6 15:21:01 2011 CEST
2852 * originating_invocation_id: 0d36ca05-5507-4e62-aca3-354bab0d39e1
2853 * - originating_usn : 0x00000000000037a5 (14245)
2854 * - local_usn : 0x00000000000037a5 (14245)
2855 * + originating_usn : 0x0000000000003834 (14388)
2856 * + local_usn : 0x0000000000003834 (14388)
2857 * array: struct replPropertyMetaData1
2858 * attid : DRSUAPI_ATTID_userAccountControl (0x90008)
2859 * version : 0x00000004 (4)
2861 attrs[0] = "replPropertyMetaData";
2862 attrs[1] = "objectClass";
2863 attrs[2] = "instanceType";
2864 attrs[3] = rdn_name;
2867 ret = replmd_update_rpmd(ac->module, ac->schema, req, attrs,
2868 msg, &ac->seq_num, t,
2869 is_schema_nc, &is_urgent, &rodc);
2870 if (rodc && (ret == LDB_ERR_REFERRAL)) {
2871 struct ldb_dn *olddn = ac->req->op.rename.olddn;
2872 struct loadparm_context *lp_ctx;
2875 lp_ctx = talloc_get_type(ldb_get_opaque(ldb, "loadparm"),
2876 struct loadparm_context);
2878 referral = talloc_asprintf(req,
2880 lpcfg_dnsdomain(lp_ctx),
2881 ldb_dn_get_linearized(olddn));
2882 ret = ldb_module_send_referral(req, referral);
2884 return ldb_module_done(req, NULL, NULL, ret);
2887 if (ret != LDB_SUCCESS) {
2889 return ldb_module_done(ac->req, NULL, NULL, ret);
2892 if (ac->seq_num == 0) {
2894 return ldb_module_done(ac->req, NULL, NULL,
2896 "internal error seq_num == 0"));
2898 ac->is_urgent = is_urgent;
2900 ret = ldb_build_mod_req(&down_req, ldb, ac,
2903 ac, replmd_op_callback,
2905 LDB_REQ_SET_LOCATION(down_req);
2906 if (ret != LDB_SUCCESS) {
2911 /* current partition control is needed by "replmd_op_callback" */
2912 if (ldb_request_get_control(req, DSDB_CONTROL_CURRENT_PARTITION_OID) == NULL) {
2913 ret = ldb_request_add_control(down_req,
2914 DSDB_CONTROL_CURRENT_PARTITION_OID,
2916 if (ret != LDB_SUCCESS) {
2922 talloc_steal(down_req, msg);
2924 ret = add_time_element(msg, "whenChanged", t);
2925 if (ret != LDB_SUCCESS) {
2931 ret = add_uint64_element(ldb, msg, "uSNChanged", ac->seq_num);
2932 if (ret != LDB_SUCCESS) {
2938 /* go on with the call chain - do the modify after the rename */
2939 return ldb_next_request(ac->module, down_req);
2943 * remove links from objects that point at this object when an object
2944 * is deleted. We remove it from the NEXT module per MS-DRSR 5.160
2945 * RemoveObj which states that link removal due to the object being
2946 * deleted is NOT an originating update - they just go away!
2949 static int replmd_delete_remove_link(struct ldb_module *module,
2950 const struct dsdb_schema *schema,
2952 struct ldb_message_element *el,
2953 const struct dsdb_attribute *sa,
2954 struct ldb_request *parent)
2957 TALLOC_CTX *tmp_ctx = talloc_new(module);
2958 struct ldb_context *ldb = ldb_module_get_ctx(module);
2960 for (i=0; i<el->num_values; i++) {
2961 struct dsdb_dn *dsdb_dn;
2965 struct ldb_message *msg;
2966 const struct dsdb_attribute *target_attr;
2967 struct ldb_message_element *el2;
2968 struct ldb_val dn_val;
2970 if (dsdb_dn_is_deleted_val(&el->values[i])) {
2974 dsdb_dn = dsdb_dn_parse(tmp_ctx, ldb, &el->values[i], sa->syntax->ldap_oid);
2976 talloc_free(tmp_ctx);
2977 return LDB_ERR_OPERATIONS_ERROR;
2980 status = dsdb_get_extended_dn_guid(dsdb_dn->dn, &guid2, "GUID");
2981 if (!NT_STATUS_IS_OK(status)) {
2982 talloc_free(tmp_ctx);
2983 return LDB_ERR_OPERATIONS_ERROR;
2986 /* remove the link */
2987 msg = ldb_msg_new(tmp_ctx);
2989 ldb_module_oom(module);
2990 talloc_free(tmp_ctx);
2991 return LDB_ERR_OPERATIONS_ERROR;
2995 msg->dn = dsdb_dn->dn;
2997 target_attr = dsdb_attribute_by_linkID(schema, sa->linkID ^ 1);
2998 if (target_attr == NULL) {
3002 ret = ldb_msg_add_empty(msg, target_attr->lDAPDisplayName, LDB_FLAG_MOD_DELETE, &el2);
3003 if (ret != LDB_SUCCESS) {
3004 ldb_module_oom(module);
3005 talloc_free(tmp_ctx);
3006 return LDB_ERR_OPERATIONS_ERROR;
3008 dn_val = data_blob_string_const(ldb_dn_get_linearized(dn));
3009 el2->values = &dn_val;
3010 el2->num_values = 1;
3012 ret = dsdb_module_modify(module, msg, DSDB_FLAG_OWN_MODULE, parent);
3013 if (ret != LDB_SUCCESS) {
3014 talloc_free(tmp_ctx);
3018 talloc_free(tmp_ctx);
3024 handle update of replication meta data for deletion of objects
3026 This also handles the mapping of delete to a rename operation
3027 to allow deletes to be replicated.
3029 It also handles the incoming deleted objects, to ensure they are
3030 fully deleted here. In that case re_delete is true, and we do not
3031 use this as a signal to change the deleted state, just reinforce it.
3034 static int replmd_delete_internals(struct ldb_module *module, struct ldb_request *req, bool re_delete)
3036 int ret = LDB_ERR_OTHER;
3037 bool retb, disallow_move_on_delete;
3038 struct ldb_dn *old_dn, *new_dn;
3039 const char *rdn_name;
3040 const struct ldb_val *rdn_value, *new_rdn_value;
3042 struct ldb_context *ldb = ldb_module_get_ctx(module);
3043 const struct dsdb_schema *schema;
3044 struct ldb_message *msg, *old_msg;
3045 struct ldb_message_element *el;
3046 TALLOC_CTX *tmp_ctx;
3047 struct ldb_result *res, *parent_res;
3048 const char *preserved_attrs[] = {
3049 /* yes, this really is a hard coded list. See MS-ADTS
3050 section 3.1.1.5.5.1.1 */
3051 "nTSecurityDescriptor", "attributeID", "attributeSyntax", "dNReferenceUpdate", "dNSHostName",
3052 "flatName", "governsID", "groupType", "instanceType", "lDAPDisplayName", "legacyExchangeDN",
3053 "isDeleted", "isRecycled", "lastKnownParent", "msDS-LastKnownRDN", "mS-DS-CreatorSID",
3054 "mSMQOwnerID", "nCName", "objectClass", "distinguishedName", "objectGUID", "objectSid",
3055 "oMSyntax", "proxiedObjectName", "name", "replPropertyMetaData", "sAMAccountName",
3056 "securityIdentifier", "sIDHistory", "subClassOf", "systemFlags", "trustPartner", "trustDirection",
3057 "trustType", "trustAttributes", "userAccountControl", "uSNChanged", "uSNCreated", "whenCreated",
3058 "whenChanged", NULL};
3059 unsigned int i, el_count = 0;
3060 enum deletion_state deletion_state, next_deletion_state;
3062 if (ldb_dn_is_special(req->op.del.dn)) {
3063 return ldb_next_request(module, req);
3067 * We have to allow dbcheck to remove an object that
3068 * is beyond repair, and to do so totally. This could
3069 * mean we we can get a partial object from the other
3070 * DC, causing havoc, so dbcheck suggests
3071 * re-replication first. dbcheck sets both DBCHECK
3072 * and RELAX in this situation.
3074 if (ldb_request_get_control(req, LDB_CONTROL_RELAX_OID)
3075 && ldb_request_get_control(req, DSDB_CONTROL_DBCHECK)) {
3076 /* really, really remove it */
3077 return ldb_next_request(module, req);
3080 tmp_ctx = talloc_new(ldb);
3083 return LDB_ERR_OPERATIONS_ERROR;
3086 schema = dsdb_get_schema(ldb, tmp_ctx);
3088 talloc_free(tmp_ctx);
3089 return LDB_ERR_OPERATIONS_ERROR;
3092 old_dn = ldb_dn_copy(tmp_ctx, req->op.del.dn);
3094 /* we need the complete msg off disk, so we can work out which
3095 attributes need to be removed */
3096 ret = dsdb_module_search_dn(module, tmp_ctx, &res, old_dn, NULL,
3097 DSDB_FLAG_NEXT_MODULE |
3098 DSDB_SEARCH_SHOW_RECYCLED |
3099 DSDB_SEARCH_REVEAL_INTERNALS |
3100 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT, req);
3101 if (ret != LDB_SUCCESS) {
3102 ldb_asprintf_errstring(ldb_module_get_ctx(module),
3103 "repmd_delete: Failed to %s %s, because we failed to find it: %s",
3104 re_delete ? "re-delete" : "delete",
3105 ldb_dn_get_linearized(old_dn),
3106 ldb_errstring(ldb_module_get_ctx(module)));
3107 talloc_free(tmp_ctx);
3110 old_msg = res->msgs[0];
3112 replmd_deletion_state(module, old_msg,
3114 &next_deletion_state);
3116 /* This supports us noticing an incoming isDeleted and acting on it */
3118 SMB_ASSERT(deletion_state > OBJECT_NOT_DELETED);
3119 next_deletion_state = deletion_state;
3122 if (next_deletion_state == OBJECT_REMOVED) {
3124 * We have to prevent objects being deleted, even if
3125 * the administrator really wants them gone, as
3126 * without the tombstone, we can get a partial object
3127 * from the other DC, causing havoc.
3129 * The only other valid case is when the 180 day
3130 * timeout has expired, when relax is specified.
3132 if (ldb_request_get_control(req, LDB_CONTROL_RELAX_OID)) {
3133 /* it is already deleted - really remove it this time */
3134 talloc_free(tmp_ctx);
3135 return ldb_next_request(module, req);
3138 ldb_asprintf_errstring(ldb, "Refusing to delete tombstone object %s. "
3139 "This check is to prevent corruption of the replicated state.",
3140 ldb_dn_get_linearized(old_msg->dn));
3141 return LDB_ERR_UNWILLING_TO_PERFORM;
3144 rdn_name = ldb_dn_get_rdn_name(old_dn);
3145 rdn_value = ldb_dn_get_rdn_val(old_dn);
3146 if ((rdn_name == NULL) || (rdn_value == NULL)) {
3147 talloc_free(tmp_ctx);
3148 return ldb_operr(ldb);
3151 msg = ldb_msg_new(tmp_ctx);
3153 ldb_module_oom(module);
3154 talloc_free(tmp_ctx);
3155 return LDB_ERR_OPERATIONS_ERROR;
3160 /* consider the SYSTEM_FLAG_DISALLOW_MOVE_ON_DELETE flag */
3161 disallow_move_on_delete =
3162 (ldb_msg_find_attr_as_int(old_msg, "systemFlags", 0)
3163 & SYSTEM_FLAG_DISALLOW_MOVE_ON_DELETE);
3165 /* work out where we will be renaming this object to */
3166 if (!disallow_move_on_delete) {
3167 struct ldb_dn *deleted_objects_dn;
3168 ret = dsdb_get_deleted_objects_dn(ldb, tmp_ctx, old_dn,
3169 &deleted_objects_dn);
3172 * We should not move objects if we can't find the
3173 * deleted objects DN. Not moving (or otherwise
3174 * harming) the Deleted Objects DN itself is handled
3177 if (re_delete && (ret != LDB_SUCCESS)) {
3178 new_dn = ldb_dn_get_parent(tmp_ctx, old_dn);
3179 if (new_dn == NULL) {
3180 ldb_module_oom(module);
3181 talloc_free(tmp_ctx);
3182 return LDB_ERR_OPERATIONS_ERROR;
3184 } else if (ret != LDB_SUCCESS) {
3185 /* this is probably an attempted delete on a partition
3186 * that doesn't allow delete operations, such as the
3187 * schema partition */
3188 ldb_asprintf_errstring(ldb, "No Deleted Objects container for DN %s",
3189 ldb_dn_get_linearized(old_dn));
3190 talloc_free(tmp_ctx);
3191 return LDB_ERR_UNWILLING_TO_PERFORM;
3193 new_dn = deleted_objects_dn;
3196 new_dn = ldb_dn_get_parent(tmp_ctx, old_dn);
3197 if (new_dn == NULL) {
3198 ldb_module_oom(module);
3199 talloc_free(tmp_ctx);
3200 return LDB_ERR_OPERATIONS_ERROR;
3204 if (deletion_state == OBJECT_NOT_DELETED) {
3205 /* get the objects GUID from the search we just did */
3206 guid = samdb_result_guid(old_msg, "objectGUID");
3208 /* Add a formatted child */
3209 retb = ldb_dn_add_child_fmt(new_dn, "%s=%s\\0ADEL:%s",
3211 ldb_dn_escape_value(tmp_ctx, *rdn_value),
3212 GUID_string(tmp_ctx, &guid));
3214 ldb_asprintf_errstring(ldb, __location__
3215 ": Unable to add a formatted child to dn: %s",
3216 ldb_dn_get_linearized(new_dn));
3217 talloc_free(tmp_ctx);
3218 return LDB_ERR_OPERATIONS_ERROR;
3221 ret = ldb_msg_add_string(msg, "isDeleted", "TRUE");
3222 if (ret != LDB_SUCCESS) {
3223 ldb_asprintf_errstring(ldb, __location__
3224 ": Failed to add isDeleted string to the msg");
3225 talloc_free(tmp_ctx);
3228 msg->elements[el_count++].flags = LDB_FLAG_MOD_REPLACE;
3231 * No matter what has happened with other renames etc, try again to
3232 * get this to be under the deleted DN. See MS-DRSR 5.160 RemoveObj
3235 struct ldb_dn *rdn = ldb_dn_copy(tmp_ctx, old_dn);
3236 retb = ldb_dn_remove_base_components(rdn, ldb_dn_get_comp_num(rdn) - 1);
3238 ldb_asprintf_errstring(ldb, __location__
3239 ": Unable to add a prepare rdn of %s",
3240 ldb_dn_get_linearized(rdn));
3241 talloc_free(tmp_ctx);
3242 return LDB_ERR_OPERATIONS_ERROR;
3244 SMB_ASSERT(ldb_dn_get_comp_num(rdn) == 1);
3246 retb = ldb_dn_add_child(new_dn, rdn);
3248 ldb_asprintf_errstring(ldb, __location__
3249 ": Unable to add rdn %s to base dn: %s",
3250 ldb_dn_get_linearized(rdn),
3251 ldb_dn_get_linearized(new_dn));
3252 talloc_free(tmp_ctx);
3253 return LDB_ERR_OPERATIONS_ERROR;
3258 now we need to modify the object in the following ways:
3260 - add isDeleted=TRUE
3261 - update rDN and name, with new rDN
3262 - remove linked attributes
3263 - remove objectCategory and sAMAccountType
3264 - remove attribs not on the preserved list
3265 - preserved if in above list, or is rDN
3266 - remove all linked attribs from this object
3267 - remove all links from other objects to this object
3268 - add lastKnownParent
3269 - update replPropertyMetaData?
3271 see MS-ADTS "Tombstone Requirements" section 3.1.1.5.5.1.1
3274 if (deletion_state == OBJECT_NOT_DELETED) {
3275 struct ldb_dn *parent_dn = ldb_dn_get_parent(tmp_ctx, old_dn);
3276 char *parent_dn_str = NULL;
3278 /* we need the storage form of the parent GUID */
3279 ret = dsdb_module_search_dn(module, tmp_ctx, &parent_res,
3281 DSDB_FLAG_NEXT_MODULE |
3282 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT |
3283 DSDB_SEARCH_REVEAL_INTERNALS|
3284 DSDB_SEARCH_SHOW_RECYCLED, req);
3285 if (ret != LDB_SUCCESS) {
3286 ldb_asprintf_errstring(ldb_module_get_ctx(module),
3287 "repmd_delete: Failed to %s %s, "
3288 "because we failed to find it's parent (%s): %s",
3289 re_delete ? "re-delete" : "delete",
3290 ldb_dn_get_linearized(old_dn),
3291 ldb_dn_get_linearized(parent_dn),
3292 ldb_errstring(ldb_module_get_ctx(module)));
3293 talloc_free(tmp_ctx);
3298 * Now we can use the DB version,
3299 * it will have the extended DN info in it
3301 parent_dn = parent_res->msgs[0]->dn;
3302 parent_dn_str = ldb_dn_get_extended_linearized(tmp_ctx,
3305 if (parent_dn_str == NULL) {
3306 talloc_free(tmp_ctx);
3307 return ldb_module_oom(module);
3310 ret = ldb_msg_add_steal_string(msg, "lastKnownParent",
3312 if (ret != LDB_SUCCESS) {
3313 ldb_asprintf_errstring(ldb, __location__
3314 ": Failed to add lastKnownParent "
3315 "string when deleting %s",
3316 ldb_dn_get_linearized(old_dn));
3317 talloc_free(tmp_ctx);
3320 msg->elements[el_count++].flags = LDB_FLAG_MOD_REPLACE;
3322 if (next_deletion_state == OBJECT_DELETED) {
3323 ret = ldb_msg_add_value(msg, "msDS-LastKnownRDN", rdn_value, NULL);
3324 if (ret != LDB_SUCCESS) {
3325 ldb_asprintf_errstring(ldb, __location__
3326 ": Failed to add msDS-LastKnownRDN "
3327 "string when deleting %s",
3328 ldb_dn_get_linearized(old_dn));
3329 talloc_free(tmp_ctx);
3332 msg->elements[el_count++].flags = LDB_FLAG_MOD_ADD;
3336 switch (next_deletion_state) {
3338 case OBJECT_RECYCLED:
3339 case OBJECT_TOMBSTONE:
3342 * MS-ADTS 3.1.1.5.5.1.1 Tombstone Requirements
3343 * describes what must be removed from a tombstone
3346 * MS-ADTS 3.1.1.5.5.1.3 Recycled-Object Requirements
3347 * describes what must be removed from a recycled
3353 * we also mark it as recycled, meaning this object can't be
3354 * recovered (we are stripping its attributes).
3355 * This is done only if we have this schema object of course ...
3356 * This behavior is identical to the one of Windows 2008R2 which
3357 * always set the isRecycled attribute, even if the recycle-bin is
3358 * not activated and what ever the forest level is.
3360 if (dsdb_attribute_by_lDAPDisplayName(schema, "isRecycled") != NULL) {
3361 ret = ldb_msg_add_string(msg, "isRecycled", "TRUE");
3362 if (ret != LDB_SUCCESS) {
3363 DEBUG(0,(__location__ ": Failed to add isRecycled string to the msg\n"));
3364 ldb_module_oom(module);
3365 talloc_free(tmp_ctx);
3368 msg->elements[el_count++].flags = LDB_FLAG_MOD_REPLACE;
3371 /* work out which of the old attributes we will be removing */
3372 for (i=0; i<old_msg->num_elements; i++) {
3373 const struct dsdb_attribute *sa;
3374 el = &old_msg->elements[i];
3375 sa = dsdb_attribute_by_lDAPDisplayName(schema, el->name);
3377 talloc_free(tmp_ctx);
3378 return LDB_ERR_OPERATIONS_ERROR;
3380 if (ldb_attr_cmp(el->name, rdn_name) == 0) {
3381 /* don't remove the rDN */
3384 if (sa->linkID && (sa->linkID & 1)) {
3386 we have a backlink in this object
3387 that needs to be removed. We're not
3388 allowed to remove it directly
3389 however, so we instead setup a
3390 modify to delete the corresponding
3393 ret = replmd_delete_remove_link(module, schema, old_dn, el, sa, req);
3394 if (ret != LDB_SUCCESS) {
3395 const char *old_dn_str
3396 = ldb_dn_get_linearized(old_dn);
3397 ldb_asprintf_errstring(ldb,
3399 ": Failed to remove backlink of "
3400 "%s when deleting %s",
3403 talloc_free(tmp_ctx);
3404 return LDB_ERR_OPERATIONS_ERROR;
3406 /* now we continue, which means we
3407 won't remove this backlink
3413 if (ldb_attr_in_list(preserved_attrs, el->name)) {
3416 if (sa->searchFlags & SEARCH_FLAG_PRESERVEONDELETE) {
3420 ret = ldb_msg_add_empty(msg, el->name, LDB_FLAG_MOD_DELETE, &el);
3421 if (ret != LDB_SUCCESS) {
3422 talloc_free(tmp_ctx);
3423 ldb_module_oom(module);
3430 case OBJECT_DELETED:
3432 * MS-ADTS 3.1.1.5.5.1.2 Deleted-Object Requirements
3433 * describes what must be removed from a deleted
3437 ret = ldb_msg_add_empty(msg, "objectCategory", LDB_FLAG_MOD_REPLACE, NULL);
3438 if (ret != LDB_SUCCESS) {
3439 talloc_free(tmp_ctx);
3440 ldb_module_oom(module);
3444 ret = ldb_msg_add_empty(msg, "sAMAccountType", LDB_FLAG_MOD_REPLACE, NULL);
3445 if (ret != LDB_SUCCESS) {
3446 talloc_free(tmp_ctx);
3447 ldb_module_oom(module);
3457 if (deletion_state == OBJECT_NOT_DELETED) {
3458 const struct dsdb_attribute *sa;
3460 /* work out what the new rdn value is, for updating the
3461 rDN and name fields */
3462 new_rdn_value = ldb_dn_get_rdn_val(new_dn);
3463 if (new_rdn_value == NULL) {
3464 talloc_free(tmp_ctx);
3465 return ldb_operr(ldb);
3468 sa = dsdb_attribute_by_lDAPDisplayName(schema, rdn_name);
3470 talloc_free(tmp_ctx);
3471 return LDB_ERR_OPERATIONS_ERROR;
3474 ret = ldb_msg_add_value(msg, sa->lDAPDisplayName, new_rdn_value,
3476 if (ret != LDB_SUCCESS) {
3477 talloc_free(tmp_ctx);
3480 el->flags = LDB_FLAG_MOD_REPLACE;
3482 el = ldb_msg_find_element(old_msg, "name");
3484 ret = ldb_msg_add_value(msg, "name", new_rdn_value, &el);
3485 if (ret != LDB_SUCCESS) {
3486 talloc_free(tmp_ctx);
3489 el->flags = LDB_FLAG_MOD_REPLACE;
3494 * TODO: Per MS-DRSR 5.160 RemoveObj we should remove links directly, not as an originating update!
3499 * No matter what has happned with other renames, try again to
3500 * get this to be under the deleted DN.
3502 if (strcmp(ldb_dn_get_linearized(old_dn), ldb_dn_get_linearized(new_dn)) != 0) {
3503 /* now rename onto the new DN */
3504 ret = dsdb_module_rename(module, old_dn, new_dn, DSDB_FLAG_NEXT_MODULE, req);
3505 if (ret != LDB_SUCCESS){
3506 DEBUG(0,(__location__ ": Failed to rename object from '%s' to '%s' - %s\n",
3507 ldb_dn_get_linearized(old_dn),
3508 ldb_dn_get_linearized(new_dn),
3509 ldb_errstring(ldb)));
3510 talloc_free(tmp_ctx);
3516 ret = dsdb_module_modify(module, msg, DSDB_FLAG_OWN_MODULE, req);
3517 if (ret != LDB_SUCCESS) {
3518 ldb_asprintf_errstring(ldb, "replmd_delete: Failed to modify object %s in delete - %s",
3519 ldb_dn_get_linearized(old_dn), ldb_errstring(ldb));
3520 talloc_free(tmp_ctx);
3524 talloc_free(tmp_ctx);
3526 return ldb_module_done(req, NULL, NULL, LDB_SUCCESS);
3529 static int replmd_delete(struct ldb_module *module, struct ldb_request *req)
3531 return replmd_delete_internals(module, req, false);
3535 static int replmd_replicated_request_error(struct replmd_replicated_request *ar, int ret)
3540 static int replmd_replicated_request_werror(struct replmd_replicated_request *ar, WERROR status)
3542 int ret = LDB_ERR_OTHER;
3543 /* TODO: do some error mapping */
3545 /* Let the caller know the full WERROR */
3546 ar->objs->error = status;
3552 static struct replPropertyMetaData1 *
3553 replmd_replPropertyMetaData1_find_attid(struct replPropertyMetaDataBlob *md_blob,
3554 enum drsuapi_DsAttributeId attid)
3557 struct replPropertyMetaDataCtr1 *rpmd_ctr = &md_blob->ctr.ctr1;
3559 for (i = 0; i < rpmd_ctr->count; i++) {
3560 if (rpmd_ctr->array[i].attid == attid) {
3561 return &rpmd_ctr->array[i];
3569 return true if an update is newer than an existing entry
3570 see section 5.11 of MS-ADTS
3572 static bool replmd_update_is_newer(const struct GUID *current_invocation_id,
3573 const struct GUID *update_invocation_id,
3574 uint32_t current_version,
3575 uint32_t update_version,
3576 NTTIME current_change_time,
3577 NTTIME update_change_time)
3579 if (update_version != current_version) {
3580 return update_version > current_version;
3582 if (update_change_time != current_change_time) {
3583 return update_change_time > current_change_time;
3585 return GUID_compare(update_invocation_id, current_invocation_id) > 0;
3588 static bool replmd_replPropertyMetaData1_is_newer(struct replPropertyMetaData1 *cur_m,
3589 struct replPropertyMetaData1 *new_m)
3591 return replmd_update_is_newer(&cur_m->originating_invocation_id,
3592 &new_m->originating_invocation_id,
3595 cur_m->originating_change_time,
3596 new_m->originating_change_time);
3599 static bool replmd_replPropertyMetaData1_new_should_be_taken(uint32_t dsdb_repl_flags,
3600 struct replPropertyMetaData1 *cur_m,
3601 struct replPropertyMetaData1 *new_m)
3606 * If the new replPropertyMetaData entry for this attribute is
3607 * not provided (this happens in the case where we look for
3608 * ATTID_name, but the name was not changed), then the local
3609 * state is clearly still current, as the remote
3610 * server didn't send it due to being older the high watermark
3613 if (new_m == NULL) {
3617 if (dsdb_repl_flags & DSDB_REPL_FLAG_PRIORITISE_INCOMING) {
3619 * if we compare equal then do an
3620 * update. This is used when a client
3621 * asks for a FULL_SYNC, and can be
3622 * used to recover a corrupt
3625 * This call is a bit tricky, what we
3626 * are doing it turning the 'is_newer'
3627 * call into a 'not is older' by
3628 * swapping cur_m and new_m, and negating the
3631 cmp = !replmd_replPropertyMetaData1_is_newer(new_m,
3634 cmp = replmd_replPropertyMetaData1_is_newer(cur_m,
3644 static struct ldb_dn *replmd_conflict_dn(TALLOC_CTX *mem_ctx, struct ldb_dn *dn, struct GUID *guid)
3646 const struct ldb_val *rdn_val;
3647 const char *rdn_name;
3648 struct ldb_dn *new_dn;
3650 rdn_val = ldb_dn_get_rdn_val(dn);
3651 rdn_name = ldb_dn_get_rdn_name(dn);
3652 if (!rdn_val || !rdn_name) {
3656 new_dn = ldb_dn_copy(mem_ctx, dn);
3661 if (!ldb_dn_remove_child_components(new_dn, 1)) {
3665 if (!ldb_dn_add_child_fmt(new_dn, "%s=%s\\0ACNF:%s",
3667 ldb_dn_escape_value(new_dn, *rdn_val),
3668 GUID_string(new_dn, guid))) {
3677 perform a modify operation which sets the rDN and name attributes to
3678 their current values. This has the effect of changing these
3679 attributes to have been last updated by the current DC. This is
3680 needed to ensure that renames performed as part of conflict
3681 resolution are propogated to other DCs
3683 static int replmd_name_modify(struct replmd_replicated_request *ar,
3684 struct ldb_request *req, struct ldb_dn *dn)
3686 struct ldb_message *msg;
3687 const char *rdn_name;
3688 const struct ldb_val *rdn_val;
3689 const struct dsdb_attribute *rdn_attr;
3692 msg = ldb_msg_new(req);
3698 rdn_name = ldb_dn_get_rdn_name(dn);
3699 if (rdn_name == NULL) {
3703 /* normalize the rdn attribute name */
3704 rdn_attr = dsdb_attribute_by_lDAPDisplayName(ar->schema, rdn_name);
3705 if (rdn_attr == NULL) {
3708 rdn_name = rdn_attr->lDAPDisplayName;
3710 rdn_val = ldb_dn_get_rdn_val(dn);
3711 if (rdn_val == NULL) {
3715 if (ldb_msg_add_empty(msg, rdn_name, LDB_FLAG_MOD_REPLACE, NULL) != 0) {
3718 if (ldb_msg_add_value(msg, rdn_name, rdn_val, NULL) != 0) {
3721 if (ldb_msg_add_empty(msg, "name", LDB_FLAG_MOD_REPLACE, NULL) != 0) {
3724 if (ldb_msg_add_value(msg, "name", rdn_val, NULL) != 0) {
3728 ret = dsdb_module_modify(ar->module, msg, DSDB_FLAG_OWN_MODULE, req);
3729 if (ret != LDB_SUCCESS) {
3730 DEBUG(0,(__location__ ": Failed to modify rDN/name of conflict DN '%s' - %s",
3731 ldb_dn_get_linearized(dn),
3732 ldb_errstring(ldb_module_get_ctx(ar->module))));
3742 DEBUG(0,(__location__ ": Failed to setup modify rDN/name of conflict DN '%s'",
3743 ldb_dn_get_linearized(dn)));
3744 return LDB_ERR_OPERATIONS_ERROR;
3749 callback for conflict DN handling where we have renamed the incoming
3750 record. After renaming it, we need to ensure the change of name and
3751 rDN for the incoming record is seen as an originating update by this DC.
3753 This also handles updating lastKnownParent for entries sent to lostAndFound
3755 static int replmd_op_name_modify_callback(struct ldb_request *req, struct ldb_reply *ares)
3757 struct replmd_replicated_request *ar =
3758 talloc_get_type_abort(req->context, struct replmd_replicated_request);
3759 struct ldb_dn *conflict_dn = NULL;
3762 if (ares->error != LDB_SUCCESS) {
3763 /* call the normal callback for everything except success */
3764 return replmd_op_callback(req, ares);
3767 switch (req->operation) {
3769 conflict_dn = req->op.add.message->dn;
3772 conflict_dn = req->op.mod.message->dn;
3775 smb_panic("replmd_op_name_modify_callback called in unknown circumstances");
3778 /* perform a modify of the rDN and name of the record */
3779 ret = replmd_name_modify(ar, req, conflict_dn);
3780 if (ret != LDB_SUCCESS) {
3782 return replmd_op_callback(req, ares);
3785 if (ar->objs->objects[ar->index_current].last_known_parent) {
3786 struct ldb_message *msg = ldb_msg_new(req);
3788 ldb_module_oom(ar->module);
3789 return LDB_ERR_OPERATIONS_ERROR;
3792 msg->dn = req->op.add.message->dn;
3794 ret = ldb_msg_add_steal_string(msg, "lastKnownParent",
3795 ldb_dn_get_extended_linearized(msg, ar->objs->objects[ar->index_current].last_known_parent, 1));
3796 if (ret != LDB_SUCCESS) {
3797 DEBUG(0,(__location__ ": Failed to add lastKnownParent string to the msg\n"));
3798 ldb_module_oom(ar->module);
3801 msg->elements[0].flags = LDB_FLAG_MOD_REPLACE;
3803 ret = dsdb_module_modify(ar->module, msg, DSDB_FLAG_OWN_MODULE, req);
3804 if (ret != LDB_SUCCESS) {
3805 DEBUG(0,(__location__ ": Failed to modify lastKnownParent of lostAndFound DN '%s' - %s",
3806 ldb_dn_get_linearized(msg->dn),
3807 ldb_errstring(ldb_module_get_ctx(ar->module))));
3813 return replmd_op_callback(req, ares);
3817 callback for replmd_replicated_apply_add()
3818 This copes with the creation of conflict records in the case where
3819 the DN exists, but with a different objectGUID
3821 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))
3823 struct ldb_dn *conflict_dn;
3824 struct replmd_replicated_request *ar =
3825 talloc_get_type_abort(req->context, struct replmd_replicated_request);
3826 struct ldb_result *res;
3827 const char *attrs[] = { "replPropertyMetaData", "objectGUID", NULL };
3829 const struct ldb_val *omd_value;
3830 struct replPropertyMetaDataBlob omd, *rmd;
3831 enum ndr_err_code ndr_err;
3832 bool rename_incoming_record, rodc;
3833 struct replPropertyMetaData1 *rmd_name, *omd_name;
3834 struct ldb_message *msg;
3835 struct ldb_request *down_req = NULL;
3837 /* call the normal callback for success */
3838 if (ares->error == LDB_SUCCESS) {
3839 return callback(req, ares);
3843 * we have a conflict, and need to decide if we will keep the
3844 * new record or the old record
3847 msg = ar->objs->objects[ar->index_current].msg;
3848 conflict_dn = msg->dn;
3850 /* For failures other than conflicts, fail the whole operation here */
3851 if (ares->error != LDB_ERR_ENTRY_ALREADY_EXISTS) {
3852 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module), "Failed to locally apply remote add of %s: %s",
3853 ldb_dn_get_linearized(conflict_dn),
3854 ldb_errstring(ldb_module_get_ctx(ar->module)));
3856 return ldb_module_done(ar->req, NULL, NULL,
3857 LDB_ERR_OPERATIONS_ERROR);
3860 ret = samdb_rodc(ldb_module_get_ctx(ar->module), &rodc);
3861 if (ret != LDB_SUCCESS) {
3862 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)));
3863 return ldb_module_done(ar->req, NULL, NULL,
3864 LDB_ERR_OPERATIONS_ERROR);
3870 * We are on an RODC, or were a GC for this
3871 * partition, so we have to fail this until
3872 * someone who owns the partition sorts it
3875 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
3876 "Conflict adding object '%s' from incoming replication as we are read only for the partition. \n"
3877 " - We must fail the operation until a master for this partition resolves the conflict",
3878 ldb_dn_get_linearized(conflict_dn));
3883 * first we need the replPropertyMetaData attribute from the
3884 * local, conflicting record
3886 ret = dsdb_module_search_dn(ar->module, req, &res, conflict_dn,
3888 DSDB_FLAG_NEXT_MODULE |
3889 DSDB_SEARCH_SHOW_DELETED |
3890 DSDB_SEARCH_SHOW_RECYCLED, req);
3891 if (ret != LDB_SUCCESS) {
3892 DEBUG(0,(__location__ ": Unable to find object for conflicting record '%s'\n",
3893 ldb_dn_get_linearized(conflict_dn)));
3897 omd_value = ldb_msg_find_ldb_val(res->msgs[0], "replPropertyMetaData");
3898 if (omd_value == NULL) {
3899 DEBUG(0,(__location__ ": Unable to find replPropertyMetaData for conflicting record '%s'\n",
3900 ldb_dn_get_linearized(conflict_dn)));
3904 ndr_err = ndr_pull_struct_blob(omd_value, res->msgs[0], &omd,
3905 (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
3906 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
3907 DEBUG(0,(__location__ ": Failed to parse old replPropertyMetaData for %s\n",
3908 ldb_dn_get_linearized(conflict_dn)));
3912 rmd = ar->objs->objects[ar->index_current].meta_data;
3915 * we decide which is newer based on the RPMD on the name
3916 * attribute. See [MS-DRSR] ResolveNameConflict.
3918 * We expect omd_name to be present, as this is from a local
3919 * search, but while rmd_name should have been given to us by
3920 * the remote server, if it is missing we just prefer the
3922 * replmd_replPropertyMetaData1_new_should_be_taken()
3924 rmd_name = replmd_replPropertyMetaData1_find_attid(rmd, DRSUAPI_ATTID_name);
3925 omd_name = replmd_replPropertyMetaData1_find_attid(&omd, DRSUAPI_ATTID_name);
3927 DEBUG(0,(__location__ ": Failed to find name attribute in local LDB replPropertyMetaData for %s\n",
3928 ldb_dn_get_linearized(conflict_dn)));
3933 * Should we preserve the current record, and so rename the
3934 * incoming record to be a conflict?
3936 rename_incoming_record
3937 = !replmd_replPropertyMetaData1_new_should_be_taken(ar->objs->dsdb_repl_flags & DSDB_REPL_FLAG_PRIORITISE_INCOMING,
3938 omd_name, rmd_name);
3940 if (rename_incoming_record) {
3942 struct ldb_dn *new_dn;
3944 guid = samdb_result_guid(msg, "objectGUID");
3945 if (GUID_all_zero(&guid)) {
3946 DEBUG(0,(__location__ ": Failed to find objectGUID for conflicting incoming record %s\n",
3947 ldb_dn_get_linearized(conflict_dn)));
3950 new_dn = replmd_conflict_dn(req, conflict_dn, &guid);
3951 if (new_dn == NULL) {
3952 DEBUG(0,(__location__ ": Failed to form conflict DN for %s\n",
3953 ldb_dn_get_linearized(conflict_dn)));
3957 DEBUG(2,(__location__ ": Resolving conflict record via incoming rename '%s' -> '%s'\n",
3958 ldb_dn_get_linearized(conflict_dn), ldb_dn_get_linearized(new_dn)));
3960 /* re-submit the request, but with the new DN */
3961 callback = replmd_op_name_modify_callback;
3964 /* we are renaming the existing record */
3966 struct ldb_dn *new_dn;
3968 guid = samdb_result_guid(res->msgs[0], "objectGUID");
3969 if (GUID_all_zero(&guid)) {
3970 DEBUG(0,(__location__ ": Failed to find objectGUID for existing conflict record %s\n",
3971 ldb_dn_get_linearized(conflict_dn)));
3975 new_dn = replmd_conflict_dn(req, conflict_dn, &guid);
3976 if (new_dn == NULL) {
3977 DEBUG(0,(__location__ ": Failed to form conflict DN for %s\n",
3978 ldb_dn_get_linearized(conflict_dn)));
3982 DEBUG(2,(__location__ ": Resolving conflict record via existing-record rename '%s' -> '%s'\n",
3983 ldb_dn_get_linearized(conflict_dn), ldb_dn_get_linearized(new_dn)));
3985 ret = dsdb_module_rename(ar->module, conflict_dn, new_dn,
3986 DSDB_FLAG_OWN_MODULE, req);
3987 if (ret != LDB_SUCCESS) {
3988 DEBUG(0,(__location__ ": Failed to rename conflict dn '%s' to '%s' - %s\n",
3989 ldb_dn_get_linearized(conflict_dn),
3990 ldb_dn_get_linearized(new_dn),
3991 ldb_errstring(ldb_module_get_ctx(ar->module))));
3996 * now we need to ensure that the rename is seen as an
3997 * originating update. We do that with a modify.
3999 ret = replmd_name_modify(ar, req, new_dn);
4000 if (ret != LDB_SUCCESS) {
4004 DEBUG(2,(__location__ ": With conflicting record renamed, re-apply replicated creation of '%s'\n",
4005 ldb_dn_get_linearized(req->op.add.message->dn)));
4008 ret = ldb_build_add_req(&down_req,
4009 ldb_module_get_ctx(ar->module),
4016 if (ret != LDB_SUCCESS) {
4019 LDB_REQ_SET_LOCATION(down_req);
4021 /* current partition control needed by "repmd_op_callback" */
4022 ret = ldb_request_add_control(down_req,
4023 DSDB_CONTROL_CURRENT_PARTITION_OID,
4025 if (ret != LDB_SUCCESS) {
4026 return replmd_replicated_request_error(ar, ret);
4029 if (ar->objs->dsdb_repl_flags & DSDB_REPL_FLAG_PARTIAL_REPLICA) {
4030 /* this tells the partition module to make it a
4031 partial replica if creating an NC */
4032 ret = ldb_request_add_control(down_req,
4033 DSDB_CONTROL_PARTIAL_REPLICA,
4035 if (ret != LDB_SUCCESS) {
4036 return replmd_replicated_request_error(ar, ret);
4041 * Finally we re-run the add, otherwise the new record won't
4042 * exist, as we are here because of that exact failure!
4044 return ldb_next_request(ar->module, down_req);
4047 /* on failure make the caller get the error. This means
4048 * replication will stop with an error, but there is not much
4051 return ldb_module_done(ar->req, NULL, NULL,
4056 callback for replmd_replicated_apply_add()
4057 This copes with the creation of conflict records in the case where
4058 the DN exists, but with a different objectGUID
4060 static int replmd_op_add_callback(struct ldb_request *req, struct ldb_reply *ares)
4062 struct replmd_replicated_request *ar =
4063 talloc_get_type_abort(req->context, struct replmd_replicated_request);
4065 if (ar->objs->objects[ar->index_current].last_known_parent) {
4066 /* This is like a conflict DN, where we put the object in LostAndFound
4067 see MS-DRSR 4.1.10.6.10 FindBestParentObject */
4068 return replmd_op_possible_conflict_callback(req, ares, replmd_op_name_modify_callback);
4071 return replmd_op_possible_conflict_callback(req, ares, replmd_op_callback);
4075 this is called when a new object comes in over DRS
4077 static int replmd_replicated_apply_add(struct replmd_replicated_request *ar)
4079 struct ldb_context *ldb;
4080 struct ldb_request *change_req;
4081 enum ndr_err_code ndr_err;
4082 struct ldb_message *msg;
4083 struct replPropertyMetaDataBlob *md;
4084 struct ldb_val md_value;
4087 bool remote_isDeleted = false;
4090 time_t t = time(NULL);
4091 const struct ldb_val *rdn_val;
4092 struct replmd_private *replmd_private =
4093 talloc_get_type(ldb_module_get_private(ar->module),
4094 struct replmd_private);
4095 unix_to_nt_time(&now, t);
4097 ldb = ldb_module_get_ctx(ar->module);
4098 msg = ar->objs->objects[ar->index_current].msg;
4099 md = ar->objs->objects[ar->index_current].meta_data;
4100 is_schema_nc = ldb_dn_compare_base(replmd_private->schema_dn, msg->dn) == 0;
4102 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &ar->seq_num);
4103 if (ret != LDB_SUCCESS) {
4104 return replmd_replicated_request_error(ar, ret);
4107 ret = dsdb_msg_add_guid(msg,
4108 &ar->objs->objects[ar->index_current].object_guid,
4110 if (ret != LDB_SUCCESS) {
4111 return replmd_replicated_request_error(ar, ret);
4114 ret = ldb_msg_add_string(msg, "whenChanged", ar->objs->objects[ar->index_current].when_changed);
4115 if (ret != LDB_SUCCESS) {
4116 return replmd_replicated_request_error(ar, ret);
4119 ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNCreated", ar->seq_num);
4120 if (ret != LDB_SUCCESS) {
4121 return replmd_replicated_request_error(ar, ret);
4124 ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNChanged", ar->seq_num);
4125 if (ret != LDB_SUCCESS) {
4126 return replmd_replicated_request_error(ar, ret);
4129 /* remove any message elements that have zero values */
4130 for (i=0; i<msg->num_elements; i++) {
4131 struct ldb_message_element *el = &msg->elements[i];
4133 if (el->num_values == 0) {
4134 if (ldb_attr_cmp(msg->elements[i].name, "objectClass") == 0) {
4135 ldb_asprintf_errstring(ldb, __location__
4136 ": empty objectClass sent on %s, aborting replication\n",
4137 ldb_dn_get_linearized(msg->dn));
4138 return replmd_replicated_request_error(ar, LDB_ERR_OBJECT_CLASS_VIOLATION);
4141 DEBUG(4,(__location__ ": Removing attribute %s with num_values==0\n",
4143 memmove(el, el+1, sizeof(*el)*(msg->num_elements - (i+1)));
4144 msg->num_elements--;
4151 struct GUID_txt_buf guid_txt;
4153 char *s = ldb_ldif_message_string(ldb, ar, LDB_CHANGETYPE_ADD, msg);
4154 DEBUG(4, ("DRS replication add message of %s:\n%s\n",
4155 GUID_buf_string(&ar->objs->objects[ar->index_current].object_guid, &guid_txt),
4160 remote_isDeleted = ldb_msg_find_attr_as_bool(msg,
4161 "isDeleted", false);
4164 * the meta data array is already sorted by the caller, except
4165 * for the RDN, which needs to be added.
4169 rdn_val = ldb_dn_get_rdn_val(msg->dn);
4170 ret = replmd_update_rpmd_rdn_attr(ldb, msg, rdn_val, NULL,
4171 md, ar, now, is_schema_nc);
4172 if (ret != LDB_SUCCESS) {
4173 ldb_asprintf_errstring(ldb, "%s: error during DRS repl ADD: %s", __func__, ldb_errstring(ldb));
4174 return replmd_replicated_request_error(ar, ret);
4177 ret = replmd_replPropertyMetaDataCtr1_sort_and_verify(ldb, &md->ctr.ctr1, msg->dn);
4178 if (ret != LDB_SUCCESS) {
4179 ldb_asprintf_errstring(ldb, "%s: error during DRS repl ADD: %s", __func__, ldb_errstring(ldb));
4180 return replmd_replicated_request_error(ar, ret);
4183 for (i=0; i < md->ctr.ctr1.count; i++) {
4184 md->ctr.ctr1.array[i].local_usn = ar->seq_num;
4186 ndr_err = ndr_push_struct_blob(&md_value, msg, md,
4187 (ndr_push_flags_fn_t)ndr_push_replPropertyMetaDataBlob);
4188 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
4189 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
4190 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
4192 ret = ldb_msg_add_value(msg, "replPropertyMetaData", &md_value, NULL);
4193 if (ret != LDB_SUCCESS) {
4194 return replmd_replicated_request_error(ar, ret);
4197 replmd_ldb_message_sort(msg, ar->schema);
4199 if (!remote_isDeleted) {
4200 ret = dsdb_module_schedule_sd_propagation(ar->module,
4201 ar->objs->partition_dn,
4203 if (ret != LDB_SUCCESS) {
4204 return replmd_replicated_request_error(ar, ret);
4208 ar->isDeleted = remote_isDeleted;
4210 ret = ldb_build_add_req(&change_req,
4216 replmd_op_add_callback,
4218 LDB_REQ_SET_LOCATION(change_req);
4219 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
4221 /* current partition control needed by "repmd_op_callback" */
4222 ret = ldb_request_add_control(change_req,
4223 DSDB_CONTROL_CURRENT_PARTITION_OID,
4225 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
4227 if (ar->objs->dsdb_repl_flags & DSDB_REPL_FLAG_PARTIAL_REPLICA) {
4228 /* this tells the partition module to make it a
4229 partial replica if creating an NC */
4230 ret = ldb_request_add_control(change_req,
4231 DSDB_CONTROL_PARTIAL_REPLICA,
4233 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
4236 return ldb_next_request(ar->module, change_req);
4239 static int replmd_replicated_apply_search_for_parent_callback(struct ldb_request *req,
4240 struct ldb_reply *ares)
4242 struct replmd_replicated_request *ar = talloc_get_type(req->context,
4243 struct replmd_replicated_request);
4247 return ldb_module_done(ar->req, NULL, NULL,
4248 LDB_ERR_OPERATIONS_ERROR);
4252 * The error NO_SUCH_OBJECT is not expected, unless the search
4253 * base is the partition DN, and that case doesn't happen here
4254 * because then we wouldn't get a parent_guid_value in any
4257 if (ares->error != LDB_SUCCESS) {
4258 return ldb_module_done(ar->req, ares->controls,
4259 ares->response, ares->error);
4262 switch (ares->type) {
4263 case LDB_REPLY_ENTRY:
4265 struct ldb_message *parent_msg = ares->message;
4266 struct ldb_message *msg = ar->objs->objects[ar->index_current].msg;
4267 struct ldb_dn *parent_dn;
4270 if (!ldb_msg_check_string_attribute(msg, "isDeleted", "TRUE")
4271 && ldb_msg_check_string_attribute(parent_msg, "isDeleted", "TRUE")) {
4272 /* Per MS-DRSR 4.1.10.6.10
4273 * FindBestParentObject we need to move this
4274 * new object under a deleted object to
4276 struct ldb_dn *nc_root;
4278 ret = dsdb_find_nc_root(ldb_module_get_ctx(ar->module), msg, msg->dn, &nc_root);
4279 if (ret == LDB_ERR_NO_SUCH_OBJECT) {
4280 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
4281 "No suitable NC root found for %s. "
4282 "We need to move this object because parent object %s "
4283 "is deleted, but this object is not.",
4284 ldb_dn_get_linearized(msg->dn),
4285 ldb_dn_get_linearized(parent_msg->dn));
4286 return ldb_module_done(ar->req, NULL, NULL, LDB_ERR_OPERATIONS_ERROR);
4287 } else if (ret != LDB_SUCCESS) {
4288 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
4289 "Unable to find NC root for %s: %s. "
4290 "We need to move this object because parent object %s "
4291 "is deleted, but this object is not.",
4292 ldb_dn_get_linearized(msg->dn),
4293 ldb_errstring(ldb_module_get_ctx(ar->module)),
4294 ldb_dn_get_linearized(parent_msg->dn));
4295 return ldb_module_done(ar->req, NULL, NULL, LDB_ERR_OPERATIONS_ERROR);
4298 ret = dsdb_wellknown_dn(ldb_module_get_ctx(ar->module), msg,
4300 DS_GUID_LOSTANDFOUND_CONTAINER,
4302 if (ret != LDB_SUCCESS) {
4303 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
4304 "Unable to find LostAndFound Container for %s "
4305 "in partition %s: %s. "
4306 "We need to move this object because parent object %s "
4307 "is deleted, but this object is not.",
4308 ldb_dn_get_linearized(msg->dn), ldb_dn_get_linearized(nc_root),
4309 ldb_errstring(ldb_module_get_ctx(ar->module)),
4310 ldb_dn_get_linearized(parent_msg->dn));
4311 return ldb_module_done(ar->req, NULL, NULL, LDB_ERR_OPERATIONS_ERROR);
4313 ar->objs->objects[ar->index_current].last_known_parent
4314 = talloc_steal(ar->objs->objects[ar->index_current].msg, parent_msg->dn);
4318 = talloc_steal(ar->objs->objects[ar->index_current].msg, parent_msg->dn);
4321 ar->objs->objects[ar->index_current].local_parent_dn = parent_dn;
4323 comp_num = ldb_dn_get_comp_num(msg->dn);
4325 if (!ldb_dn_remove_base_components(msg->dn, comp_num - 1)) {
4327 return ldb_module_done(ar->req, NULL, NULL, ldb_module_operr(ar->module));
4330 if (!ldb_dn_add_base(msg->dn, parent_dn)) {
4332 return ldb_module_done(ar->req, NULL, NULL, ldb_module_operr(ar->module));
4336 case LDB_REPLY_REFERRAL:
4337 /* we ignore referrals */
4340 case LDB_REPLY_DONE:
4342 if (ar->objs->objects[ar->index_current].local_parent_dn == NULL) {
4343 struct GUID_txt_buf str_buf;
4344 if (ar->search_msg != NULL) {
4345 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
4346 "No parent with GUID %s found for object locally known as %s",
4347 GUID_buf_string(ar->objs->objects[ar->index_current].parent_guid, &str_buf),
4348 ldb_dn_get_linearized(ar->search_msg->dn));
4350 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
4351 "No parent with GUID %s found for object remotely known as %s",
4352 GUID_buf_string(ar->objs->objects[ar->index_current].parent_guid, &str_buf),
4353 ldb_dn_get_linearized(ar->objs->objects[ar->index_current].msg->dn));
4357 * This error code is really important, as it
4358 * is the flag back to the callers to retry
4359 * this with DRSUAPI_DRS_GET_ANC, and so get
4360 * the parent objects before the child
4363 return ldb_module_done(ar->req, NULL, NULL,
4364 replmd_replicated_request_werror(ar, WERR_DS_DRA_MISSING_PARENT));
4367 if (ar->search_msg != NULL) {
4368 ret = replmd_replicated_apply_merge(ar);
4370 ret = replmd_replicated_apply_add(ar);
4372 if (ret != LDB_SUCCESS) {
4373 return ldb_module_done(ar->req, NULL, NULL, ret);
4382 * Look for the parent object, so we put the new object in the right
4383 * place This is akin to NameObject in MS-DRSR - this routine and the
4384 * callbacks find the right parent name, and correct name for this
4388 static int replmd_replicated_apply_search_for_parent(struct replmd_replicated_request *ar)
4390 struct ldb_context *ldb;
4394 struct ldb_request *search_req;
4395 static const char *attrs[] = {"isDeleted", NULL};
4396 struct GUID_txt_buf guid_str_buf;
4398 ldb = ldb_module_get_ctx(ar->module);
4400 if (ar->objs->objects[ar->index_current].parent_guid == NULL) {
4401 if (ar->search_msg != NULL) {
4402 return replmd_replicated_apply_merge(ar);
4404 return replmd_replicated_apply_add(ar);
4408 tmp_str = GUID_buf_string(ar->objs->objects[ar->index_current].parent_guid,
4411 filter = talloc_asprintf(ar, "(objectGUID=%s)", tmp_str);
4412 if (!filter) return replmd_replicated_request_werror(ar, WERR_NOMEM);
4414 ret = ldb_build_search_req(&search_req,
4417 ar->objs->partition_dn,
4423 replmd_replicated_apply_search_for_parent_callback,
4425 LDB_REQ_SET_LOCATION(search_req);
4427 ret = dsdb_request_add_controls(search_req,
4428 DSDB_SEARCH_SHOW_RECYCLED|
4429 DSDB_SEARCH_SHOW_DELETED|
4430 DSDB_SEARCH_SHOW_EXTENDED_DN);
4431 if (ret != LDB_SUCCESS) {
4435 return ldb_next_request(ar->module, search_req);
4439 handle renames that come in over DRS replication
4441 static int replmd_replicated_handle_rename(struct replmd_replicated_request *ar,
4442 struct ldb_message *msg,
4443 struct ldb_request *parent,
4447 TALLOC_CTX *tmp_ctx = talloc_new(msg);
4448 struct ldb_result *res;
4449 struct ldb_dn *conflict_dn;
4450 const char *attrs[] = { "replPropertyMetaData", "objectGUID", NULL };
4451 const struct ldb_val *omd_value;
4452 struct replPropertyMetaDataBlob omd, *rmd;
4453 enum ndr_err_code ndr_err;
4454 bool rename_incoming_record, rodc;
4455 struct replPropertyMetaData1 *rmd_name, *omd_name;
4456 struct ldb_dn *new_dn;
4459 DEBUG(4,("replmd_replicated_request rename %s => %s\n",
4460 ldb_dn_get_linearized(ar->search_msg->dn),
4461 ldb_dn_get_linearized(msg->dn)));
4464 ret = dsdb_module_rename(ar->module, ar->search_msg->dn, msg->dn,
4465 DSDB_FLAG_NEXT_MODULE, ar->req);
4466 if (ret == LDB_SUCCESS) {
4467 talloc_free(tmp_ctx);
4472 if (ret != LDB_ERR_ENTRY_ALREADY_EXISTS) {
4473 talloc_free(tmp_ctx);
4474 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module), "Failed to locally apply remote rename from %s to %s: %s",
4475 ldb_dn_get_linearized(ar->search_msg->dn),
4476 ldb_dn_get_linearized(msg->dn),
4477 ldb_errstring(ldb_module_get_ctx(ar->module)));
4481 ret = samdb_rodc(ldb_module_get_ctx(ar->module), &rodc);
4482 if (ret != LDB_SUCCESS) {
4483 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
4484 "Failed to determine if we are an RODC when attempting to form conflict DN: %s",
4485 ldb_errstring(ldb_module_get_ctx(ar->module)));
4486 return LDB_ERR_OPERATIONS_ERROR;
4489 * we have a conflict, and need to decide if we will keep the
4490 * new record or the old record
4493 conflict_dn = msg->dn;
4497 * We are on an RODC, or were a GC for this
4498 * partition, so we have to fail this until
4499 * someone who owns the partition sorts it
4502 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
4503 "Conflict adding object '%s' from incoming replication but we are read only for the partition. \n"
4504 " - We must fail the operation until a master for this partition resolves the conflict",
4505 ldb_dn_get_linearized(conflict_dn));
4510 * first we need the replPropertyMetaData attribute from the
4513 ret = dsdb_module_search_dn(ar->module, tmp_ctx, &res, conflict_dn,
4515 DSDB_FLAG_NEXT_MODULE |
4516 DSDB_SEARCH_SHOW_DELETED |
4517 DSDB_SEARCH_SHOW_RECYCLED, ar->req);
4518 if (ret != LDB_SUCCESS) {
4519 DEBUG(0,(__location__ ": Unable to find object for conflicting record '%s'\n",
4520 ldb_dn_get_linearized(conflict_dn)));
4524 omd_value = ldb_msg_find_ldb_val(res->msgs[0], "replPropertyMetaData");
4525 if (omd_value == NULL) {
4526 DEBUG(0,(__location__ ": Unable to find replPropertyMetaData for conflicting record '%s'\n",
4527 ldb_dn_get_linearized(conflict_dn)));
4531 ndr_err = ndr_pull_struct_blob(omd_value, res->msgs[0], &omd,
4532 (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
4533 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
4534 DEBUG(0,(__location__ ": Failed to parse old replPropertyMetaData for %s\n",
4535 ldb_dn_get_linearized(conflict_dn)));
4539 rmd = ar->objs->objects[ar->index_current].meta_data;
4542 * we decide which is newer based on the RPMD on the name
4543 * attribute. See [MS-DRSR] ResolveNameConflict.
4545 * We expect omd_name to be present, as this is from a local
4546 * search, but while rmd_name should have been given to us by
4547 * the remote server, if it is missing we just prefer the
4549 * replmd_replPropertyMetaData1_new_should_be_taken()
4551 rmd_name = replmd_replPropertyMetaData1_find_attid(rmd, DRSUAPI_ATTID_name);
4552 omd_name = replmd_replPropertyMetaData1_find_attid(&omd, DRSUAPI_ATTID_name);
4554 DEBUG(0,(__location__ ": Failed to find name attribute in local LDB replPropertyMetaData for %s\n",
4555 ldb_dn_get_linearized(conflict_dn)));
4560 * Should we preserve the current record, and so rename the
4561 * incoming record to be a conflict?
4563 rename_incoming_record =
4564 !replmd_replPropertyMetaData1_new_should_be_taken(
4565 ar->objs->dsdb_repl_flags & DSDB_REPL_FLAG_PRIORITISE_INCOMING,
4566 omd_name, rmd_name);
4568 if (rename_incoming_record) {
4570 new_dn = replmd_conflict_dn(msg, msg->dn,
4571 &ar->objs->objects[ar->index_current].object_guid);
4572 if (new_dn == NULL) {
4573 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
4574 "Failed to form conflict DN for %s\n",
4575 ldb_dn_get_linearized(msg->dn));
4577 return replmd_replicated_request_werror(ar, WERR_NOMEM);
4580 ret = dsdb_module_rename(ar->module, ar->search_msg->dn, new_dn,
4581 DSDB_FLAG_NEXT_MODULE, ar->req);
4582 if (ret != LDB_SUCCESS) {
4583 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
4584 "Failed to rename incoming conflicting dn '%s' (was '%s') to '%s' - %s\n",
4585 ldb_dn_get_linearized(conflict_dn),
4586 ldb_dn_get_linearized(ar->search_msg->dn),
4587 ldb_dn_get_linearized(new_dn),
4588 ldb_errstring(ldb_module_get_ctx(ar->module)));
4589 return replmd_replicated_request_werror(ar, WERR_DS_DRA_DB_ERROR);
4597 /* we are renaming the existing record */
4599 guid = samdb_result_guid(res->msgs[0], "objectGUID");
4600 if (GUID_all_zero(&guid)) {
4601 DEBUG(0,(__location__ ": Failed to find objectGUID for existing conflict record %s\n",
4602 ldb_dn_get_linearized(conflict_dn)));
4606 new_dn = replmd_conflict_dn(tmp_ctx, conflict_dn, &guid);
4607 if (new_dn == NULL) {
4608 DEBUG(0,(__location__ ": Failed to form conflict DN for %s\n",
4609 ldb_dn_get_linearized(conflict_dn)));
4613 DEBUG(2,(__location__ ": Resolving conflict record via existing-record rename '%s' -> '%s'\n",
4614 ldb_dn_get_linearized(conflict_dn), ldb_dn_get_linearized(new_dn)));
4616 ret = dsdb_module_rename(ar->module, conflict_dn, new_dn,
4617 DSDB_FLAG_OWN_MODULE, ar->req);
4618 if (ret != LDB_SUCCESS) {
4619 DEBUG(0,(__location__ ": Failed to rename conflict dn '%s' to '%s' - %s\n",
4620 ldb_dn_get_linearized(conflict_dn),
4621 ldb_dn_get_linearized(new_dn),
4622 ldb_errstring(ldb_module_get_ctx(ar->module))));
4627 * now we need to ensure that the rename is seen as an
4628 * originating update. We do that with a modify.
4630 ret = replmd_name_modify(ar, ar->req, new_dn);
4631 if (ret != LDB_SUCCESS) {
4635 DEBUG(2,(__location__ ": With conflicting record renamed, re-apply replicated rename '%s' -> '%s'\n",
4636 ldb_dn_get_linearized(ar->search_msg->dn),
4637 ldb_dn_get_linearized(msg->dn)));
4640 ret = dsdb_module_rename(ar->module, ar->search_msg->dn, msg->dn,
4641 DSDB_FLAG_NEXT_MODULE, ar->req);
4642 if (ret != LDB_SUCCESS) {
4643 DEBUG(0,(__location__ ": After conflict resolution, failed to rename dn '%s' to '%s' - %s\n",
4644 ldb_dn_get_linearized(ar->search_msg->dn),
4645 ldb_dn_get_linearized(msg->dn),
4646 ldb_errstring(ldb_module_get_ctx(ar->module))));
4652 * On failure make the caller get the error
4653 * This means replication will stop with an error,
4654 * but there is not much else we can do. In the
4655 * LDB_ERR_ENTRY_ALREADY_EXISTS case this is exactly what is
4659 talloc_free(tmp_ctx);
4664 static int replmd_replicated_apply_merge(struct replmd_replicated_request *ar)
4666 struct ldb_context *ldb;
4667 struct ldb_request *change_req;
4668 enum ndr_err_code ndr_err;
4669 struct ldb_message *msg;
4670 struct replPropertyMetaDataBlob *rmd;
4671 struct replPropertyMetaDataBlob omd;
4672 const struct ldb_val *omd_value;
4673 struct replPropertyMetaDataBlob nmd;
4674 struct ldb_val nmd_value;
4675 struct GUID remote_parent_guid;
4678 unsigned int removed_attrs = 0;
4680 int (*callback)(struct ldb_request *req, struct ldb_reply *ares) = replmd_op_callback;
4681 bool isDeleted = false;
4682 bool local_isDeleted = false;
4683 bool remote_isDeleted = false;
4684 bool take_remote_isDeleted = false;
4685 bool sd_updated = false;
4686 bool renamed = false;
4687 bool is_schema_nc = false;
4689 const struct ldb_val *old_rdn, *new_rdn;
4690 struct replmd_private *replmd_private =
4691 talloc_get_type(ldb_module_get_private(ar->module),
4692 struct replmd_private);
4694 time_t t = time(NULL);
4695 unix_to_nt_time(&now, t);
4697 ldb = ldb_module_get_ctx(ar->module);
4698 msg = ar->objs->objects[ar->index_current].msg;
4700 is_schema_nc = ldb_dn_compare_base(replmd_private->schema_dn, msg->dn) == 0;
4702 rmd = ar->objs->objects[ar->index_current].meta_data;
4706 /* find existing meta data */
4707 omd_value = ldb_msg_find_ldb_val(ar->search_msg, "replPropertyMetaData");
4709 ndr_err = ndr_pull_struct_blob(omd_value, ar, &omd,
4710 (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
4711 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
4712 nt_status = ndr_map_error2ntstatus(ndr_err);
4713 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
4716 if (omd.version != 1) {
4717 return replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
4722 struct GUID_txt_buf guid_txt;
4724 char *s = ldb_ldif_message_string(ldb, ar, LDB_CHANGETYPE_MODIFY, msg);
4725 DEBUG(5, ("Initial DRS replication modify message of %s is:\n%s\n"
4728 GUID_buf_string(&ar->objs->objects[ar->index_current].object_guid, &guid_txt),
4730 ndr_print_struct_string(s,
4731 (ndr_print_fn_t)ndr_print_replPropertyMetaDataBlob,
4732 "existing replPropertyMetaData",
4734 ndr_print_struct_string(s,
4735 (ndr_print_fn_t)ndr_print_replPropertyMetaDataBlob,
4736 "incoming replPropertyMetaData",
4741 local_isDeleted = ldb_msg_find_attr_as_bool(ar->search_msg,
4742 "isDeleted", false);
4743 remote_isDeleted = ldb_msg_find_attr_as_bool(msg,
4744 "isDeleted", false);
4747 * Fill in the remote_parent_guid with the GUID or an all-zero
4750 if (ar->objs->objects[ar->index_current].parent_guid != NULL) {
4751 remote_parent_guid = *ar->objs->objects[ar->index_current].parent_guid;
4753 remote_parent_guid = GUID_zero();
4757 * To ensure we follow a complex rename chain around, we have
4758 * to confirm that the DN is the same (mostly to confirm the
4759 * RDN) and the parentGUID is the same.
4761 * This ensures we keep things under the correct parent, which
4762 * replmd_replicated_handle_rename() will do.
4765 if (strcmp(ldb_dn_get_linearized(msg->dn), ldb_dn_get_linearized(ar->search_msg->dn)) == 0
4766 && GUID_equal(&remote_parent_guid, &ar->local_parent_guid)) {
4770 * handle renames, even just by case that come in over
4771 * DRS. Changes in the parent DN don't hit us here,
4772 * because the search for a parent will clean up those
4775 * We also have already filtered out the case where
4776 * the peer has an older name to what we have (see
4777 * replmd_replicated_apply_search_callback())
4779 ret = replmd_replicated_handle_rename(ar, msg, ar->req, &renamed);
4782 if (ret != LDB_SUCCESS) {
4783 ldb_debug(ldb, LDB_DEBUG_FATAL,
4784 "replmd_replicated_request rename %s => %s failed - %s\n",
4785 ldb_dn_get_linearized(ar->search_msg->dn),
4786 ldb_dn_get_linearized(msg->dn),
4787 ldb_errstring(ldb));
4788 return replmd_replicated_request_werror(ar, WERR_DS_DRA_DB_ERROR);
4791 if (renamed == true) {
4793 * Set the callback to one that will fix up the name
4794 * metadata on the new conflict DN
4796 callback = replmd_op_name_modify_callback;
4801 nmd.ctr.ctr1.count = omd.ctr.ctr1.count + rmd->ctr.ctr1.count;
4802 nmd.ctr.ctr1.array = talloc_array(ar,
4803 struct replPropertyMetaData1,
4804 nmd.ctr.ctr1.count);
4805 if (!nmd.ctr.ctr1.array) return replmd_replicated_request_werror(ar, WERR_NOMEM);
4807 /* first copy the old meta data */
4808 for (i=0; i < omd.ctr.ctr1.count; i++) {
4809 nmd.ctr.ctr1.array[ni] = omd.ctr.ctr1.array[i];
4814 /* now merge in the new meta data */
4815 for (i=0; i < rmd->ctr.ctr1.count; i++) {
4818 for (j=0; j < ni; j++) {
4821 if (rmd->ctr.ctr1.array[i].attid != nmd.ctr.ctr1.array[j].attid) {
4825 cmp = replmd_replPropertyMetaData1_new_should_be_taken(
4826 ar->objs->dsdb_repl_flags,
4827 &nmd.ctr.ctr1.array[j],
4828 &rmd->ctr.ctr1.array[i]);
4830 /* replace the entry */
4831 nmd.ctr.ctr1.array[j] = rmd->ctr.ctr1.array[i];
4832 if (ar->seq_num == 0) {
4833 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &ar->seq_num);
4834 if (ret != LDB_SUCCESS) {
4835 return replmd_replicated_request_error(ar, ret);
4838 nmd.ctr.ctr1.array[j].local_usn = ar->seq_num;
4839 switch (nmd.ctr.ctr1.array[j].attid) {
4840 case DRSUAPI_ATTID_ntSecurityDescriptor:
4843 case DRSUAPI_ATTID_isDeleted:
4844 take_remote_isDeleted = true;
4853 if (rmd->ctr.ctr1.array[i].attid != DRSUAPI_ATTID_instanceType) {
4854 DEBUG(3,("Discarding older DRS attribute update to %s on %s from %s\n",
4855 msg->elements[i-removed_attrs].name,
4856 ldb_dn_get_linearized(msg->dn),
4857 GUID_string(ar, &rmd->ctr.ctr1.array[i].originating_invocation_id)));
4860 /* we don't want to apply this change so remove the attribute */
4861 ldb_msg_remove_element(msg, &msg->elements[i-removed_attrs]);
4868 if (found) continue;
4870 nmd.ctr.ctr1.array[ni] = rmd->ctr.ctr1.array[i];
4871 if (ar->seq_num == 0) {
4872 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &ar->seq_num);
4873 if (ret != LDB_SUCCESS) {
4874 return replmd_replicated_request_error(ar, ret);
4877 nmd.ctr.ctr1.array[ni].local_usn = ar->seq_num;
4878 switch (nmd.ctr.ctr1.array[ni].attid) {
4879 case DRSUAPI_ATTID_ntSecurityDescriptor:
4882 case DRSUAPI_ATTID_isDeleted:
4883 take_remote_isDeleted = true;
4892 * finally correct the size of the meta_data array
4894 nmd.ctr.ctr1.count = ni;
4896 new_rdn = ldb_dn_get_rdn_val(msg->dn);
4897 old_rdn = ldb_dn_get_rdn_val(ar->search_msg->dn);
4900 ret = replmd_update_rpmd_rdn_attr(ldb, msg, new_rdn, old_rdn,
4901 &nmd, ar, now, is_schema_nc);
4902 if (ret != LDB_SUCCESS) {
4903 ldb_asprintf_errstring(ldb, "%s: error during DRS repl merge: %s", __func__, ldb_errstring(ldb));
4904 return replmd_replicated_request_error(ar, ret);
4908 * sort the new meta data array
4910 ret = replmd_replPropertyMetaDataCtr1_sort_and_verify(ldb, &nmd.ctr.ctr1, msg->dn);
4911 if (ret != LDB_SUCCESS) {
4912 ldb_asprintf_errstring(ldb, "%s: error during DRS repl merge: %s", __func__, ldb_errstring(ldb));
4917 * Work out if this object is deleted, so we can prune any extra attributes. See MS-DRSR 4.1.10.6.9
4920 * This also controls SD propagation below
4922 if (take_remote_isDeleted) {
4923 isDeleted = remote_isDeleted;
4925 isDeleted = local_isDeleted;
4928 ar->isDeleted = isDeleted;
4931 * check if some replicated attributes left, otherwise skip the ldb_modify() call
4933 if (msg->num_elements == 0) {
4934 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_replicated_apply_merge[%u]: skip replace\n",
4937 return replmd_replicated_apply_isDeleted(ar);
4940 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_replicated_apply_merge[%u]: replace %u attributes\n",
4941 ar->index_current, msg->num_elements);
4947 if (sd_updated && !isDeleted) {
4948 ret = dsdb_module_schedule_sd_propagation(ar->module,
4949 ar->objs->partition_dn,
4951 if (ret != LDB_SUCCESS) {
4952 return ldb_operr(ldb);
4956 /* create the meta data value */
4957 ndr_err = ndr_push_struct_blob(&nmd_value, msg, &nmd,
4958 (ndr_push_flags_fn_t)ndr_push_replPropertyMetaDataBlob);
4959 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
4960 nt_status = ndr_map_error2ntstatus(ndr_err);
4961 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
4965 * when we know that we'll modify the record, add the whenChanged, uSNChanged
4966 * and replPopertyMetaData attributes
4968 ret = ldb_msg_add_string(msg, "whenChanged", ar->objs->objects[ar->index_current].when_changed);
4969 if (ret != LDB_SUCCESS) {
4970 return replmd_replicated_request_error(ar, ret);
4972 ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNChanged", ar->seq_num);
4973 if (ret != LDB_SUCCESS) {
4974 return replmd_replicated_request_error(ar, ret);
4976 ret = ldb_msg_add_value(msg, "replPropertyMetaData", &nmd_value, NULL);
4977 if (ret != LDB_SUCCESS) {
4978 return replmd_replicated_request_error(ar, ret);
4981 replmd_ldb_message_sort(msg, ar->schema);
4983 /* we want to replace the old values */
4984 for (i=0; i < msg->num_elements; i++) {
4985 msg->elements[i].flags = LDB_FLAG_MOD_REPLACE;
4986 if (ldb_attr_cmp(msg->elements[i].name, "objectClass") == 0) {
4987 if (msg->elements[i].num_values == 0) {
4988 ldb_asprintf_errstring(ldb, __location__
4989 ": objectClass removed on %s, aborting replication\n",
4990 ldb_dn_get_linearized(msg->dn));
4991 return replmd_replicated_request_error(ar, LDB_ERR_OBJECT_CLASS_VIOLATION);
4997 struct GUID_txt_buf guid_txt;
4999 char *s = ldb_ldif_message_string(ldb, ar, LDB_CHANGETYPE_MODIFY, msg);
5000 DEBUG(4, ("Final DRS replication modify message of %s:\n%s\n",
5001 GUID_buf_string(&ar->objs->objects[ar->index_current].object_guid, &guid_txt),
5006 ret = ldb_build_mod_req(&change_req,
5014 LDB_REQ_SET_LOCATION(change_req);
5015 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
5017 /* current partition control needed by "repmd_op_callback" */
5018 ret = ldb_request_add_control(change_req,
5019 DSDB_CONTROL_CURRENT_PARTITION_OID,
5021 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
5023 return ldb_next_request(ar->module, change_req);
5026 static int replmd_replicated_apply_search_callback(struct ldb_request *req,
5027 struct ldb_reply *ares)
5029 struct replmd_replicated_request *ar = talloc_get_type(req->context,
5030 struct replmd_replicated_request);
5034 return ldb_module_done(ar->req, NULL, NULL,
5035 LDB_ERR_OPERATIONS_ERROR);
5037 if (ares->error != LDB_SUCCESS &&
5038 ares->error != LDB_ERR_NO_SUCH_OBJECT) {
5039 return ldb_module_done(ar->req, ares->controls,
5040 ares->response, ares->error);
5043 switch (ares->type) {
5044 case LDB_REPLY_ENTRY:
5045 ar->search_msg = talloc_steal(ar, ares->message);
5048 case LDB_REPLY_REFERRAL:
5049 /* we ignore referrals */
5052 case LDB_REPLY_DONE:
5054 struct replPropertyMetaData1 *md_remote;
5055 struct replPropertyMetaData1 *md_local;
5057 struct replPropertyMetaDataBlob omd;
5058 const struct ldb_val *omd_value;
5059 struct replPropertyMetaDataBlob *rmd;
5060 struct ldb_message *msg;
5062 ar->objs->objects[ar->index_current].local_parent_dn = NULL;
5063 ar->objs->objects[ar->index_current].last_known_parent = NULL;
5066 * This is the ADD case, find the appropriate parent,
5067 * as this object doesn't exist locally:
5069 if (ar->search_msg == NULL) {
5070 ret = replmd_replicated_apply_search_for_parent(ar);
5071 if (ret != LDB_SUCCESS) {
5072 return ldb_module_done(ar->req, NULL, NULL, ret);
5079 * Otherwise, in the MERGE case, work out if we are
5080 * attempting a rename, and if so find the parent the
5081 * newly renamed object wants to belong under (which
5082 * may not be the parent in it's attached string DN
5084 rmd = ar->objs->objects[ar->index_current].meta_data;
5088 /* find existing meta data */
5089 omd_value = ldb_msg_find_ldb_val(ar->search_msg, "replPropertyMetaData");
5091 enum ndr_err_code ndr_err;
5092 ndr_err = ndr_pull_struct_blob(omd_value, ar, &omd,
5093 (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
5094 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
5095 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
5096 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
5099 if (omd.version != 1) {
5100 return replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
5104 ar->local_parent_guid = samdb_result_guid(ar->search_msg, "parentGUID");
5106 instanceType = ldb_msg_find_attr_as_int(ar->search_msg, "instanceType", 0);
5107 if (((instanceType & INSTANCE_TYPE_IS_NC_HEAD) == 0)
5108 && GUID_all_zero(&ar->local_parent_guid)) {
5109 DEBUG(0, ("Refusing to replicate new version of %s "
5110 "as local object has an all-zero parentGUID attribute, "
5111 "despite not being an NC root\n",
5112 ldb_dn_get_linearized(ar->search_msg->dn)));
5113 return replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
5117 * now we need to check for double renames. We could have a
5118 * local rename pending which our replication partner hasn't
5119 * received yet. We choose which one wins by looking at the
5120 * attribute stamps on the two objects, the newer one wins.
5122 * This also simply applies the correct algorithms for
5123 * determining if a change was made to name at all, or
5124 * if the object has just been renamed under the same
5127 md_remote = replmd_replPropertyMetaData1_find_attid(rmd, DRSUAPI_ATTID_name);
5128 md_local = replmd_replPropertyMetaData1_find_attid(&omd, DRSUAPI_ATTID_name);
5130 DEBUG(0,(__location__ ": Failed to find name attribute in local LDB replPropertyMetaData for %s\n",
5131 ldb_dn_get_linearized(ar->search_msg->dn)));
5132 return replmd_replicated_request_werror(ar, WERR_DS_DRA_DB_ERROR);
5136 * if there is no name attribute given then we have to assume the
5137 * object we've received has the older name
5139 if (replmd_replPropertyMetaData1_new_should_be_taken(
5140 ar->objs->dsdb_repl_flags & DSDB_REPL_FLAG_PRIORITISE_INCOMING,
5141 md_local, md_remote)) {
5142 struct GUID_txt_buf p_guid_local;
5143 struct GUID_txt_buf p_guid_remote;
5144 msg = ar->objs->objects[ar->index_current].msg;
5146 /* Merge on the existing object, with rename */
5148 DEBUG(4,(__location__ ": Looking for new parent for object %s currently under %s "
5149 "as incoming object changing to %s under %s\n",
5150 ldb_dn_get_linearized(ar->search_msg->dn),
5151 GUID_buf_string(&ar->local_parent_guid, &p_guid_local),
5152 ldb_dn_get_linearized(msg->dn),
5153 GUID_buf_string(ar->objs->objects[ar->index_current].parent_guid,
5155 ret = replmd_replicated_apply_search_for_parent(ar);
5157 struct GUID_txt_buf p_guid_local;
5158 struct GUID_txt_buf p_guid_remote;
5159 msg = ar->objs->objects[ar->index_current].msg;
5162 * Merge on the existing object, force no
5163 * rename (code below just to explain why in
5167 if (strcmp(ldb_dn_get_linearized(ar->search_msg->dn),
5168 ldb_dn_get_linearized(msg->dn)) == 0) {
5169 if (ar->objs->objects[ar->index_current].parent_guid != NULL &&
5170 GUID_equal(&ar->local_parent_guid,
5171 ar->objs->objects[ar->index_current].parent_guid)
5173 DEBUG(4,(__location__ ": Keeping object %s at under %s "
5174 "despite incoming object changing parent to %s\n",
5175 ldb_dn_get_linearized(ar->search_msg->dn),
5176 GUID_buf_string(&ar->local_parent_guid, &p_guid_local),
5177 GUID_buf_string(ar->objs->objects[ar->index_current].parent_guid,
5181 DEBUG(4,(__location__ ": Keeping object %s at under %s "
5182 " and rejecting older rename to %s under %s\n",
5183 ldb_dn_get_linearized(ar->search_msg->dn),
5184 GUID_buf_string(&ar->local_parent_guid, &p_guid_local),
5185 ldb_dn_get_linearized(msg->dn),
5186 GUID_buf_string(ar->objs->objects[ar->index_current].parent_guid,
5190 * This assignment ensures that the strcmp()
5191 * and GUID_equal() calls in
5192 * replmd_replicated_apply_merge() avoids the
5195 ar->objs->objects[ar->index_current].parent_guid =
5196 &ar->local_parent_guid;
5198 msg->dn = ar->search_msg->dn;
5199 ret = replmd_replicated_apply_merge(ar);
5201 if (ret != LDB_SUCCESS) {
5202 return ldb_module_done(ar->req, NULL, NULL, ret);
5211 static int replmd_replicated_uptodate_vector(struct replmd_replicated_request *ar);
5213 static int replmd_replicated_apply_next(struct replmd_replicated_request *ar)
5215 struct ldb_context *ldb;
5219 struct ldb_request *search_req;
5220 static const char *attrs[] = { "*", "parentGUID", "instanceType",
5221 "replPropertyMetaData", "nTSecurityDescriptor",
5223 struct GUID_txt_buf guid_str_buf;
5225 if (ar->index_current >= ar->objs->num_objects) {
5226 /* done with it, go to next stage */
5227 return replmd_replicated_uptodate_vector(ar);
5230 ldb = ldb_module_get_ctx(ar->module);
5231 ar->search_msg = NULL;
5232 ar->isDeleted = false;
5234 tmp_str = GUID_buf_string(&ar->objs->objects[ar->index_current].object_guid,
5237 filter = talloc_asprintf(ar, "(objectGUID=%s)", tmp_str);
5238 if (!filter) return replmd_replicated_request_werror(ar, WERR_NOMEM);
5240 ret = ldb_build_search_req(&search_req,
5243 ar->objs->partition_dn,
5249 replmd_replicated_apply_search_callback,
5251 LDB_REQ_SET_LOCATION(search_req);
5253 ret = dsdb_request_add_controls(search_req, DSDB_SEARCH_SHOW_RECYCLED);
5255 if (ret != LDB_SUCCESS) {
5259 return ldb_next_request(ar->module, search_req);
5263 * This is essentially a wrapper for replmd_replicated_apply_next()
5265 * This is needed to ensure that both codepaths call this handler.
5267 static int replmd_replicated_apply_isDeleted(struct replmd_replicated_request *ar)
5269 struct ldb_dn *deleted_objects_dn;
5270 struct ldb_message *msg = ar->objs->objects[ar->index_current].msg;
5271 int ret = dsdb_get_deleted_objects_dn(ldb_module_get_ctx(ar->module), msg, msg->dn,
5272 &deleted_objects_dn);
5273 if (ar->isDeleted && (ret != LDB_SUCCESS || ldb_dn_compare(msg->dn, deleted_objects_dn) != 0)) {
5275 * Do a delete here again, so that if there is
5276 * anything local that conflicts with this
5277 * object being deleted, it is removed. This
5278 * includes links. See MS-DRSR 4.1.10.6.9
5281 * If the object is already deleted, and there
5282 * is no more work required, it doesn't do
5286 /* This has been updated to point to the DN we eventually did the modify on */
5288 struct ldb_request *del_req;
5289 struct ldb_result *res;
5291 TALLOC_CTX *tmp_ctx = talloc_new(ar);
5293 ret = ldb_oom(ldb_module_get_ctx(ar->module));
5297 res = talloc_zero(tmp_ctx, struct ldb_result);
5299 ret = ldb_oom(ldb_module_get_ctx(ar->module));
5300 talloc_free(tmp_ctx);
5304 /* Build a delete request, which hopefully will artually turn into nothing */
5305 ret = ldb_build_del_req(&del_req, ldb_module_get_ctx(ar->module), tmp_ctx,
5309 ldb_modify_default_callback,
5311 LDB_REQ_SET_LOCATION(del_req);
5312 if (ret != LDB_SUCCESS) {
5313 talloc_free(tmp_ctx);
5318 * This is the guts of the call, call back
5319 * into our delete code, but setting the
5320 * re_delete flag so we delete anything that
5321 * shouldn't be there on a deleted or recycled
5324 ret = replmd_delete_internals(ar->module, del_req, true);
5325 if (ret == LDB_SUCCESS) {
5326 ret = ldb_wait(del_req->handle, LDB_WAIT_ALL);
5329 talloc_free(tmp_ctx);
5330 if (ret != LDB_SUCCESS) {
5335 ar->index_current++;
5336 return replmd_replicated_apply_next(ar);
5339 static int replmd_replicated_uptodate_modify_callback(struct ldb_request *req,
5340 struct ldb_reply *ares)
5342 struct ldb_context *ldb;
5343 struct replmd_replicated_request *ar = talloc_get_type(req->context,
5344 struct replmd_replicated_request);
5345 ldb = ldb_module_get_ctx(ar->module);
5348 return ldb_module_done(ar->req, NULL, NULL,
5349 LDB_ERR_OPERATIONS_ERROR);
5351 if (ares->error != LDB_SUCCESS) {
5352 return ldb_module_done(ar->req, ares->controls,
5353 ares->response, ares->error);
5356 if (ares->type != LDB_REPLY_DONE) {
5357 ldb_asprintf_errstring(ldb, "Invalid LDB reply type %d", ares->type);
5358 return ldb_module_done(ar->req, NULL, NULL,
5359 LDB_ERR_OPERATIONS_ERROR);
5364 return ldb_module_done(ar->req, NULL, NULL, LDB_SUCCESS);
5367 static int replmd_replicated_uptodate_modify(struct replmd_replicated_request *ar)
5369 struct ldb_context *ldb;
5370 struct ldb_request *change_req;
5371 enum ndr_err_code ndr_err;
5372 struct ldb_message *msg;
5373 struct replUpToDateVectorBlob ouv;
5374 const struct ldb_val *ouv_value;
5375 const struct drsuapi_DsReplicaCursor2CtrEx *ruv;
5376 struct replUpToDateVectorBlob nuv;
5377 struct ldb_val nuv_value;
5378 struct ldb_message_element *nuv_el = NULL;
5379 struct ldb_message_element *orf_el = NULL;
5380 struct repsFromToBlob nrf;
5381 struct ldb_val *nrf_value = NULL;
5382 struct ldb_message_element *nrf_el = NULL;
5386 time_t t = time(NULL);
5389 uint32_t instanceType;
5391 ldb = ldb_module_get_ctx(ar->module);
5392 ruv = ar->objs->uptodateness_vector;
5398 unix_to_nt_time(&now, t);
5400 if (ar->search_msg == NULL) {
5401 /* this happens for a REPL_OBJ call where we are
5402 creating the target object by replicating it. The
5403 subdomain join code does this for the partition DN
5405 DEBUG(4,(__location__ ": Skipping UDV and repsFrom update as no target DN\n"));
5406 return ldb_module_done(ar->req, NULL, NULL, LDB_SUCCESS);
5409 instanceType = ldb_msg_find_attr_as_uint(ar->search_msg, "instanceType", 0);
5410 if (! (instanceType & INSTANCE_TYPE_IS_NC_HEAD)) {
5411 DEBUG(4,(__location__ ": Skipping UDV and repsFrom update as not NC root: %s\n",
5412 ldb_dn_get_linearized(ar->search_msg->dn)));
5413 return ldb_module_done(ar->req, NULL, NULL, LDB_SUCCESS);
5417 * first create the new replUpToDateVector
5419 ouv_value = ldb_msg_find_ldb_val(ar->search_msg, "replUpToDateVector");
5421 ndr_err = ndr_pull_struct_blob(ouv_value, ar, &ouv,
5422 (ndr_pull_flags_fn_t)ndr_pull_replUpToDateVectorBlob);
5423 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
5424 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
5425 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
5428 if (ouv.version != 2) {
5429 return replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
5434 * the new uptodateness vector will at least
5435 * contain 1 entry, one for the source_dsa
5437 * plus optional values from our old vector and the one from the source_dsa
5439 nuv.ctr.ctr2.count = ouv.ctr.ctr2.count;
5440 if (ruv) nuv.ctr.ctr2.count += ruv->count;
5441 nuv.ctr.ctr2.cursors = talloc_array(ar,
5442 struct drsuapi_DsReplicaCursor2,
5443 nuv.ctr.ctr2.count);
5444 if (!nuv.ctr.ctr2.cursors) return replmd_replicated_request_werror(ar, WERR_NOMEM);
5446 /* first copy the old vector */
5447 for (i=0; i < ouv.ctr.ctr2.count; i++) {
5448 nuv.ctr.ctr2.cursors[ni] = ouv.ctr.ctr2.cursors[i];
5452 /* merge in the source_dsa vector is available */
5453 for (i=0; (ruv && i < ruv->count); i++) {
5456 if (GUID_equal(&ruv->cursors[i].source_dsa_invocation_id,
5457 &ar->our_invocation_id)) {
5461 for (j=0; j < ni; j++) {
5462 if (!GUID_equal(&ruv->cursors[i].source_dsa_invocation_id,
5463 &nuv.ctr.ctr2.cursors[j].source_dsa_invocation_id)) {
5469 if (ruv->cursors[i].highest_usn > nuv.ctr.ctr2.cursors[j].highest_usn) {
5470 nuv.ctr.ctr2.cursors[j] = ruv->cursors[i];
5475 if (found) continue;
5477 /* if it's not there yet, add it */
5478 nuv.ctr.ctr2.cursors[ni] = ruv->cursors[i];
5483 * finally correct the size of the cursors array
5485 nuv.ctr.ctr2.count = ni;
5490 TYPESAFE_QSORT(nuv.ctr.ctr2.cursors, nuv.ctr.ctr2.count, drsuapi_DsReplicaCursor2_compare);
5493 * create the change ldb_message
5495 msg = ldb_msg_new(ar);
5496 if (!msg) return replmd_replicated_request_werror(ar, WERR_NOMEM);
5497 msg->dn = ar->search_msg->dn;
5499 ndr_err = ndr_push_struct_blob(&nuv_value, msg, &nuv,
5500 (ndr_push_flags_fn_t)ndr_push_replUpToDateVectorBlob);
5501 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
5502 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
5503 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
5505 ret = ldb_msg_add_value(msg, "replUpToDateVector", &nuv_value, &nuv_el);
5506 if (ret != LDB_SUCCESS) {
5507 return replmd_replicated_request_error(ar, ret);
5509 nuv_el->flags = LDB_FLAG_MOD_REPLACE;
5512 * now create the new repsFrom value from the given repsFromTo1 structure
5516 nrf.ctr.ctr1 = *ar->objs->source_dsa;
5517 nrf.ctr.ctr1.last_attempt = now;
5518 nrf.ctr.ctr1.last_success = now;
5519 nrf.ctr.ctr1.result_last_attempt = WERR_OK;
5522 * first see if we already have a repsFrom value for the current source dsa
5523 * if so we'll later replace this value
5525 orf_el = ldb_msg_find_element(ar->search_msg, "repsFrom");
5527 for (i=0; i < orf_el->num_values; i++) {
5528 struct repsFromToBlob *trf;
5530 trf = talloc(ar, struct repsFromToBlob);
5531 if (!trf) return replmd_replicated_request_werror(ar, WERR_NOMEM);
5533 ndr_err = ndr_pull_struct_blob(&orf_el->values[i], trf, trf,
5534 (ndr_pull_flags_fn_t)ndr_pull_repsFromToBlob);
5535 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
5536 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
5537 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
5540 if (trf->version != 1) {
5541 return replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
5545 * we compare the source dsa objectGUID not the invocation_id
5546 * because we want only one repsFrom value per source dsa
5547 * and when the invocation_id of the source dsa has changed we don't need
5548 * the old repsFrom with the old invocation_id
5550 if (!GUID_equal(&trf->ctr.ctr1.source_dsa_obj_guid,
5551 &ar->objs->source_dsa->source_dsa_obj_guid)) {
5557 nrf_value = &orf_el->values[i];
5562 * copy over all old values to the new ldb_message
5564 ret = ldb_msg_add_empty(msg, "repsFrom", 0, &nrf_el);
5565 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
5570 * if we haven't found an old repsFrom value for the current source dsa
5571 * we'll add a new value
5574 struct ldb_val zero_value;
5575 ZERO_STRUCT(zero_value);
5576 ret = ldb_msg_add_value(msg, "repsFrom", &zero_value, &nrf_el);
5577 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
5579 nrf_value = &nrf_el->values[nrf_el->num_values - 1];
5582 /* we now fill the value which is already attached to ldb_message */
5583 ndr_err = ndr_push_struct_blob(nrf_value, msg,
5585 (ndr_push_flags_fn_t)ndr_push_repsFromToBlob);
5586 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
5587 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
5588 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
5592 * the ldb_message_element for the attribute, has all the old values and the new one
5593 * so we'll replace the whole attribute with all values
5595 nrf_el->flags = LDB_FLAG_MOD_REPLACE;
5597 if (CHECK_DEBUGLVL(4)) {
5598 char *s = ldb_ldif_message_string(ldb, ar, LDB_CHANGETYPE_MODIFY, msg);
5599 DEBUG(4, ("DRS replication uptodate modify message:\n%s\n", s));
5603 /* prepare the ldb_modify() request */
5604 ret = ldb_build_mod_req(&change_req,
5610 replmd_replicated_uptodate_modify_callback,
5612 LDB_REQ_SET_LOCATION(change_req);
5613 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
5615 return ldb_next_request(ar->module, change_req);
5618 static int replmd_replicated_uptodate_search_callback(struct ldb_request *req,
5619 struct ldb_reply *ares)
5621 struct replmd_replicated_request *ar = talloc_get_type(req->context,
5622 struct replmd_replicated_request);
5626 return ldb_module_done(ar->req, NULL, NULL,
5627 LDB_ERR_OPERATIONS_ERROR);
5629 if (ares->error != LDB_SUCCESS &&
5630 ares->error != LDB_ERR_NO_SUCH_OBJECT) {
5631 return ldb_module_done(ar->req, ares->controls,
5632 ares->response, ares->error);
5635 switch (ares->type) {
5636 case LDB_REPLY_ENTRY:
5637 ar->search_msg = talloc_steal(ar, ares->message);
5640 case LDB_REPLY_REFERRAL:
5641 /* we ignore referrals */
5644 case LDB_REPLY_DONE:
5645 ret = replmd_replicated_uptodate_modify(ar);
5646 if (ret != LDB_SUCCESS) {
5647 return ldb_module_done(ar->req, NULL, NULL, ret);
5656 static int replmd_replicated_uptodate_vector(struct replmd_replicated_request *ar)
5658 struct ldb_context *ldb;
5660 static const char *attrs[] = {
5661 "replUpToDateVector",
5666 struct ldb_request *search_req;
5668 ldb = ldb_module_get_ctx(ar->module);
5669 ar->search_msg = NULL;
5671 ret = ldb_build_search_req(&search_req,
5674 ar->objs->partition_dn,
5680 replmd_replicated_uptodate_search_callback,
5682 LDB_REQ_SET_LOCATION(search_req);
5683 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
5685 return ldb_next_request(ar->module, search_req);
5690 static int replmd_extended_replicated_objects(struct ldb_module *module, struct ldb_request *req)
5692 struct ldb_context *ldb;
5693 struct dsdb_extended_replicated_objects *objs;
5694 struct replmd_replicated_request *ar;
5695 struct ldb_control **ctrls;
5698 struct replmd_private *replmd_private =
5699 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
5700 struct dsdb_control_replicated_update *rep_update;
5702 ldb = ldb_module_get_ctx(module);
5704 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_extended_replicated_objects\n");
5706 objs = talloc_get_type(req->op.extended.data, struct dsdb_extended_replicated_objects);
5708 ldb_debug(ldb, LDB_DEBUG_FATAL, "replmd_extended_replicated_objects: invalid extended data\n");
5709 return LDB_ERR_PROTOCOL_ERROR;
5712 if (objs->version != DSDB_EXTENDED_REPLICATED_OBJECTS_VERSION) {
5713 ldb_debug(ldb, LDB_DEBUG_FATAL, "replmd_extended_replicated_objects: extended data invalid version [%u != %u]\n",
5714 objs->version, DSDB_EXTENDED_REPLICATED_OBJECTS_VERSION);
5715 return LDB_ERR_PROTOCOL_ERROR;
5718 ar = replmd_ctx_init(module, req);
5720 return LDB_ERR_OPERATIONS_ERROR;
5722 /* Set the flags to have the replmd_op_callback run over the full set of objects */
5723 ar->apply_mode = true;
5725 ar->schema = dsdb_get_schema(ldb, ar);
5727 ldb_debug_set(ldb, LDB_DEBUG_FATAL, "replmd_ctx_init: no loaded schema found\n");
5729 DEBUG(0,(__location__ ": %s\n", ldb_errstring(ldb)));
5730 return LDB_ERR_CONSTRAINT_VIOLATION;
5733 ctrls = req->controls;
5735 if (req->controls) {
5736 req->controls = talloc_memdup(ar, req->controls,
5737 talloc_get_size(req->controls));
5738 if (!req->controls) return replmd_replicated_request_werror(ar, WERR_NOMEM);
5741 /* This allows layers further down to know if a change came in
5742 over replication and what the replication flags were */
5743 rep_update = talloc_zero(ar, struct dsdb_control_replicated_update);
5744 if (rep_update == NULL) {
5745 return ldb_module_oom(module);
5747 rep_update->dsdb_repl_flags = objs->dsdb_repl_flags;
5749 ret = ldb_request_add_control(req, DSDB_CONTROL_REPLICATED_UPDATE_OID, false, rep_update);
5750 if (ret != LDB_SUCCESS) {
5754 /* If this change contained linked attributes in the body
5755 * (rather than in the links section) we need to update
5756 * backlinks in linked_attributes */
5757 ret = ldb_request_add_control(req, DSDB_CONTROL_APPLY_LINKS, false, NULL);
5758 if (ret != LDB_SUCCESS) {
5762 ar->controls = req->controls;
5763 req->controls = ctrls;
5765 DEBUG(4,("linked_attributes_count=%u\n", objs->linked_attributes_count));
5767 /* save away the linked attributes for the end of the
5769 for (i=0; i<ar->objs->linked_attributes_count; i++) {
5770 struct la_entry *la_entry;
5772 if (replmd_private->la_ctx == NULL) {
5773 replmd_private->la_ctx = talloc_new(replmd_private);
5775 la_entry = talloc(replmd_private->la_ctx, struct la_entry);
5776 if (la_entry == NULL) {
5778 return LDB_ERR_OPERATIONS_ERROR;
5780 la_entry->la = talloc(la_entry, struct drsuapi_DsReplicaLinkedAttribute);
5781 if (la_entry->la == NULL) {
5782 talloc_free(la_entry);
5784 return LDB_ERR_OPERATIONS_ERROR;
5786 *la_entry->la = ar->objs->linked_attributes[i];
5788 /* we need to steal the non-scalars so they stay
5789 around until the end of the transaction */
5790 talloc_steal(la_entry->la, la_entry->la->identifier);
5791 talloc_steal(la_entry->la, la_entry->la->value.blob);
5793 DLIST_ADD(replmd_private->la_list, la_entry);
5796 return replmd_replicated_apply_next(ar);
5800 process one linked attribute structure
5802 static int replmd_process_linked_attribute(struct ldb_module *module,
5803 struct la_entry *la_entry,
5804 struct ldb_request *parent)
5806 struct drsuapi_DsReplicaLinkedAttribute *la = la_entry->la;
5807 struct ldb_context *ldb = ldb_module_get_ctx(module);
5808 struct ldb_message *msg;
5809 struct ldb_message *target_msg = NULL;
5810 TALLOC_CTX *tmp_ctx = talloc_new(la_entry);
5811 const struct dsdb_schema *schema = dsdb_get_schema(ldb, tmp_ctx);
5813 const struct dsdb_attribute *attr;
5814 struct dsdb_dn *dsdb_dn;
5815 uint64_t seq_num = 0;
5816 struct ldb_message_element *old_el;
5818 time_t t = time(NULL);
5819 struct ldb_result *res;
5820 struct ldb_result *target_res;
5821 const char *attrs[4];
5822 const char *attrs2[] = { "isDeleted", "isRecycled", NULL };
5823 struct parsed_dn *pdn_list, *pdn;
5824 struct GUID guid = GUID_zero();
5826 bool active = (la->flags & DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE)?true:false;
5827 const struct GUID *our_invocation_id;
5829 enum deletion_state deletion_state = OBJECT_NOT_DELETED;
5830 enum deletion_state target_deletion_state = OBJECT_NOT_DELETED;
5833 linked_attributes[0]:
5834 &objs->linked_attributes[i]: struct drsuapi_DsReplicaLinkedAttribute
5836 identifier: struct drsuapi_DsReplicaObjectIdentifier
5837 __ndr_size : 0x0000003a (58)
5838 __ndr_size_sid : 0x00000000 (0)
5839 guid : 8e95b6a9-13dd-4158-89db-3220a5be5cc7
5841 __ndr_size_dn : 0x00000000 (0)
5843 attid : DRSUAPI_ATTID_member (0x1F)
5844 value: struct drsuapi_DsAttributeValue
5845 __ndr_size : 0x0000007e (126)
5847 blob : DATA_BLOB length=126
5848 flags : 0x00000001 (1)
5849 1: DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE
5850 originating_add_time : Wed Sep 2 22:20:01 2009 EST
5851 meta_data: struct drsuapi_DsReplicaMetaData
5852 version : 0x00000015 (21)
5853 originating_change_time : Wed Sep 2 23:39:07 2009 EST
5854 originating_invocation_id: 794640f3-18cf-40ee-a211-a93992b67a64
5855 originating_usn : 0x000000000001e19c (123292)
5857 (for cases where the link is to a normal DN)
5858 &target: struct drsuapi_DsReplicaObjectIdentifier3
5859 __ndr_size : 0x0000007e (126)
5860 __ndr_size_sid : 0x0000001c (28)
5861 guid : 7639e594-db75-4086-b0d4-67890ae46031
5862 sid : S-1-5-21-2848215498-2472035911-1947525656-19924
5863 __ndr_size_dn : 0x00000022 (34)
5864 dn : 'CN=UOne,OU=TestOU,DC=vsofs8,DC=com'
5867 /* find the attribute being modified */
5868 attr = dsdb_attribute_by_attributeID_id(schema, la->attid);
5870 DEBUG(0, (__location__ ": Unable to find attributeID 0x%x\n", la->attid));
5871 talloc_free(tmp_ctx);
5872 return LDB_ERR_OPERATIONS_ERROR;
5875 attrs[0] = attr->lDAPDisplayName;
5876 attrs[1] = "isDeleted";
5877 attrs[2] = "isRecycled";
5880 /* get the existing message from the db for the object with
5881 this GUID, returning attribute being modified. We will then
5882 use this msg as the basis for a modify call */
5883 ret = dsdb_module_search(module, tmp_ctx, &res, NULL, LDB_SCOPE_SUBTREE, attrs,
5884 DSDB_FLAG_NEXT_MODULE |
5885 DSDB_SEARCH_SEARCH_ALL_PARTITIONS |
5886 DSDB_SEARCH_SHOW_RECYCLED |
5887 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT |
5888 DSDB_SEARCH_REVEAL_INTERNALS,
5890 "objectGUID=%s", GUID_string(tmp_ctx, &la->identifier->guid));
5891 if (ret != LDB_SUCCESS) {
5892 talloc_free(tmp_ctx);
5895 if (res->count != 1) {
5896 ldb_asprintf_errstring(ldb, "DRS linked attribute for GUID %s - DN not found",
5897 GUID_string(tmp_ctx, &la->identifier->guid));
5898 talloc_free(tmp_ctx);
5899 return LDB_ERR_NO_SUCH_OBJECT;
5904 * Check for deleted objects per MS-DRSR 4.1.10.6.13
5905 * ProcessLinkValue, because link updates are not applied to
5906 * recycled and tombstone objects. We don't have to delete
5907 * any existing link, that should have happened when the
5908 * object deletion was replicated or initiated.
5911 replmd_deletion_state(module, msg, &deletion_state, NULL);
5913 if (deletion_state >= OBJECT_RECYCLED) {
5914 talloc_free(tmp_ctx);
5918 old_el = ldb_msg_find_element(msg, attr->lDAPDisplayName);
5919 if (old_el == NULL) {
5920 ret = ldb_msg_add_empty(msg, attr->lDAPDisplayName, LDB_FLAG_MOD_REPLACE, &old_el);
5921 if (ret != LDB_SUCCESS) {
5922 ldb_module_oom(module);
5923 talloc_free(tmp_ctx);
5924 return LDB_ERR_OPERATIONS_ERROR;
5927 old_el->flags = LDB_FLAG_MOD_REPLACE;
5930 /* parse the existing links */
5931 ret = get_parsed_dns(module, tmp_ctx, old_el, &pdn_list, attr->syntax->ldap_oid, parent);
5932 if (ret != LDB_SUCCESS) {
5933 talloc_free(tmp_ctx);
5937 /* get our invocationId */
5938 our_invocation_id = samdb_ntds_invocation_id(ldb);
5939 if (!our_invocation_id) {
5940 ldb_debug_set(ldb, LDB_DEBUG_ERROR, __location__ ": unable to find invocationId\n");
5941 talloc_free(tmp_ctx);
5942 return LDB_ERR_OPERATIONS_ERROR;
5945 ret = replmd_check_upgrade_links(pdn_list, old_el->num_values, old_el, our_invocation_id);
5946 if (ret != LDB_SUCCESS) {
5947 talloc_free(tmp_ctx);
5951 status = dsdb_dn_la_from_blob(ldb, attr, schema, tmp_ctx, la->value.blob, &dsdb_dn);
5952 if (!W_ERROR_IS_OK(status)) {
5953 ldb_asprintf_errstring(ldb, "Failed to parsed linked attribute blob for %s on %s - %s\n",
5954 old_el->name, ldb_dn_get_linearized(msg->dn), win_errstr(status));
5955 talloc_free(tmp_ctx);
5956 return LDB_ERR_OPERATIONS_ERROR;
5959 ntstatus = dsdb_get_extended_dn_guid(dsdb_dn->dn, &guid, "GUID");
5960 if (!NT_STATUS_IS_OK(ntstatus) && !active) {
5962 * This strange behaviour (allowing a NULL/missing
5963 * GUID) originally comes from:
5965 * commit e3054ce0fe0f8f62d2f5b2a77893e7a1479128bd
5966 * Author: Andrew Tridgell <tridge@samba.org>
5967 * Date: Mon Dec 21 21:21:55 2009 +1100
5969 * s4-drs: cope better with NULL GUIDS from DRS
5971 * It is valid to get a NULL GUID over DRS for a deleted forward link. We
5972 * need to match by DN if possible when seeing if we should update an
5975 * Pair-Programmed-With: Andrew Bartlett <abartlet@samba.org>
5978 ret = dsdb_module_search_dn(module, tmp_ctx, &target_res,
5979 dsdb_dn->dn, attrs2,
5980 DSDB_FLAG_NEXT_MODULE |
5981 DSDB_SEARCH_SHOW_RECYCLED |
5982 DSDB_SEARCH_SEARCH_ALL_PARTITIONS |
5983 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT,
5985 } else if (!NT_STATUS_IS_OK(ntstatus)) {
5986 ldb_asprintf_errstring(ldb, "Failed to find GUID in linked attribute blob for %s on %s from %s",
5988 ldb_dn_get_linearized(dsdb_dn->dn),
5989 ldb_dn_get_linearized(msg->dn));
5990 talloc_free(tmp_ctx);
5991 return LDB_ERR_OPERATIONS_ERROR;
5993 ret = dsdb_module_search(module, tmp_ctx, &target_res,
5994 NULL, LDB_SCOPE_SUBTREE,
5996 DSDB_FLAG_NEXT_MODULE |
5997 DSDB_SEARCH_SHOW_RECYCLED |
5998 DSDB_SEARCH_SEARCH_ALL_PARTITIONS |
5999 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT,
6002 GUID_string(tmp_ctx, &guid));
6005 if (ret != LDB_SUCCESS) {
6006 ldb_asprintf_errstring(ldb_module_get_ctx(module), "Failed to re-resolve GUID %s: %s\n",
6007 GUID_string(tmp_ctx, &guid),
6008 ldb_errstring(ldb_module_get_ctx(module)));
6009 talloc_free(tmp_ctx);
6013 if (target_res->count == 0) {
6014 DEBUG(2,(__location__ ": WARNING: Failed to re-resolve GUID %s - using %s\n",
6015 GUID_string(tmp_ctx, &guid),
6016 ldb_dn_get_linearized(dsdb_dn->dn)));
6017 } else if (target_res->count != 1) {
6018 ldb_asprintf_errstring(ldb_module_get_ctx(module), "More than one object found matching objectGUID %s\n",
6019 GUID_string(tmp_ctx, &guid));
6020 talloc_free(tmp_ctx);
6021 return LDB_ERR_OPERATIONS_ERROR;
6023 target_msg = target_res->msgs[0];
6024 dsdb_dn->dn = talloc_steal(dsdb_dn, target_msg->dn);
6028 * Check for deleted objects per MS-DRSR 4.1.10.6.13
6029 * ProcessLinkValue, because link updates are not applied to
6030 * recycled and tombstone objects. We don't have to delete
6031 * any existing link, that should have happened when the
6032 * object deletion was replicated or initiated.
6034 replmd_deletion_state(module, target_msg,
6035 &target_deletion_state, NULL);
6037 if (target_deletion_state >= OBJECT_RECYCLED) {
6038 talloc_free(tmp_ctx);
6042 /* see if this link already exists */
6043 pdn = parsed_dn_find(pdn_list, old_el->num_values, &guid, dsdb_dn->dn);
6045 /* see if this update is newer than what we have already */
6046 struct GUID invocation_id = GUID_zero();
6047 uint32_t version = 0;
6048 uint32_t originating_usn = 0;
6049 NTTIME change_time = 0;
6050 uint32_t rmd_flags = dsdb_dn_rmd_flags(pdn->dsdb_dn->dn);
6052 dsdb_get_extended_dn_guid(pdn->dsdb_dn->dn, &invocation_id, "RMD_INVOCID");
6053 dsdb_get_extended_dn_uint32(pdn->dsdb_dn->dn, &version, "RMD_VERSION");
6054 dsdb_get_extended_dn_uint32(pdn->dsdb_dn->dn, &originating_usn, "RMD_ORIGINATING_USN");
6055 dsdb_get_extended_dn_nttime(pdn->dsdb_dn->dn, &change_time, "RMD_CHANGETIME");
6057 if (!replmd_update_is_newer(&invocation_id,
6058 &la->meta_data.originating_invocation_id,
6060 la->meta_data.version,
6062 la->meta_data.originating_change_time)) {
6063 DEBUG(3,("Discarding older DRS linked attribute update to %s on %s from %s\n",
6064 old_el->name, ldb_dn_get_linearized(msg->dn),
6065 GUID_string(tmp_ctx, &la->meta_data.originating_invocation_id)));
6066 talloc_free(tmp_ctx);
6070 /* get a seq_num for this change */
6071 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &seq_num);
6072 if (ret != LDB_SUCCESS) {
6073 talloc_free(tmp_ctx);
6077 if (!(rmd_flags & DSDB_RMD_FLAG_DELETED)) {
6078 /* remove the existing backlink */
6079 ret = replmd_add_backlink(module, schema, &la->identifier->guid, &guid, false, attr, true);
6080 if (ret != LDB_SUCCESS) {
6081 talloc_free(tmp_ctx);
6086 ret = replmd_update_la_val(tmp_ctx, pdn->v, dsdb_dn, pdn->dsdb_dn,
6087 &la->meta_data.originating_invocation_id,
6088 la->meta_data.originating_usn, seq_num,
6089 la->meta_data.originating_change_time,
6090 la->meta_data.version,
6092 if (ret != LDB_SUCCESS) {
6093 talloc_free(tmp_ctx);
6098 /* add the new backlink */
6099 ret = replmd_add_backlink(module, schema, &la->identifier->guid, &guid, true, attr, true);
6100 if (ret != LDB_SUCCESS) {
6101 talloc_free(tmp_ctx);
6106 /* get a seq_num for this change */
6107 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &seq_num);
6108 if (ret != LDB_SUCCESS) {
6109 talloc_free(tmp_ctx);
6113 old_el->values = talloc_realloc(msg->elements, old_el->values,
6114 struct ldb_val, old_el->num_values+1);
6115 if (!old_el->values) {
6116 ldb_module_oom(module);
6117 return LDB_ERR_OPERATIONS_ERROR;
6119 old_el->num_values++;
6121 ret = replmd_build_la_val(tmp_ctx, &old_el->values[old_el->num_values-1], dsdb_dn,
6122 &la->meta_data.originating_invocation_id,
6123 la->meta_data.originating_usn, seq_num,
6124 la->meta_data.originating_change_time,
6125 la->meta_data.version,
6126 (la->flags & DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE)?false:true);
6127 if (ret != LDB_SUCCESS) {
6128 talloc_free(tmp_ctx);
6133 ret = replmd_add_backlink(module, schema, &la->identifier->guid, &guid,
6135 if (ret != LDB_SUCCESS) {
6136 talloc_free(tmp_ctx);
6142 /* we only change whenChanged and uSNChanged if the seq_num
6144 ret = add_time_element(msg, "whenChanged", t);
6145 if (ret != LDB_SUCCESS) {
6146 talloc_free(tmp_ctx);
6151 ret = add_uint64_element(ldb, msg, "uSNChanged", seq_num);
6152 if (ret != LDB_SUCCESS) {
6153 talloc_free(tmp_ctx);
6158 old_el = ldb_msg_find_element(msg, attr->lDAPDisplayName);
6159 if (old_el == NULL) {
6160 talloc_free(tmp_ctx);
6161 return ldb_operr(ldb);
6164 ret = dsdb_check_single_valued_link(attr, old_el);
6165 if (ret != LDB_SUCCESS) {
6166 talloc_free(tmp_ctx);
6170 old_el->flags |= LDB_FLAG_INTERNAL_DISABLE_SINGLE_VALUE_CHECK;
6172 ret = dsdb_module_modify(module, msg, DSDB_FLAG_NEXT_MODULE, parent);
6173 if (ret != LDB_SUCCESS) {
6174 ldb_debug(ldb, LDB_DEBUG_WARNING, "Failed to apply linked attribute change '%s'\n%s\n",
6176 ldb_ldif_message_string(ldb, tmp_ctx, LDB_CHANGETYPE_MODIFY, msg));
6177 talloc_free(tmp_ctx);
6181 talloc_free(tmp_ctx);
6186 static int replmd_extended(struct ldb_module *module, struct ldb_request *req)
6188 if (strcmp(req->op.extended.oid, DSDB_EXTENDED_REPLICATED_OBJECTS_OID) == 0) {
6189 return replmd_extended_replicated_objects(module, req);
6192 return ldb_next_request(module, req);
6197 we hook into the transaction operations to allow us to
6198 perform the linked attribute updates at the end of the whole
6199 transaction. This allows a forward linked attribute to be created
6200 before the object is created. During a vampire, w2k8 sends us linked
6201 attributes before the objects they are part of.
6203 static int replmd_start_transaction(struct ldb_module *module)
6205 /* create our private structure for this transaction */
6206 struct replmd_private *replmd_private = talloc_get_type(ldb_module_get_private(module),
6207 struct replmd_private);
6208 replmd_txn_cleanup(replmd_private);
6210 /* free any leftover mod_usn records from cancelled
6212 while (replmd_private->ncs) {
6213 struct nc_entry *e = replmd_private->ncs;
6214 DLIST_REMOVE(replmd_private->ncs, e);
6218 return ldb_next_start_trans(module);
6222 on prepare commit we loop over our queued la_context structures and
6225 static int replmd_prepare_commit(struct ldb_module *module)
6227 struct replmd_private *replmd_private =
6228 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
6229 struct la_entry *la, *prev;
6230 struct la_backlink *bl;
6233 /* walk the list backwards, to do the first entry first, as we
6234 * added the entries with DLIST_ADD() which puts them at the
6235 * start of the list */
6236 for (la = DLIST_TAIL(replmd_private->la_list); la; la=prev) {
6237 prev = DLIST_PREV(la);
6238 DLIST_REMOVE(replmd_private->la_list, la);
6239 ret = replmd_process_linked_attribute(module, la, NULL);
6240 if (ret != LDB_SUCCESS) {
6241 replmd_txn_cleanup(replmd_private);
6246 /* process our backlink list, creating and deleting backlinks
6248 for (bl=replmd_private->la_backlinks; bl; bl=bl->next) {
6249 ret = replmd_process_backlink(module, bl, NULL);
6250 if (ret != LDB_SUCCESS) {
6251 replmd_txn_cleanup(replmd_private);
6256 replmd_txn_cleanup(replmd_private);
6258 /* possibly change @REPLCHANGED */
6259 ret = replmd_notify_store(module, NULL);
6260 if (ret != LDB_SUCCESS) {
6264 return ldb_next_prepare_commit(module);
6267 static int replmd_del_transaction(struct ldb_module *module)
6269 struct replmd_private *replmd_private =
6270 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
6271 replmd_txn_cleanup(replmd_private);
6273 return ldb_next_del_trans(module);
6277 static const struct ldb_module_ops ldb_repl_meta_data_module_ops = {
6278 .name = "repl_meta_data",
6279 .init_context = replmd_init,
6281 .modify = replmd_modify,
6282 .rename = replmd_rename,
6283 .del = replmd_delete,
6284 .extended = replmd_extended,
6285 .start_transaction = replmd_start_transaction,
6286 .prepare_commit = replmd_prepare_commit,
6287 .del_transaction = replmd_del_transaction,
6290 int ldb_repl_meta_data_module_init(const char *version)
6292 LDB_MODULE_CHECK_VERSION(version);
6293 return ldb_register_module(&ldb_repl_meta_data_module_ops);