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, time_t t,
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);
789 unix_to_nt_time(&now, t);
791 for (i=0; i<el->num_values; i++) {
792 struct ldb_val *v = &el->values[i];
793 struct dsdb_dn *dsdb_dn = dsdb_dn_parse(tmp_ctx, ldb, v, sa->syntax->ldap_oid);
794 struct GUID target_guid;
798 /* note that the DN already has the extended
799 components from the extended_dn_store module */
800 status = dsdb_get_extended_dn_guid(dsdb_dn->dn, &target_guid, "GUID");
801 if (!NT_STATUS_IS_OK(status) || GUID_all_zero(&target_guid)) {
802 ret = dsdb_module_guid_by_dn(module, dsdb_dn->dn, &target_guid, parent);
803 if (ret != LDB_SUCCESS) {
804 talloc_free(tmp_ctx);
807 ret = dsdb_set_extended_dn_guid(dsdb_dn->dn, &target_guid, "GUID");
808 if (ret != LDB_SUCCESS) {
809 talloc_free(tmp_ctx);
814 ret = replmd_build_la_val(el->values, v, dsdb_dn, invocationId,
815 seq_num, seq_num, now, 0, false);
816 if (ret != LDB_SUCCESS) {
817 talloc_free(tmp_ctx);
821 ret = replmd_add_backlink(module, schema, guid, &target_guid, true, sa, false);
822 if (ret != LDB_SUCCESS) {
823 talloc_free(tmp_ctx);
828 talloc_free(tmp_ctx);
834 intercept add requests
836 static int replmd_add(struct ldb_module *module, struct ldb_request *req)
838 struct samldb_msds_intid_persistant *msds_intid_struct;
839 struct ldb_context *ldb;
840 struct ldb_control *control;
841 struct replmd_replicated_request *ac;
842 enum ndr_err_code ndr_err;
843 struct ldb_request *down_req;
844 struct ldb_message *msg;
845 const DATA_BLOB *guid_blob;
847 struct replPropertyMetaDataBlob nmd;
848 struct ldb_val nmd_value;
851 * The use of a time_t here seems odd, but as the NTTIME
852 * elements are actually declared as NTTIME_1sec in the IDL,
853 * getting a higher resolution timestamp is not required.
855 time_t t = time(NULL);
860 unsigned int functional_level;
862 bool allow_add_guid = false;
863 bool remove_current_guid = false;
864 bool is_urgent = false;
865 bool is_schema_nc = false;
866 struct ldb_message_element *objectclass_el;
867 struct replmd_private *replmd_private =
868 talloc_get_type_abort(ldb_module_get_private(module), struct replmd_private);
870 /* check if there's a show relax control (used by provision to say 'I know what I'm doing') */
871 control = ldb_request_get_control(req, LDB_CONTROL_RELAX_OID);
873 allow_add_guid = true;
876 /* do not manipulate our control entries */
877 if (ldb_dn_is_special(req->op.add.message->dn)) {
878 return ldb_next_request(module, req);
881 ldb = ldb_module_get_ctx(module);
883 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_add\n");
885 guid_blob = ldb_msg_find_ldb_val(req->op.add.message, "objectGUID");
886 if (guid_blob != NULL) {
887 if (!allow_add_guid) {
888 ldb_set_errstring(ldb,
889 "replmd_add: it's not allowed to add an object with objectGUID!");
890 return LDB_ERR_UNWILLING_TO_PERFORM;
892 NTSTATUS status = GUID_from_data_blob(guid_blob,&guid);
893 if (!NT_STATUS_IS_OK(status)) {
894 ldb_set_errstring(ldb,
895 "replmd_add: Unable to parse the 'objectGUID' as a GUID!");
896 return LDB_ERR_UNWILLING_TO_PERFORM;
898 /* we remove this attribute as it can be a string and
899 * will not be treated correctly and then we will re-add
900 * it later on in the good format */
901 remove_current_guid = true;
905 guid = GUID_random();
908 ac = replmd_ctx_init(module, req);
910 return ldb_module_oom(module);
913 functional_level = dsdb_functional_level(ldb);
915 /* Get a sequence number from the backend */
916 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &ac->seq_num);
917 if (ret != LDB_SUCCESS) {
922 /* we have to copy the message as the caller might have it as a const */
923 msg = ldb_msg_copy_shallow(ac, req->op.add.message);
927 return LDB_ERR_OPERATIONS_ERROR;
930 /* generated times */
931 unix_to_nt_time(&now, t);
932 time_str = ldb_timestring(msg, t);
936 return LDB_ERR_OPERATIONS_ERROR;
938 if (remove_current_guid) {
939 ldb_msg_remove_attr(msg,"objectGUID");
943 * remove autogenerated attributes
945 ldb_msg_remove_attr(msg, "whenCreated");
946 ldb_msg_remove_attr(msg, "whenChanged");
947 ldb_msg_remove_attr(msg, "uSNCreated");
948 ldb_msg_remove_attr(msg, "uSNChanged");
949 ldb_msg_remove_attr(msg, "replPropertyMetaData");
952 * readd replicated attributes
954 ret = ldb_msg_add_string(msg, "whenCreated", time_str);
955 if (ret != LDB_SUCCESS) {
961 /* build the replication meta_data */
964 nmd.ctr.ctr1.count = msg->num_elements;
965 nmd.ctr.ctr1.array = talloc_array(msg,
966 struct replPropertyMetaData1,
968 if (!nmd.ctr.ctr1.array) {
971 return LDB_ERR_OPERATIONS_ERROR;
974 is_schema_nc = ldb_dn_compare_base(replmd_private->schema_dn, msg->dn) == 0;
976 for (i=0; i < msg->num_elements; i++) {
977 struct ldb_message_element *e = &msg->elements[i];
978 struct replPropertyMetaData1 *m = &nmd.ctr.ctr1.array[ni];
979 const struct dsdb_attribute *sa;
981 if (e->name[0] == '@') continue;
983 sa = dsdb_attribute_by_lDAPDisplayName(ac->schema, e->name);
985 ldb_debug_set(ldb, LDB_DEBUG_ERROR,
986 "replmd_add: attribute '%s' not defined in schema\n",
989 return LDB_ERR_NO_SUCH_ATTRIBUTE;
992 if ((sa->systemFlags & DS_FLAG_ATTR_NOT_REPLICATED) || (sa->systemFlags & DS_FLAG_ATTR_IS_CONSTRUCTED)) {
993 /* if the attribute is not replicated (0x00000001)
994 * or constructed (0x00000004) it has no metadata
999 if (sa->linkID != 0 && functional_level > DS_DOMAIN_FUNCTION_2000) {
1000 ret = replmd_add_fix_la(module, e, ac->seq_num, &ac->our_invocation_id, t, &guid, sa, req);
1001 if (ret != LDB_SUCCESS) {
1005 /* linked attributes are not stored in
1006 replPropertyMetaData in FL above w2k */
1010 m->attid = dsdb_attribute_get_attid(sa, is_schema_nc);
1012 if (m->attid == DRSUAPI_ATTID_isDeleted) {
1013 const struct ldb_val *rdn_val = ldb_dn_get_rdn_val(msg->dn);
1016 if (rdn_val == NULL) {
1019 return LDB_ERR_OPERATIONS_ERROR;
1022 rdn = (const char*)rdn_val->data;
1023 if (strcmp(rdn, "Deleted Objects") == 0) {
1025 * Set the originating_change_time to 29/12/9999 at 23:59:59
1026 * as specified in MS-ADTS 7.1.1.4.2 Deleted Objects Container
1028 m->originating_change_time = DELETED_OBJECT_CONTAINER_CHANGE_TIME;
1030 m->originating_change_time = now;
1033 m->originating_change_time = now;
1035 m->originating_invocation_id = ac->our_invocation_id;
1036 m->originating_usn = ac->seq_num;
1037 m->local_usn = ac->seq_num;
1041 /* fix meta data count */
1042 nmd.ctr.ctr1.count = ni;
1045 * sort meta data array
1047 ret = replmd_replPropertyMetaDataCtr1_sort_and_verify(ldb, &nmd.ctr.ctr1, msg->dn);
1048 if (ret != LDB_SUCCESS) {
1049 ldb_asprintf_errstring(ldb, "%s: error during direct ADD: %s", __func__, ldb_errstring(ldb));
1054 /* generated NDR encoded values */
1055 ndr_err = ndr_push_struct_blob(&nmd_value, msg,
1057 (ndr_push_flags_fn_t)ndr_push_replPropertyMetaDataBlob);
1058 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1061 return LDB_ERR_OPERATIONS_ERROR;
1065 * add the autogenerated values
1067 ret = dsdb_msg_add_guid(msg, &guid, "objectGUID");
1068 if (ret != LDB_SUCCESS) {
1073 ret = ldb_msg_add_string(msg, "whenChanged", time_str);
1074 if (ret != LDB_SUCCESS) {
1079 ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNCreated", ac->seq_num);
1080 if (ret != LDB_SUCCESS) {
1085 ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNChanged", ac->seq_num);
1086 if (ret != LDB_SUCCESS) {
1091 ret = ldb_msg_add_value(msg, "replPropertyMetaData", &nmd_value, NULL);
1092 if (ret != LDB_SUCCESS) {
1099 * sort the attributes by attid before storing the object
1101 replmd_ldb_message_sort(msg, ac->schema);
1104 * Assert that we do have an objectClass
1106 objectclass_el = ldb_msg_find_element(msg, "objectClass");
1107 if (objectclass_el == NULL) {
1108 ldb_asprintf_errstring(ldb, __location__
1109 ": objectClass missing on %s\n",
1110 ldb_dn_get_linearized(msg->dn));
1112 return LDB_ERR_OBJECT_CLASS_VIOLATION;
1114 is_urgent = replmd_check_urgent_objectclass(objectclass_el,
1115 REPL_URGENT_ON_CREATE);
1117 ac->is_urgent = is_urgent;
1118 ret = ldb_build_add_req(&down_req, ldb, ac,
1121 ac, replmd_op_callback,
1124 LDB_REQ_SET_LOCATION(down_req);
1125 if (ret != LDB_SUCCESS) {
1130 /* current partition control is needed by "replmd_op_callback" */
1131 if (ldb_request_get_control(req, DSDB_CONTROL_CURRENT_PARTITION_OID) == NULL) {
1132 ret = ldb_request_add_control(down_req,
1133 DSDB_CONTROL_CURRENT_PARTITION_OID,
1135 if (ret != LDB_SUCCESS) {
1141 if (functional_level == DS_DOMAIN_FUNCTION_2000) {
1142 ret = ldb_request_add_control(down_req, DSDB_CONTROL_APPLY_LINKS, false, NULL);
1143 if (ret != LDB_SUCCESS) {
1149 /* mark the control done */
1151 control->critical = 0;
1153 if (ldb_dn_compare_base(replmd_private->schema_dn, req->op.add.message->dn) != 0) {
1155 /* Update the usn in the SAMLDB_MSDS_INTID_OPAQUE opaque */
1156 msds_intid_struct = (struct samldb_msds_intid_persistant *) ldb_get_opaque(ldb, SAMLDB_MSDS_INTID_OPAQUE);
1157 if (msds_intid_struct) {
1158 msds_intid_struct->usn = ac->seq_num;
1161 /* go on with the call chain */
1162 return ldb_next_request(module, down_req);
1167 * update the replPropertyMetaData for one element
1169 static int replmd_update_rpmd_element(struct ldb_context *ldb,
1170 struct ldb_message *msg,
1171 struct ldb_message_element *el,
1172 struct ldb_message_element *old_el,
1173 struct replPropertyMetaDataBlob *omd,
1174 const struct dsdb_schema *schema,
1176 const struct GUID *our_invocation_id,
1179 struct ldb_request *req)
1182 const struct dsdb_attribute *a;
1183 struct replPropertyMetaData1 *md1;
1184 bool may_skip = false;
1187 a = dsdb_attribute_by_lDAPDisplayName(schema, el->name);
1189 if (ldb_request_get_control(req, LDB_CONTROL_RELAX_OID)) {
1190 /* allow this to make it possible for dbcheck
1191 to remove bad attributes */
1195 DEBUG(0,(__location__ ": Unable to find attribute %s in schema\n",
1197 return LDB_ERR_OPERATIONS_ERROR;
1200 attid = dsdb_attribute_get_attid(a, is_schema_nc);
1202 if ((a->systemFlags & DS_FLAG_ATTR_NOT_REPLICATED) || (a->systemFlags & DS_FLAG_ATTR_IS_CONSTRUCTED)) {
1207 * if the attribute's value haven't changed, and this isn't
1208 * just a delete of everything then return LDB_SUCCESS Unless
1209 * we have the provision control or if the attribute is
1210 * interSiteTopologyGenerator as this page explain:
1211 * http://support.microsoft.com/kb/224815 this attribute is
1212 * periodicaly written by the DC responsible for the intersite
1213 * generation in a given site
1215 * Unchanged could be deleting or replacing an already-gone
1216 * thing with an unconstrained delete/empty replace or a
1217 * replace with the same value, but not an add with the same
1218 * value because that could be about adding a duplicate (which
1219 * is for someone else to error out on).
1221 if (old_el != NULL && ldb_msg_element_equal_ordered(el, old_el)) {
1222 if (LDB_FLAG_MOD_TYPE(el->flags) == LDB_FLAG_MOD_REPLACE) {
1225 } else if (old_el == NULL && el->num_values == 0) {
1226 if (LDB_FLAG_MOD_TYPE(el->flags) == LDB_FLAG_MOD_REPLACE) {
1228 } else if (LDB_FLAG_MOD_TYPE(el->flags) == LDB_FLAG_MOD_DELETE) {
1234 if (strcmp(el->name, "interSiteTopologyGenerator") != 0 &&
1235 !ldb_request_get_control(req, LDB_CONTROL_PROVISION_OID)) {
1237 * allow this to make it possible for dbcheck
1238 * to rebuild broken metadata
1244 for (i=0; i<omd->ctr.ctr1.count; i++) {
1246 * First check if we find it under the msDS-IntID,
1247 * then check if we find it under the OID and
1250 * This allows the administrator to simply re-write
1251 * the attributes and so restore replication, which is
1252 * likely what they will try to do.
1254 if (attid == omd->ctr.ctr1.array[i].attid) {
1258 if (a->attributeID_id == omd->ctr.ctr1.array[i].attid) {
1263 if (a->linkID != 0 && dsdb_functional_level(ldb) > DS_DOMAIN_FUNCTION_2000) {
1264 /* linked attributes are not stored in
1265 replPropertyMetaData in FL above w2k, but we do
1266 raise the seqnum for the object */
1267 if (*seq_num == 0 &&
1268 ldb_sequence_number(ldb, LDB_SEQ_NEXT, seq_num) != LDB_SUCCESS) {
1269 return LDB_ERR_OPERATIONS_ERROR;
1274 if (i == omd->ctr.ctr1.count) {
1275 /* we need to add a new one */
1276 omd->ctr.ctr1.array = talloc_realloc(msg, omd->ctr.ctr1.array,
1277 struct replPropertyMetaData1, omd->ctr.ctr1.count+1);
1278 if (omd->ctr.ctr1.array == NULL) {
1280 return LDB_ERR_OPERATIONS_ERROR;
1282 omd->ctr.ctr1.count++;
1283 ZERO_STRUCT(omd->ctr.ctr1.array[i]);
1286 /* Get a new sequence number from the backend. We only do this
1287 * if we have a change that requires a new
1288 * replPropertyMetaData element
1290 if (*seq_num == 0) {
1291 int ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, seq_num);
1292 if (ret != LDB_SUCCESS) {
1293 return LDB_ERR_OPERATIONS_ERROR;
1297 md1 = &omd->ctr.ctr1.array[i];
1300 if (md1->attid == DRSUAPI_ATTID_isDeleted) {
1301 const struct ldb_val *rdn_val = ldb_dn_get_rdn_val(msg->dn);
1304 if (rdn_val == NULL) {
1306 return LDB_ERR_OPERATIONS_ERROR;
1309 rdn = (const char*)rdn_val->data;
1310 if (strcmp(rdn, "Deleted Objects") == 0) {
1312 * Set the originating_change_time to 29/12/9999 at 23:59:59
1313 * as specified in MS-ADTS 7.1.1.4.2 Deleted Objects Container
1315 md1->originating_change_time = DELETED_OBJECT_CONTAINER_CHANGE_TIME;
1317 md1->originating_change_time = now;
1320 md1->originating_change_time = now;
1322 md1->originating_invocation_id = *our_invocation_id;
1323 md1->originating_usn = *seq_num;
1324 md1->local_usn = *seq_num;
1330 * Bump the replPropertyMetaData version on an attribute, and if it
1331 * has changed (or forced by leaving rdn_old NULL), update the value
1334 * This is important, as calling a modify operation may not change the
1335 * version number if the values appear unchanged, but a rename between
1336 * parents bumps this value.
1339 static int replmd_update_rpmd_rdn_attr(struct ldb_context *ldb,
1340 struct ldb_message *msg,
1341 const struct ldb_val *rdn_new,
1342 const struct ldb_val *rdn_old,
1343 struct replPropertyMetaDataBlob *omd,
1344 struct replmd_replicated_request *ar,
1348 struct ldb_message_element new_el = {
1349 .flags = LDB_FLAG_MOD_REPLACE,
1350 .name = ldb_dn_get_rdn_name(msg->dn),
1352 .values = discard_const_p(struct ldb_val, rdn_new)
1354 struct ldb_message_element old_el = {
1355 .flags = LDB_FLAG_MOD_REPLACE,
1356 .name = ldb_dn_get_rdn_name(msg->dn),
1357 .num_values = rdn_old ? 1 : 0,
1358 .values = discard_const_p(struct ldb_val, rdn_old)
1361 if (ldb_msg_element_equal_ordered(&new_el, &old_el) == false) {
1362 int ret = ldb_msg_add(msg, &new_el, LDB_FLAG_MOD_REPLACE);
1363 if (ret != LDB_SUCCESS) {
1364 return ldb_oom(ldb);
1368 return replmd_update_rpmd_element(ldb, msg, &new_el, NULL,
1369 omd, ar->schema, &ar->seq_num,
1370 &ar->our_invocation_id,
1371 now, is_schema_nc, ar->req);
1375 static uint64_t find_max_local_usn(struct replPropertyMetaDataBlob omd)
1377 uint32_t count = omd.ctr.ctr1.count;
1380 for (i=0; i < count; i++) {
1381 struct replPropertyMetaData1 m = omd.ctr.ctr1.array[i];
1382 if (max < m.local_usn) {
1390 * update the replPropertyMetaData object each time we modify an
1391 * object. This is needed for DRS replication, as the merge on the
1392 * client is based on this object
1394 static int replmd_update_rpmd(struct ldb_module *module,
1395 const struct dsdb_schema *schema,
1396 struct ldb_request *req,
1397 const char * const *rename_attrs,
1398 struct ldb_message *msg, uint64_t *seq_num,
1399 time_t t, bool is_schema_nc,
1400 bool *is_urgent, bool *rodc)
1402 const struct ldb_val *omd_value;
1403 enum ndr_err_code ndr_err;
1404 struct replPropertyMetaDataBlob omd;
1407 const struct GUID *our_invocation_id;
1409 const char * const *attrs = NULL;
1410 const char * const attrs2[] = { "uSNChanged", "objectClass", "instanceType", NULL };
1411 struct ldb_result *res;
1412 struct ldb_context *ldb;
1413 struct ldb_message_element *objectclass_el;
1414 enum urgent_situation situation;
1415 bool rmd_is_provided;
1416 bool rmd_is_just_resorted = false;
1417 const char *not_rename_attrs[4 + msg->num_elements];
1420 attrs = rename_attrs;
1422 for (i = 0; i < msg->num_elements; i++) {
1423 not_rename_attrs[i] = msg->elements[i].name;
1425 not_rename_attrs[i] = "replPropertyMetaData";
1426 not_rename_attrs[i+1] = "objectClass";
1427 not_rename_attrs[i+2] = "instanceType";
1428 not_rename_attrs[i+3] = NULL;
1429 attrs = not_rename_attrs;
1432 ldb = ldb_module_get_ctx(module);
1434 our_invocation_id = samdb_ntds_invocation_id(ldb);
1435 if (!our_invocation_id) {
1436 /* this happens during an initial vampire while
1437 updating the schema */
1438 DEBUG(5,("No invocationID - skipping replPropertyMetaData update\n"));
1442 unix_to_nt_time(&now, t);
1444 if (ldb_request_get_control(req, DSDB_CONTROL_CHANGEREPLMETADATA_OID)) {
1445 rmd_is_provided = true;
1446 if (ldb_request_get_control(req, DSDB_CONTROL_CHANGEREPLMETADATA_RESORT_OID)) {
1447 rmd_is_just_resorted = true;
1450 rmd_is_provided = false;
1453 /* if isDeleted is present and is TRUE, then we consider we are deleting,
1454 * otherwise we consider we are updating */
1455 if (ldb_msg_check_string_attribute(msg, "isDeleted", "TRUE")) {
1456 situation = REPL_URGENT_ON_DELETE;
1457 } else if (rename_attrs) {
1458 situation = REPL_URGENT_ON_CREATE | REPL_URGENT_ON_DELETE;
1460 situation = REPL_URGENT_ON_UPDATE;
1463 if (rmd_is_provided) {
1464 /* In this case the change_replmetadata control was supplied */
1465 /* We check that it's the only attribute that is provided
1466 * (it's a rare case so it's better to keep the code simplier)
1467 * We also check that the highest local_usn is bigger or the same as
1470 if( msg->num_elements != 1 ||
1471 strncmp(msg->elements[0].name,
1472 "replPropertyMetaData", 20) ) {
1473 DEBUG(0,(__location__ ": changereplmetada control called without "\
1474 "a specified replPropertyMetaData attribute or with others\n"));
1475 return LDB_ERR_OPERATIONS_ERROR;
1477 if (situation != REPL_URGENT_ON_UPDATE) {
1478 DEBUG(0,(__location__ ": changereplmetada control can't be called when deleting an object\n"));
1479 return LDB_ERR_OPERATIONS_ERROR;
1481 omd_value = ldb_msg_find_ldb_val(msg, "replPropertyMetaData");
1483 DEBUG(0,(__location__ ": replPropertyMetaData was not specified for Object %s\n",
1484 ldb_dn_get_linearized(msg->dn)));
1485 return LDB_ERR_OPERATIONS_ERROR;
1487 ndr_err = ndr_pull_struct_blob(omd_value, msg, &omd,
1488 (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
1489 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1490 DEBUG(0,(__location__ ": Failed to parse replPropertyMetaData for %s\n",
1491 ldb_dn_get_linearized(msg->dn)));
1492 return LDB_ERR_OPERATIONS_ERROR;
1495 ret = dsdb_module_search_dn(module, msg, &res, msg->dn, attrs2,
1496 DSDB_FLAG_NEXT_MODULE |
1497 DSDB_SEARCH_SHOW_RECYCLED |
1498 DSDB_SEARCH_SHOW_EXTENDED_DN |
1499 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT |
1500 DSDB_SEARCH_REVEAL_INTERNALS, req);
1502 if (ret != LDB_SUCCESS) {
1506 if (rmd_is_just_resorted == false) {
1507 *seq_num = find_max_local_usn(omd);
1509 db_seq = ldb_msg_find_attr_as_uint64(res->msgs[0], "uSNChanged", 0);
1512 * The test here now allows for a new
1513 * replPropertyMetaData with no change, if was
1514 * just dbcheck re-sorting the values.
1516 if (*seq_num <= db_seq) {
1517 DEBUG(0,(__location__ ": changereplmetada control provided but max(local_usn)" \
1518 " is less than uSNChanged (max = %lld uSNChanged = %lld)\n",
1519 (long long)*seq_num, (long long)db_seq));
1520 return LDB_ERR_OPERATIONS_ERROR;
1525 /* search for the existing replPropertyMetaDataBlob. We need
1526 * to use REVEAL and ask for DNs in storage format to support
1527 * the check for values being the same in
1528 * replmd_update_rpmd_element()
1530 ret = dsdb_module_search_dn(module, msg, &res, msg->dn, attrs,
1531 DSDB_FLAG_NEXT_MODULE |
1532 DSDB_SEARCH_SHOW_RECYCLED |
1533 DSDB_SEARCH_SHOW_EXTENDED_DN |
1534 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT |
1535 DSDB_SEARCH_REVEAL_INTERNALS, req);
1536 if (ret != LDB_SUCCESS) {
1540 omd_value = ldb_msg_find_ldb_val(res->msgs[0], "replPropertyMetaData");
1542 DEBUG(0,(__location__ ": Object %s does not have a replPropertyMetaData attribute\n",
1543 ldb_dn_get_linearized(msg->dn)));
1544 return LDB_ERR_OPERATIONS_ERROR;
1547 ndr_err = ndr_pull_struct_blob(omd_value, msg, &omd,
1548 (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
1549 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1550 DEBUG(0,(__location__ ": Failed to parse replPropertyMetaData for %s\n",
1551 ldb_dn_get_linearized(msg->dn)));
1552 return LDB_ERR_OPERATIONS_ERROR;
1555 if (omd.version != 1) {
1556 DEBUG(0,(__location__ ": bad version %u in replPropertyMetaData for %s\n",
1557 omd.version, ldb_dn_get_linearized(msg->dn)));
1558 return LDB_ERR_OPERATIONS_ERROR;
1561 for (i=0; i<msg->num_elements; i++) {
1562 struct ldb_message_element *old_el;
1563 old_el = ldb_msg_find_element(res->msgs[0], msg->elements[i].name);
1564 ret = replmd_update_rpmd_element(ldb, msg, &msg->elements[i], old_el, &omd, schema, seq_num,
1568 if (ret != LDB_SUCCESS) {
1572 if (!*is_urgent && (situation == REPL_URGENT_ON_UPDATE)) {
1573 *is_urgent = replmd_check_urgent_attribute(&msg->elements[i]);
1580 * Assert that we have an objectClass attribute - this is major
1581 * corruption if we don't have this!
1583 objectclass_el = ldb_msg_find_element(res->msgs[0], "objectClass");
1584 if (objectclass_el != NULL) {
1586 * Now check if this objectClass means we need to do urgent replication
1588 if (!*is_urgent && replmd_check_urgent_objectclass(objectclass_el,
1592 } else if (!ldb_request_get_control(req, DSDB_CONTROL_DBCHECK)) {
1593 ldb_asprintf_errstring(ldb, __location__
1594 ": objectClass missing on %s\n",
1595 ldb_dn_get_linearized(msg->dn));
1596 return LDB_ERR_OBJECT_CLASS_VIOLATION;
1600 * replmd_update_rpmd_element has done an update if the
1603 if (*seq_num != 0 || rmd_is_just_resorted == true) {
1604 struct ldb_val *md_value;
1605 struct ldb_message_element *el;
1607 /*if we are RODC and this is a DRSR update then its ok*/
1608 if (!ldb_request_get_control(req, DSDB_CONTROL_REPLICATED_UPDATE_OID)
1609 && !ldb_request_get_control(req, DSDB_CONTROL_DBCHECK_MODIFY_RO_REPLICA)) {
1610 unsigned instanceType;
1612 ret = samdb_rodc(ldb, rodc);
1613 if (ret != LDB_SUCCESS) {
1614 DEBUG(4, (__location__ ": unable to tell if we are an RODC\n"));
1616 ldb_set_errstring(ldb, "RODC modify is forbidden!");
1617 return LDB_ERR_REFERRAL;
1620 instanceType = ldb_msg_find_attr_as_uint(res->msgs[0], "instanceType", INSTANCE_TYPE_WRITE);
1621 if (!(instanceType & INSTANCE_TYPE_WRITE)) {
1622 return ldb_error(ldb, LDB_ERR_UNWILLING_TO_PERFORM,
1623 "cannot change replicated attribute on partial replica");
1627 md_value = talloc(msg, struct ldb_val);
1628 if (md_value == NULL) {
1630 return LDB_ERR_OPERATIONS_ERROR;
1633 ret = replmd_replPropertyMetaDataCtr1_sort_and_verify(ldb, &omd.ctr.ctr1, msg->dn);
1634 if (ret != LDB_SUCCESS) {
1635 ldb_asprintf_errstring(ldb, "%s: %s", __func__, ldb_errstring(ldb));
1639 ndr_err = ndr_push_struct_blob(md_value, msg, &omd,
1640 (ndr_push_flags_fn_t)ndr_push_replPropertyMetaDataBlob);
1641 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1642 DEBUG(0,(__location__ ": Failed to marshall replPropertyMetaData for %s\n",
1643 ldb_dn_get_linearized(msg->dn)));
1644 return LDB_ERR_OPERATIONS_ERROR;
1647 ret = ldb_msg_add_empty(msg, "replPropertyMetaData", LDB_FLAG_MOD_REPLACE, &el);
1648 if (ret != LDB_SUCCESS) {
1649 DEBUG(0,(__location__ ": Failed to add updated replPropertyMetaData %s\n",
1650 ldb_dn_get_linearized(msg->dn)));
1655 el->values = md_value;
1662 struct dsdb_dn *dsdb_dn;
1667 static int parsed_dn_compare(struct parsed_dn *pdn1, struct parsed_dn *pdn2)
1669 return GUID_compare(pdn1->guid, pdn2->guid);
1672 static struct parsed_dn *parsed_dn_find(struct parsed_dn *pdn,
1673 unsigned int count, struct GUID *guid,
1676 struct parsed_dn *ret;
1678 if (dn && GUID_all_zero(guid)) {
1679 /* when updating a link using DRS, we sometimes get a
1680 NULL GUID. We then need to try and match by DN */
1681 for (i=0; i<count; i++) {
1682 if (ldb_dn_compare(pdn[i].dsdb_dn->dn, dn) == 0) {
1683 dsdb_get_extended_dn_guid(pdn[i].dsdb_dn->dn, guid, "GUID");
1689 BINARY_ARRAY_SEARCH(pdn, count, guid, guid, GUID_compare, ret);
1694 get a series of message element values as an array of DNs and GUIDs
1695 the result is sorted by GUID
1697 static int get_parsed_dns(struct ldb_module *module, TALLOC_CTX *mem_ctx,
1698 struct ldb_message_element *el, struct parsed_dn **pdn,
1699 const char *ldap_oid, struct ldb_request *parent)
1702 struct ldb_context *ldb = ldb_module_get_ctx(module);
1709 (*pdn) = talloc_array(mem_ctx, struct parsed_dn, el->num_values);
1711 ldb_module_oom(module);
1712 return LDB_ERR_OPERATIONS_ERROR;
1715 for (i=0; i<el->num_values; i++) {
1716 struct ldb_val *v = &el->values[i];
1719 struct parsed_dn *p;
1723 p->dsdb_dn = dsdb_dn_parse(*pdn, ldb, v, ldap_oid);
1724 if (p->dsdb_dn == NULL) {
1725 return LDB_ERR_INVALID_DN_SYNTAX;
1728 dn = p->dsdb_dn->dn;
1730 p->guid = talloc(*pdn, struct GUID);
1731 if (p->guid == NULL) {
1732 ldb_module_oom(module);
1733 return LDB_ERR_OPERATIONS_ERROR;
1736 status = dsdb_get_extended_dn_guid(dn, p->guid, "GUID");
1737 if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
1738 /* we got a DN without a GUID - go find the GUID */
1739 int ret = dsdb_module_guid_by_dn(module, dn, p->guid, parent);
1740 if (ret != LDB_SUCCESS) {
1741 ldb_asprintf_errstring(ldb, "Unable to find GUID for DN %s\n",
1742 ldb_dn_get_linearized(dn));
1743 if (ret == LDB_ERR_NO_SUCH_OBJECT &&
1744 LDB_FLAG_MOD_TYPE(el->flags) == LDB_FLAG_MOD_DELETE &&
1745 ldb_attr_cmp(el->name, "member") == 0) {
1746 return LDB_ERR_UNWILLING_TO_PERFORM;
1750 ret = dsdb_set_extended_dn_guid(dn, p->guid, "GUID");
1751 if (ret != LDB_SUCCESS) {
1754 } else if (!NT_STATUS_IS_OK(status)) {
1755 return LDB_ERR_OPERATIONS_ERROR;
1758 /* keep a pointer to the original ldb_val */
1762 TYPESAFE_QSORT(*pdn, el->num_values, parsed_dn_compare);
1768 build a new extended DN, including all meta data fields
1770 RMD_FLAGS = DSDB_RMD_FLAG_* bits
1771 RMD_ADDTIME = originating_add_time
1772 RMD_INVOCID = originating_invocation_id
1773 RMD_CHANGETIME = originating_change_time
1774 RMD_ORIGINATING_USN = originating_usn
1775 RMD_LOCAL_USN = local_usn
1776 RMD_VERSION = version
1778 static int replmd_build_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct dsdb_dn *dsdb_dn,
1779 const struct GUID *invocation_id, uint64_t seq_num,
1780 uint64_t local_usn, NTTIME nttime, uint32_t version, bool deleted)
1782 struct ldb_dn *dn = dsdb_dn->dn;
1783 const char *tstring, *usn_string, *flags_string;
1784 struct ldb_val tval;
1786 struct ldb_val usnv, local_usnv;
1787 struct ldb_val vers, flagsv;
1790 const char *dnstring;
1792 uint32_t rmd_flags = deleted?DSDB_RMD_FLAG_DELETED:0;
1794 tstring = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)nttime);
1796 return LDB_ERR_OPERATIONS_ERROR;
1798 tval = data_blob_string_const(tstring);
1800 usn_string = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)seq_num);
1802 return LDB_ERR_OPERATIONS_ERROR;
1804 usnv = data_blob_string_const(usn_string);
1806 usn_string = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)local_usn);
1808 return LDB_ERR_OPERATIONS_ERROR;
1810 local_usnv = data_blob_string_const(usn_string);
1812 vstring = talloc_asprintf(mem_ctx, "%lu", (unsigned long)version);
1814 return LDB_ERR_OPERATIONS_ERROR;
1816 vers = data_blob_string_const(vstring);
1818 status = GUID_to_ndr_blob(invocation_id, dn, &iid);
1819 if (!NT_STATUS_IS_OK(status)) {
1820 return LDB_ERR_OPERATIONS_ERROR;
1823 flags_string = talloc_asprintf(mem_ctx, "%u", rmd_flags);
1824 if (!flags_string) {
1825 return LDB_ERR_OPERATIONS_ERROR;
1827 flagsv = data_blob_string_const(flags_string);
1829 ret = ldb_dn_set_extended_component(dn, "RMD_FLAGS", &flagsv);
1830 if (ret != LDB_SUCCESS) return ret;
1831 ret = ldb_dn_set_extended_component(dn, "RMD_ADDTIME", &tval);
1832 if (ret != LDB_SUCCESS) return ret;
1833 ret = ldb_dn_set_extended_component(dn, "RMD_INVOCID", &iid);
1834 if (ret != LDB_SUCCESS) return ret;
1835 ret = ldb_dn_set_extended_component(dn, "RMD_CHANGETIME", &tval);
1836 if (ret != LDB_SUCCESS) return ret;
1837 ret = ldb_dn_set_extended_component(dn, "RMD_LOCAL_USN", &local_usnv);
1838 if (ret != LDB_SUCCESS) return ret;
1839 ret = ldb_dn_set_extended_component(dn, "RMD_ORIGINATING_USN", &usnv);
1840 if (ret != LDB_SUCCESS) return ret;
1841 ret = ldb_dn_set_extended_component(dn, "RMD_VERSION", &vers);
1842 if (ret != LDB_SUCCESS) return ret;
1844 dnstring = dsdb_dn_get_extended_linearized(mem_ctx, dsdb_dn, 1);
1845 if (dnstring == NULL) {
1846 return LDB_ERR_OPERATIONS_ERROR;
1848 *v = data_blob_string_const(dnstring);
1853 static int replmd_update_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct dsdb_dn *dsdb_dn,
1854 struct dsdb_dn *old_dsdb_dn, const struct GUID *invocation_id,
1855 uint64_t seq_num, uint64_t local_usn, NTTIME nttime,
1856 uint32_t version, bool deleted);
1859 check if any links need upgrading from w2k format
1861 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.
1863 static int replmd_check_upgrade_links(struct parsed_dn *dns, uint32_t count, struct ldb_message_element *parent_ctx, const struct GUID *invocation_id)
1866 for (i=0; i<count; i++) {
1871 status = dsdb_get_extended_dn_uint32(dns[i].dsdb_dn->dn, &version, "RMD_VERSION");
1872 if (!NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
1876 /* it's an old one that needs upgrading */
1877 ret = replmd_update_la_val(parent_ctx->values, dns[i].v, dns[i].dsdb_dn, dns[i].dsdb_dn, invocation_id,
1879 if (ret != LDB_SUCCESS) {
1887 update an extended DN, including all meta data fields
1889 see replmd_build_la_val for value names
1891 static int replmd_update_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct dsdb_dn *dsdb_dn,
1892 struct dsdb_dn *old_dsdb_dn, const struct GUID *invocation_id,
1893 uint64_t usn, uint64_t local_usn, NTTIME nttime,
1894 uint32_t version, bool deleted)
1896 struct ldb_dn *dn = dsdb_dn->dn;
1897 const char *tstring, *usn_string, *flags_string;
1898 struct ldb_val tval;
1900 struct ldb_val usnv, local_usnv;
1901 struct ldb_val vers, flagsv;
1902 const struct ldb_val *old_addtime;
1903 uint32_t old_version;
1906 const char *dnstring;
1908 uint32_t rmd_flags = deleted?DSDB_RMD_FLAG_DELETED:0;
1910 tstring = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)nttime);
1912 return LDB_ERR_OPERATIONS_ERROR;
1914 tval = data_blob_string_const(tstring);
1916 usn_string = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)usn);
1918 return LDB_ERR_OPERATIONS_ERROR;
1920 usnv = data_blob_string_const(usn_string);
1922 usn_string = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)local_usn);
1924 return LDB_ERR_OPERATIONS_ERROR;
1926 local_usnv = data_blob_string_const(usn_string);
1928 status = GUID_to_ndr_blob(invocation_id, dn, &iid);
1929 if (!NT_STATUS_IS_OK(status)) {
1930 return LDB_ERR_OPERATIONS_ERROR;
1933 flags_string = talloc_asprintf(mem_ctx, "%u", rmd_flags);
1934 if (!flags_string) {
1935 return LDB_ERR_OPERATIONS_ERROR;
1937 flagsv = data_blob_string_const(flags_string);
1939 ret = ldb_dn_set_extended_component(dn, "RMD_FLAGS", &flagsv);
1940 if (ret != LDB_SUCCESS) return ret;
1942 /* get the ADDTIME from the original */
1943 old_addtime = ldb_dn_get_extended_component(old_dsdb_dn->dn, "RMD_ADDTIME");
1944 if (old_addtime == NULL) {
1945 old_addtime = &tval;
1947 if (dsdb_dn != old_dsdb_dn ||
1948 ldb_dn_get_extended_component(dn, "RMD_ADDTIME") == NULL) {
1949 ret = ldb_dn_set_extended_component(dn, "RMD_ADDTIME", old_addtime);
1950 if (ret != LDB_SUCCESS) return ret;
1953 /* use our invocation id */
1954 ret = ldb_dn_set_extended_component(dn, "RMD_INVOCID", &iid);
1955 if (ret != LDB_SUCCESS) return ret;
1957 /* changetime is the current time */
1958 ret = ldb_dn_set_extended_component(dn, "RMD_CHANGETIME", &tval);
1959 if (ret != LDB_SUCCESS) return ret;
1961 /* update the USN */
1962 ret = ldb_dn_set_extended_component(dn, "RMD_ORIGINATING_USN", &usnv);
1963 if (ret != LDB_SUCCESS) return ret;
1965 ret = ldb_dn_set_extended_component(dn, "RMD_LOCAL_USN", &local_usnv);
1966 if (ret != LDB_SUCCESS) return ret;
1968 /* increase the version by 1 */
1969 status = dsdb_get_extended_dn_uint32(old_dsdb_dn->dn, &old_version, "RMD_VERSION");
1970 if (NT_STATUS_IS_OK(status) && old_version >= version) {
1971 version = old_version+1;
1973 vstring = talloc_asprintf(dn, "%lu", (unsigned long)version);
1974 vers = data_blob_string_const(vstring);
1975 ret = ldb_dn_set_extended_component(dn, "RMD_VERSION", &vers);
1976 if (ret != LDB_SUCCESS) return ret;
1978 dnstring = dsdb_dn_get_extended_linearized(mem_ctx, dsdb_dn, 1);
1979 if (dnstring == NULL) {
1980 return LDB_ERR_OPERATIONS_ERROR;
1982 *v = data_blob_string_const(dnstring);
1988 handle adding a linked attribute
1990 static int replmd_modify_la_add(struct ldb_module *module,
1991 const struct dsdb_schema *schema,
1992 struct ldb_message *msg,
1993 struct ldb_message_element *el,
1994 struct ldb_message_element *old_el,
1995 const struct dsdb_attribute *schema_attr,
1998 struct GUID *msg_guid,
1999 struct ldb_request *parent)
2002 struct parsed_dn *dns, *old_dns;
2003 TALLOC_CTX *tmp_ctx = talloc_new(msg);
2005 struct ldb_val *new_values = NULL;
2006 unsigned int num_new_values = 0;
2007 unsigned old_num_values = old_el?old_el->num_values:0;
2008 const struct GUID *invocation_id;
2009 struct ldb_context *ldb = ldb_module_get_ctx(module);
2012 unix_to_nt_time(&now, t);
2014 ret = get_parsed_dns(module, tmp_ctx, el, &dns, schema_attr->syntax->ldap_oid, parent);
2015 if (ret != LDB_SUCCESS) {
2016 talloc_free(tmp_ctx);
2020 ret = get_parsed_dns(module, tmp_ctx, old_el, &old_dns, schema_attr->syntax->ldap_oid, parent);
2021 if (ret != LDB_SUCCESS) {
2022 talloc_free(tmp_ctx);
2026 invocation_id = samdb_ntds_invocation_id(ldb);
2027 if (!invocation_id) {
2028 talloc_free(tmp_ctx);
2029 return LDB_ERR_OPERATIONS_ERROR;
2032 ret = replmd_check_upgrade_links(old_dns, old_num_values, old_el, invocation_id);
2033 if (ret != LDB_SUCCESS) {
2034 talloc_free(tmp_ctx);
2038 /* for each new value, see if it exists already with the same GUID */
2039 for (i=0; i<el->num_values; i++) {
2040 struct parsed_dn *p = parsed_dn_find(old_dns, old_num_values, dns[i].guid, NULL);
2042 /* this is a new linked attribute value */
2043 new_values = talloc_realloc(tmp_ctx, new_values, struct ldb_val, num_new_values+1);
2044 if (new_values == NULL) {
2045 ldb_module_oom(module);
2046 talloc_free(tmp_ctx);
2047 return LDB_ERR_OPERATIONS_ERROR;
2049 ret = replmd_build_la_val(new_values, &new_values[num_new_values], dns[i].dsdb_dn,
2050 invocation_id, seq_num, seq_num, now, 0, false);
2051 if (ret != LDB_SUCCESS) {
2052 talloc_free(tmp_ctx);
2057 /* this is only allowed if the GUID was
2058 previously deleted. */
2059 uint32_t rmd_flags = dsdb_dn_rmd_flags(p->dsdb_dn->dn);
2061 if (!(rmd_flags & DSDB_RMD_FLAG_DELETED)) {
2062 ldb_asprintf_errstring(ldb, "Attribute %s already exists for target GUID %s",
2063 el->name, GUID_string(tmp_ctx, p->guid));
2064 talloc_free(tmp_ctx);
2065 /* error codes for 'member' need to be
2067 if (ldb_attr_cmp(el->name, "member") == 0) {
2068 return LDB_ERR_ENTRY_ALREADY_EXISTS;
2070 return LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS;
2073 ret = replmd_update_la_val(old_el->values, p->v, dns[i].dsdb_dn, p->dsdb_dn,
2074 invocation_id, seq_num, seq_num, now, 0, false);
2075 if (ret != LDB_SUCCESS) {
2076 talloc_free(tmp_ctx);
2081 ret = replmd_add_backlink(module, schema, msg_guid, dns[i].guid, true, schema_attr, true);
2082 if (ret != LDB_SUCCESS) {
2083 talloc_free(tmp_ctx);
2088 /* add the new ones on to the end of the old values, constructing a new el->values */
2089 el->values = talloc_realloc(msg->elements, old_el?old_el->values:NULL,
2091 old_num_values+num_new_values);
2092 if (el->values == NULL) {
2093 ldb_module_oom(module);
2094 return LDB_ERR_OPERATIONS_ERROR;
2097 memcpy(&el->values[old_num_values], new_values, num_new_values*sizeof(struct ldb_val));
2098 el->num_values = old_num_values + num_new_values;
2100 talloc_steal(msg->elements, el->values);
2101 talloc_steal(el->values, new_values);
2103 talloc_free(tmp_ctx);
2105 /* we now tell the backend to replace all existing values
2106 with the one we have constructed */
2107 el->flags = LDB_FLAG_MOD_REPLACE;
2114 handle deleting all active linked attributes
2116 static int replmd_modify_la_delete(struct ldb_module *module,
2117 const struct dsdb_schema *schema,
2118 struct ldb_message *msg,
2119 struct ldb_message_element *el,
2120 struct ldb_message_element *old_el,
2121 const struct dsdb_attribute *schema_attr,
2124 struct GUID *msg_guid,
2125 struct ldb_request *parent)
2128 struct parsed_dn *dns, *old_dns;
2129 TALLOC_CTX *tmp_ctx = talloc_new(msg);
2131 const struct GUID *invocation_id;
2132 struct ldb_context *ldb = ldb_module_get_ctx(module);
2135 unix_to_nt_time(&now, t);
2137 /* check if there is nothing to delete */
2138 if ((!old_el || old_el->num_values == 0) &&
2139 el->num_values == 0) {
2143 if (!old_el || old_el->num_values == 0) {
2144 return LDB_ERR_NO_SUCH_ATTRIBUTE;
2147 ret = get_parsed_dns(module, tmp_ctx, el, &dns, schema_attr->syntax->ldap_oid, parent);
2148 if (ret != LDB_SUCCESS) {
2149 talloc_free(tmp_ctx);
2153 ret = get_parsed_dns(module, tmp_ctx, old_el, &old_dns, schema_attr->syntax->ldap_oid, parent);
2154 if (ret != LDB_SUCCESS) {
2155 talloc_free(tmp_ctx);
2159 invocation_id = samdb_ntds_invocation_id(ldb);
2160 if (!invocation_id) {
2161 return LDB_ERR_OPERATIONS_ERROR;
2164 ret = replmd_check_upgrade_links(old_dns, old_el->num_values, old_el, invocation_id);
2165 if (ret != LDB_SUCCESS) {
2166 talloc_free(tmp_ctx);
2172 /* see if we are being asked to delete any links that
2173 don't exist or are already deleted */
2174 for (i=0; i<el->num_values; i++) {
2175 struct parsed_dn *p = &dns[i];
2176 struct parsed_dn *p2;
2179 p2 = parsed_dn_find(old_dns, old_el->num_values, p->guid, NULL);
2181 ldb_asprintf_errstring(ldb, "Attribute %s doesn't exist for target GUID %s",
2182 el->name, GUID_string(tmp_ctx, p->guid));
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 ldb_asprintf_errstring(ldb, "Attribute %s already deleted for target GUID %s",
2192 el->name, GUID_string(tmp_ctx, p->guid));
2193 if (ldb_attr_cmp(el->name, "member") == 0) {
2194 return LDB_ERR_UNWILLING_TO_PERFORM;
2196 return LDB_ERR_NO_SUCH_ATTRIBUTE;
2201 /* for each new value, see if it exists already with the same GUID
2202 if it is not already deleted and matches the delete list then delete it
2204 for (i=0; i<old_el->num_values; i++) {
2205 struct parsed_dn *p = &old_dns[i];
2208 if (el->num_values && parsed_dn_find(dns, el->num_values, p->guid, NULL) == NULL) {
2212 rmd_flags = dsdb_dn_rmd_flags(p->dsdb_dn->dn);
2213 if (rmd_flags & DSDB_RMD_FLAG_DELETED) continue;
2215 ret = replmd_update_la_val(old_el->values, p->v, p->dsdb_dn, p->dsdb_dn,
2216 invocation_id, seq_num, seq_num, now, 0, true);
2217 if (ret != LDB_SUCCESS) {
2218 talloc_free(tmp_ctx);
2222 ret = replmd_add_backlink(module, schema, msg_guid, old_dns[i].guid, false, schema_attr, true);
2223 if (ret != LDB_SUCCESS) {
2224 talloc_free(tmp_ctx);
2229 el->values = talloc_steal(msg->elements, old_el->values);
2230 el->num_values = old_el->num_values;
2232 talloc_free(tmp_ctx);
2234 /* we now tell the backend to replace all existing values
2235 with the one we have constructed */
2236 el->flags = LDB_FLAG_MOD_REPLACE;
2242 handle replacing a linked attribute
2244 static int replmd_modify_la_replace(struct ldb_module *module,
2245 const struct dsdb_schema *schema,
2246 struct ldb_message *msg,
2247 struct ldb_message_element *el,
2248 struct ldb_message_element *old_el,
2249 const struct dsdb_attribute *schema_attr,
2252 struct GUID *msg_guid,
2253 struct ldb_request *parent)
2256 struct parsed_dn *dns, *old_dns;
2257 TALLOC_CTX *tmp_ctx = talloc_new(msg);
2259 const struct GUID *invocation_id;
2260 struct ldb_context *ldb = ldb_module_get_ctx(module);
2261 struct ldb_val *new_values = NULL;
2262 unsigned int num_new_values = 0;
2263 unsigned int old_num_values = old_el?old_el->num_values:0;
2266 unix_to_nt_time(&now, t);
2268 /* check if there is nothing to replace */
2269 if ((!old_el || old_el->num_values == 0) &&
2270 el->num_values == 0) {
2274 ret = get_parsed_dns(module, tmp_ctx, el, &dns, schema_attr->syntax->ldap_oid, parent);
2275 if (ret != LDB_SUCCESS) {
2276 talloc_free(tmp_ctx);
2280 ret = get_parsed_dns(module, tmp_ctx, old_el, &old_dns, schema_attr->syntax->ldap_oid, parent);
2281 if (ret != LDB_SUCCESS) {
2282 talloc_free(tmp_ctx);
2286 invocation_id = samdb_ntds_invocation_id(ldb);
2287 if (!invocation_id) {
2288 return LDB_ERR_OPERATIONS_ERROR;
2291 ret = replmd_check_upgrade_links(old_dns, old_num_values, old_el, invocation_id);
2292 if (ret != LDB_SUCCESS) {
2293 talloc_free(tmp_ctx);
2297 /* mark all the old ones as deleted */
2298 for (i=0; i<old_num_values; i++) {
2299 struct parsed_dn *old_p = &old_dns[i];
2300 struct parsed_dn *p;
2301 uint32_t rmd_flags = dsdb_dn_rmd_flags(old_p->dsdb_dn->dn);
2303 if (rmd_flags & DSDB_RMD_FLAG_DELETED) continue;
2305 ret = replmd_add_backlink(module, schema, msg_guid, old_dns[i].guid, false, schema_attr, false);
2306 if (ret != LDB_SUCCESS) {
2307 talloc_free(tmp_ctx);
2311 p = parsed_dn_find(dns, el->num_values, old_p->guid, NULL);
2313 /* we don't delete it if we are re-adding it */
2317 ret = replmd_update_la_val(old_el->values, old_p->v, old_p->dsdb_dn, old_p->dsdb_dn,
2318 invocation_id, seq_num, seq_num, now, 0, true);
2319 if (ret != LDB_SUCCESS) {
2320 talloc_free(tmp_ctx);
2325 /* for each new value, either update its meta-data, or add it
2328 for (i=0; i<el->num_values; i++) {
2329 struct parsed_dn *p = &dns[i], *old_p;
2332 (old_p = parsed_dn_find(old_dns,
2333 old_num_values, p->guid, NULL)) != NULL) {
2334 /* update in place */
2335 ret = replmd_update_la_val(old_el->values, old_p->v, p->dsdb_dn,
2336 old_p->dsdb_dn, invocation_id,
2337 seq_num, seq_num, now, 0, false);
2338 if (ret != LDB_SUCCESS) {
2339 talloc_free(tmp_ctx);
2344 new_values = talloc_realloc(tmp_ctx, new_values, struct ldb_val,
2346 if (new_values == NULL) {
2347 ldb_module_oom(module);
2348 talloc_free(tmp_ctx);
2349 return LDB_ERR_OPERATIONS_ERROR;
2351 ret = replmd_build_la_val(new_values, &new_values[num_new_values], dns[i].dsdb_dn,
2352 invocation_id, seq_num, seq_num, now, 0, false);
2353 if (ret != LDB_SUCCESS) {
2354 talloc_free(tmp_ctx);
2360 ret = replmd_add_backlink(module, schema, msg_guid, dns[i].guid, true, schema_attr, false);
2361 if (ret != LDB_SUCCESS) {
2362 talloc_free(tmp_ctx);
2367 /* add the new values to the end of old_el */
2368 if (num_new_values != 0) {
2369 el->values = talloc_realloc(msg->elements, old_el?old_el->values:NULL,
2370 struct ldb_val, old_num_values+num_new_values);
2371 if (el->values == NULL) {
2372 ldb_module_oom(module);
2373 return LDB_ERR_OPERATIONS_ERROR;
2375 memcpy(&el->values[old_num_values], &new_values[0],
2376 sizeof(struct ldb_val)*num_new_values);
2377 el->num_values = old_num_values + num_new_values;
2378 talloc_steal(msg->elements, new_values);
2380 el->values = old_el->values;
2381 el->num_values = old_el->num_values;
2382 talloc_steal(msg->elements, el->values);
2385 talloc_free(tmp_ctx);
2387 /* we now tell the backend to replace all existing values
2388 with the one we have constructed */
2389 el->flags = LDB_FLAG_MOD_REPLACE;
2396 handle linked attributes in modify requests
2398 static int replmd_modify_handle_linked_attribs(struct ldb_module *module,
2399 struct ldb_message *msg,
2400 uint64_t seq_num, time_t t,
2401 struct ldb_request *parent)
2403 struct ldb_result *res;
2406 struct ldb_context *ldb = ldb_module_get_ctx(module);
2407 struct ldb_message *old_msg;
2409 const struct dsdb_schema *schema;
2410 struct GUID old_guid;
2413 /* there the replmd_update_rpmd code has already
2414 * checked and saw that there are no linked
2419 if (dsdb_functional_level(ldb) == DS_DOMAIN_FUNCTION_2000) {
2420 /* don't do anything special for linked attributes */
2424 ret = dsdb_module_search_dn(module, msg, &res, msg->dn, NULL,
2425 DSDB_FLAG_NEXT_MODULE |
2426 DSDB_SEARCH_SHOW_RECYCLED |
2427 DSDB_SEARCH_REVEAL_INTERNALS |
2428 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT,
2430 if (ret != LDB_SUCCESS) {
2433 schema = dsdb_get_schema(ldb, res);
2435 return LDB_ERR_OPERATIONS_ERROR;
2438 old_msg = res->msgs[0];
2440 old_guid = samdb_result_guid(old_msg, "objectGUID");
2442 for (i=0; i<msg->num_elements; i++) {
2443 struct ldb_message_element *el = &msg->elements[i];
2444 struct ldb_message_element *old_el, *new_el;
2445 const struct dsdb_attribute *schema_attr
2446 = dsdb_attribute_by_lDAPDisplayName(schema, el->name);
2448 ldb_asprintf_errstring(ldb,
2449 "%s: attribute %s is not a valid attribute in schema",
2450 __FUNCTION__, el->name);
2451 return LDB_ERR_OBJECT_CLASS_VIOLATION;
2453 if (schema_attr->linkID == 0) {
2456 if ((schema_attr->linkID & 1) == 1) {
2457 if (parent && ldb_request_get_control(parent, DSDB_CONTROL_DBCHECK)) {
2460 /* Odd is for the target. Illegal to modify */
2461 ldb_asprintf_errstring(ldb,
2462 "attribute %s must not be modified directly, it is a linked attribute", el->name);
2463 return LDB_ERR_UNWILLING_TO_PERFORM;
2465 old_el = ldb_msg_find_element(old_msg, el->name);
2466 switch (el->flags & LDB_FLAG_MOD_MASK) {
2467 case LDB_FLAG_MOD_REPLACE:
2468 ret = replmd_modify_la_replace(module, schema, msg, el, old_el, schema_attr, seq_num, t, &old_guid, parent);
2470 case LDB_FLAG_MOD_DELETE:
2471 ret = replmd_modify_la_delete(module, schema, msg, el, old_el, schema_attr, seq_num, t, &old_guid, parent);
2473 case LDB_FLAG_MOD_ADD:
2474 ret = replmd_modify_la_add(module, schema, msg, el, old_el, schema_attr, seq_num, t, &old_guid, parent);
2477 ldb_asprintf_errstring(ldb,
2478 "invalid flags 0x%x for %s linked attribute",
2479 el->flags, el->name);
2480 return LDB_ERR_UNWILLING_TO_PERFORM;
2482 if (dsdb_check_single_valued_link(schema_attr, el) != LDB_SUCCESS) {
2483 ldb_asprintf_errstring(ldb,
2484 "Attribute %s is single valued but more than one value has been supplied",
2486 return LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS;
2488 el->flags |= LDB_FLAG_INTERNAL_DISABLE_SINGLE_VALUE_CHECK;
2493 if (ret != LDB_SUCCESS) {
2497 ldb_msg_remove_attr(old_msg, el->name);
2499 ldb_msg_add_empty(old_msg, el->name, 0, &new_el);
2500 new_el->num_values = el->num_values;
2501 new_el->values = talloc_steal(msg->elements, el->values);
2503 /* TODO: this relises a bit too heavily on the exact
2504 behaviour of ldb_msg_find_element and
2505 ldb_msg_remove_element */
2506 old_el = ldb_msg_find_element(msg, el->name);
2508 ldb_msg_remove_element(msg, old_el);
2519 static int replmd_modify(struct ldb_module *module, struct ldb_request *req)
2521 struct samldb_msds_intid_persistant *msds_intid_struct;
2522 struct ldb_context *ldb;
2523 struct replmd_replicated_request *ac;
2524 struct ldb_request *down_req;
2525 struct ldb_message *msg;
2526 time_t t = time(NULL);
2528 bool is_urgent = false, rodc = false;
2529 bool is_schema_nc = false;
2530 unsigned int functional_level;
2531 const struct ldb_message_element *guid_el = NULL;
2532 struct ldb_control *sd_propagation_control;
2533 struct replmd_private *replmd_private =
2534 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
2536 /* do not manipulate our control entries */
2537 if (ldb_dn_is_special(req->op.mod.message->dn)) {
2538 return ldb_next_request(module, req);
2541 sd_propagation_control = ldb_request_get_control(req,
2542 DSDB_CONTROL_SEC_DESC_PROPAGATION_OID);
2543 if (sd_propagation_control != NULL) {
2544 if (req->op.mod.message->num_elements != 1) {
2545 return ldb_module_operr(module);
2547 ret = strcmp(req->op.mod.message->elements[0].name,
2548 "nTSecurityDescriptor");
2550 return ldb_module_operr(module);
2553 return ldb_next_request(module, req);
2556 ldb = ldb_module_get_ctx(module);
2558 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_modify\n");
2560 guid_el = ldb_msg_find_element(req->op.mod.message, "objectGUID");
2561 if (guid_el != NULL) {
2562 ldb_set_errstring(ldb,
2563 "replmd_modify: it's not allowed to change the objectGUID!");
2564 return LDB_ERR_CONSTRAINT_VIOLATION;
2567 ac = replmd_ctx_init(module, req);
2569 return ldb_module_oom(module);
2572 functional_level = dsdb_functional_level(ldb);
2574 /* we have to copy the message as the caller might have it as a const */
2575 msg = ldb_msg_copy_shallow(ac, req->op.mod.message);
2579 return LDB_ERR_OPERATIONS_ERROR;
2582 ldb_msg_remove_attr(msg, "whenChanged");
2583 ldb_msg_remove_attr(msg, "uSNChanged");
2585 is_schema_nc = ldb_dn_compare_base(replmd_private->schema_dn, msg->dn) == 0;
2587 ret = replmd_update_rpmd(module, ac->schema, req, NULL,
2588 msg, &ac->seq_num, t, is_schema_nc,
2590 if (rodc && (ret == LDB_ERR_REFERRAL)) {
2591 struct loadparm_context *lp_ctx;
2594 lp_ctx = talloc_get_type(ldb_get_opaque(ldb, "loadparm"),
2595 struct loadparm_context);
2597 referral = talloc_asprintf(req,
2599 lpcfg_dnsdomain(lp_ctx),
2600 ldb_dn_get_linearized(msg->dn));
2601 ret = ldb_module_send_referral(req, referral);
2606 if (ret != LDB_SUCCESS) {
2611 ret = replmd_modify_handle_linked_attribs(module, msg, ac->seq_num, t, req);
2612 if (ret != LDB_SUCCESS) {
2618 * - replace the old object with the newly constructed one
2621 ac->is_urgent = is_urgent;
2623 ret = ldb_build_mod_req(&down_req, ldb, ac,
2626 ac, replmd_op_callback,
2628 LDB_REQ_SET_LOCATION(down_req);
2629 if (ret != LDB_SUCCESS) {
2634 /* current partition control is needed by "replmd_op_callback" */
2635 if (ldb_request_get_control(req, DSDB_CONTROL_CURRENT_PARTITION_OID) == NULL) {
2636 ret = ldb_request_add_control(down_req,
2637 DSDB_CONTROL_CURRENT_PARTITION_OID,
2639 if (ret != LDB_SUCCESS) {
2645 /* If we are in functional level 2000, then
2646 * replmd_modify_handle_linked_attribs will have done
2648 if (functional_level == DS_DOMAIN_FUNCTION_2000) {
2649 ret = ldb_request_add_control(down_req, DSDB_CONTROL_APPLY_LINKS, false, NULL);
2650 if (ret != LDB_SUCCESS) {
2656 talloc_steal(down_req, msg);
2658 /* we only change whenChanged and uSNChanged if the seq_num
2660 if (ac->seq_num != 0) {
2661 ret = add_time_element(msg, "whenChanged", t);
2662 if (ret != LDB_SUCCESS) {
2668 ret = add_uint64_element(ldb, msg, "uSNChanged", ac->seq_num);
2669 if (ret != LDB_SUCCESS) {
2676 if (!ldb_dn_compare_base(replmd_private->schema_dn, msg->dn)) {
2677 /* Update the usn in the SAMLDB_MSDS_INTID_OPAQUE opaque */
2678 msds_intid_struct = (struct samldb_msds_intid_persistant *) ldb_get_opaque(ldb, SAMLDB_MSDS_INTID_OPAQUE);
2679 if (msds_intid_struct) {
2680 msds_intid_struct->usn = ac->seq_num;
2684 /* go on with the call chain */
2685 return ldb_next_request(module, down_req);
2688 static int replmd_rename_callback(struct ldb_request *req, struct ldb_reply *ares);
2691 handle a rename request
2693 On a rename we need to do an extra ldb_modify which sets the
2694 whenChanged and uSNChanged attributes. We do this in a callback after the success.
2696 static int replmd_rename(struct ldb_module *module, struct ldb_request *req)
2698 struct ldb_context *ldb;
2699 struct replmd_replicated_request *ac;
2701 struct ldb_request *down_req;
2703 /* do not manipulate our control entries */
2704 if (ldb_dn_is_special(req->op.mod.message->dn)) {
2705 return ldb_next_request(module, req);
2708 ldb = ldb_module_get_ctx(module);
2710 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_rename\n");
2712 ac = replmd_ctx_init(module, req);
2714 return ldb_module_oom(module);
2717 ret = ldb_build_rename_req(&down_req, ldb, ac,
2718 ac->req->op.rename.olddn,
2719 ac->req->op.rename.newdn,
2721 ac, replmd_rename_callback,
2723 LDB_REQ_SET_LOCATION(down_req);
2724 if (ret != LDB_SUCCESS) {
2729 /* go on with the call chain */
2730 return ldb_next_request(module, down_req);
2733 /* After the rename is compleated, update the whenchanged etc */
2734 static int replmd_rename_callback(struct ldb_request *req, struct ldb_reply *ares)
2736 struct ldb_context *ldb;
2737 struct ldb_request *down_req;
2738 struct ldb_message *msg;
2739 const struct dsdb_attribute *rdn_attr;
2740 const char *rdn_name;
2741 const struct ldb_val *rdn_val;
2742 const char *attrs[5] = { NULL, };
2743 time_t t = time(NULL);
2745 bool is_urgent = false, rodc = false;
2747 struct replmd_replicated_request *ac =
2748 talloc_get_type(req->context, struct replmd_replicated_request);
2749 struct replmd_private *replmd_private =
2750 talloc_get_type(ldb_module_get_private(ac->module),
2751 struct replmd_private);
2753 ldb = ldb_module_get_ctx(ac->module);
2755 if (ares->error != LDB_SUCCESS) {
2756 return ldb_module_done(ac->req, ares->controls,
2757 ares->response, ares->error);
2760 if (ares->type != LDB_REPLY_DONE) {
2761 ldb_set_errstring(ldb,
2762 "invalid ldb_reply_type in callback");
2764 return ldb_module_done(ac->req, NULL, NULL,
2765 LDB_ERR_OPERATIONS_ERROR);
2769 * - replace the old object with the newly constructed one
2772 msg = ldb_msg_new(ac);
2775 return LDB_ERR_OPERATIONS_ERROR;
2778 msg->dn = ac->req->op.rename.newdn;
2780 is_schema_nc = ldb_dn_compare_base(replmd_private->schema_dn, msg->dn) == 0;
2782 rdn_name = ldb_dn_get_rdn_name(msg->dn);
2783 if (rdn_name == NULL) {
2785 return ldb_module_done(ac->req, NULL, NULL,
2789 /* normalize the rdn attribute name */
2790 rdn_attr = dsdb_attribute_by_lDAPDisplayName(ac->schema, rdn_name);
2791 if (rdn_attr == NULL) {
2793 return ldb_module_done(ac->req, NULL, NULL,
2796 rdn_name = rdn_attr->lDAPDisplayName;
2798 rdn_val = ldb_dn_get_rdn_val(msg->dn);
2799 if (rdn_val == NULL) {
2801 return ldb_module_done(ac->req, NULL, NULL,
2805 if (ldb_msg_add_empty(msg, rdn_name, LDB_FLAG_MOD_REPLACE, NULL) != 0) {
2807 return ldb_module_done(ac->req, NULL, NULL,
2810 if (ldb_msg_add_value(msg, rdn_name, rdn_val, NULL) != 0) {
2812 return ldb_module_done(ac->req, NULL, NULL,
2815 if (ldb_msg_add_empty(msg, "name", LDB_FLAG_MOD_REPLACE, NULL) != 0) {
2817 return ldb_module_done(ac->req, NULL, NULL,
2820 if (ldb_msg_add_value(msg, "name", rdn_val, NULL) != 0) {
2822 return ldb_module_done(ac->req, NULL, NULL,
2827 * here we let replmd_update_rpmd() only search for
2828 * the existing "replPropertyMetaData" and rdn_name attributes.
2830 * We do not want the existing "name" attribute as
2831 * the "name" attribute needs to get the version
2832 * updated on rename even if the rdn value hasn't changed.
2834 * This is the diff of the meta data, for a moved user
2835 * on a w2k8r2 server:
2838 * -dn: CN=sdf df,CN=Users,DC=bla,DC=base
2839 * +dn: CN=sdf df,OU=TestOU,DC=bla,DC=base
2840 * replPropertyMetaData: NDR: struct replPropertyMetaDataBlob
2841 * version : 0x00000001 (1)
2842 * reserved : 0x00000000 (0)
2843 * @@ -66,11 +66,11 @@ replPropertyMetaData: NDR: struct re
2844 * local_usn : 0x00000000000037a5 (14245)
2845 * array: struct replPropertyMetaData1
2846 * attid : DRSUAPI_ATTID_name (0x90001)
2847 * - version : 0x00000001 (1)
2848 * - originating_change_time : Wed Feb 9 17:20:49 2011 CET
2849 * + version : 0x00000002 (2)
2850 * + originating_change_time : Wed Apr 6 15:21:01 2011 CEST
2851 * originating_invocation_id: 0d36ca05-5507-4e62-aca3-354bab0d39e1
2852 * - originating_usn : 0x00000000000037a5 (14245)
2853 * - local_usn : 0x00000000000037a5 (14245)
2854 * + originating_usn : 0x0000000000003834 (14388)
2855 * + local_usn : 0x0000000000003834 (14388)
2856 * array: struct replPropertyMetaData1
2857 * attid : DRSUAPI_ATTID_userAccountControl (0x90008)
2858 * version : 0x00000004 (4)
2860 attrs[0] = "replPropertyMetaData";
2861 attrs[1] = "objectClass";
2862 attrs[2] = "instanceType";
2863 attrs[3] = rdn_name;
2866 ret = replmd_update_rpmd(ac->module, ac->schema, req, attrs,
2867 msg, &ac->seq_num, t,
2868 is_schema_nc, &is_urgent, &rodc);
2869 if (rodc && (ret == LDB_ERR_REFERRAL)) {
2870 struct ldb_dn *olddn = ac->req->op.rename.olddn;
2871 struct loadparm_context *lp_ctx;
2874 lp_ctx = talloc_get_type(ldb_get_opaque(ldb, "loadparm"),
2875 struct loadparm_context);
2877 referral = talloc_asprintf(req,
2879 lpcfg_dnsdomain(lp_ctx),
2880 ldb_dn_get_linearized(olddn));
2881 ret = ldb_module_send_referral(req, referral);
2883 return ldb_module_done(req, NULL, NULL, ret);
2886 if (ret != LDB_SUCCESS) {
2888 return ldb_module_done(ac->req, NULL, NULL, ret);
2891 if (ac->seq_num == 0) {
2893 return ldb_module_done(ac->req, NULL, NULL,
2895 "internal error seq_num == 0"));
2897 ac->is_urgent = is_urgent;
2899 ret = ldb_build_mod_req(&down_req, ldb, ac,
2902 ac, replmd_op_callback,
2904 LDB_REQ_SET_LOCATION(down_req);
2905 if (ret != LDB_SUCCESS) {
2910 /* current partition control is needed by "replmd_op_callback" */
2911 if (ldb_request_get_control(req, DSDB_CONTROL_CURRENT_PARTITION_OID) == NULL) {
2912 ret = ldb_request_add_control(down_req,
2913 DSDB_CONTROL_CURRENT_PARTITION_OID,
2915 if (ret != LDB_SUCCESS) {
2921 talloc_steal(down_req, msg);
2923 ret = add_time_element(msg, "whenChanged", t);
2924 if (ret != LDB_SUCCESS) {
2930 ret = add_uint64_element(ldb, msg, "uSNChanged", ac->seq_num);
2931 if (ret != LDB_SUCCESS) {
2937 /* go on with the call chain - do the modify after the rename */
2938 return ldb_next_request(ac->module, down_req);
2942 * remove links from objects that point at this object when an object
2943 * is deleted. We remove it from the NEXT module per MS-DRSR 5.160
2944 * RemoveObj which states that link removal due to the object being
2945 * deleted is NOT an originating update - they just go away!
2948 static int replmd_delete_remove_link(struct ldb_module *module,
2949 const struct dsdb_schema *schema,
2951 struct ldb_message_element *el,
2952 const struct dsdb_attribute *sa,
2953 struct ldb_request *parent)
2956 TALLOC_CTX *tmp_ctx = talloc_new(module);
2957 struct ldb_context *ldb = ldb_module_get_ctx(module);
2959 for (i=0; i<el->num_values; i++) {
2960 struct dsdb_dn *dsdb_dn;
2964 struct ldb_message *msg;
2965 const struct dsdb_attribute *target_attr;
2966 struct ldb_message_element *el2;
2967 struct ldb_val dn_val;
2969 if (dsdb_dn_is_deleted_val(&el->values[i])) {
2973 dsdb_dn = dsdb_dn_parse(tmp_ctx, ldb, &el->values[i], sa->syntax->ldap_oid);
2975 talloc_free(tmp_ctx);
2976 return LDB_ERR_OPERATIONS_ERROR;
2979 status = dsdb_get_extended_dn_guid(dsdb_dn->dn, &guid2, "GUID");
2980 if (!NT_STATUS_IS_OK(status)) {
2981 talloc_free(tmp_ctx);
2982 return LDB_ERR_OPERATIONS_ERROR;
2985 /* remove the link */
2986 msg = ldb_msg_new(tmp_ctx);
2988 ldb_module_oom(module);
2989 talloc_free(tmp_ctx);
2990 return LDB_ERR_OPERATIONS_ERROR;
2994 msg->dn = dsdb_dn->dn;
2996 target_attr = dsdb_attribute_by_linkID(schema, sa->linkID ^ 1);
2997 if (target_attr == NULL) {
3001 ret = ldb_msg_add_empty(msg, target_attr->lDAPDisplayName, LDB_FLAG_MOD_DELETE, &el2);
3002 if (ret != LDB_SUCCESS) {
3003 ldb_module_oom(module);
3004 talloc_free(tmp_ctx);
3005 return LDB_ERR_OPERATIONS_ERROR;
3007 dn_val = data_blob_string_const(ldb_dn_get_linearized(dn));
3008 el2->values = &dn_val;
3009 el2->num_values = 1;
3011 ret = dsdb_module_modify(module, msg, DSDB_FLAG_OWN_MODULE, parent);
3012 if (ret != LDB_SUCCESS) {
3013 talloc_free(tmp_ctx);
3017 talloc_free(tmp_ctx);
3023 handle update of replication meta data for deletion of objects
3025 This also handles the mapping of delete to a rename operation
3026 to allow deletes to be replicated.
3028 It also handles the incoming deleted objects, to ensure they are
3029 fully deleted here. In that case re_delete is true, and we do not
3030 use this as a signal to change the deleted state, just reinforce it.
3033 static int replmd_delete_internals(struct ldb_module *module, struct ldb_request *req, bool re_delete)
3035 int ret = LDB_ERR_OTHER;
3036 bool retb, disallow_move_on_delete;
3037 struct ldb_dn *old_dn, *new_dn;
3038 const char *rdn_name;
3039 const struct ldb_val *rdn_value, *new_rdn_value;
3041 struct ldb_context *ldb = ldb_module_get_ctx(module);
3042 const struct dsdb_schema *schema;
3043 struct ldb_message *msg, *old_msg;
3044 struct ldb_message_element *el;
3045 TALLOC_CTX *tmp_ctx;
3046 struct ldb_result *res, *parent_res;
3047 const char *preserved_attrs[] = {
3048 /* yes, this really is a hard coded list. See MS-ADTS
3049 section 3.1.1.5.5.1.1 */
3050 "nTSecurityDescriptor", "attributeID", "attributeSyntax", "dNReferenceUpdate", "dNSHostName",
3051 "flatName", "governsID", "groupType", "instanceType", "lDAPDisplayName", "legacyExchangeDN",
3052 "isDeleted", "isRecycled", "lastKnownParent", "msDS-LastKnownRDN", "mS-DS-CreatorSID",
3053 "mSMQOwnerID", "nCName", "objectClass", "distinguishedName", "objectGUID", "objectSid",
3054 "oMSyntax", "proxiedObjectName", "name", "replPropertyMetaData", "sAMAccountName",
3055 "securityIdentifier", "sIDHistory", "subClassOf", "systemFlags", "trustPartner", "trustDirection",
3056 "trustType", "trustAttributes", "userAccountControl", "uSNChanged", "uSNCreated", "whenCreated",
3057 "whenChanged", NULL};
3058 unsigned int i, el_count = 0;
3059 enum deletion_state deletion_state, next_deletion_state;
3061 if (ldb_dn_is_special(req->op.del.dn)) {
3062 return ldb_next_request(module, req);
3066 * We have to allow dbcheck to remove an object that
3067 * is beyond repair, and to do so totally. This could
3068 * mean we we can get a partial object from the other
3069 * DC, causing havoc, so dbcheck suggests
3070 * re-replication first. dbcheck sets both DBCHECK
3071 * and RELAX in this situation.
3073 if (ldb_request_get_control(req, LDB_CONTROL_RELAX_OID)
3074 && ldb_request_get_control(req, DSDB_CONTROL_DBCHECK)) {
3075 /* really, really remove it */
3076 return ldb_next_request(module, req);
3079 tmp_ctx = talloc_new(ldb);
3082 return LDB_ERR_OPERATIONS_ERROR;
3085 schema = dsdb_get_schema(ldb, tmp_ctx);
3087 talloc_free(tmp_ctx);
3088 return LDB_ERR_OPERATIONS_ERROR;
3091 old_dn = ldb_dn_copy(tmp_ctx, req->op.del.dn);
3093 /* we need the complete msg off disk, so we can work out which
3094 attributes need to be removed */
3095 ret = dsdb_module_search_dn(module, tmp_ctx, &res, old_dn, NULL,
3096 DSDB_FLAG_NEXT_MODULE |
3097 DSDB_SEARCH_SHOW_RECYCLED |
3098 DSDB_SEARCH_REVEAL_INTERNALS |
3099 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT, req);
3100 if (ret != LDB_SUCCESS) {
3101 ldb_asprintf_errstring(ldb_module_get_ctx(module),
3102 "repmd_delete: Failed to %s %s, because we failed to find it: %s",
3103 re_delete ? "re-delete" : "delete",
3104 ldb_dn_get_linearized(old_dn),
3105 ldb_errstring(ldb_module_get_ctx(module)));
3106 talloc_free(tmp_ctx);
3109 old_msg = res->msgs[0];
3111 replmd_deletion_state(module, old_msg,
3113 &next_deletion_state);
3115 /* This supports us noticing an incoming isDeleted and acting on it */
3117 SMB_ASSERT(deletion_state > OBJECT_NOT_DELETED);
3118 next_deletion_state = deletion_state;
3121 if (next_deletion_state == OBJECT_REMOVED) {
3123 * We have to prevent objects being deleted, even if
3124 * the administrator really wants them gone, as
3125 * without the tombstone, we can get a partial object
3126 * from the other DC, causing havoc.
3128 * The only other valid case is when the 180 day
3129 * timeout has expired, when relax is specified.
3131 if (ldb_request_get_control(req, LDB_CONTROL_RELAX_OID)) {
3132 /* it is already deleted - really remove it this time */
3133 talloc_free(tmp_ctx);
3134 return ldb_next_request(module, req);
3137 ldb_asprintf_errstring(ldb, "Refusing to delete tombstone object %s. "
3138 "This check is to prevent corruption of the replicated state.",
3139 ldb_dn_get_linearized(old_msg->dn));
3140 return LDB_ERR_UNWILLING_TO_PERFORM;
3143 rdn_name = ldb_dn_get_rdn_name(old_dn);
3144 rdn_value = ldb_dn_get_rdn_val(old_dn);
3145 if ((rdn_name == NULL) || (rdn_value == NULL)) {
3146 talloc_free(tmp_ctx);
3147 return ldb_operr(ldb);
3150 msg = ldb_msg_new(tmp_ctx);
3152 ldb_module_oom(module);
3153 talloc_free(tmp_ctx);
3154 return LDB_ERR_OPERATIONS_ERROR;
3159 /* consider the SYSTEM_FLAG_DISALLOW_MOVE_ON_DELETE flag */
3160 disallow_move_on_delete =
3161 (ldb_msg_find_attr_as_int(old_msg, "systemFlags", 0)
3162 & SYSTEM_FLAG_DISALLOW_MOVE_ON_DELETE);
3164 /* work out where we will be renaming this object to */
3165 if (!disallow_move_on_delete) {
3166 struct ldb_dn *deleted_objects_dn;
3167 ret = dsdb_get_deleted_objects_dn(ldb, tmp_ctx, old_dn,
3168 &deleted_objects_dn);
3171 * We should not move objects if we can't find the
3172 * deleted objects DN. Not moving (or otherwise
3173 * harming) the Deleted Objects DN itself is handled
3176 if (re_delete && (ret != LDB_SUCCESS)) {
3177 new_dn = ldb_dn_get_parent(tmp_ctx, old_dn);
3178 if (new_dn == NULL) {
3179 ldb_module_oom(module);
3180 talloc_free(tmp_ctx);
3181 return LDB_ERR_OPERATIONS_ERROR;
3183 } else if (ret != LDB_SUCCESS) {
3184 /* this is probably an attempted delete on a partition
3185 * that doesn't allow delete operations, such as the
3186 * schema partition */
3187 ldb_asprintf_errstring(ldb, "No Deleted Objects container for DN %s",
3188 ldb_dn_get_linearized(old_dn));
3189 talloc_free(tmp_ctx);
3190 return LDB_ERR_UNWILLING_TO_PERFORM;
3192 new_dn = deleted_objects_dn;
3195 new_dn = ldb_dn_get_parent(tmp_ctx, old_dn);
3196 if (new_dn == NULL) {
3197 ldb_module_oom(module);
3198 talloc_free(tmp_ctx);
3199 return LDB_ERR_OPERATIONS_ERROR;
3203 if (deletion_state == OBJECT_NOT_DELETED) {
3204 /* get the objects GUID from the search we just did */
3205 guid = samdb_result_guid(old_msg, "objectGUID");
3207 /* Add a formatted child */
3208 retb = ldb_dn_add_child_fmt(new_dn, "%s=%s\\0ADEL:%s",
3210 ldb_dn_escape_value(tmp_ctx, *rdn_value),
3211 GUID_string(tmp_ctx, &guid));
3213 ldb_asprintf_errstring(ldb, __location__
3214 ": Unable to add a formatted child to dn: %s",
3215 ldb_dn_get_linearized(new_dn));
3216 talloc_free(tmp_ctx);
3217 return LDB_ERR_OPERATIONS_ERROR;
3220 ret = ldb_msg_add_string(msg, "isDeleted", "TRUE");
3221 if (ret != LDB_SUCCESS) {
3222 ldb_asprintf_errstring(ldb, __location__
3223 ": Failed to add isDeleted string to the msg");
3224 talloc_free(tmp_ctx);
3227 msg->elements[el_count++].flags = LDB_FLAG_MOD_REPLACE;
3230 * No matter what has happened with other renames etc, try again to
3231 * get this to be under the deleted DN. See MS-DRSR 5.160 RemoveObj
3234 struct ldb_dn *rdn = ldb_dn_copy(tmp_ctx, old_dn);
3235 retb = ldb_dn_remove_base_components(rdn, ldb_dn_get_comp_num(rdn) - 1);
3237 ldb_asprintf_errstring(ldb, __location__
3238 ": Unable to add a prepare rdn of %s",
3239 ldb_dn_get_linearized(rdn));
3240 talloc_free(tmp_ctx);
3241 return LDB_ERR_OPERATIONS_ERROR;
3243 SMB_ASSERT(ldb_dn_get_comp_num(rdn) == 1);
3245 retb = ldb_dn_add_child(new_dn, rdn);
3247 ldb_asprintf_errstring(ldb, __location__
3248 ": Unable to add rdn %s to base dn: %s",
3249 ldb_dn_get_linearized(rdn),
3250 ldb_dn_get_linearized(new_dn));
3251 talloc_free(tmp_ctx);
3252 return LDB_ERR_OPERATIONS_ERROR;
3257 now we need to modify the object in the following ways:
3259 - add isDeleted=TRUE
3260 - update rDN and name, with new rDN
3261 - remove linked attributes
3262 - remove objectCategory and sAMAccountType
3263 - remove attribs not on the preserved list
3264 - preserved if in above list, or is rDN
3265 - remove all linked attribs from this object
3266 - remove all links from other objects to this object
3267 - add lastKnownParent
3268 - update replPropertyMetaData?
3270 see MS-ADTS "Tombstone Requirements" section 3.1.1.5.5.1.1
3273 if (deletion_state == OBJECT_NOT_DELETED) {
3274 struct ldb_dn *parent_dn = ldb_dn_get_parent(tmp_ctx, old_dn);
3275 char *parent_dn_str = NULL;
3277 /* we need the storage form of the parent GUID */
3278 ret = dsdb_module_search_dn(module, tmp_ctx, &parent_res,
3280 DSDB_FLAG_NEXT_MODULE |
3281 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT |
3282 DSDB_SEARCH_REVEAL_INTERNALS|
3283 DSDB_SEARCH_SHOW_RECYCLED, req);
3284 if (ret != LDB_SUCCESS) {
3285 ldb_asprintf_errstring(ldb_module_get_ctx(module),
3286 "repmd_delete: Failed to %s %s, "
3287 "because we failed to find it's parent (%s): %s",
3288 re_delete ? "re-delete" : "delete",
3289 ldb_dn_get_linearized(old_dn),
3290 ldb_dn_get_linearized(parent_dn),
3291 ldb_errstring(ldb_module_get_ctx(module)));
3292 talloc_free(tmp_ctx);
3297 * Now we can use the DB version,
3298 * it will have the extended DN info in it
3300 parent_dn = parent_res->msgs[0]->dn;
3301 parent_dn_str = ldb_dn_get_extended_linearized(tmp_ctx,
3304 if (parent_dn_str == NULL) {
3305 talloc_free(tmp_ctx);
3306 return ldb_module_oom(module);
3309 ret = ldb_msg_add_steal_string(msg, "lastKnownParent",
3311 if (ret != LDB_SUCCESS) {
3312 ldb_asprintf_errstring(ldb, __location__
3313 ": Failed to add lastKnownParent "
3314 "string when deleting %s",
3315 ldb_dn_get_linearized(old_dn));
3316 talloc_free(tmp_ctx);
3319 msg->elements[el_count++].flags = LDB_FLAG_MOD_REPLACE;
3321 if (next_deletion_state == OBJECT_DELETED) {
3322 ret = ldb_msg_add_value(msg, "msDS-LastKnownRDN", rdn_value, NULL);
3323 if (ret != LDB_SUCCESS) {
3324 ldb_asprintf_errstring(ldb, __location__
3325 ": Failed to add msDS-LastKnownRDN "
3326 "string when deleting %s",
3327 ldb_dn_get_linearized(old_dn));
3328 talloc_free(tmp_ctx);
3331 msg->elements[el_count++].flags = LDB_FLAG_MOD_ADD;
3335 switch (next_deletion_state) {
3337 case OBJECT_RECYCLED:
3338 case OBJECT_TOMBSTONE:
3341 * MS-ADTS 3.1.1.5.5.1.1 Tombstone Requirements
3342 * describes what must be removed from a tombstone
3345 * MS-ADTS 3.1.1.5.5.1.3 Recycled-Object Requirements
3346 * describes what must be removed from a recycled
3352 * we also mark it as recycled, meaning this object can't be
3353 * recovered (we are stripping its attributes).
3354 * This is done only if we have this schema object of course ...
3355 * This behavior is identical to the one of Windows 2008R2 which
3356 * always set the isRecycled attribute, even if the recycle-bin is
3357 * not activated and what ever the forest level is.
3359 if (dsdb_attribute_by_lDAPDisplayName(schema, "isRecycled") != NULL) {
3360 ret = ldb_msg_add_string(msg, "isRecycled", "TRUE");
3361 if (ret != LDB_SUCCESS) {
3362 DEBUG(0,(__location__ ": Failed to add isRecycled string to the msg\n"));
3363 ldb_module_oom(module);
3364 talloc_free(tmp_ctx);
3367 msg->elements[el_count++].flags = LDB_FLAG_MOD_REPLACE;
3370 /* work out which of the old attributes we will be removing */
3371 for (i=0; i<old_msg->num_elements; i++) {
3372 const struct dsdb_attribute *sa;
3373 el = &old_msg->elements[i];
3374 sa = dsdb_attribute_by_lDAPDisplayName(schema, el->name);
3376 talloc_free(tmp_ctx);
3377 return LDB_ERR_OPERATIONS_ERROR;
3379 if (ldb_attr_cmp(el->name, rdn_name) == 0) {
3380 /* don't remove the rDN */
3383 if (sa->linkID && (sa->linkID & 1)) {
3385 we have a backlink in this object
3386 that needs to be removed. We're not
3387 allowed to remove it directly
3388 however, so we instead setup a
3389 modify to delete the corresponding
3392 ret = replmd_delete_remove_link(module, schema, old_dn, el, sa, req);
3393 if (ret != LDB_SUCCESS) {
3394 const char *old_dn_str
3395 = ldb_dn_get_linearized(old_dn);
3396 ldb_asprintf_errstring(ldb,
3398 ": Failed to remove backlink of "
3399 "%s when deleting %s",
3402 talloc_free(tmp_ctx);
3403 return LDB_ERR_OPERATIONS_ERROR;
3405 /* now we continue, which means we
3406 won't remove this backlink
3412 if (ldb_attr_in_list(preserved_attrs, el->name)) {
3415 if (sa->searchFlags & SEARCH_FLAG_PRESERVEONDELETE) {
3419 ret = ldb_msg_add_empty(msg, el->name, LDB_FLAG_MOD_DELETE, &el);
3420 if (ret != LDB_SUCCESS) {
3421 talloc_free(tmp_ctx);
3422 ldb_module_oom(module);
3429 case OBJECT_DELETED:
3431 * MS-ADTS 3.1.1.5.5.1.2 Deleted-Object Requirements
3432 * describes what must be removed from a deleted
3436 ret = ldb_msg_add_empty(msg, "objectCategory", LDB_FLAG_MOD_REPLACE, NULL);
3437 if (ret != LDB_SUCCESS) {
3438 talloc_free(tmp_ctx);
3439 ldb_module_oom(module);
3443 ret = ldb_msg_add_empty(msg, "sAMAccountType", LDB_FLAG_MOD_REPLACE, NULL);
3444 if (ret != LDB_SUCCESS) {
3445 talloc_free(tmp_ctx);
3446 ldb_module_oom(module);
3456 if (deletion_state == OBJECT_NOT_DELETED) {
3457 const struct dsdb_attribute *sa;
3459 /* work out what the new rdn value is, for updating the
3460 rDN and name fields */
3461 new_rdn_value = ldb_dn_get_rdn_val(new_dn);
3462 if (new_rdn_value == NULL) {
3463 talloc_free(tmp_ctx);
3464 return ldb_operr(ldb);
3467 sa = dsdb_attribute_by_lDAPDisplayName(schema, rdn_name);
3469 talloc_free(tmp_ctx);
3470 return LDB_ERR_OPERATIONS_ERROR;
3473 ret = ldb_msg_add_value(msg, sa->lDAPDisplayName, new_rdn_value,
3475 if (ret != LDB_SUCCESS) {
3476 talloc_free(tmp_ctx);
3479 el->flags = LDB_FLAG_MOD_REPLACE;
3481 el = ldb_msg_find_element(old_msg, "name");
3483 ret = ldb_msg_add_value(msg, "name", new_rdn_value, &el);
3484 if (ret != LDB_SUCCESS) {
3485 talloc_free(tmp_ctx);
3488 el->flags = LDB_FLAG_MOD_REPLACE;
3493 * TODO: Per MS-DRSR 5.160 RemoveObj we should remove links directly, not as an originating update!
3498 * No matter what has happned with other renames, try again to
3499 * get this to be under the deleted DN.
3501 if (strcmp(ldb_dn_get_linearized(old_dn), ldb_dn_get_linearized(new_dn)) != 0) {
3502 /* now rename onto the new DN */
3503 ret = dsdb_module_rename(module, old_dn, new_dn, DSDB_FLAG_NEXT_MODULE, req);
3504 if (ret != LDB_SUCCESS){
3505 DEBUG(0,(__location__ ": Failed to rename object from '%s' to '%s' - %s\n",
3506 ldb_dn_get_linearized(old_dn),
3507 ldb_dn_get_linearized(new_dn),
3508 ldb_errstring(ldb)));
3509 talloc_free(tmp_ctx);
3515 ret = dsdb_module_modify(module, msg, DSDB_FLAG_OWN_MODULE, req);
3516 if (ret != LDB_SUCCESS) {
3517 ldb_asprintf_errstring(ldb, "replmd_delete: Failed to modify object %s in delete - %s",
3518 ldb_dn_get_linearized(old_dn), ldb_errstring(ldb));
3519 talloc_free(tmp_ctx);
3523 talloc_free(tmp_ctx);
3525 return ldb_module_done(req, NULL, NULL, LDB_SUCCESS);
3528 static int replmd_delete(struct ldb_module *module, struct ldb_request *req)
3530 return replmd_delete_internals(module, req, false);
3534 static int replmd_replicated_request_error(struct replmd_replicated_request *ar, int ret)
3539 static int replmd_replicated_request_werror(struct replmd_replicated_request *ar, WERROR status)
3541 int ret = LDB_ERR_OTHER;
3542 /* TODO: do some error mapping */
3544 /* Let the caller know the full WERROR */
3545 ar->objs->error = status;
3551 static struct replPropertyMetaData1 *
3552 replmd_replPropertyMetaData1_find_attid(struct replPropertyMetaDataBlob *md_blob,
3553 enum drsuapi_DsAttributeId attid)
3556 struct replPropertyMetaDataCtr1 *rpmd_ctr = &md_blob->ctr.ctr1;
3558 for (i = 0; i < rpmd_ctr->count; i++) {
3559 if (rpmd_ctr->array[i].attid == attid) {
3560 return &rpmd_ctr->array[i];
3568 return true if an update is newer than an existing entry
3569 see section 5.11 of MS-ADTS
3571 static bool replmd_update_is_newer(const struct GUID *current_invocation_id,
3572 const struct GUID *update_invocation_id,
3573 uint32_t current_version,
3574 uint32_t update_version,
3575 NTTIME current_change_time,
3576 NTTIME update_change_time)
3578 if (update_version != current_version) {
3579 return update_version > current_version;
3581 if (update_change_time != current_change_time) {
3582 return update_change_time > current_change_time;
3584 return GUID_compare(update_invocation_id, current_invocation_id) > 0;
3587 static bool replmd_replPropertyMetaData1_is_newer(struct replPropertyMetaData1 *cur_m,
3588 struct replPropertyMetaData1 *new_m)
3590 return replmd_update_is_newer(&cur_m->originating_invocation_id,
3591 &new_m->originating_invocation_id,
3594 cur_m->originating_change_time,
3595 new_m->originating_change_time);
3598 static bool replmd_replPropertyMetaData1_new_should_be_taken(uint32_t dsdb_repl_flags,
3599 struct replPropertyMetaData1 *cur_m,
3600 struct replPropertyMetaData1 *new_m)
3605 * If the new replPropertyMetaData entry for this attribute is
3606 * not provided (this happens in the case where we look for
3607 * ATTID_name, but the name was not changed), then the local
3608 * state is clearly still current, as the remote
3609 * server didn't send it due to being older the high watermark
3612 if (new_m == NULL) {
3616 if (dsdb_repl_flags & DSDB_REPL_FLAG_PRIORITISE_INCOMING) {
3618 * if we compare equal then do an
3619 * update. This is used when a client
3620 * asks for a FULL_SYNC, and can be
3621 * used to recover a corrupt
3624 * This call is a bit tricky, what we
3625 * are doing it turning the 'is_newer'
3626 * call into a 'not is older' by
3627 * swapping cur_m and new_m, and negating the
3630 cmp = !replmd_replPropertyMetaData1_is_newer(new_m,
3633 cmp = replmd_replPropertyMetaData1_is_newer(cur_m,
3643 static struct ldb_dn *replmd_conflict_dn(TALLOC_CTX *mem_ctx, struct ldb_dn *dn, struct GUID *guid)
3645 const struct ldb_val *rdn_val;
3646 const char *rdn_name;
3647 struct ldb_dn *new_dn;
3649 rdn_val = ldb_dn_get_rdn_val(dn);
3650 rdn_name = ldb_dn_get_rdn_name(dn);
3651 if (!rdn_val || !rdn_name) {
3655 new_dn = ldb_dn_copy(mem_ctx, dn);
3660 if (!ldb_dn_remove_child_components(new_dn, 1)) {
3664 if (!ldb_dn_add_child_fmt(new_dn, "%s=%s\\0ACNF:%s",
3666 ldb_dn_escape_value(new_dn, *rdn_val),
3667 GUID_string(new_dn, guid))) {
3676 perform a modify operation which sets the rDN and name attributes to
3677 their current values. This has the effect of changing these
3678 attributes to have been last updated by the current DC. This is
3679 needed to ensure that renames performed as part of conflict
3680 resolution are propogated to other DCs
3682 static int replmd_name_modify(struct replmd_replicated_request *ar,
3683 struct ldb_request *req, struct ldb_dn *dn)
3685 struct ldb_message *msg;
3686 const char *rdn_name;
3687 const struct ldb_val *rdn_val;
3688 const struct dsdb_attribute *rdn_attr;
3691 msg = ldb_msg_new(req);
3697 rdn_name = ldb_dn_get_rdn_name(dn);
3698 if (rdn_name == NULL) {
3702 /* normalize the rdn attribute name */
3703 rdn_attr = dsdb_attribute_by_lDAPDisplayName(ar->schema, rdn_name);
3704 if (rdn_attr == NULL) {
3707 rdn_name = rdn_attr->lDAPDisplayName;
3709 rdn_val = ldb_dn_get_rdn_val(dn);
3710 if (rdn_val == NULL) {
3714 if (ldb_msg_add_empty(msg, rdn_name, LDB_FLAG_MOD_REPLACE, NULL) != 0) {
3717 if (ldb_msg_add_value(msg, rdn_name, rdn_val, NULL) != 0) {
3720 if (ldb_msg_add_empty(msg, "name", LDB_FLAG_MOD_REPLACE, NULL) != 0) {
3723 if (ldb_msg_add_value(msg, "name", rdn_val, NULL) != 0) {
3727 ret = dsdb_module_modify(ar->module, msg, DSDB_FLAG_OWN_MODULE, req);
3728 if (ret != LDB_SUCCESS) {
3729 DEBUG(0,(__location__ ": Failed to modify rDN/name of conflict DN '%s' - %s",
3730 ldb_dn_get_linearized(dn),
3731 ldb_errstring(ldb_module_get_ctx(ar->module))));
3741 DEBUG(0,(__location__ ": Failed to setup modify rDN/name of conflict DN '%s'",
3742 ldb_dn_get_linearized(dn)));
3743 return LDB_ERR_OPERATIONS_ERROR;
3748 callback for conflict DN handling where we have renamed the incoming
3749 record. After renaming it, we need to ensure the change of name and
3750 rDN for the incoming record is seen as an originating update by this DC.
3752 This also handles updating lastKnownParent for entries sent to lostAndFound
3754 static int replmd_op_name_modify_callback(struct ldb_request *req, struct ldb_reply *ares)
3756 struct replmd_replicated_request *ar =
3757 talloc_get_type_abort(req->context, struct replmd_replicated_request);
3758 struct ldb_dn *conflict_dn = NULL;
3761 if (ares->error != LDB_SUCCESS) {
3762 /* call the normal callback for everything except success */
3763 return replmd_op_callback(req, ares);
3766 switch (req->operation) {
3768 conflict_dn = req->op.add.message->dn;
3771 conflict_dn = req->op.mod.message->dn;
3774 smb_panic("replmd_op_name_modify_callback called in unknown circumstances");
3777 /* perform a modify of the rDN and name of the record */
3778 ret = replmd_name_modify(ar, req, conflict_dn);
3779 if (ret != LDB_SUCCESS) {
3781 return replmd_op_callback(req, ares);
3784 if (ar->objs->objects[ar->index_current].last_known_parent) {
3785 struct ldb_message *msg = ldb_msg_new(req);
3787 ldb_module_oom(ar->module);
3788 return LDB_ERR_OPERATIONS_ERROR;
3791 msg->dn = req->op.add.message->dn;
3793 ret = ldb_msg_add_steal_string(msg, "lastKnownParent",
3794 ldb_dn_get_extended_linearized(msg, ar->objs->objects[ar->index_current].last_known_parent, 1));
3795 if (ret != LDB_SUCCESS) {
3796 DEBUG(0,(__location__ ": Failed to add lastKnownParent string to the msg\n"));
3797 ldb_module_oom(ar->module);
3800 msg->elements[0].flags = LDB_FLAG_MOD_REPLACE;
3802 ret = dsdb_module_modify(ar->module, msg, DSDB_FLAG_OWN_MODULE, req);
3803 if (ret != LDB_SUCCESS) {
3804 DEBUG(0,(__location__ ": Failed to modify lastKnownParent of lostAndFound DN '%s' - %s",
3805 ldb_dn_get_linearized(msg->dn),
3806 ldb_errstring(ldb_module_get_ctx(ar->module))));
3812 return replmd_op_callback(req, ares);
3816 callback for replmd_replicated_apply_add()
3817 This copes with the creation of conflict records in the case where
3818 the DN exists, but with a different objectGUID
3820 static int replmd_op_possible_conflict_callback(struct ldb_request *req, struct ldb_reply *ares, int (*callback)(struct ldb_request *req, struct ldb_reply *ares))
3822 struct ldb_dn *conflict_dn;
3823 struct replmd_replicated_request *ar =
3824 talloc_get_type_abort(req->context, struct replmd_replicated_request);
3825 struct ldb_result *res;
3826 const char *attrs[] = { "replPropertyMetaData", "objectGUID", NULL };
3828 const struct ldb_val *omd_value;
3829 struct replPropertyMetaDataBlob omd, *rmd;
3830 enum ndr_err_code ndr_err;
3831 bool rename_incoming_record, rodc;
3832 struct replPropertyMetaData1 *rmd_name, *omd_name;
3833 struct ldb_message *msg;
3834 struct ldb_request *down_req = NULL;
3836 /* call the normal callback for success */
3837 if (ares->error == LDB_SUCCESS) {
3838 return callback(req, ares);
3842 * we have a conflict, and need to decide if we will keep the
3843 * new record or the old record
3846 msg = ar->objs->objects[ar->index_current].msg;
3847 conflict_dn = msg->dn;
3849 /* For failures other than conflicts, fail the whole operation here */
3850 if (ares->error != LDB_ERR_ENTRY_ALREADY_EXISTS) {
3851 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module), "Failed to locally apply remote add of %s: %s",
3852 ldb_dn_get_linearized(conflict_dn),
3853 ldb_errstring(ldb_module_get_ctx(ar->module)));
3855 return ldb_module_done(ar->req, NULL, NULL,
3856 LDB_ERR_OPERATIONS_ERROR);
3859 ret = samdb_rodc(ldb_module_get_ctx(ar->module), &rodc);
3860 if (ret != LDB_SUCCESS) {
3861 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module), "Failed to determine if we are an RODC when attempting to form conflict DN: %s", ldb_errstring(ldb_module_get_ctx(ar->module)));
3862 return ldb_module_done(ar->req, NULL, NULL,
3863 LDB_ERR_OPERATIONS_ERROR);
3869 * We are on an RODC, or were a GC for this
3870 * partition, so we have to fail this until
3871 * someone who owns the partition sorts it
3874 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
3875 "Conflict adding object '%s' from incoming replication as we are read only for the partition. \n"
3876 " - We must fail the operation until a master for this partition resolves the conflict",
3877 ldb_dn_get_linearized(conflict_dn));
3882 * first we need the replPropertyMetaData attribute from the
3883 * local, conflicting record
3885 ret = dsdb_module_search_dn(ar->module, req, &res, conflict_dn,
3887 DSDB_FLAG_NEXT_MODULE |
3888 DSDB_SEARCH_SHOW_DELETED |
3889 DSDB_SEARCH_SHOW_RECYCLED, req);
3890 if (ret != LDB_SUCCESS) {
3891 DEBUG(0,(__location__ ": Unable to find object for conflicting record '%s'\n",
3892 ldb_dn_get_linearized(conflict_dn)));
3896 omd_value = ldb_msg_find_ldb_val(res->msgs[0], "replPropertyMetaData");
3897 if (omd_value == NULL) {
3898 DEBUG(0,(__location__ ": Unable to find replPropertyMetaData for conflicting record '%s'\n",
3899 ldb_dn_get_linearized(conflict_dn)));
3903 ndr_err = ndr_pull_struct_blob(omd_value, res->msgs[0], &omd,
3904 (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
3905 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
3906 DEBUG(0,(__location__ ": Failed to parse old replPropertyMetaData for %s\n",
3907 ldb_dn_get_linearized(conflict_dn)));
3911 rmd = ar->objs->objects[ar->index_current].meta_data;
3914 * we decide which is newer based on the RPMD on the name
3915 * attribute. See [MS-DRSR] ResolveNameConflict.
3917 * We expect omd_name to be present, as this is from a local
3918 * search, but while rmd_name should have been given to us by
3919 * the remote server, if it is missing we just prefer the
3921 * replmd_replPropertyMetaData1_new_should_be_taken()
3923 rmd_name = replmd_replPropertyMetaData1_find_attid(rmd, DRSUAPI_ATTID_name);
3924 omd_name = replmd_replPropertyMetaData1_find_attid(&omd, DRSUAPI_ATTID_name);
3926 DEBUG(0,(__location__ ": Failed to find name attribute in local LDB replPropertyMetaData for %s\n",
3927 ldb_dn_get_linearized(conflict_dn)));
3932 * Should we preserve the current record, and so rename the
3933 * incoming record to be a conflict?
3935 rename_incoming_record
3936 = !replmd_replPropertyMetaData1_new_should_be_taken(ar->objs->dsdb_repl_flags & DSDB_REPL_FLAG_PRIORITISE_INCOMING,
3937 omd_name, rmd_name);
3939 if (rename_incoming_record) {
3941 struct ldb_dn *new_dn;
3943 guid = samdb_result_guid(msg, "objectGUID");
3944 if (GUID_all_zero(&guid)) {
3945 DEBUG(0,(__location__ ": Failed to find objectGUID for conflicting incoming record %s\n",
3946 ldb_dn_get_linearized(conflict_dn)));
3949 new_dn = replmd_conflict_dn(req, conflict_dn, &guid);
3950 if (new_dn == NULL) {
3951 DEBUG(0,(__location__ ": Failed to form conflict DN for %s\n",
3952 ldb_dn_get_linearized(conflict_dn)));
3956 DEBUG(2,(__location__ ": Resolving conflict record via incoming rename '%s' -> '%s'\n",
3957 ldb_dn_get_linearized(conflict_dn), ldb_dn_get_linearized(new_dn)));
3959 /* re-submit the request, but with the new DN */
3960 callback = replmd_op_name_modify_callback;
3963 /* we are renaming the existing record */
3965 struct ldb_dn *new_dn;
3967 guid = samdb_result_guid(res->msgs[0], "objectGUID");
3968 if (GUID_all_zero(&guid)) {
3969 DEBUG(0,(__location__ ": Failed to find objectGUID for existing conflict record %s\n",
3970 ldb_dn_get_linearized(conflict_dn)));
3974 new_dn = replmd_conflict_dn(req, conflict_dn, &guid);
3975 if (new_dn == NULL) {
3976 DEBUG(0,(__location__ ": Failed to form conflict DN for %s\n",
3977 ldb_dn_get_linearized(conflict_dn)));
3981 DEBUG(2,(__location__ ": Resolving conflict record via existing-record rename '%s' -> '%s'\n",
3982 ldb_dn_get_linearized(conflict_dn), ldb_dn_get_linearized(new_dn)));
3984 ret = dsdb_module_rename(ar->module, conflict_dn, new_dn,
3985 DSDB_FLAG_OWN_MODULE, req);
3986 if (ret != LDB_SUCCESS) {
3987 DEBUG(0,(__location__ ": Failed to rename conflict dn '%s' to '%s' - %s\n",
3988 ldb_dn_get_linearized(conflict_dn),
3989 ldb_dn_get_linearized(new_dn),
3990 ldb_errstring(ldb_module_get_ctx(ar->module))));
3995 * now we need to ensure that the rename is seen as an
3996 * originating update. We do that with a modify.
3998 ret = replmd_name_modify(ar, req, new_dn);
3999 if (ret != LDB_SUCCESS) {
4003 DEBUG(2,(__location__ ": With conflicting record renamed, re-apply replicated creation of '%s'\n",
4004 ldb_dn_get_linearized(req->op.add.message->dn)));
4007 ret = ldb_build_add_req(&down_req,
4008 ldb_module_get_ctx(ar->module),
4015 if (ret != LDB_SUCCESS) {
4018 LDB_REQ_SET_LOCATION(down_req);
4020 /* current partition control needed by "repmd_op_callback" */
4021 ret = ldb_request_add_control(down_req,
4022 DSDB_CONTROL_CURRENT_PARTITION_OID,
4024 if (ret != LDB_SUCCESS) {
4025 return replmd_replicated_request_error(ar, ret);
4028 if (ar->objs->dsdb_repl_flags & DSDB_REPL_FLAG_PARTIAL_REPLICA) {
4029 /* this tells the partition module to make it a
4030 partial replica if creating an NC */
4031 ret = ldb_request_add_control(down_req,
4032 DSDB_CONTROL_PARTIAL_REPLICA,
4034 if (ret != LDB_SUCCESS) {
4035 return replmd_replicated_request_error(ar, ret);
4040 * Finally we re-run the add, otherwise the new record won't
4041 * exist, as we are here because of that exact failure!
4043 return ldb_next_request(ar->module, down_req);
4046 /* on failure make the caller get the error. This means
4047 * replication will stop with an error, but there is not much
4050 return ldb_module_done(ar->req, NULL, NULL,
4055 callback for replmd_replicated_apply_add()
4056 This copes with the creation of conflict records in the case where
4057 the DN exists, but with a different objectGUID
4059 static int replmd_op_add_callback(struct ldb_request *req, struct ldb_reply *ares)
4061 struct replmd_replicated_request *ar =
4062 talloc_get_type_abort(req->context, struct replmd_replicated_request);
4064 if (ar->objs->objects[ar->index_current].last_known_parent) {
4065 /* This is like a conflict DN, where we put the object in LostAndFound
4066 see MS-DRSR 4.1.10.6.10 FindBestParentObject */
4067 return replmd_op_possible_conflict_callback(req, ares, replmd_op_name_modify_callback);
4070 return replmd_op_possible_conflict_callback(req, ares, replmd_op_callback);
4074 this is called when a new object comes in over DRS
4076 static int replmd_replicated_apply_add(struct replmd_replicated_request *ar)
4078 struct ldb_context *ldb;
4079 struct ldb_request *change_req;
4080 enum ndr_err_code ndr_err;
4081 struct ldb_message *msg;
4082 struct replPropertyMetaDataBlob *md;
4083 struct ldb_val md_value;
4086 bool remote_isDeleted = false;
4089 time_t t = time(NULL);
4090 const struct ldb_val *rdn_val;
4091 struct replmd_private *replmd_private =
4092 talloc_get_type(ldb_module_get_private(ar->module),
4093 struct replmd_private);
4094 unix_to_nt_time(&now, t);
4096 ldb = ldb_module_get_ctx(ar->module);
4097 msg = ar->objs->objects[ar->index_current].msg;
4098 md = ar->objs->objects[ar->index_current].meta_data;
4099 is_schema_nc = ldb_dn_compare_base(replmd_private->schema_dn, msg->dn) == 0;
4101 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &ar->seq_num);
4102 if (ret != LDB_SUCCESS) {
4103 return replmd_replicated_request_error(ar, ret);
4106 ret = dsdb_msg_add_guid(msg,
4107 &ar->objs->objects[ar->index_current].object_guid,
4109 if (ret != LDB_SUCCESS) {
4110 return replmd_replicated_request_error(ar, ret);
4113 ret = ldb_msg_add_string(msg, "whenChanged", ar->objs->objects[ar->index_current].when_changed);
4114 if (ret != LDB_SUCCESS) {
4115 return replmd_replicated_request_error(ar, ret);
4118 ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNCreated", ar->seq_num);
4119 if (ret != LDB_SUCCESS) {
4120 return replmd_replicated_request_error(ar, ret);
4123 ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNChanged", ar->seq_num);
4124 if (ret != LDB_SUCCESS) {
4125 return replmd_replicated_request_error(ar, ret);
4128 /* remove any message elements that have zero values */
4129 for (i=0; i<msg->num_elements; i++) {
4130 struct ldb_message_element *el = &msg->elements[i];
4132 if (el->num_values == 0) {
4133 if (ldb_attr_cmp(msg->elements[i].name, "objectClass") == 0) {
4134 ldb_asprintf_errstring(ldb, __location__
4135 ": empty objectClass sent on %s, aborting replication\n",
4136 ldb_dn_get_linearized(msg->dn));
4137 return replmd_replicated_request_error(ar, LDB_ERR_OBJECT_CLASS_VIOLATION);
4140 DEBUG(4,(__location__ ": Removing attribute %s with num_values==0\n",
4142 memmove(el, el+1, sizeof(*el)*(msg->num_elements - (i+1)));
4143 msg->num_elements--;
4150 struct GUID_txt_buf guid_txt;
4152 char *s = ldb_ldif_message_string(ldb, ar, LDB_CHANGETYPE_ADD, msg);
4153 DEBUG(4, ("DRS replication add message of %s:\n%s\n",
4154 GUID_buf_string(&ar->objs->objects[ar->index_current].object_guid, &guid_txt),
4159 remote_isDeleted = ldb_msg_find_attr_as_bool(msg,
4160 "isDeleted", false);
4163 * the meta data array is already sorted by the caller, except
4164 * for the RDN, which needs to be added.
4168 rdn_val = ldb_dn_get_rdn_val(msg->dn);
4169 ret = replmd_update_rpmd_rdn_attr(ldb, msg, rdn_val, NULL,
4170 md, ar, now, is_schema_nc);
4171 if (ret != LDB_SUCCESS) {
4172 ldb_asprintf_errstring(ldb, "%s: error during DRS repl ADD: %s", __func__, ldb_errstring(ldb));
4173 return replmd_replicated_request_error(ar, ret);
4176 ret = replmd_replPropertyMetaDataCtr1_sort_and_verify(ldb, &md->ctr.ctr1, msg->dn);
4177 if (ret != LDB_SUCCESS) {
4178 ldb_asprintf_errstring(ldb, "%s: error during DRS repl ADD: %s", __func__, ldb_errstring(ldb));
4179 return replmd_replicated_request_error(ar, ret);
4182 for (i=0; i < md->ctr.ctr1.count; i++) {
4183 md->ctr.ctr1.array[i].local_usn = ar->seq_num;
4185 ndr_err = ndr_push_struct_blob(&md_value, msg, md,
4186 (ndr_push_flags_fn_t)ndr_push_replPropertyMetaDataBlob);
4187 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
4188 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
4189 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
4191 ret = ldb_msg_add_value(msg, "replPropertyMetaData", &md_value, NULL);
4192 if (ret != LDB_SUCCESS) {
4193 return replmd_replicated_request_error(ar, ret);
4196 replmd_ldb_message_sort(msg, ar->schema);
4198 if (!remote_isDeleted) {
4199 ret = dsdb_module_schedule_sd_propagation(ar->module,
4200 ar->objs->partition_dn,
4202 if (ret != LDB_SUCCESS) {
4203 return replmd_replicated_request_error(ar, ret);
4207 ar->isDeleted = remote_isDeleted;
4209 ret = ldb_build_add_req(&change_req,
4215 replmd_op_add_callback,
4217 LDB_REQ_SET_LOCATION(change_req);
4218 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
4220 /* current partition control needed by "repmd_op_callback" */
4221 ret = ldb_request_add_control(change_req,
4222 DSDB_CONTROL_CURRENT_PARTITION_OID,
4224 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
4226 if (ar->objs->dsdb_repl_flags & DSDB_REPL_FLAG_PARTIAL_REPLICA) {
4227 /* this tells the partition module to make it a
4228 partial replica if creating an NC */
4229 ret = ldb_request_add_control(change_req,
4230 DSDB_CONTROL_PARTIAL_REPLICA,
4232 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
4235 return ldb_next_request(ar->module, change_req);
4238 static int replmd_replicated_apply_search_for_parent_callback(struct ldb_request *req,
4239 struct ldb_reply *ares)
4241 struct replmd_replicated_request *ar = talloc_get_type(req->context,
4242 struct replmd_replicated_request);
4246 return ldb_module_done(ar->req, NULL, NULL,
4247 LDB_ERR_OPERATIONS_ERROR);
4251 * The error NO_SUCH_OBJECT is not expected, unless the search
4252 * base is the partition DN, and that case doesn't happen here
4253 * because then we wouldn't get a parent_guid_value in any
4256 if (ares->error != LDB_SUCCESS) {
4257 return ldb_module_done(ar->req, ares->controls,
4258 ares->response, ares->error);
4261 switch (ares->type) {
4262 case LDB_REPLY_ENTRY:
4264 struct ldb_message *parent_msg = ares->message;
4265 struct ldb_message *msg = ar->objs->objects[ar->index_current].msg;
4266 struct ldb_dn *parent_dn;
4269 if (!ldb_msg_check_string_attribute(msg, "isDeleted", "TRUE")
4270 && ldb_msg_check_string_attribute(parent_msg, "isDeleted", "TRUE")) {
4271 /* Per MS-DRSR 4.1.10.6.10
4272 * FindBestParentObject we need to move this
4273 * new object under a deleted object to
4275 struct ldb_dn *nc_root;
4277 ret = dsdb_find_nc_root(ldb_module_get_ctx(ar->module), msg, msg->dn, &nc_root);
4278 if (ret == LDB_ERR_NO_SUCH_OBJECT) {
4279 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
4280 "No suitable NC root found for %s. "
4281 "We need to move this object because parent object %s "
4282 "is deleted, but this object is not.",
4283 ldb_dn_get_linearized(msg->dn),
4284 ldb_dn_get_linearized(parent_msg->dn));
4285 return ldb_module_done(ar->req, NULL, NULL, LDB_ERR_OPERATIONS_ERROR);
4286 } else if (ret != LDB_SUCCESS) {
4287 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
4288 "Unable to find NC root for %s: %s. "
4289 "We need to move this object because parent object %s "
4290 "is deleted, but this object is not.",
4291 ldb_dn_get_linearized(msg->dn),
4292 ldb_errstring(ldb_module_get_ctx(ar->module)),
4293 ldb_dn_get_linearized(parent_msg->dn));
4294 return ldb_module_done(ar->req, NULL, NULL, LDB_ERR_OPERATIONS_ERROR);
4297 ret = dsdb_wellknown_dn(ldb_module_get_ctx(ar->module), msg,
4299 DS_GUID_LOSTANDFOUND_CONTAINER,
4301 if (ret != LDB_SUCCESS) {
4302 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
4303 "Unable to find LostAndFound Container for %s "
4304 "in partition %s: %s. "
4305 "We need to move this object because parent object %s "
4306 "is deleted, but this object is not.",
4307 ldb_dn_get_linearized(msg->dn), ldb_dn_get_linearized(nc_root),
4308 ldb_errstring(ldb_module_get_ctx(ar->module)),
4309 ldb_dn_get_linearized(parent_msg->dn));
4310 return ldb_module_done(ar->req, NULL, NULL, LDB_ERR_OPERATIONS_ERROR);
4312 ar->objs->objects[ar->index_current].last_known_parent
4313 = talloc_steal(ar->objs->objects[ar->index_current].msg, parent_msg->dn);
4317 = talloc_steal(ar->objs->objects[ar->index_current].msg, parent_msg->dn);
4320 ar->objs->objects[ar->index_current].local_parent_dn = parent_dn;
4322 comp_num = ldb_dn_get_comp_num(msg->dn);
4324 if (!ldb_dn_remove_base_components(msg->dn, comp_num - 1)) {
4326 return ldb_module_done(ar->req, NULL, NULL, ldb_module_operr(ar->module));
4329 if (!ldb_dn_add_base(msg->dn, parent_dn)) {
4331 return ldb_module_done(ar->req, NULL, NULL, ldb_module_operr(ar->module));
4335 case LDB_REPLY_REFERRAL:
4336 /* we ignore referrals */
4339 case LDB_REPLY_DONE:
4341 if (ar->objs->objects[ar->index_current].local_parent_dn == NULL) {
4342 struct GUID_txt_buf str_buf;
4343 if (ar->search_msg != NULL) {
4344 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
4345 "No parent with GUID %s found for object locally known as %s",
4346 GUID_buf_string(ar->objs->objects[ar->index_current].parent_guid, &str_buf),
4347 ldb_dn_get_linearized(ar->search_msg->dn));
4349 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
4350 "No parent with GUID %s found for object remotely known as %s",
4351 GUID_buf_string(ar->objs->objects[ar->index_current].parent_guid, &str_buf),
4352 ldb_dn_get_linearized(ar->objs->objects[ar->index_current].msg->dn));
4356 * This error code is really important, as it
4357 * is the flag back to the callers to retry
4358 * this with DRSUAPI_DRS_GET_ANC, and so get
4359 * the parent objects before the child
4362 return ldb_module_done(ar->req, NULL, NULL,
4363 replmd_replicated_request_werror(ar, WERR_DS_DRA_MISSING_PARENT));
4366 if (ar->search_msg != NULL) {
4367 ret = replmd_replicated_apply_merge(ar);
4369 ret = replmd_replicated_apply_add(ar);
4371 if (ret != LDB_SUCCESS) {
4372 return ldb_module_done(ar->req, NULL, NULL, ret);
4381 * Look for the parent object, so we put the new object in the right
4382 * place This is akin to NameObject in MS-DRSR - this routine and the
4383 * callbacks find the right parent name, and correct name for this
4387 static int replmd_replicated_apply_search_for_parent(struct replmd_replicated_request *ar)
4389 struct ldb_context *ldb;
4393 struct ldb_request *search_req;
4394 static const char *attrs[] = {"isDeleted", NULL};
4395 struct GUID_txt_buf guid_str_buf;
4397 ldb = ldb_module_get_ctx(ar->module);
4399 if (ar->objs->objects[ar->index_current].parent_guid == NULL) {
4400 if (ar->search_msg != NULL) {
4401 return replmd_replicated_apply_merge(ar);
4403 return replmd_replicated_apply_add(ar);
4407 tmp_str = GUID_buf_string(ar->objs->objects[ar->index_current].parent_guid,
4410 filter = talloc_asprintf(ar, "(objectGUID=%s)", tmp_str);
4411 if (!filter) return replmd_replicated_request_werror(ar, WERR_NOMEM);
4413 ret = ldb_build_search_req(&search_req,
4416 ar->objs->partition_dn,
4422 replmd_replicated_apply_search_for_parent_callback,
4424 LDB_REQ_SET_LOCATION(search_req);
4426 ret = dsdb_request_add_controls(search_req,
4427 DSDB_SEARCH_SHOW_RECYCLED|
4428 DSDB_SEARCH_SHOW_DELETED|
4429 DSDB_SEARCH_SHOW_EXTENDED_DN);
4430 if (ret != LDB_SUCCESS) {
4434 return ldb_next_request(ar->module, search_req);
4438 handle renames that come in over DRS replication
4440 static int replmd_replicated_handle_rename(struct replmd_replicated_request *ar,
4441 struct ldb_message *msg,
4442 struct ldb_request *parent,
4446 TALLOC_CTX *tmp_ctx = talloc_new(msg);
4447 struct ldb_result *res;
4448 struct ldb_dn *conflict_dn;
4449 const char *attrs[] = { "replPropertyMetaData", "objectGUID", NULL };
4450 const struct ldb_val *omd_value;
4451 struct replPropertyMetaDataBlob omd, *rmd;
4452 enum ndr_err_code ndr_err;
4453 bool rename_incoming_record, rodc;
4454 struct replPropertyMetaData1 *rmd_name, *omd_name;
4455 struct ldb_dn *new_dn;
4458 DEBUG(4,("replmd_replicated_request rename %s => %s\n",
4459 ldb_dn_get_linearized(ar->search_msg->dn),
4460 ldb_dn_get_linearized(msg->dn)));
4463 ret = dsdb_module_rename(ar->module, ar->search_msg->dn, msg->dn,
4464 DSDB_FLAG_NEXT_MODULE, ar->req);
4465 if (ret == LDB_SUCCESS) {
4466 talloc_free(tmp_ctx);
4471 if (ret != LDB_ERR_ENTRY_ALREADY_EXISTS) {
4472 talloc_free(tmp_ctx);
4473 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module), "Failed to locally apply remote rename from %s to %s: %s",
4474 ldb_dn_get_linearized(ar->search_msg->dn),
4475 ldb_dn_get_linearized(msg->dn),
4476 ldb_errstring(ldb_module_get_ctx(ar->module)));
4480 ret = samdb_rodc(ldb_module_get_ctx(ar->module), &rodc);
4481 if (ret != LDB_SUCCESS) {
4482 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
4483 "Failed to determine if we are an RODC when attempting to form conflict DN: %s",
4484 ldb_errstring(ldb_module_get_ctx(ar->module)));
4485 return LDB_ERR_OPERATIONS_ERROR;
4488 * we have a conflict, and need to decide if we will keep the
4489 * new record or the old record
4492 conflict_dn = msg->dn;
4496 * We are on an RODC, or were a GC for this
4497 * partition, so we have to fail this until
4498 * someone who owns the partition sorts it
4501 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
4502 "Conflict adding object '%s' from incoming replication but we are read only for the partition. \n"
4503 " - We must fail the operation until a master for this partition resolves the conflict",
4504 ldb_dn_get_linearized(conflict_dn));
4509 * first we need the replPropertyMetaData attribute from the
4512 ret = dsdb_module_search_dn(ar->module, tmp_ctx, &res, conflict_dn,
4514 DSDB_FLAG_NEXT_MODULE |
4515 DSDB_SEARCH_SHOW_DELETED |
4516 DSDB_SEARCH_SHOW_RECYCLED, ar->req);
4517 if (ret != LDB_SUCCESS) {
4518 DEBUG(0,(__location__ ": Unable to find object for conflicting record '%s'\n",
4519 ldb_dn_get_linearized(conflict_dn)));
4523 omd_value = ldb_msg_find_ldb_val(res->msgs[0], "replPropertyMetaData");
4524 if (omd_value == NULL) {
4525 DEBUG(0,(__location__ ": Unable to find replPropertyMetaData for conflicting record '%s'\n",
4526 ldb_dn_get_linearized(conflict_dn)));
4530 ndr_err = ndr_pull_struct_blob(omd_value, res->msgs[0], &omd,
4531 (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
4532 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
4533 DEBUG(0,(__location__ ": Failed to parse old replPropertyMetaData for %s\n",
4534 ldb_dn_get_linearized(conflict_dn)));
4538 rmd = ar->objs->objects[ar->index_current].meta_data;
4541 * we decide which is newer based on the RPMD on the name
4542 * attribute. See [MS-DRSR] ResolveNameConflict.
4544 * We expect omd_name to be present, as this is from a local
4545 * search, but while rmd_name should have been given to us by
4546 * the remote server, if it is missing we just prefer the
4548 * replmd_replPropertyMetaData1_new_should_be_taken()
4550 rmd_name = replmd_replPropertyMetaData1_find_attid(rmd, DRSUAPI_ATTID_name);
4551 omd_name = replmd_replPropertyMetaData1_find_attid(&omd, DRSUAPI_ATTID_name);
4553 DEBUG(0,(__location__ ": Failed to find name attribute in local LDB replPropertyMetaData for %s\n",
4554 ldb_dn_get_linearized(conflict_dn)));
4559 * Should we preserve the current record, and so rename the
4560 * incoming record to be a conflict?
4562 rename_incoming_record =
4563 !replmd_replPropertyMetaData1_new_should_be_taken(
4564 ar->objs->dsdb_repl_flags & DSDB_REPL_FLAG_PRIORITISE_INCOMING,
4565 omd_name, rmd_name);
4567 if (rename_incoming_record) {
4569 new_dn = replmd_conflict_dn(msg, msg->dn,
4570 &ar->objs->objects[ar->index_current].object_guid);
4571 if (new_dn == NULL) {
4572 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
4573 "Failed to form conflict DN for %s\n",
4574 ldb_dn_get_linearized(msg->dn));
4576 return replmd_replicated_request_werror(ar, WERR_NOMEM);
4579 ret = dsdb_module_rename(ar->module, ar->search_msg->dn, new_dn,
4580 DSDB_FLAG_NEXT_MODULE, ar->req);
4581 if (ret != LDB_SUCCESS) {
4582 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
4583 "Failed to rename incoming conflicting dn '%s' (was '%s') to '%s' - %s\n",
4584 ldb_dn_get_linearized(conflict_dn),
4585 ldb_dn_get_linearized(ar->search_msg->dn),
4586 ldb_dn_get_linearized(new_dn),
4587 ldb_errstring(ldb_module_get_ctx(ar->module)));
4588 return replmd_replicated_request_werror(ar, WERR_DS_DRA_DB_ERROR);
4596 /* we are renaming the existing record */
4598 guid = samdb_result_guid(res->msgs[0], "objectGUID");
4599 if (GUID_all_zero(&guid)) {
4600 DEBUG(0,(__location__ ": Failed to find objectGUID for existing conflict record %s\n",
4601 ldb_dn_get_linearized(conflict_dn)));
4605 new_dn = replmd_conflict_dn(tmp_ctx, conflict_dn, &guid);
4606 if (new_dn == NULL) {
4607 DEBUG(0,(__location__ ": Failed to form conflict DN for %s\n",
4608 ldb_dn_get_linearized(conflict_dn)));
4612 DEBUG(2,(__location__ ": Resolving conflict record via existing-record rename '%s' -> '%s'\n",
4613 ldb_dn_get_linearized(conflict_dn), ldb_dn_get_linearized(new_dn)));
4615 ret = dsdb_module_rename(ar->module, conflict_dn, new_dn,
4616 DSDB_FLAG_OWN_MODULE, ar->req);
4617 if (ret != LDB_SUCCESS) {
4618 DEBUG(0,(__location__ ": Failed to rename conflict dn '%s' to '%s' - %s\n",
4619 ldb_dn_get_linearized(conflict_dn),
4620 ldb_dn_get_linearized(new_dn),
4621 ldb_errstring(ldb_module_get_ctx(ar->module))));
4626 * now we need to ensure that the rename is seen as an
4627 * originating update. We do that with a modify.
4629 ret = replmd_name_modify(ar, ar->req, new_dn);
4630 if (ret != LDB_SUCCESS) {
4634 DEBUG(2,(__location__ ": With conflicting record renamed, re-apply replicated rename '%s' -> '%s'\n",
4635 ldb_dn_get_linearized(ar->search_msg->dn),
4636 ldb_dn_get_linearized(msg->dn)));
4639 ret = dsdb_module_rename(ar->module, ar->search_msg->dn, msg->dn,
4640 DSDB_FLAG_NEXT_MODULE, ar->req);
4641 if (ret != LDB_SUCCESS) {
4642 DEBUG(0,(__location__ ": After conflict resolution, failed to rename dn '%s' to '%s' - %s\n",
4643 ldb_dn_get_linearized(ar->search_msg->dn),
4644 ldb_dn_get_linearized(msg->dn),
4645 ldb_errstring(ldb_module_get_ctx(ar->module))));
4651 * On failure make the caller get the error
4652 * This means replication will stop with an error,
4653 * but there is not much else we can do. In the
4654 * LDB_ERR_ENTRY_ALREADY_EXISTS case this is exactly what is
4658 talloc_free(tmp_ctx);
4663 static int replmd_replicated_apply_merge(struct replmd_replicated_request *ar)
4665 struct ldb_context *ldb;
4666 struct ldb_request *change_req;
4667 enum ndr_err_code ndr_err;
4668 struct ldb_message *msg;
4669 struct replPropertyMetaDataBlob *rmd;
4670 struct replPropertyMetaDataBlob omd;
4671 const struct ldb_val *omd_value;
4672 struct replPropertyMetaDataBlob nmd;
4673 struct ldb_val nmd_value;
4674 struct GUID remote_parent_guid;
4677 unsigned int removed_attrs = 0;
4679 int (*callback)(struct ldb_request *req, struct ldb_reply *ares) = replmd_op_callback;
4680 bool isDeleted = false;
4681 bool local_isDeleted = false;
4682 bool remote_isDeleted = false;
4683 bool take_remote_isDeleted = false;
4684 bool sd_updated = false;
4685 bool renamed = false;
4686 bool is_schema_nc = false;
4688 const struct ldb_val *old_rdn, *new_rdn;
4689 struct replmd_private *replmd_private =
4690 talloc_get_type(ldb_module_get_private(ar->module),
4691 struct replmd_private);
4693 time_t t = time(NULL);
4694 unix_to_nt_time(&now, t);
4696 ldb = ldb_module_get_ctx(ar->module);
4697 msg = ar->objs->objects[ar->index_current].msg;
4699 is_schema_nc = ldb_dn_compare_base(replmd_private->schema_dn, msg->dn) == 0;
4701 rmd = ar->objs->objects[ar->index_current].meta_data;
4705 /* find existing meta data */
4706 omd_value = ldb_msg_find_ldb_val(ar->search_msg, "replPropertyMetaData");
4708 ndr_err = ndr_pull_struct_blob(omd_value, ar, &omd,
4709 (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
4710 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
4711 nt_status = ndr_map_error2ntstatus(ndr_err);
4712 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
4715 if (omd.version != 1) {
4716 return replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
4721 struct GUID_txt_buf guid_txt;
4723 char *s = ldb_ldif_message_string(ldb, ar, LDB_CHANGETYPE_MODIFY, msg);
4724 DEBUG(5, ("Initial DRS replication modify message of %s is:\n%s\n"
4727 GUID_buf_string(&ar->objs->objects[ar->index_current].object_guid, &guid_txt),
4729 ndr_print_struct_string(s,
4730 (ndr_print_fn_t)ndr_print_replPropertyMetaDataBlob,
4731 "existing replPropertyMetaData",
4733 ndr_print_struct_string(s,
4734 (ndr_print_fn_t)ndr_print_replPropertyMetaDataBlob,
4735 "incoming replPropertyMetaData",
4740 local_isDeleted = ldb_msg_find_attr_as_bool(ar->search_msg,
4741 "isDeleted", false);
4742 remote_isDeleted = ldb_msg_find_attr_as_bool(msg,
4743 "isDeleted", false);
4746 * Fill in the remote_parent_guid with the GUID or an all-zero
4749 if (ar->objs->objects[ar->index_current].parent_guid != NULL) {
4750 remote_parent_guid = *ar->objs->objects[ar->index_current].parent_guid;
4752 remote_parent_guid = GUID_zero();
4756 * To ensure we follow a complex rename chain around, we have
4757 * to confirm that the DN is the same (mostly to confirm the
4758 * RDN) and the parentGUID is the same.
4760 * This ensures we keep things under the correct parent, which
4761 * replmd_replicated_handle_rename() will do.
4764 if (strcmp(ldb_dn_get_linearized(msg->dn), ldb_dn_get_linearized(ar->search_msg->dn)) == 0
4765 && GUID_equal(&remote_parent_guid, &ar->local_parent_guid)) {
4769 * handle renames, even just by case that come in over
4770 * DRS. Changes in the parent DN don't hit us here,
4771 * because the search for a parent will clean up those
4774 * We also have already filtered out the case where
4775 * the peer has an older name to what we have (see
4776 * replmd_replicated_apply_search_callback())
4778 ret = replmd_replicated_handle_rename(ar, msg, ar->req, &renamed);
4781 if (ret != LDB_SUCCESS) {
4782 ldb_debug(ldb, LDB_DEBUG_FATAL,
4783 "replmd_replicated_request rename %s => %s failed - %s\n",
4784 ldb_dn_get_linearized(ar->search_msg->dn),
4785 ldb_dn_get_linearized(msg->dn),
4786 ldb_errstring(ldb));
4787 return replmd_replicated_request_werror(ar, WERR_DS_DRA_DB_ERROR);
4790 if (renamed == true) {
4792 * Set the callback to one that will fix up the name
4793 * metadata on the new conflict DN
4795 callback = replmd_op_name_modify_callback;
4800 nmd.ctr.ctr1.count = omd.ctr.ctr1.count + rmd->ctr.ctr1.count;
4801 nmd.ctr.ctr1.array = talloc_array(ar,
4802 struct replPropertyMetaData1,
4803 nmd.ctr.ctr1.count);
4804 if (!nmd.ctr.ctr1.array) return replmd_replicated_request_werror(ar, WERR_NOMEM);
4806 /* first copy the old meta data */
4807 for (i=0; i < omd.ctr.ctr1.count; i++) {
4808 nmd.ctr.ctr1.array[ni] = omd.ctr.ctr1.array[i];
4813 /* now merge in the new meta data */
4814 for (i=0; i < rmd->ctr.ctr1.count; i++) {
4817 for (j=0; j < ni; j++) {
4820 if (rmd->ctr.ctr1.array[i].attid != nmd.ctr.ctr1.array[j].attid) {
4824 cmp = replmd_replPropertyMetaData1_new_should_be_taken(
4825 ar->objs->dsdb_repl_flags,
4826 &nmd.ctr.ctr1.array[j],
4827 &rmd->ctr.ctr1.array[i]);
4829 /* replace the entry */
4830 nmd.ctr.ctr1.array[j] = rmd->ctr.ctr1.array[i];
4831 if (ar->seq_num == 0) {
4832 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &ar->seq_num);
4833 if (ret != LDB_SUCCESS) {
4834 return replmd_replicated_request_error(ar, ret);
4837 nmd.ctr.ctr1.array[j].local_usn = ar->seq_num;
4838 switch (nmd.ctr.ctr1.array[j].attid) {
4839 case DRSUAPI_ATTID_ntSecurityDescriptor:
4842 case DRSUAPI_ATTID_isDeleted:
4843 take_remote_isDeleted = true;
4852 if (rmd->ctr.ctr1.array[i].attid != DRSUAPI_ATTID_instanceType) {
4853 DEBUG(3,("Discarding older DRS attribute update to %s on %s from %s\n",
4854 msg->elements[i-removed_attrs].name,
4855 ldb_dn_get_linearized(msg->dn),
4856 GUID_string(ar, &rmd->ctr.ctr1.array[i].originating_invocation_id)));
4859 /* we don't want to apply this change so remove the attribute */
4860 ldb_msg_remove_element(msg, &msg->elements[i-removed_attrs]);
4867 if (found) continue;
4869 nmd.ctr.ctr1.array[ni] = rmd->ctr.ctr1.array[i];
4870 if (ar->seq_num == 0) {
4871 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &ar->seq_num);
4872 if (ret != LDB_SUCCESS) {
4873 return replmd_replicated_request_error(ar, ret);
4876 nmd.ctr.ctr1.array[ni].local_usn = ar->seq_num;
4877 switch (nmd.ctr.ctr1.array[ni].attid) {
4878 case DRSUAPI_ATTID_ntSecurityDescriptor:
4881 case DRSUAPI_ATTID_isDeleted:
4882 take_remote_isDeleted = true;
4891 * finally correct the size of the meta_data array
4893 nmd.ctr.ctr1.count = ni;
4895 new_rdn = ldb_dn_get_rdn_val(msg->dn);
4896 old_rdn = ldb_dn_get_rdn_val(ar->search_msg->dn);
4899 ret = replmd_update_rpmd_rdn_attr(ldb, msg, new_rdn, old_rdn,
4900 &nmd, ar, now, is_schema_nc);
4901 if (ret != LDB_SUCCESS) {
4902 ldb_asprintf_errstring(ldb, "%s: error during DRS repl merge: %s", __func__, ldb_errstring(ldb));
4903 return replmd_replicated_request_error(ar, ret);
4907 * sort the new meta data array
4909 ret = replmd_replPropertyMetaDataCtr1_sort_and_verify(ldb, &nmd.ctr.ctr1, msg->dn);
4910 if (ret != LDB_SUCCESS) {
4911 ldb_asprintf_errstring(ldb, "%s: error during DRS repl merge: %s", __func__, ldb_errstring(ldb));
4916 * Work out if this object is deleted, so we can prune any extra attributes. See MS-DRSR 4.1.10.6.9
4919 * This also controls SD propagation below
4921 if (take_remote_isDeleted) {
4922 isDeleted = remote_isDeleted;
4924 isDeleted = local_isDeleted;
4927 ar->isDeleted = isDeleted;
4930 * check if some replicated attributes left, otherwise skip the ldb_modify() call
4932 if (msg->num_elements == 0) {
4933 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_replicated_apply_merge[%u]: skip replace\n",
4936 return replmd_replicated_apply_isDeleted(ar);
4939 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_replicated_apply_merge[%u]: replace %u attributes\n",
4940 ar->index_current, msg->num_elements);
4946 if (sd_updated && !isDeleted) {
4947 ret = dsdb_module_schedule_sd_propagation(ar->module,
4948 ar->objs->partition_dn,
4950 if (ret != LDB_SUCCESS) {
4951 return ldb_operr(ldb);
4955 /* create the meta data value */
4956 ndr_err = ndr_push_struct_blob(&nmd_value, msg, &nmd,
4957 (ndr_push_flags_fn_t)ndr_push_replPropertyMetaDataBlob);
4958 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
4959 nt_status = ndr_map_error2ntstatus(ndr_err);
4960 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
4964 * when we know that we'll modify the record, add the whenChanged, uSNChanged
4965 * and replPopertyMetaData attributes
4967 ret = ldb_msg_add_string(msg, "whenChanged", ar->objs->objects[ar->index_current].when_changed);
4968 if (ret != LDB_SUCCESS) {
4969 return replmd_replicated_request_error(ar, ret);
4971 ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNChanged", ar->seq_num);
4972 if (ret != LDB_SUCCESS) {
4973 return replmd_replicated_request_error(ar, ret);
4975 ret = ldb_msg_add_value(msg, "replPropertyMetaData", &nmd_value, NULL);
4976 if (ret != LDB_SUCCESS) {
4977 return replmd_replicated_request_error(ar, ret);
4980 replmd_ldb_message_sort(msg, ar->schema);
4982 /* we want to replace the old values */
4983 for (i=0; i < msg->num_elements; i++) {
4984 msg->elements[i].flags = LDB_FLAG_MOD_REPLACE;
4985 if (ldb_attr_cmp(msg->elements[i].name, "objectClass") == 0) {
4986 if (msg->elements[i].num_values == 0) {
4987 ldb_asprintf_errstring(ldb, __location__
4988 ": objectClass removed on %s, aborting replication\n",
4989 ldb_dn_get_linearized(msg->dn));
4990 return replmd_replicated_request_error(ar, LDB_ERR_OBJECT_CLASS_VIOLATION);
4996 struct GUID_txt_buf guid_txt;
4998 char *s = ldb_ldif_message_string(ldb, ar, LDB_CHANGETYPE_MODIFY, msg);
4999 DEBUG(4, ("Final DRS replication modify message of %s:\n%s\n",
5000 GUID_buf_string(&ar->objs->objects[ar->index_current].object_guid, &guid_txt),
5005 ret = ldb_build_mod_req(&change_req,
5013 LDB_REQ_SET_LOCATION(change_req);
5014 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
5016 /* current partition control needed by "repmd_op_callback" */
5017 ret = ldb_request_add_control(change_req,
5018 DSDB_CONTROL_CURRENT_PARTITION_OID,
5020 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
5022 return ldb_next_request(ar->module, change_req);
5025 static int replmd_replicated_apply_search_callback(struct ldb_request *req,
5026 struct ldb_reply *ares)
5028 struct replmd_replicated_request *ar = talloc_get_type(req->context,
5029 struct replmd_replicated_request);
5033 return ldb_module_done(ar->req, NULL, NULL,
5034 LDB_ERR_OPERATIONS_ERROR);
5036 if (ares->error != LDB_SUCCESS &&
5037 ares->error != LDB_ERR_NO_SUCH_OBJECT) {
5038 return ldb_module_done(ar->req, ares->controls,
5039 ares->response, ares->error);
5042 switch (ares->type) {
5043 case LDB_REPLY_ENTRY:
5044 ar->search_msg = talloc_steal(ar, ares->message);
5047 case LDB_REPLY_REFERRAL:
5048 /* we ignore referrals */
5051 case LDB_REPLY_DONE:
5053 struct replPropertyMetaData1 *md_remote;
5054 struct replPropertyMetaData1 *md_local;
5056 struct replPropertyMetaDataBlob omd;
5057 const struct ldb_val *omd_value;
5058 struct replPropertyMetaDataBlob *rmd;
5059 struct ldb_message *msg;
5061 ar->objs->objects[ar->index_current].local_parent_dn = NULL;
5062 ar->objs->objects[ar->index_current].last_known_parent = NULL;
5065 * This is the ADD case, find the appropriate parent,
5066 * as this object doesn't exist locally:
5068 if (ar->search_msg == NULL) {
5069 ret = replmd_replicated_apply_search_for_parent(ar);
5070 if (ret != LDB_SUCCESS) {
5071 return ldb_module_done(ar->req, NULL, NULL, ret);
5078 * Otherwise, in the MERGE case, work out if we are
5079 * attempting a rename, and if so find the parent the
5080 * newly renamed object wants to belong under (which
5081 * may not be the parent in it's attached string DN
5083 rmd = ar->objs->objects[ar->index_current].meta_data;
5087 /* find existing meta data */
5088 omd_value = ldb_msg_find_ldb_val(ar->search_msg, "replPropertyMetaData");
5090 enum ndr_err_code ndr_err;
5091 ndr_err = ndr_pull_struct_blob(omd_value, ar, &omd,
5092 (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
5093 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
5094 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
5095 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
5098 if (omd.version != 1) {
5099 return replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
5103 ar->local_parent_guid = samdb_result_guid(ar->search_msg, "parentGUID");
5105 instanceType = ldb_msg_find_attr_as_int(ar->search_msg, "instanceType", 0);
5106 if (((instanceType & INSTANCE_TYPE_IS_NC_HEAD) == 0)
5107 && GUID_all_zero(&ar->local_parent_guid)) {
5108 DEBUG(0, ("Refusing to replicate new version of %s "
5109 "as local object has an all-zero parentGUID attribute, "
5110 "despite not being an NC root\n",
5111 ldb_dn_get_linearized(ar->search_msg->dn)));
5112 return replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
5116 * now we need to check for double renames. We could have a
5117 * local rename pending which our replication partner hasn't
5118 * received yet. We choose which one wins by looking at the
5119 * attribute stamps on the two objects, the newer one wins.
5121 * This also simply applies the correct algorithms for
5122 * determining if a change was made to name at all, or
5123 * if the object has just been renamed under the same
5126 md_remote = replmd_replPropertyMetaData1_find_attid(rmd, DRSUAPI_ATTID_name);
5127 md_local = replmd_replPropertyMetaData1_find_attid(&omd, DRSUAPI_ATTID_name);
5129 DEBUG(0,(__location__ ": Failed to find name attribute in local LDB replPropertyMetaData for %s\n",
5130 ldb_dn_get_linearized(ar->search_msg->dn)));
5131 return replmd_replicated_request_werror(ar, WERR_DS_DRA_DB_ERROR);
5135 * if there is no name attribute given then we have to assume the
5136 * object we've received has the older name
5138 if (replmd_replPropertyMetaData1_new_should_be_taken(
5139 ar->objs->dsdb_repl_flags & DSDB_REPL_FLAG_PRIORITISE_INCOMING,
5140 md_local, md_remote)) {
5141 struct GUID_txt_buf p_guid_local;
5142 struct GUID_txt_buf p_guid_remote;
5143 msg = ar->objs->objects[ar->index_current].msg;
5145 /* Merge on the existing object, with rename */
5147 DEBUG(4,(__location__ ": Looking for new parent for object %s currently under %s "
5148 "as incoming object changing to %s under %s\n",
5149 ldb_dn_get_linearized(ar->search_msg->dn),
5150 GUID_buf_string(&ar->local_parent_guid, &p_guid_local),
5151 ldb_dn_get_linearized(msg->dn),
5152 GUID_buf_string(ar->objs->objects[ar->index_current].parent_guid,
5154 ret = replmd_replicated_apply_search_for_parent(ar);
5156 struct GUID_txt_buf p_guid_local;
5157 struct GUID_txt_buf p_guid_remote;
5158 msg = ar->objs->objects[ar->index_current].msg;
5161 * Merge on the existing object, force no
5162 * rename (code below just to explain why in
5166 if (strcmp(ldb_dn_get_linearized(ar->search_msg->dn),
5167 ldb_dn_get_linearized(msg->dn)) == 0) {
5168 if (ar->objs->objects[ar->index_current].parent_guid != NULL &&
5169 GUID_equal(&ar->local_parent_guid,
5170 ar->objs->objects[ar->index_current].parent_guid)
5172 DEBUG(4,(__location__ ": Keeping object %s at under %s "
5173 "despite incoming object changing parent to %s\n",
5174 ldb_dn_get_linearized(ar->search_msg->dn),
5175 GUID_buf_string(&ar->local_parent_guid, &p_guid_local),
5176 GUID_buf_string(ar->objs->objects[ar->index_current].parent_guid,
5180 DEBUG(4,(__location__ ": Keeping object %s at under %s "
5181 " and rejecting older rename to %s under %s\n",
5182 ldb_dn_get_linearized(ar->search_msg->dn),
5183 GUID_buf_string(&ar->local_parent_guid, &p_guid_local),
5184 ldb_dn_get_linearized(msg->dn),
5185 GUID_buf_string(ar->objs->objects[ar->index_current].parent_guid,
5189 * This assignment ensures that the strcmp()
5190 * and GUID_equal() calls in
5191 * replmd_replicated_apply_merge() avoids the
5194 ar->objs->objects[ar->index_current].parent_guid =
5195 &ar->local_parent_guid;
5197 msg->dn = ar->search_msg->dn;
5198 ret = replmd_replicated_apply_merge(ar);
5200 if (ret != LDB_SUCCESS) {
5201 return ldb_module_done(ar->req, NULL, NULL, ret);
5210 static int replmd_replicated_uptodate_vector(struct replmd_replicated_request *ar);
5212 static int replmd_replicated_apply_next(struct replmd_replicated_request *ar)
5214 struct ldb_context *ldb;
5218 struct ldb_request *search_req;
5219 static const char *attrs[] = { "*", "parentGUID", "instanceType",
5220 "replPropertyMetaData", "nTSecurityDescriptor",
5222 struct GUID_txt_buf guid_str_buf;
5224 if (ar->index_current >= ar->objs->num_objects) {
5225 /* done with it, go to next stage */
5226 return replmd_replicated_uptodate_vector(ar);
5229 ldb = ldb_module_get_ctx(ar->module);
5230 ar->search_msg = NULL;
5231 ar->isDeleted = false;
5233 tmp_str = GUID_buf_string(&ar->objs->objects[ar->index_current].object_guid,
5236 filter = talloc_asprintf(ar, "(objectGUID=%s)", tmp_str);
5237 if (!filter) return replmd_replicated_request_werror(ar, WERR_NOMEM);
5239 ret = ldb_build_search_req(&search_req,
5242 ar->objs->partition_dn,
5248 replmd_replicated_apply_search_callback,
5250 LDB_REQ_SET_LOCATION(search_req);
5252 ret = dsdb_request_add_controls(search_req, DSDB_SEARCH_SHOW_RECYCLED);
5254 if (ret != LDB_SUCCESS) {
5258 return ldb_next_request(ar->module, search_req);
5262 * This is essentially a wrapper for replmd_replicated_apply_next()
5264 * This is needed to ensure that both codepaths call this handler.
5266 static int replmd_replicated_apply_isDeleted(struct replmd_replicated_request *ar)
5268 struct ldb_dn *deleted_objects_dn;
5269 struct ldb_message *msg = ar->objs->objects[ar->index_current].msg;
5270 int ret = dsdb_get_deleted_objects_dn(ldb_module_get_ctx(ar->module), msg, msg->dn,
5271 &deleted_objects_dn);
5272 if (ar->isDeleted && (ret != LDB_SUCCESS || ldb_dn_compare(msg->dn, deleted_objects_dn) != 0)) {
5274 * Do a delete here again, so that if there is
5275 * anything local that conflicts with this
5276 * object being deleted, it is removed. This
5277 * includes links. See MS-DRSR 4.1.10.6.9
5280 * If the object is already deleted, and there
5281 * is no more work required, it doesn't do
5285 /* This has been updated to point to the DN we eventually did the modify on */
5287 struct ldb_request *del_req;
5288 struct ldb_result *res;
5290 TALLOC_CTX *tmp_ctx = talloc_new(ar);
5292 ret = ldb_oom(ldb_module_get_ctx(ar->module));
5296 res = talloc_zero(tmp_ctx, struct ldb_result);
5298 ret = ldb_oom(ldb_module_get_ctx(ar->module));
5299 talloc_free(tmp_ctx);
5303 /* Build a delete request, which hopefully will artually turn into nothing */
5304 ret = ldb_build_del_req(&del_req, ldb_module_get_ctx(ar->module), tmp_ctx,
5308 ldb_modify_default_callback,
5310 LDB_REQ_SET_LOCATION(del_req);
5311 if (ret != LDB_SUCCESS) {
5312 talloc_free(tmp_ctx);
5317 * This is the guts of the call, call back
5318 * into our delete code, but setting the
5319 * re_delete flag so we delete anything that
5320 * shouldn't be there on a deleted or recycled
5323 ret = replmd_delete_internals(ar->module, del_req, true);
5324 if (ret == LDB_SUCCESS) {
5325 ret = ldb_wait(del_req->handle, LDB_WAIT_ALL);
5328 talloc_free(tmp_ctx);
5329 if (ret != LDB_SUCCESS) {
5334 ar->index_current++;
5335 return replmd_replicated_apply_next(ar);
5338 static int replmd_replicated_uptodate_modify_callback(struct ldb_request *req,
5339 struct ldb_reply *ares)
5341 struct ldb_context *ldb;
5342 struct replmd_replicated_request *ar = talloc_get_type(req->context,
5343 struct replmd_replicated_request);
5344 ldb = ldb_module_get_ctx(ar->module);
5347 return ldb_module_done(ar->req, NULL, NULL,
5348 LDB_ERR_OPERATIONS_ERROR);
5350 if (ares->error != LDB_SUCCESS) {
5351 return ldb_module_done(ar->req, ares->controls,
5352 ares->response, ares->error);
5355 if (ares->type != LDB_REPLY_DONE) {
5356 ldb_asprintf_errstring(ldb, "Invalid LDB reply type %d", ares->type);
5357 return ldb_module_done(ar->req, NULL, NULL,
5358 LDB_ERR_OPERATIONS_ERROR);
5363 return ldb_module_done(ar->req, NULL, NULL, LDB_SUCCESS);
5366 static int replmd_replicated_uptodate_modify(struct replmd_replicated_request *ar)
5368 struct ldb_context *ldb;
5369 struct ldb_request *change_req;
5370 enum ndr_err_code ndr_err;
5371 struct ldb_message *msg;
5372 struct replUpToDateVectorBlob ouv;
5373 const struct ldb_val *ouv_value;
5374 const struct drsuapi_DsReplicaCursor2CtrEx *ruv;
5375 struct replUpToDateVectorBlob nuv;
5376 struct ldb_val nuv_value;
5377 struct ldb_message_element *nuv_el = NULL;
5378 struct ldb_message_element *orf_el = NULL;
5379 struct repsFromToBlob nrf;
5380 struct ldb_val *nrf_value = NULL;
5381 struct ldb_message_element *nrf_el = NULL;
5385 time_t t = time(NULL);
5388 uint32_t instanceType;
5390 ldb = ldb_module_get_ctx(ar->module);
5391 ruv = ar->objs->uptodateness_vector;
5397 unix_to_nt_time(&now, t);
5399 if (ar->search_msg == NULL) {
5400 /* this happens for a REPL_OBJ call where we are
5401 creating the target object by replicating it. The
5402 subdomain join code does this for the partition DN
5404 DEBUG(4,(__location__ ": Skipping UDV and repsFrom update as no target DN\n"));
5405 return ldb_module_done(ar->req, NULL, NULL, LDB_SUCCESS);
5408 instanceType = ldb_msg_find_attr_as_uint(ar->search_msg, "instanceType", 0);
5409 if (! (instanceType & INSTANCE_TYPE_IS_NC_HEAD)) {
5410 DEBUG(4,(__location__ ": Skipping UDV and repsFrom update as not NC root: %s\n",
5411 ldb_dn_get_linearized(ar->search_msg->dn)));
5412 return ldb_module_done(ar->req, NULL, NULL, LDB_SUCCESS);
5416 * first create the new replUpToDateVector
5418 ouv_value = ldb_msg_find_ldb_val(ar->search_msg, "replUpToDateVector");
5420 ndr_err = ndr_pull_struct_blob(ouv_value, ar, &ouv,
5421 (ndr_pull_flags_fn_t)ndr_pull_replUpToDateVectorBlob);
5422 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
5423 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
5424 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
5427 if (ouv.version != 2) {
5428 return replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
5433 * the new uptodateness vector will at least
5434 * contain 1 entry, one for the source_dsa
5436 * plus optional values from our old vector and the one from the source_dsa
5438 nuv.ctr.ctr2.count = ouv.ctr.ctr2.count;
5439 if (ruv) nuv.ctr.ctr2.count += ruv->count;
5440 nuv.ctr.ctr2.cursors = talloc_array(ar,
5441 struct drsuapi_DsReplicaCursor2,
5442 nuv.ctr.ctr2.count);
5443 if (!nuv.ctr.ctr2.cursors) return replmd_replicated_request_werror(ar, WERR_NOMEM);
5445 /* first copy the old vector */
5446 for (i=0; i < ouv.ctr.ctr2.count; i++) {
5447 nuv.ctr.ctr2.cursors[ni] = ouv.ctr.ctr2.cursors[i];
5451 /* merge in the source_dsa vector is available */
5452 for (i=0; (ruv && i < ruv->count); i++) {
5455 if (GUID_equal(&ruv->cursors[i].source_dsa_invocation_id,
5456 &ar->our_invocation_id)) {
5460 for (j=0; j < ni; j++) {
5461 if (!GUID_equal(&ruv->cursors[i].source_dsa_invocation_id,
5462 &nuv.ctr.ctr2.cursors[j].source_dsa_invocation_id)) {
5468 if (ruv->cursors[i].highest_usn > nuv.ctr.ctr2.cursors[j].highest_usn) {
5469 nuv.ctr.ctr2.cursors[j] = ruv->cursors[i];
5474 if (found) continue;
5476 /* if it's not there yet, add it */
5477 nuv.ctr.ctr2.cursors[ni] = ruv->cursors[i];
5482 * finally correct the size of the cursors array
5484 nuv.ctr.ctr2.count = ni;
5489 TYPESAFE_QSORT(nuv.ctr.ctr2.cursors, nuv.ctr.ctr2.count, drsuapi_DsReplicaCursor2_compare);
5492 * create the change ldb_message
5494 msg = ldb_msg_new(ar);
5495 if (!msg) return replmd_replicated_request_werror(ar, WERR_NOMEM);
5496 msg->dn = ar->search_msg->dn;
5498 ndr_err = ndr_push_struct_blob(&nuv_value, msg, &nuv,
5499 (ndr_push_flags_fn_t)ndr_push_replUpToDateVectorBlob);
5500 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
5501 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
5502 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
5504 ret = ldb_msg_add_value(msg, "replUpToDateVector", &nuv_value, &nuv_el);
5505 if (ret != LDB_SUCCESS) {
5506 return replmd_replicated_request_error(ar, ret);
5508 nuv_el->flags = LDB_FLAG_MOD_REPLACE;
5511 * now create the new repsFrom value from the given repsFromTo1 structure
5515 nrf.ctr.ctr1 = *ar->objs->source_dsa;
5516 nrf.ctr.ctr1.last_attempt = now;
5517 nrf.ctr.ctr1.last_success = now;
5518 nrf.ctr.ctr1.result_last_attempt = WERR_OK;
5521 * first see if we already have a repsFrom value for the current source dsa
5522 * if so we'll later replace this value
5524 orf_el = ldb_msg_find_element(ar->search_msg, "repsFrom");
5526 for (i=0; i < orf_el->num_values; i++) {
5527 struct repsFromToBlob *trf;
5529 trf = talloc(ar, struct repsFromToBlob);
5530 if (!trf) return replmd_replicated_request_werror(ar, WERR_NOMEM);
5532 ndr_err = ndr_pull_struct_blob(&orf_el->values[i], trf, trf,
5533 (ndr_pull_flags_fn_t)ndr_pull_repsFromToBlob);
5534 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
5535 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
5536 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
5539 if (trf->version != 1) {
5540 return replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
5544 * we compare the source dsa objectGUID not the invocation_id
5545 * because we want only one repsFrom value per source dsa
5546 * and when the invocation_id of the source dsa has changed we don't need
5547 * the old repsFrom with the old invocation_id
5549 if (!GUID_equal(&trf->ctr.ctr1.source_dsa_obj_guid,
5550 &ar->objs->source_dsa->source_dsa_obj_guid)) {
5556 nrf_value = &orf_el->values[i];
5561 * copy over all old values to the new ldb_message
5563 ret = ldb_msg_add_empty(msg, "repsFrom", 0, &nrf_el);
5564 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
5569 * if we haven't found an old repsFrom value for the current source dsa
5570 * we'll add a new value
5573 struct ldb_val zero_value;
5574 ZERO_STRUCT(zero_value);
5575 ret = ldb_msg_add_value(msg, "repsFrom", &zero_value, &nrf_el);
5576 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
5578 nrf_value = &nrf_el->values[nrf_el->num_values - 1];
5581 /* we now fill the value which is already attached to ldb_message */
5582 ndr_err = ndr_push_struct_blob(nrf_value, msg,
5584 (ndr_push_flags_fn_t)ndr_push_repsFromToBlob);
5585 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
5586 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
5587 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
5591 * the ldb_message_element for the attribute, has all the old values and the new one
5592 * so we'll replace the whole attribute with all values
5594 nrf_el->flags = LDB_FLAG_MOD_REPLACE;
5596 if (CHECK_DEBUGLVL(4)) {
5597 char *s = ldb_ldif_message_string(ldb, ar, LDB_CHANGETYPE_MODIFY, msg);
5598 DEBUG(4, ("DRS replication uptodate modify message:\n%s\n", s));
5602 /* prepare the ldb_modify() request */
5603 ret = ldb_build_mod_req(&change_req,
5609 replmd_replicated_uptodate_modify_callback,
5611 LDB_REQ_SET_LOCATION(change_req);
5612 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
5614 return ldb_next_request(ar->module, change_req);
5617 static int replmd_replicated_uptodate_search_callback(struct ldb_request *req,
5618 struct ldb_reply *ares)
5620 struct replmd_replicated_request *ar = talloc_get_type(req->context,
5621 struct replmd_replicated_request);
5625 return ldb_module_done(ar->req, NULL, NULL,
5626 LDB_ERR_OPERATIONS_ERROR);
5628 if (ares->error != LDB_SUCCESS &&
5629 ares->error != LDB_ERR_NO_SUCH_OBJECT) {
5630 return ldb_module_done(ar->req, ares->controls,
5631 ares->response, ares->error);
5634 switch (ares->type) {
5635 case LDB_REPLY_ENTRY:
5636 ar->search_msg = talloc_steal(ar, ares->message);
5639 case LDB_REPLY_REFERRAL:
5640 /* we ignore referrals */
5643 case LDB_REPLY_DONE:
5644 ret = replmd_replicated_uptodate_modify(ar);
5645 if (ret != LDB_SUCCESS) {
5646 return ldb_module_done(ar->req, NULL, NULL, ret);
5655 static int replmd_replicated_uptodate_vector(struct replmd_replicated_request *ar)
5657 struct ldb_context *ldb;
5659 static const char *attrs[] = {
5660 "replUpToDateVector",
5665 struct ldb_request *search_req;
5667 ldb = ldb_module_get_ctx(ar->module);
5668 ar->search_msg = NULL;
5670 ret = ldb_build_search_req(&search_req,
5673 ar->objs->partition_dn,
5679 replmd_replicated_uptodate_search_callback,
5681 LDB_REQ_SET_LOCATION(search_req);
5682 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
5684 return ldb_next_request(ar->module, search_req);
5689 static int replmd_extended_replicated_objects(struct ldb_module *module, struct ldb_request *req)
5691 struct ldb_context *ldb;
5692 struct dsdb_extended_replicated_objects *objs;
5693 struct replmd_replicated_request *ar;
5694 struct ldb_control **ctrls;
5697 struct replmd_private *replmd_private =
5698 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
5699 struct dsdb_control_replicated_update *rep_update;
5701 ldb = ldb_module_get_ctx(module);
5703 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_extended_replicated_objects\n");
5705 objs = talloc_get_type(req->op.extended.data, struct dsdb_extended_replicated_objects);
5707 ldb_debug(ldb, LDB_DEBUG_FATAL, "replmd_extended_replicated_objects: invalid extended data\n");
5708 return LDB_ERR_PROTOCOL_ERROR;
5711 if (objs->version != DSDB_EXTENDED_REPLICATED_OBJECTS_VERSION) {
5712 ldb_debug(ldb, LDB_DEBUG_FATAL, "replmd_extended_replicated_objects: extended data invalid version [%u != %u]\n",
5713 objs->version, DSDB_EXTENDED_REPLICATED_OBJECTS_VERSION);
5714 return LDB_ERR_PROTOCOL_ERROR;
5717 ar = replmd_ctx_init(module, req);
5719 return LDB_ERR_OPERATIONS_ERROR;
5721 /* Set the flags to have the replmd_op_callback run over the full set of objects */
5722 ar->apply_mode = true;
5724 ar->schema = dsdb_get_schema(ldb, ar);
5726 ldb_debug_set(ldb, LDB_DEBUG_FATAL, "replmd_ctx_init: no loaded schema found\n");
5728 DEBUG(0,(__location__ ": %s\n", ldb_errstring(ldb)));
5729 return LDB_ERR_CONSTRAINT_VIOLATION;
5732 ctrls = req->controls;
5734 if (req->controls) {
5735 req->controls = talloc_memdup(ar, req->controls,
5736 talloc_get_size(req->controls));
5737 if (!req->controls) return replmd_replicated_request_werror(ar, WERR_NOMEM);
5740 /* This allows layers further down to know if a change came in
5741 over replication and what the replication flags were */
5742 rep_update = talloc_zero(ar, struct dsdb_control_replicated_update);
5743 if (rep_update == NULL) {
5744 return ldb_module_oom(module);
5746 rep_update->dsdb_repl_flags = objs->dsdb_repl_flags;
5748 ret = ldb_request_add_control(req, DSDB_CONTROL_REPLICATED_UPDATE_OID, false, rep_update);
5749 if (ret != LDB_SUCCESS) {
5753 /* If this change contained linked attributes in the body
5754 * (rather than in the links section) we need to update
5755 * backlinks in linked_attributes */
5756 ret = ldb_request_add_control(req, DSDB_CONTROL_APPLY_LINKS, false, NULL);
5757 if (ret != LDB_SUCCESS) {
5761 ar->controls = req->controls;
5762 req->controls = ctrls;
5764 DEBUG(4,("linked_attributes_count=%u\n", objs->linked_attributes_count));
5766 /* save away the linked attributes for the end of the
5768 for (i=0; i<ar->objs->linked_attributes_count; i++) {
5769 struct la_entry *la_entry;
5771 if (replmd_private->la_ctx == NULL) {
5772 replmd_private->la_ctx = talloc_new(replmd_private);
5774 la_entry = talloc(replmd_private->la_ctx, struct la_entry);
5775 if (la_entry == NULL) {
5777 return LDB_ERR_OPERATIONS_ERROR;
5779 la_entry->la = talloc(la_entry, struct drsuapi_DsReplicaLinkedAttribute);
5780 if (la_entry->la == NULL) {
5781 talloc_free(la_entry);
5783 return LDB_ERR_OPERATIONS_ERROR;
5785 *la_entry->la = ar->objs->linked_attributes[i];
5787 /* we need to steal the non-scalars so they stay
5788 around until the end of the transaction */
5789 talloc_steal(la_entry->la, la_entry->la->identifier);
5790 talloc_steal(la_entry->la, la_entry->la->value.blob);
5792 DLIST_ADD(replmd_private->la_list, la_entry);
5795 return replmd_replicated_apply_next(ar);
5799 process one linked attribute structure
5801 static int replmd_process_linked_attribute(struct ldb_module *module,
5802 struct la_entry *la_entry,
5803 struct ldb_request *parent)
5805 struct drsuapi_DsReplicaLinkedAttribute *la = la_entry->la;
5806 struct ldb_context *ldb = ldb_module_get_ctx(module);
5807 struct ldb_message *msg;
5808 struct ldb_message *target_msg = NULL;
5809 TALLOC_CTX *tmp_ctx = talloc_new(la_entry);
5810 const struct dsdb_schema *schema = dsdb_get_schema(ldb, tmp_ctx);
5812 const struct dsdb_attribute *attr;
5813 struct dsdb_dn *dsdb_dn;
5814 uint64_t seq_num = 0;
5815 struct ldb_message_element *old_el;
5817 time_t t = time(NULL);
5818 struct ldb_result *res;
5819 struct ldb_result *target_res;
5820 const char *attrs[4];
5821 const char *attrs2[] = { "isDeleted", "isRecycled", NULL };
5822 struct parsed_dn *pdn_list, *pdn;
5823 struct GUID guid = GUID_zero();
5825 bool active = (la->flags & DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE)?true:false;
5826 const struct GUID *our_invocation_id;
5828 enum deletion_state deletion_state = OBJECT_NOT_DELETED;
5829 enum deletion_state target_deletion_state = OBJECT_NOT_DELETED;
5832 linked_attributes[0]:
5833 &objs->linked_attributes[i]: struct drsuapi_DsReplicaLinkedAttribute
5835 identifier: struct drsuapi_DsReplicaObjectIdentifier
5836 __ndr_size : 0x0000003a (58)
5837 __ndr_size_sid : 0x00000000 (0)
5838 guid : 8e95b6a9-13dd-4158-89db-3220a5be5cc7
5840 __ndr_size_dn : 0x00000000 (0)
5842 attid : DRSUAPI_ATTID_member (0x1F)
5843 value: struct drsuapi_DsAttributeValue
5844 __ndr_size : 0x0000007e (126)
5846 blob : DATA_BLOB length=126
5847 flags : 0x00000001 (1)
5848 1: DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE
5849 originating_add_time : Wed Sep 2 22:20:01 2009 EST
5850 meta_data: struct drsuapi_DsReplicaMetaData
5851 version : 0x00000015 (21)
5852 originating_change_time : Wed Sep 2 23:39:07 2009 EST
5853 originating_invocation_id: 794640f3-18cf-40ee-a211-a93992b67a64
5854 originating_usn : 0x000000000001e19c (123292)
5856 (for cases where the link is to a normal DN)
5857 &target: struct drsuapi_DsReplicaObjectIdentifier3
5858 __ndr_size : 0x0000007e (126)
5859 __ndr_size_sid : 0x0000001c (28)
5860 guid : 7639e594-db75-4086-b0d4-67890ae46031
5861 sid : S-1-5-21-2848215498-2472035911-1947525656-19924
5862 __ndr_size_dn : 0x00000022 (34)
5863 dn : 'CN=UOne,OU=TestOU,DC=vsofs8,DC=com'
5866 /* find the attribute being modified */
5867 attr = dsdb_attribute_by_attributeID_id(schema, la->attid);
5869 DEBUG(0, (__location__ ": Unable to find attributeID 0x%x\n", la->attid));
5870 talloc_free(tmp_ctx);
5871 return LDB_ERR_OPERATIONS_ERROR;
5874 attrs[0] = attr->lDAPDisplayName;
5875 attrs[1] = "isDeleted";
5876 attrs[2] = "isRecycled";
5879 /* get the existing message from the db for the object with
5880 this GUID, returning attribute being modified. We will then
5881 use this msg as the basis for a modify call */
5882 ret = dsdb_module_search(module, tmp_ctx, &res, NULL, LDB_SCOPE_SUBTREE, attrs,
5883 DSDB_FLAG_NEXT_MODULE |
5884 DSDB_SEARCH_SEARCH_ALL_PARTITIONS |
5885 DSDB_SEARCH_SHOW_RECYCLED |
5886 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT |
5887 DSDB_SEARCH_REVEAL_INTERNALS,
5889 "objectGUID=%s", GUID_string(tmp_ctx, &la->identifier->guid));
5890 if (ret != LDB_SUCCESS) {
5891 talloc_free(tmp_ctx);
5894 if (res->count != 1) {
5895 ldb_asprintf_errstring(ldb, "DRS linked attribute for GUID %s - DN not found",
5896 GUID_string(tmp_ctx, &la->identifier->guid));
5897 talloc_free(tmp_ctx);
5898 return LDB_ERR_NO_SUCH_OBJECT;
5903 * Check for deleted objects per MS-DRSR 4.1.10.6.13
5904 * ProcessLinkValue, because link updates are not applied to
5905 * recycled and tombstone objects. We don't have to delete
5906 * any existing link, that should have happened when the
5907 * object deletion was replicated or initiated.
5910 replmd_deletion_state(module, msg, &deletion_state, NULL);
5912 if (deletion_state >= OBJECT_RECYCLED) {
5913 talloc_free(tmp_ctx);
5917 old_el = ldb_msg_find_element(msg, attr->lDAPDisplayName);
5918 if (old_el == NULL) {
5919 ret = ldb_msg_add_empty(msg, attr->lDAPDisplayName, LDB_FLAG_MOD_REPLACE, &old_el);
5920 if (ret != LDB_SUCCESS) {
5921 ldb_module_oom(module);
5922 talloc_free(tmp_ctx);
5923 return LDB_ERR_OPERATIONS_ERROR;
5926 old_el->flags = LDB_FLAG_MOD_REPLACE;
5929 /* parse the existing links */
5930 ret = get_parsed_dns(module, tmp_ctx, old_el, &pdn_list, attr->syntax->ldap_oid, parent);
5931 if (ret != LDB_SUCCESS) {
5932 talloc_free(tmp_ctx);
5936 /* get our invocationId */
5937 our_invocation_id = samdb_ntds_invocation_id(ldb);
5938 if (!our_invocation_id) {
5939 ldb_debug_set(ldb, LDB_DEBUG_ERROR, __location__ ": unable to find invocationId\n");
5940 talloc_free(tmp_ctx);
5941 return LDB_ERR_OPERATIONS_ERROR;
5944 ret = replmd_check_upgrade_links(pdn_list, old_el->num_values, old_el, our_invocation_id);
5945 if (ret != LDB_SUCCESS) {
5946 talloc_free(tmp_ctx);
5950 status = dsdb_dn_la_from_blob(ldb, attr, schema, tmp_ctx, la->value.blob, &dsdb_dn);
5951 if (!W_ERROR_IS_OK(status)) {
5952 ldb_asprintf_errstring(ldb, "Failed to parsed linked attribute blob for %s on %s - %s\n",
5953 old_el->name, ldb_dn_get_linearized(msg->dn), win_errstr(status));
5954 talloc_free(tmp_ctx);
5955 return LDB_ERR_OPERATIONS_ERROR;
5958 ntstatus = dsdb_get_extended_dn_guid(dsdb_dn->dn, &guid, "GUID");
5959 if (!NT_STATUS_IS_OK(ntstatus) && !active) {
5961 * This strange behaviour (allowing a NULL/missing
5962 * GUID) originally comes from:
5964 * commit e3054ce0fe0f8f62d2f5b2a77893e7a1479128bd
5965 * Author: Andrew Tridgell <tridge@samba.org>
5966 * Date: Mon Dec 21 21:21:55 2009 +1100
5968 * s4-drs: cope better with NULL GUIDS from DRS
5970 * It is valid to get a NULL GUID over DRS for a deleted forward link. We
5971 * need to match by DN if possible when seeing if we should update an
5974 * Pair-Programmed-With: Andrew Bartlett <abartlet@samba.org>
5977 ret = dsdb_module_search_dn(module, tmp_ctx, &target_res,
5978 dsdb_dn->dn, attrs2,
5979 DSDB_FLAG_NEXT_MODULE |
5980 DSDB_SEARCH_SHOW_RECYCLED |
5981 DSDB_SEARCH_SEARCH_ALL_PARTITIONS |
5982 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT,
5984 } else if (!NT_STATUS_IS_OK(ntstatus)) {
5985 ldb_asprintf_errstring(ldb, "Failed to find GUID in linked attribute blob for %s on %s from %s",
5987 ldb_dn_get_linearized(dsdb_dn->dn),
5988 ldb_dn_get_linearized(msg->dn));
5989 talloc_free(tmp_ctx);
5990 return LDB_ERR_OPERATIONS_ERROR;
5992 ret = dsdb_module_search(module, tmp_ctx, &target_res,
5993 NULL, LDB_SCOPE_SUBTREE,
5995 DSDB_FLAG_NEXT_MODULE |
5996 DSDB_SEARCH_SHOW_RECYCLED |
5997 DSDB_SEARCH_SEARCH_ALL_PARTITIONS |
5998 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT,
6001 GUID_string(tmp_ctx, &guid));
6004 if (ret != LDB_SUCCESS) {
6005 ldb_asprintf_errstring(ldb_module_get_ctx(module), "Failed to re-resolve GUID %s: %s\n",
6006 GUID_string(tmp_ctx, &guid),
6007 ldb_errstring(ldb_module_get_ctx(module)));
6008 talloc_free(tmp_ctx);
6012 if (target_res->count == 0) {
6013 DEBUG(2,(__location__ ": WARNING: Failed to re-resolve GUID %s - using %s\n",
6014 GUID_string(tmp_ctx, &guid),
6015 ldb_dn_get_linearized(dsdb_dn->dn)));
6016 } else if (target_res->count != 1) {
6017 ldb_asprintf_errstring(ldb_module_get_ctx(module), "More than one object found matching objectGUID %s\n",
6018 GUID_string(tmp_ctx, &guid));
6019 talloc_free(tmp_ctx);
6020 return LDB_ERR_OPERATIONS_ERROR;
6022 target_msg = target_res->msgs[0];
6023 dsdb_dn->dn = talloc_steal(dsdb_dn, target_msg->dn);
6027 * Check for deleted objects per MS-DRSR 4.1.10.6.13
6028 * ProcessLinkValue, because link updates are not applied to
6029 * recycled and tombstone objects. We don't have to delete
6030 * any existing link, that should have happened when the
6031 * object deletion was replicated or initiated.
6033 replmd_deletion_state(module, target_msg,
6034 &target_deletion_state, NULL);
6036 if (target_deletion_state >= OBJECT_RECYCLED) {
6037 talloc_free(tmp_ctx);
6041 /* see if this link already exists */
6042 pdn = parsed_dn_find(pdn_list, old_el->num_values, &guid, dsdb_dn->dn);
6044 /* see if this update is newer than what we have already */
6045 struct GUID invocation_id = GUID_zero();
6046 uint32_t version = 0;
6047 uint32_t originating_usn = 0;
6048 NTTIME change_time = 0;
6049 uint32_t rmd_flags = dsdb_dn_rmd_flags(pdn->dsdb_dn->dn);
6051 dsdb_get_extended_dn_guid(pdn->dsdb_dn->dn, &invocation_id, "RMD_INVOCID");
6052 dsdb_get_extended_dn_uint32(pdn->dsdb_dn->dn, &version, "RMD_VERSION");
6053 dsdb_get_extended_dn_uint32(pdn->dsdb_dn->dn, &originating_usn, "RMD_ORIGINATING_USN");
6054 dsdb_get_extended_dn_nttime(pdn->dsdb_dn->dn, &change_time, "RMD_CHANGETIME");
6056 if (!replmd_update_is_newer(&invocation_id,
6057 &la->meta_data.originating_invocation_id,
6059 la->meta_data.version,
6061 la->meta_data.originating_change_time)) {
6062 DEBUG(3,("Discarding older DRS linked attribute update to %s on %s from %s\n",
6063 old_el->name, ldb_dn_get_linearized(msg->dn),
6064 GUID_string(tmp_ctx, &la->meta_data.originating_invocation_id)));
6065 talloc_free(tmp_ctx);
6069 /* get a seq_num for this change */
6070 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &seq_num);
6071 if (ret != LDB_SUCCESS) {
6072 talloc_free(tmp_ctx);
6076 if (!(rmd_flags & DSDB_RMD_FLAG_DELETED)) {
6077 /* remove the existing backlink */
6078 ret = replmd_add_backlink(module, schema, &la->identifier->guid, &guid, false, attr, false);
6079 if (ret != LDB_SUCCESS) {
6080 talloc_free(tmp_ctx);
6085 ret = replmd_update_la_val(tmp_ctx, pdn->v, dsdb_dn, pdn->dsdb_dn,
6086 &la->meta_data.originating_invocation_id,
6087 la->meta_data.originating_usn, seq_num,
6088 la->meta_data.originating_change_time,
6089 la->meta_data.version,
6091 if (ret != LDB_SUCCESS) {
6092 talloc_free(tmp_ctx);
6097 /* add the new backlink */
6098 ret = replmd_add_backlink(module, schema, &la->identifier->guid, &guid, true, attr, false);
6099 if (ret != LDB_SUCCESS) {
6100 talloc_free(tmp_ctx);
6105 /* get a seq_num for this change */
6106 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &seq_num);
6107 if (ret != LDB_SUCCESS) {
6108 talloc_free(tmp_ctx);
6112 old_el->values = talloc_realloc(msg->elements, old_el->values,
6113 struct ldb_val, old_el->num_values+1);
6114 if (!old_el->values) {
6115 ldb_module_oom(module);
6116 return LDB_ERR_OPERATIONS_ERROR;
6118 old_el->num_values++;
6120 ret = replmd_build_la_val(tmp_ctx, &old_el->values[old_el->num_values-1], dsdb_dn,
6121 &la->meta_data.originating_invocation_id,
6122 la->meta_data.originating_usn, seq_num,
6123 la->meta_data.originating_change_time,
6124 la->meta_data.version,
6125 (la->flags & DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE)?false:true);
6126 if (ret != LDB_SUCCESS) {
6127 talloc_free(tmp_ctx);
6132 ret = replmd_add_backlink(module, schema, &la->identifier->guid, &guid,
6134 if (ret != LDB_SUCCESS) {
6135 talloc_free(tmp_ctx);
6141 /* we only change whenChanged and uSNChanged if the seq_num
6143 ret = add_time_element(msg, "whenChanged", t);
6144 if (ret != LDB_SUCCESS) {
6145 talloc_free(tmp_ctx);
6150 ret = add_uint64_element(ldb, msg, "uSNChanged", seq_num);
6151 if (ret != LDB_SUCCESS) {
6152 talloc_free(tmp_ctx);
6157 old_el = ldb_msg_find_element(msg, attr->lDAPDisplayName);
6158 if (old_el == NULL) {
6159 talloc_free(tmp_ctx);
6160 return ldb_operr(ldb);
6163 ret = dsdb_check_single_valued_link(attr, old_el);
6164 if (ret != LDB_SUCCESS) {
6165 talloc_free(tmp_ctx);
6169 old_el->flags |= LDB_FLAG_INTERNAL_DISABLE_SINGLE_VALUE_CHECK;
6171 ret = dsdb_module_modify(module, msg, DSDB_FLAG_NEXT_MODULE, parent);
6172 if (ret != LDB_SUCCESS) {
6173 ldb_debug(ldb, LDB_DEBUG_WARNING, "Failed to apply linked attribute change '%s'\n%s\n",
6175 ldb_ldif_message_string(ldb, tmp_ctx, LDB_CHANGETYPE_MODIFY, msg));
6176 talloc_free(tmp_ctx);
6180 talloc_free(tmp_ctx);
6185 static int replmd_extended(struct ldb_module *module, struct ldb_request *req)
6187 if (strcmp(req->op.extended.oid, DSDB_EXTENDED_REPLICATED_OBJECTS_OID) == 0) {
6188 return replmd_extended_replicated_objects(module, req);
6191 return ldb_next_request(module, req);
6196 we hook into the transaction operations to allow us to
6197 perform the linked attribute updates at the end of the whole
6198 transaction. This allows a forward linked attribute to be created
6199 before the object is created. During a vampire, w2k8 sends us linked
6200 attributes before the objects they are part of.
6202 static int replmd_start_transaction(struct ldb_module *module)
6204 /* create our private structure for this transaction */
6205 struct replmd_private *replmd_private = talloc_get_type(ldb_module_get_private(module),
6206 struct replmd_private);
6207 replmd_txn_cleanup(replmd_private);
6209 /* free any leftover mod_usn records from cancelled
6211 while (replmd_private->ncs) {
6212 struct nc_entry *e = replmd_private->ncs;
6213 DLIST_REMOVE(replmd_private->ncs, e);
6217 return ldb_next_start_trans(module);
6221 on prepare commit we loop over our queued la_context structures and
6224 static int replmd_prepare_commit(struct ldb_module *module)
6226 struct replmd_private *replmd_private =
6227 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
6228 struct la_entry *la, *prev;
6229 struct la_backlink *bl;
6232 /* walk the list backwards, to do the first entry first, as we
6233 * added the entries with DLIST_ADD() which puts them at the
6234 * start of the list */
6235 for (la = DLIST_TAIL(replmd_private->la_list); la; la=prev) {
6236 prev = DLIST_PREV(la);
6237 DLIST_REMOVE(replmd_private->la_list, la);
6238 ret = replmd_process_linked_attribute(module, la, NULL);
6239 if (ret != LDB_SUCCESS) {
6240 replmd_txn_cleanup(replmd_private);
6245 /* process our backlink list, creating and deleting backlinks
6247 for (bl=replmd_private->la_backlinks; bl; bl=bl->next) {
6248 ret = replmd_process_backlink(module, bl, NULL);
6249 if (ret != LDB_SUCCESS) {
6250 replmd_txn_cleanup(replmd_private);
6255 replmd_txn_cleanup(replmd_private);
6257 /* possibly change @REPLCHANGED */
6258 ret = replmd_notify_store(module, NULL);
6259 if (ret != LDB_SUCCESS) {
6263 return ldb_next_prepare_commit(module);
6266 static int replmd_del_transaction(struct ldb_module *module)
6268 struct replmd_private *replmd_private =
6269 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
6270 replmd_txn_cleanup(replmd_private);
6272 return ldb_next_del_trans(module);
6276 static const struct ldb_module_ops ldb_repl_meta_data_module_ops = {
6277 .name = "repl_meta_data",
6278 .init_context = replmd_init,
6280 .modify = replmd_modify,
6281 .rename = replmd_rename,
6282 .del = replmd_delete,
6283 .extended = replmd_extended,
6284 .start_transaction = replmd_start_transaction,
6285 .prepare_commit = replmd_prepare_commit,
6286 .del_transaction = replmd_del_transaction,
6289 int ldb_repl_meta_data_module_init(const char *version)
6291 LDB_MODULE_CHECK_VERSION(version);
6292 return ldb_register_module(&ldb_repl_meta_data_module_ops);