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 "dsdb/common/util.h"
43 #include "../libds/common/flags.h"
44 #include "librpc/gen_ndr/irpc.h"
45 #include "librpc/gen_ndr/ndr_misc.h"
46 #include "librpc/gen_ndr/ndr_drsuapi.h"
47 #include "librpc/gen_ndr/ndr_drsblobs.h"
48 #include "param/param.h"
49 #include "libcli/security/security.h"
50 #include "lib/util/dlinklist.h"
51 #include "dsdb/samdb/ldb_modules/util.h"
52 #include "lib/util/tsort.h"
55 * It's 29/12/9999 at 23:59:59 UTC as specified in MS-ADTS 7.1.1.4.2
56 * Deleted Objects Container
58 static const NTTIME DELETED_OBJECT_CONTAINER_CHANGE_TIME = 2650466015990000000ULL;
60 struct replmd_private {
62 struct la_entry *la_list;
64 struct nc_entry *prev, *next;
67 uint64_t mod_usn_urgent;
69 struct ldb_dn *schema_dn;
70 bool originating_updates;
75 struct la_entry *next, *prev;
76 struct drsuapi_DsReplicaLinkedAttribute *la;
77 uint32_t dsdb_repl_flags;
80 struct replmd_replicated_request {
81 struct ldb_module *module;
82 struct ldb_request *req;
84 const struct dsdb_schema *schema;
85 struct GUID our_invocation_id;
87 /* the controls we pass down */
88 struct ldb_control **controls;
91 * Backlinks for the replmd_add() case (we want to create
92 * backlinks after creating the user, but before the end of
95 struct la_backlink *la_backlinks;
97 /* details for the mode where we apply a bunch of inbound replication meessages */
99 uint32_t index_current;
100 struct dsdb_extended_replicated_objects *objs;
102 struct ldb_message *search_msg;
103 struct GUID local_parent_guid;
111 static int replmd_replicated_apply_merge(struct replmd_replicated_request *ar);
112 static int replmd_delete_internals(struct ldb_module *module, struct ldb_request *req, bool re_delete);
113 static int replmd_check_upgrade_links(struct ldb_context *ldb,
114 struct parsed_dn *dns, uint32_t count,
115 struct ldb_message_element *el,
116 const char *ldap_oid);
117 static int replmd_verify_linked_attribute(struct replmd_replicated_request *ar,
118 struct la_entry *la);
120 enum urgent_situation {
121 REPL_URGENT_ON_CREATE = 1,
122 REPL_URGENT_ON_UPDATE = 2,
123 REPL_URGENT_ON_DELETE = 4
126 enum deletion_state {
127 OBJECT_NOT_DELETED=1,
134 static void replmd_deletion_state(struct ldb_module *module,
135 const struct ldb_message *msg,
136 enum deletion_state *current_state,
137 enum deletion_state *next_state)
140 bool enabled = false;
143 *current_state = OBJECT_REMOVED;
144 if (next_state != NULL) {
145 *next_state = OBJECT_REMOVED;
150 ret = dsdb_recyclebin_enabled(module, &enabled);
151 if (ret != LDB_SUCCESS) {
155 if (ldb_msg_check_string_attribute(msg, "isDeleted", "TRUE")) {
157 *current_state = OBJECT_TOMBSTONE;
158 if (next_state != NULL) {
159 *next_state = OBJECT_REMOVED;
164 if (ldb_msg_check_string_attribute(msg, "isRecycled", "TRUE")) {
165 *current_state = OBJECT_RECYCLED;
166 if (next_state != NULL) {
167 *next_state = OBJECT_REMOVED;
172 *current_state = OBJECT_DELETED;
173 if (next_state != NULL) {
174 *next_state = OBJECT_RECYCLED;
179 *current_state = OBJECT_NOT_DELETED;
180 if (next_state == NULL) {
185 *next_state = OBJECT_DELETED;
187 *next_state = OBJECT_TOMBSTONE;
191 static const struct {
192 const char *update_name;
193 enum urgent_situation repl_situation;
194 } urgent_objects[] = {
195 {"nTDSDSA", (REPL_URGENT_ON_CREATE | REPL_URGENT_ON_DELETE)},
196 {"crossRef", (REPL_URGENT_ON_CREATE | REPL_URGENT_ON_DELETE)},
197 {"attributeSchema", (REPL_URGENT_ON_CREATE | REPL_URGENT_ON_UPDATE)},
198 {"classSchema", (REPL_URGENT_ON_CREATE | REPL_URGENT_ON_UPDATE)},
199 {"secret", (REPL_URGENT_ON_CREATE | REPL_URGENT_ON_UPDATE)},
200 {"rIDManager", (REPL_URGENT_ON_CREATE | REPL_URGENT_ON_UPDATE)},
204 /* Attributes looked for when updating or deleting, to check for a urgent replication needed */
205 static const char *urgent_attrs[] = {
208 "userAccountControl",
213 static bool replmd_check_urgent_objectclass(const struct ldb_message_element *objectclass_el,
214 enum urgent_situation situation)
217 for (i=0; urgent_objects[i].update_name; i++) {
219 if ((situation & urgent_objects[i].repl_situation) == 0) {
223 for (j=0; j<objectclass_el->num_values; j++) {
224 const struct ldb_val *v = &objectclass_el->values[j];
225 if (ldb_attr_cmp((const char *)v->data, urgent_objects[i].update_name) == 0) {
233 static bool replmd_check_urgent_attribute(const struct ldb_message_element *el)
235 if (ldb_attr_in_list(urgent_attrs, el->name)) {
241 static int replmd_replicated_apply_isDeleted(struct replmd_replicated_request *ar);
244 initialise the module
245 allocate the private structure and build the list
246 of partition DNs for use by replmd_notify()
248 static int replmd_init(struct ldb_module *module)
250 struct replmd_private *replmd_private;
251 struct ldb_context *ldb = ldb_module_get_ctx(module);
252 static const char *samba_dsdb_attrs[] = { SAMBA_COMPATIBLE_FEATURES_ATTR, NULL };
253 struct ldb_dn *samba_dsdb_dn;
254 struct ldb_result *res;
256 TALLOC_CTX *frame = talloc_stackframe();
257 replmd_private = talloc_zero(module, struct replmd_private);
258 if (replmd_private == NULL) {
261 return LDB_ERR_OPERATIONS_ERROR;
263 ldb_module_set_private(module, replmd_private);
265 replmd_private->schema_dn = ldb_get_schema_basedn(ldb);
267 samba_dsdb_dn = ldb_dn_new(frame, ldb, "@SAMBA_DSDB");
268 if (!samba_dsdb_dn) {
273 ret = dsdb_module_search_dn(module, frame, &res, samba_dsdb_dn,
274 samba_dsdb_attrs, DSDB_FLAG_NEXT_MODULE, NULL);
275 if (ret == LDB_SUCCESS) {
276 replmd_private->sorted_links
277 = ldb_msg_check_string_attribute(res->msgs[0],
278 SAMBA_COMPATIBLE_FEATURES_ATTR,
279 SAMBA_SORTED_LINKS_FEATURE);
283 return ldb_next_init(module);
287 cleanup our per-transaction contexts
289 static void replmd_txn_cleanup(struct replmd_private *replmd_private)
291 talloc_free(replmd_private->la_ctx);
292 replmd_private->la_list = NULL;
293 replmd_private->la_ctx = NULL;
299 struct la_backlink *next, *prev;
300 const char *attr_name;
301 struct ldb_dn *forward_dn;
302 struct GUID target_guid;
307 a ldb_modify request operating on modules below the
310 static int linked_attr_modify(struct ldb_module *module,
311 const struct ldb_message *message,
312 struct ldb_request *parent)
314 struct ldb_request *mod_req;
316 struct ldb_context *ldb = ldb_module_get_ctx(module);
317 TALLOC_CTX *tmp_ctx = talloc_new(module);
318 struct ldb_result *res;
320 res = talloc_zero(tmp_ctx, struct ldb_result);
322 talloc_free(tmp_ctx);
323 return ldb_oom(ldb_module_get_ctx(module));
326 ret = ldb_build_mod_req(&mod_req, ldb, tmp_ctx,
330 ldb_modify_default_callback,
332 LDB_REQ_SET_LOCATION(mod_req);
333 if (ret != LDB_SUCCESS) {
334 talloc_free(tmp_ctx);
338 ret = ldb_request_add_control(mod_req, DSDB_CONTROL_REPLICATED_UPDATE_OID,
340 if (ret != LDB_SUCCESS) {
344 /* Run the new request */
345 ret = ldb_next_request(module, mod_req);
347 if (ret == LDB_SUCCESS) {
348 ret = ldb_wait(mod_req->handle, LDB_WAIT_ALL);
351 talloc_free(tmp_ctx);
356 process a backlinks we accumulated during a transaction, adding and
357 deleting the backlinks from the target objects
359 static int replmd_process_backlink(struct ldb_module *module, struct la_backlink *bl, struct ldb_request *parent)
361 struct ldb_dn *target_dn, *source_dn;
363 struct ldb_context *ldb = ldb_module_get_ctx(module);
364 struct ldb_message *msg;
365 TALLOC_CTX *frame = talloc_stackframe();
371 - construct ldb_message
372 - either an add or a delete
374 ret = dsdb_module_dn_by_guid(module, frame, &bl->target_guid, &target_dn, parent);
375 if (ret != LDB_SUCCESS) {
376 struct GUID_txt_buf guid_str;
377 DBG_WARNING("Failed to find target DN for linked attribute with GUID %s\n",
378 GUID_buf_string(&bl->target_guid, &guid_str));
379 DBG_WARNING("Please run 'samba-tool dbcheck' to resolve any missing backlinks.\n");
384 msg = ldb_msg_new(frame);
386 ldb_module_oom(module);
388 return LDB_ERR_OPERATIONS_ERROR;
391 source_dn = ldb_dn_copy(frame, bl->forward_dn);
393 ldb_module_oom(module);
395 return LDB_ERR_OPERATIONS_ERROR;
397 /* Filter down to the attributes we want in the backlink */
398 const char *accept[] = { "GUID", "SID", NULL };
399 ldb_dn_extended_filter(source_dn, accept);
402 /* construct a ldb_message for adding/deleting the backlink */
404 dn_string = ldb_dn_get_extended_linearized(frame, bl->forward_dn, 1);
406 ldb_module_oom(module);
408 return LDB_ERR_OPERATIONS_ERROR;
410 ret = ldb_msg_add_steal_string(msg, bl->attr_name, dn_string);
411 if (ret != LDB_SUCCESS) {
415 msg->elements[0].flags = bl->active?LDB_FLAG_MOD_ADD:LDB_FLAG_MOD_DELETE;
417 /* a backlink should never be single valued. Unfortunately the
418 exchange schema has a attribute
419 msExchBridgeheadedLocalConnectorsDNBL which is single
420 valued and a backlink. We need to cope with that by
421 ignoring the single value flag */
422 msg->elements[0].flags |= LDB_FLAG_INTERNAL_DISABLE_SINGLE_VALUE_CHECK;
424 ret = dsdb_module_modify(module, msg, DSDB_FLAG_NEXT_MODULE, parent);
425 if (ret == LDB_ERR_NO_SUCH_ATTRIBUTE && !bl->active) {
426 /* we allow LDB_ERR_NO_SUCH_ATTRIBUTE as success to
427 cope with possible corruption where the backlink has
428 already been removed */
429 DEBUG(3,("WARNING: backlink from %s already removed from %s - %s\n",
430 ldb_dn_get_linearized(target_dn),
431 ldb_dn_get_linearized(source_dn),
432 ldb_errstring(ldb)));
434 } else if (ret != LDB_SUCCESS) {
435 ldb_asprintf_errstring(ldb, "Failed to %s backlink from %s to %s - %s",
436 bl->active?"add":"remove",
437 ldb_dn_get_linearized(source_dn),
438 ldb_dn_get_linearized(target_dn),
448 add a backlink to the list of backlinks to add/delete in the prepare
451 forward_dn is stolen onto the defereed context
453 static int replmd_defer_add_backlink(struct ldb_module *module,
454 struct replmd_private *replmd_private,
455 const struct dsdb_schema *schema,
456 struct replmd_replicated_request *ac,
457 struct ldb_dn *forward_dn,
458 struct GUID *target_guid, bool active,
459 const struct dsdb_attribute *schema_attr,
460 struct ldb_request *parent)
462 const struct dsdb_attribute *target_attr;
463 struct la_backlink *bl;
465 bl = talloc(ac, struct la_backlink);
467 ldb_module_oom(module);
468 return LDB_ERR_OPERATIONS_ERROR;
471 target_attr = dsdb_attribute_by_linkID(schema, schema_attr->linkID ^ 1);
474 * windows 2003 has a broken schema where the
475 * definition of msDS-IsDomainFor is missing (which is
476 * supposed to be the backlink of the
477 * msDS-HasDomainNCs attribute
482 bl->attr_name = target_attr->lDAPDisplayName;
483 bl->forward_dn = talloc_steal(bl, forward_dn);
484 bl->target_guid = *target_guid;
487 DLIST_ADD(ac->la_backlinks, bl);
493 add a backlink to the list of backlinks to add/delete in the prepare
496 static int replmd_add_backlink(struct ldb_module *module,
497 struct replmd_private *replmd_private,
498 const struct dsdb_schema *schema,
499 struct ldb_dn *forward_dn,
500 struct GUID *target_guid, bool active,
501 const struct dsdb_attribute *schema_attr,
502 struct ldb_request *parent)
504 const struct dsdb_attribute *target_attr;
505 struct la_backlink bl;
508 target_attr = dsdb_attribute_by_linkID(schema, schema_attr->linkID ^ 1);
511 * windows 2003 has a broken schema where the
512 * definition of msDS-IsDomainFor is missing (which is
513 * supposed to be the backlink of the
514 * msDS-HasDomainNCs attribute
519 bl.attr_name = target_attr->lDAPDisplayName;
520 bl.forward_dn = forward_dn;
521 bl.target_guid = *target_guid;
524 ret = replmd_process_backlink(module, &bl, parent);
530 * Callback for most write operations in this module:
532 * notify the repl task that a object has changed. The notifies are
533 * gathered up in the replmd_private structure then written to the
534 * @REPLCHANGED object in each partition during the prepare_commit
536 static int replmd_op_callback(struct ldb_request *req, struct ldb_reply *ares)
539 struct replmd_replicated_request *ac =
540 talloc_get_type_abort(req->context, struct replmd_replicated_request);
541 struct replmd_private *replmd_private =
542 talloc_get_type_abort(ldb_module_get_private(ac->module), struct replmd_private);
543 struct nc_entry *modified_partition;
544 struct ldb_control *partition_ctrl;
545 const struct dsdb_control_current_partition *partition;
547 struct ldb_control **controls;
549 partition_ctrl = ldb_reply_get_control(ares, DSDB_CONTROL_CURRENT_PARTITION_OID);
551 controls = ares->controls;
552 if (ldb_request_get_control(ac->req,
553 DSDB_CONTROL_CURRENT_PARTITION_OID) == NULL) {
555 * Remove the current partition control from what we pass up
556 * the chain if it hasn't been requested manually.
558 controls = ldb_controls_except_specified(ares->controls, ares,
562 if (ares->error != LDB_SUCCESS) {
563 DEBUG(5,("%s failure. Error is: %s\n", __FUNCTION__, ldb_strerror(ares->error)));
564 return ldb_module_done(ac->req, controls,
565 ares->response, ares->error);
568 if (ares->type != LDB_REPLY_DONE) {
569 ldb_set_errstring(ldb_module_get_ctx(ac->module), "Invalid reply type for notify\n!");
570 return ldb_module_done(ac->req, NULL,
571 NULL, LDB_ERR_OPERATIONS_ERROR);
574 if (ac->apply_mode == false) {
575 struct la_backlink *bl;
577 * process our backlink list after an replmd_add(),
578 * creating and deleting backlinks as necessary (this
579 * code is sync). The other cases are handled inline
582 for (bl=ac->la_backlinks; bl; bl=bl->next) {
583 ret = replmd_process_backlink(ac->module, bl, ac->req);
584 if (ret != LDB_SUCCESS) {
585 return ldb_module_done(ac->req, NULL,
591 if (!partition_ctrl) {
592 ldb_set_errstring(ldb_module_get_ctx(ac->module),"No partition control on reply");
593 return ldb_module_done(ac->req, NULL,
594 NULL, LDB_ERR_OPERATIONS_ERROR);
597 partition = talloc_get_type_abort(partition_ctrl->data,
598 struct dsdb_control_current_partition);
600 if (ac->seq_num > 0) {
601 for (modified_partition = replmd_private->ncs; modified_partition;
602 modified_partition = modified_partition->next) {
603 if (ldb_dn_compare(modified_partition->dn, partition->dn) == 0) {
608 if (modified_partition == NULL) {
609 modified_partition = talloc_zero(replmd_private, struct nc_entry);
610 if (!modified_partition) {
611 ldb_oom(ldb_module_get_ctx(ac->module));
612 return ldb_module_done(ac->req, NULL,
613 NULL, LDB_ERR_OPERATIONS_ERROR);
615 modified_partition->dn = ldb_dn_copy(modified_partition, partition->dn);
616 if (!modified_partition->dn) {
617 ldb_oom(ldb_module_get_ctx(ac->module));
618 return ldb_module_done(ac->req, NULL,
619 NULL, LDB_ERR_OPERATIONS_ERROR);
621 DLIST_ADD(replmd_private->ncs, modified_partition);
624 if (ac->seq_num > modified_partition->mod_usn) {
625 modified_partition->mod_usn = ac->seq_num;
627 modified_partition->mod_usn_urgent = ac->seq_num;
630 if (!ac->apply_mode) {
631 replmd_private->originating_updates = true;
635 if (ac->apply_mode) {
636 ret = replmd_replicated_apply_isDeleted(ac);
637 if (ret != LDB_SUCCESS) {
638 return ldb_module_done(ac->req, NULL, NULL, ret);
642 /* free the partition control container here, for the
643 * common path. Other cases will have it cleaned up
644 * eventually with the ares */
645 talloc_free(partition_ctrl);
646 return ldb_module_done(ac->req, controls,
647 ares->response, LDB_SUCCESS);
653 * update a @REPLCHANGED record in each partition if there have been
654 * any writes of replicated data in the partition
656 static int replmd_notify_store(struct ldb_module *module, struct ldb_request *parent)
658 struct replmd_private *replmd_private =
659 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
661 while (replmd_private->ncs) {
663 struct nc_entry *modified_partition = replmd_private->ncs;
665 ret = dsdb_module_save_partition_usn(module, modified_partition->dn,
666 modified_partition->mod_usn,
667 modified_partition->mod_usn_urgent, parent);
668 if (ret != LDB_SUCCESS) {
669 DEBUG(0,(__location__ ": Failed to save partition uSN for %s\n",
670 ldb_dn_get_linearized(modified_partition->dn)));
674 if (ldb_dn_compare(modified_partition->dn,
675 replmd_private->schema_dn) == 0) {
676 struct ldb_result *ext_res;
677 ret = dsdb_module_extended(module,
678 replmd_private->schema_dn,
680 DSDB_EXTENDED_SCHEMA_UPDATE_NOW_OID,
682 DSDB_FLAG_NEXT_MODULE,
684 if (ret != LDB_SUCCESS) {
687 talloc_free(ext_res);
690 DLIST_REMOVE(replmd_private->ncs, modified_partition);
691 talloc_free(modified_partition);
699 created a replmd_replicated_request context
701 static struct replmd_replicated_request *replmd_ctx_init(struct ldb_module *module,
702 struct ldb_request *req)
704 struct ldb_context *ldb;
705 struct replmd_replicated_request *ac;
706 const struct GUID *our_invocation_id;
708 ldb = ldb_module_get_ctx(module);
710 ac = talloc_zero(req, struct replmd_replicated_request);
719 ac->schema = dsdb_get_schema(ldb, ac);
721 ldb_debug_set(ldb, LDB_DEBUG_FATAL,
722 "replmd_modify: no dsdb_schema loaded");
723 DEBUG(0,(__location__ ": %s\n", ldb_errstring(ldb)));
728 /* get our invocationId */
729 our_invocation_id = samdb_ntds_invocation_id(ldb);
730 if (!our_invocation_id) {
731 ldb_debug_set(ldb, LDB_DEBUG_FATAL,
732 "replmd_add: unable to find invocationId\n");
736 ac->our_invocation_id = *our_invocation_id;
742 add a time element to a record
744 static int add_time_element(struct ldb_message *msg, const char *attr, time_t t)
746 struct ldb_message_element *el;
750 if (ldb_msg_find_element(msg, attr) != NULL) {
754 s = ldb_timestring(msg, t);
756 return LDB_ERR_OPERATIONS_ERROR;
759 ret = ldb_msg_add_string(msg, attr, s);
760 if (ret != LDB_SUCCESS) {
764 el = ldb_msg_find_element(msg, attr);
765 /* always set as replace. This works because on add ops, the flag
767 el->flags = LDB_FLAG_MOD_REPLACE;
773 add a uint64_t element to a record
775 static int add_uint64_element(struct ldb_context *ldb, struct ldb_message *msg,
776 const char *attr, uint64_t v)
778 struct ldb_message_element *el;
781 if (ldb_msg_find_element(msg, attr) != NULL) {
785 ret = samdb_msg_add_uint64(ldb, msg, msg, attr, v);
786 if (ret != LDB_SUCCESS) {
790 el = ldb_msg_find_element(msg, attr);
791 /* always set as replace. This works because on add ops, the flag
793 el->flags = LDB_FLAG_MOD_REPLACE;
798 static int replmd_replPropertyMetaData1_attid_sort(const struct replPropertyMetaData1 *m1,
799 const struct replPropertyMetaData1 *m2,
800 const uint32_t *rdn_attid)
803 * This assignment seems inoccous, but it is critical for the
804 * system, as we need to do the comparisons as a unsigned
805 * quantity, not signed (enums are signed integers)
807 uint32_t attid_1 = m1->attid;
808 uint32_t attid_2 = m2->attid;
810 if (attid_1 == attid_2) {
815 * See above regarding this being an unsigned comparison.
816 * Otherwise when the high bit is set on non-standard
817 * attributes, they would end up first, before objectClass
820 return attid_1 > attid_2 ? 1 : -1;
823 static int replmd_replPropertyMetaDataCtr1_verify(struct ldb_context *ldb,
824 struct replPropertyMetaDataCtr1 *ctr1,
827 if (ctr1->count == 0) {
828 ldb_debug_set(ldb, LDB_DEBUG_FATAL,
829 "No elements found in replPropertyMetaData for %s!\n",
830 ldb_dn_get_linearized(dn));
831 return LDB_ERR_CONSTRAINT_VIOLATION;
834 /* the objectClass attribute is value 0x00000000, so must be first */
835 if (ctr1->array[0].attid != DRSUAPI_ATTID_objectClass) {
836 ldb_debug_set(ldb, LDB_DEBUG_FATAL,
837 "No objectClass found in replPropertyMetaData for %s!\n",
838 ldb_dn_get_linearized(dn));
839 return LDB_ERR_OBJECT_CLASS_VIOLATION;
845 static int replmd_replPropertyMetaDataCtr1_sort_and_verify(struct ldb_context *ldb,
846 struct replPropertyMetaDataCtr1 *ctr1,
849 /* Note this is O(n^2) for the almost-sorted case, which this is */
850 LDB_TYPESAFE_QSORT(ctr1->array, ctr1->count, NULL,
851 replmd_replPropertyMetaData1_attid_sort);
852 return replmd_replPropertyMetaDataCtr1_verify(ldb, ctr1, dn);
855 static int replmd_ldb_message_element_attid_sort(const struct ldb_message_element *e1,
856 const struct ldb_message_element *e2,
857 const struct dsdb_schema *schema)
859 const struct dsdb_attribute *a1;
860 const struct dsdb_attribute *a2;
863 * TODO: make this faster by caching the dsdb_attribute pointer
864 * on the ldb_messag_element
867 a1 = dsdb_attribute_by_lDAPDisplayName(schema, e1->name);
868 a2 = dsdb_attribute_by_lDAPDisplayName(schema, e2->name);
871 * TODO: remove this check, we should rely on e1 and e2 having valid attribute names
875 return strcasecmp(e1->name, e2->name);
877 if (a1->attributeID_id == a2->attributeID_id) {
880 return a1->attributeID_id > a2->attributeID_id ? 1 : -1;
883 static void replmd_ldb_message_sort(struct ldb_message *msg,
884 const struct dsdb_schema *schema)
886 LDB_TYPESAFE_QSORT(msg->elements, msg->num_elements, schema, replmd_ldb_message_element_attid_sort);
889 static int replmd_build_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct dsdb_dn *dsdb_dn,
890 const struct GUID *invocation_id, uint64_t seq_num,
891 uint64_t local_usn, NTTIME nttime, uint32_t version, bool deleted);
893 static int parsed_dn_compare(struct parsed_dn *pdn1, struct parsed_dn *pdn2);
895 static int get_parsed_dns(struct ldb_module *module, TALLOC_CTX *mem_ctx,
896 struct ldb_message_element *el, struct parsed_dn **pdn,
897 const char *ldap_oid, struct ldb_request *parent);
900 fix up linked attributes in replmd_add.
901 This involves setting up the right meta-data in extended DN
902 components, and creating backlinks to the object
904 static int replmd_add_fix_la(struct ldb_module *module, TALLOC_CTX *mem_ctx,
905 struct replmd_private *replmd_private,
906 struct ldb_message_element *el,
907 struct replmd_replicated_request *ac,
909 struct ldb_dn *forward_dn,
910 const struct dsdb_attribute *sa,
911 struct ldb_request *parent)
914 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
915 struct ldb_context *ldb = ldb_module_get_ctx(module);
916 struct parsed_dn *pdn;
917 /* We will take a reference to the schema in replmd_add_backlink */
918 const struct dsdb_schema *schema = dsdb_get_schema(ldb, NULL);
919 struct ldb_val *new_values = NULL;
922 if (dsdb_check_single_valued_link(sa, el) == LDB_SUCCESS) {
923 el->flags |= LDB_FLAG_INTERNAL_DISABLE_SINGLE_VALUE_CHECK;
925 ldb_asprintf_errstring(ldb,
926 "Attribute %s is single valued but "
927 "more than one value has been supplied",
929 talloc_free(tmp_ctx);
930 return LDB_ERR_CONSTRAINT_VIOLATION;
933 ret = get_parsed_dns(module, tmp_ctx, el, &pdn,
934 sa->syntax->ldap_oid, parent);
935 if (ret != LDB_SUCCESS) {
936 talloc_free(tmp_ctx);
940 new_values = talloc_array(tmp_ctx, struct ldb_val, el->num_values);
941 if (new_values == NULL) {
942 ldb_module_oom(module);
943 talloc_free(tmp_ctx);
944 return LDB_ERR_OPERATIONS_ERROR;
947 for (i = 0; i < el->num_values; i++) {
948 struct parsed_dn *p = &pdn[i];
949 if (i > 0 && parsed_dn_compare(p, &pdn[i - 1]) == 0) {
950 ldb_asprintf_errstring(ldb,
951 "Linked attribute %s has "
952 "multiple identical values", el->name);
953 talloc_free(tmp_ctx);
954 if (ldb_attr_cmp(el->name, "member") == 0) {
955 return LDB_ERR_ENTRY_ALREADY_EXISTS;
957 return LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS;
960 ret = replmd_build_la_val(el->values, p->v, p->dsdb_dn,
961 &ac->our_invocation_id,
962 ac->seq_num, ac->seq_num, now, 0, false);
963 if (ret != LDB_SUCCESS) {
964 talloc_free(tmp_ctx);
968 ret = replmd_defer_add_backlink(module, replmd_private,
970 forward_dn, &p->guid, true, sa,
972 if (ret != LDB_SUCCESS) {
973 talloc_free(tmp_ctx);
977 new_values[i] = *p->v;
979 el->values = talloc_steal(mem_ctx, new_values);
981 talloc_free(tmp_ctx);
985 static int replmd_add_make_extended_dn(struct ldb_request *req,
986 const DATA_BLOB *guid_blob,
987 struct ldb_dn **_extended_dn)
990 const DATA_BLOB *sid_blob;
991 /* Calculate an extended DN for any linked attributes */
992 struct ldb_dn *extended_dn = ldb_dn_copy(req, req->op.add.message->dn);
994 return LDB_ERR_OPERATIONS_ERROR;
996 ret = ldb_dn_set_extended_component(extended_dn, "GUID", guid_blob);
997 if (ret != LDB_SUCCESS) {
1001 sid_blob = ldb_msg_find_ldb_val(req->op.add.message, "objectSID");
1002 if (sid_blob != NULL) {
1003 ret = ldb_dn_set_extended_component(extended_dn, "SID", sid_blob);
1004 if (ret != LDB_SUCCESS) {
1008 *_extended_dn = extended_dn;
1013 intercept add requests
1015 static int replmd_add(struct ldb_module *module, struct ldb_request *req)
1017 struct ldb_context *ldb;
1018 struct ldb_control *control;
1019 struct replmd_replicated_request *ac;
1020 enum ndr_err_code ndr_err;
1021 struct ldb_request *down_req;
1022 struct ldb_message *msg;
1023 const DATA_BLOB *guid_blob;
1024 DATA_BLOB guid_blob_stack;
1026 uint8_t guid_data[16];
1027 struct replPropertyMetaDataBlob nmd;
1028 struct ldb_val nmd_value;
1029 struct ldb_dn *extended_dn = NULL;
1032 * The use of a time_t here seems odd, but as the NTTIME
1033 * elements are actually declared as NTTIME_1sec in the IDL,
1034 * getting a higher resolution timestamp is not required.
1036 time_t t = time(NULL);
1041 unsigned int functional_level;
1043 bool allow_add_guid = false;
1044 bool remove_current_guid = false;
1045 bool is_urgent = false;
1046 bool is_schema_nc = false;
1047 struct ldb_message_element *objectclass_el;
1048 struct replmd_private *replmd_private =
1049 talloc_get_type_abort(ldb_module_get_private(module), struct replmd_private);
1051 /* check if there's a show relax control (used by provision to say 'I know what I'm doing') */
1052 control = ldb_request_get_control(req, LDB_CONTROL_RELAX_OID);
1054 allow_add_guid = true;
1057 /* do not manipulate our control entries */
1058 if (ldb_dn_is_special(req->op.add.message->dn)) {
1059 return ldb_next_request(module, req);
1062 ldb = ldb_module_get_ctx(module);
1064 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_add\n");
1066 guid_blob = ldb_msg_find_ldb_val(req->op.add.message, "objectGUID");
1067 if (guid_blob != NULL) {
1068 if (!allow_add_guid) {
1069 ldb_set_errstring(ldb,
1070 "replmd_add: it's not allowed to add an object with objectGUID!");
1071 return LDB_ERR_UNWILLING_TO_PERFORM;
1073 NTSTATUS status = GUID_from_data_blob(guid_blob,&guid);
1074 if (!NT_STATUS_IS_OK(status)) {
1075 ldb_set_errstring(ldb,
1076 "replmd_add: Unable to parse the 'objectGUID' as a GUID!");
1077 return LDB_ERR_UNWILLING_TO_PERFORM;
1079 /* we remove this attribute as it can be a string and
1080 * will not be treated correctly and then we will re-add
1081 * it later on in the good format */
1082 remove_current_guid = true;
1086 guid = GUID_random();
1088 guid_blob_stack = data_blob_const(guid_data, sizeof(guid_data));
1090 /* This can't fail */
1091 ndr_push_struct_into_fixed_blob(&guid_blob_stack, &guid,
1092 (ndr_push_flags_fn_t)ndr_push_GUID);
1093 guid_blob = &guid_blob_stack;
1096 ac = replmd_ctx_init(module, req);
1098 return ldb_module_oom(module);
1101 functional_level = dsdb_functional_level(ldb);
1103 /* Get a sequence number from the backend */
1104 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &ac->seq_num);
1105 if (ret != LDB_SUCCESS) {
1110 /* we have to copy the message as the caller might have it as a const */
1111 msg = ldb_msg_copy_shallow(ac, req->op.add.message);
1115 return LDB_ERR_OPERATIONS_ERROR;
1118 /* generated times */
1119 unix_to_nt_time(&now, t);
1120 time_str = ldb_timestring(msg, t);
1124 return LDB_ERR_OPERATIONS_ERROR;
1126 if (remove_current_guid) {
1127 ldb_msg_remove_attr(msg,"objectGUID");
1131 * remove autogenerated attributes
1133 ldb_msg_remove_attr(msg, "whenCreated");
1134 ldb_msg_remove_attr(msg, "whenChanged");
1135 ldb_msg_remove_attr(msg, "uSNCreated");
1136 ldb_msg_remove_attr(msg, "uSNChanged");
1137 ldb_msg_remove_attr(msg, "replPropertyMetaData");
1140 * readd replicated attributes
1142 ret = ldb_msg_add_string(msg, "whenCreated", time_str);
1143 if (ret != LDB_SUCCESS) {
1149 /* build the replication meta_data */
1152 nmd.ctr.ctr1.count = msg->num_elements;
1153 nmd.ctr.ctr1.array = talloc_array(msg,
1154 struct replPropertyMetaData1,
1155 nmd.ctr.ctr1.count);
1156 if (!nmd.ctr.ctr1.array) {
1159 return LDB_ERR_OPERATIONS_ERROR;
1162 is_schema_nc = ldb_dn_compare_base(replmd_private->schema_dn, msg->dn) == 0;
1164 for (i=0; i < msg->num_elements;) {
1165 struct ldb_message_element *e = &msg->elements[i];
1166 struct replPropertyMetaData1 *m = &nmd.ctr.ctr1.array[ni];
1167 const struct dsdb_attribute *sa;
1169 if (e->name[0] == '@') {
1174 sa = dsdb_attribute_by_lDAPDisplayName(ac->schema, e->name);
1176 ldb_debug_set(ldb, LDB_DEBUG_ERROR,
1177 "replmd_add: attribute '%s' not defined in schema\n",
1180 return LDB_ERR_NO_SUCH_ATTRIBUTE;
1183 if ((sa->systemFlags & DS_FLAG_ATTR_NOT_REPLICATED) || (sa->systemFlags & DS_FLAG_ATTR_IS_CONSTRUCTED)) {
1184 /* if the attribute is not replicated (0x00000001)
1185 * or constructed (0x00000004) it has no metadata
1191 if (sa->linkID != 0 && functional_level > DS_DOMAIN_FUNCTION_2000) {
1192 if (extended_dn == NULL) {
1193 ret = replmd_add_make_extended_dn(req,
1196 if (ret != LDB_SUCCESS) {
1203 * Prepare the context for the backlinks and
1204 * create metadata for the forward links. The
1205 * backlinks are created in
1206 * replmd_op_callback() after the successful
1207 * ADD of the object.
1209 ret = replmd_add_fix_la(module, msg->elements,
1214 if (ret != LDB_SUCCESS) {
1218 /* linked attributes are not stored in
1219 replPropertyMetaData in FL above w2k */
1224 m->attid = dsdb_attribute_get_attid(sa, is_schema_nc);
1226 if (m->attid == DRSUAPI_ATTID_isDeleted) {
1227 const struct ldb_val *rdn_val = ldb_dn_get_rdn_val(msg->dn);
1230 if (rdn_val == NULL) {
1233 return LDB_ERR_OPERATIONS_ERROR;
1236 rdn = (const char*)rdn_val->data;
1237 if (strcmp(rdn, "Deleted Objects") == 0) {
1239 * Set the originating_change_time to 29/12/9999 at 23:59:59
1240 * as specified in MS-ADTS 7.1.1.4.2 Deleted Objects Container
1242 m->originating_change_time = DELETED_OBJECT_CONTAINER_CHANGE_TIME;
1244 m->originating_change_time = now;
1247 m->originating_change_time = now;
1249 m->originating_invocation_id = ac->our_invocation_id;
1250 m->originating_usn = ac->seq_num;
1251 m->local_usn = ac->seq_num;
1254 if (!(e->flags & DSDB_FLAG_INTERNAL_FORCE_META_DATA)) {
1259 e->flags &= ~DSDB_FLAG_INTERNAL_FORCE_META_DATA;
1261 if (e->num_values != 0) {
1266 ldb_msg_remove_element(msg, e);
1269 /* fix meta data count */
1270 nmd.ctr.ctr1.count = ni;
1273 * sort meta data array
1275 ret = replmd_replPropertyMetaDataCtr1_sort_and_verify(ldb, &nmd.ctr.ctr1, msg->dn);
1276 if (ret != LDB_SUCCESS) {
1277 ldb_asprintf_errstring(ldb, "%s: error during direct ADD: %s", __func__, ldb_errstring(ldb));
1282 /* generated NDR encoded values */
1283 ndr_err = ndr_push_struct_blob(&nmd_value, msg,
1285 (ndr_push_flags_fn_t)ndr_push_replPropertyMetaDataBlob);
1286 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1289 return LDB_ERR_OPERATIONS_ERROR;
1293 * add the autogenerated values
1295 ret = dsdb_msg_add_guid(msg, &guid, "objectGUID");
1296 if (ret != LDB_SUCCESS) {
1301 ret = ldb_msg_add_string(msg, "whenChanged", time_str);
1302 if (ret != LDB_SUCCESS) {
1307 ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNCreated", ac->seq_num);
1308 if (ret != LDB_SUCCESS) {
1313 ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNChanged", ac->seq_num);
1314 if (ret != LDB_SUCCESS) {
1319 ret = ldb_msg_add_value(msg, "replPropertyMetaData", &nmd_value, NULL);
1320 if (ret != LDB_SUCCESS) {
1327 * sort the attributes by attid before storing the object
1329 replmd_ldb_message_sort(msg, ac->schema);
1332 * Assert that we do have an objectClass
1334 objectclass_el = ldb_msg_find_element(msg, "objectClass");
1335 if (objectclass_el == NULL) {
1336 ldb_asprintf_errstring(ldb, __location__
1337 ": objectClass missing on %s\n",
1338 ldb_dn_get_linearized(msg->dn));
1340 return LDB_ERR_OBJECT_CLASS_VIOLATION;
1342 is_urgent = replmd_check_urgent_objectclass(objectclass_el,
1343 REPL_URGENT_ON_CREATE);
1345 ac->is_urgent = is_urgent;
1346 ret = ldb_build_add_req(&down_req, ldb, ac,
1349 ac, replmd_op_callback,
1352 LDB_REQ_SET_LOCATION(down_req);
1353 if (ret != LDB_SUCCESS) {
1358 /* current partition control is needed by "replmd_op_callback" */
1359 if (ldb_request_get_control(req, DSDB_CONTROL_CURRENT_PARTITION_OID) == NULL) {
1360 ret = ldb_request_add_control(down_req,
1361 DSDB_CONTROL_CURRENT_PARTITION_OID,
1363 if (ret != LDB_SUCCESS) {
1369 if (functional_level == DS_DOMAIN_FUNCTION_2000) {
1370 ret = ldb_request_add_control(down_req, DSDB_CONTROL_APPLY_LINKS, false, NULL);
1371 if (ret != LDB_SUCCESS) {
1377 /* mark the control done */
1379 control->critical = 0;
1381 /* go on with the call chain */
1382 return ldb_next_request(module, down_req);
1387 * update the replPropertyMetaData for one element
1389 static int replmd_update_rpmd_element(struct ldb_context *ldb,
1390 struct ldb_message *msg,
1391 struct ldb_message_element *el,
1392 struct ldb_message_element *old_el,
1393 struct replPropertyMetaDataBlob *omd,
1394 const struct dsdb_schema *schema,
1396 const struct GUID *our_invocation_id,
1399 bool is_forced_rodc,
1400 struct ldb_request *req)
1403 const struct dsdb_attribute *a;
1404 struct replPropertyMetaData1 *md1;
1405 bool may_skip = false;
1408 a = dsdb_attribute_by_lDAPDisplayName(schema, el->name);
1410 if (ldb_request_get_control(req, LDB_CONTROL_RELAX_OID)) {
1411 /* allow this to make it possible for dbcheck
1412 to remove bad attributes */
1416 DEBUG(0,(__location__ ": Unable to find attribute %s in schema\n",
1418 return LDB_ERR_OPERATIONS_ERROR;
1421 attid = dsdb_attribute_get_attid(a, is_schema_nc);
1423 if ((a->systemFlags & DS_FLAG_ATTR_NOT_REPLICATED) || (a->systemFlags & DS_FLAG_ATTR_IS_CONSTRUCTED)) {
1428 * if the attribute's value haven't changed, and this isn't
1429 * just a delete of everything then return LDB_SUCCESS Unless
1430 * we have the provision control or if the attribute is
1431 * interSiteTopologyGenerator as this page explain:
1432 * http://support.microsoft.com/kb/224815 this attribute is
1433 * periodicaly written by the DC responsible for the intersite
1434 * generation in a given site
1436 * Unchanged could be deleting or replacing an already-gone
1437 * thing with an unconstrained delete/empty replace or a
1438 * replace with the same value, but not an add with the same
1439 * value because that could be about adding a duplicate (which
1440 * is for someone else to error out on).
1442 if (old_el != NULL && ldb_msg_element_equal_ordered(el, old_el)) {
1443 if (LDB_FLAG_MOD_TYPE(el->flags) == LDB_FLAG_MOD_REPLACE) {
1446 } else if (old_el == NULL && el->num_values == 0) {
1447 if (LDB_FLAG_MOD_TYPE(el->flags) == LDB_FLAG_MOD_REPLACE) {
1449 } else if (LDB_FLAG_MOD_TYPE(el->flags) == LDB_FLAG_MOD_DELETE) {
1452 } else if (a->linkID != 0 && LDB_FLAG_MOD_TYPE(el->flags) == LDB_FLAG_MOD_DELETE &&
1453 ldb_request_get_control(req, DSDB_CONTROL_REPLMD_VANISH_LINKS) != NULL) {
1455 * We intentionally skip the version bump when attempting to
1458 * The control is set by dbcheck and expunge-tombstones which
1459 * both attempt to be non-replicating. Otherwise, making an
1460 * alteration to the replication state would trigger a
1461 * broadcast of all expunged objects.
1466 if (el->flags & DSDB_FLAG_INTERNAL_FORCE_META_DATA) {
1468 el->flags &= ~DSDB_FLAG_INTERNAL_FORCE_META_DATA;
1472 if (strcmp(el->name, "interSiteTopologyGenerator") != 0 &&
1473 !ldb_request_get_control(req, LDB_CONTROL_PROVISION_OID)) {
1475 * allow this to make it possible for dbcheck
1476 * to rebuild broken metadata
1482 for (i=0; i<omd->ctr.ctr1.count; i++) {
1484 * First check if we find it under the msDS-IntID,
1485 * then check if we find it under the OID and
1488 * This allows the administrator to simply re-write
1489 * the attributes and so restore replication, which is
1490 * likely what they will try to do.
1492 if (attid == omd->ctr.ctr1.array[i].attid) {
1496 if (a->attributeID_id == omd->ctr.ctr1.array[i].attid) {
1501 if (a->linkID != 0 && dsdb_functional_level(ldb) > DS_DOMAIN_FUNCTION_2000) {
1502 /* linked attributes are not stored in
1503 replPropertyMetaData in FL above w2k, but we do
1504 raise the seqnum for the object */
1505 if (*seq_num == 0 &&
1506 ldb_sequence_number(ldb, LDB_SEQ_NEXT, seq_num) != LDB_SUCCESS) {
1507 return LDB_ERR_OPERATIONS_ERROR;
1512 if (i == omd->ctr.ctr1.count) {
1513 /* we need to add a new one */
1514 omd->ctr.ctr1.array = talloc_realloc(msg, omd->ctr.ctr1.array,
1515 struct replPropertyMetaData1, omd->ctr.ctr1.count+1);
1516 if (omd->ctr.ctr1.array == NULL) {
1518 return LDB_ERR_OPERATIONS_ERROR;
1520 omd->ctr.ctr1.count++;
1521 ZERO_STRUCT(omd->ctr.ctr1.array[i]);
1524 /* Get a new sequence number from the backend. We only do this
1525 * if we have a change that requires a new
1526 * replPropertyMetaData element
1528 if (*seq_num == 0) {
1529 int ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, seq_num);
1530 if (ret != LDB_SUCCESS) {
1531 return LDB_ERR_OPERATIONS_ERROR;
1535 md1 = &omd->ctr.ctr1.array[i];
1539 if (md1->attid == DRSUAPI_ATTID_isDeleted) {
1540 const struct ldb_val *rdn_val = ldb_dn_get_rdn_val(msg->dn);
1543 if (rdn_val == NULL) {
1545 return LDB_ERR_OPERATIONS_ERROR;
1548 rdn = (const char*)rdn_val->data;
1549 if (strcmp(rdn, "Deleted Objects") == 0) {
1551 * Set the originating_change_time to 29/12/9999 at 23:59:59
1552 * as specified in MS-ADTS 7.1.1.4.2 Deleted Objects Container
1554 md1->originating_change_time = DELETED_OBJECT_CONTAINER_CHANGE_TIME;
1556 md1->originating_change_time = now;
1559 md1->originating_change_time = now;
1561 md1->originating_invocation_id = *our_invocation_id;
1562 md1->originating_usn = *seq_num;
1563 md1->local_usn = *seq_num;
1565 if (is_forced_rodc) {
1566 /* Force version to 0 to be overriden later via replication */
1574 * Bump the replPropertyMetaData version on an attribute, and if it
1575 * has changed (or forced by leaving rdn_old NULL), update the value
1578 * This is important, as calling a modify operation may not change the
1579 * version number if the values appear unchanged, but a rename between
1580 * parents bumps this value.
1583 static int replmd_update_rpmd_rdn_attr(struct ldb_context *ldb,
1584 struct ldb_message *msg,
1585 const struct ldb_val *rdn_new,
1586 const struct ldb_val *rdn_old,
1587 struct replPropertyMetaDataBlob *omd,
1588 struct replmd_replicated_request *ar,
1591 bool is_forced_rodc)
1593 const char *rdn_name = ldb_dn_get_rdn_name(msg->dn);
1594 const struct dsdb_attribute *rdn_attr =
1595 dsdb_attribute_by_lDAPDisplayName(ar->schema, rdn_name);
1596 const char *attr_name = rdn_attr != NULL ?
1597 rdn_attr->lDAPDisplayName :
1599 struct ldb_message_element new_el = {
1600 .flags = LDB_FLAG_MOD_REPLACE,
1603 .values = discard_const_p(struct ldb_val, rdn_new)
1605 struct ldb_message_element old_el = {
1606 .flags = LDB_FLAG_MOD_REPLACE,
1608 .num_values = rdn_old ? 1 : 0,
1609 .values = discard_const_p(struct ldb_val, rdn_old)
1612 if (ldb_msg_element_equal_ordered(&new_el, &old_el) == false) {
1613 int ret = ldb_msg_add(msg, &new_el, LDB_FLAG_MOD_REPLACE);
1614 if (ret != LDB_SUCCESS) {
1615 return ldb_oom(ldb);
1619 return replmd_update_rpmd_element(ldb, msg, &new_el, NULL,
1620 omd, ar->schema, &ar->seq_num,
1621 &ar->our_invocation_id,
1622 now, is_schema_nc, is_forced_rodc,
1627 static uint64_t find_max_local_usn(struct replPropertyMetaDataBlob omd)
1629 uint32_t count = omd.ctr.ctr1.count;
1632 for (i=0; i < count; i++) {
1633 struct replPropertyMetaData1 m = omd.ctr.ctr1.array[i];
1634 if (max < m.local_usn) {
1642 * update the replPropertyMetaData object each time we modify an
1643 * object. This is needed for DRS replication, as the merge on the
1644 * client is based on this object
1646 static int replmd_update_rpmd(struct ldb_module *module,
1647 const struct dsdb_schema *schema,
1648 struct ldb_request *req,
1649 const char * const *rename_attrs,
1650 struct ldb_message *msg, uint64_t *seq_num,
1651 time_t t, bool is_schema_nc,
1652 bool *is_urgent, bool *rodc)
1654 const struct ldb_val *omd_value;
1655 enum ndr_err_code ndr_err;
1656 struct replPropertyMetaDataBlob omd;
1659 const struct GUID *our_invocation_id;
1661 const char * const *attrs = NULL;
1662 const char * const attrs2[] = { "uSNChanged", "objectClass", "instanceType", NULL };
1663 struct ldb_result *res;
1664 struct ldb_context *ldb;
1665 struct ldb_message_element *objectclass_el;
1666 enum urgent_situation situation;
1667 bool rmd_is_provided;
1668 bool rmd_is_just_resorted = false;
1669 const char *not_rename_attrs[4 + msg->num_elements];
1670 bool is_forced_rodc = false;
1673 attrs = rename_attrs;
1675 for (i = 0; i < msg->num_elements; i++) {
1676 not_rename_attrs[i] = msg->elements[i].name;
1678 not_rename_attrs[i] = "replPropertyMetaData";
1679 not_rename_attrs[i+1] = "objectClass";
1680 not_rename_attrs[i+2] = "instanceType";
1681 not_rename_attrs[i+3] = NULL;
1682 attrs = not_rename_attrs;
1685 ldb = ldb_module_get_ctx(module);
1687 ret = samdb_rodc(ldb, rodc);
1688 if (ret != LDB_SUCCESS) {
1689 DEBUG(4, (__location__ ": unable to tell if we are an RODC\n"));
1694 ldb_request_get_control(req, DSDB_CONTROL_FORCE_RODC_LOCAL_CHANGE)) {
1695 is_forced_rodc = true;
1698 our_invocation_id = samdb_ntds_invocation_id(ldb);
1699 if (!our_invocation_id) {
1700 /* this happens during an initial vampire while
1701 updating the schema */
1702 DEBUG(5,("No invocationID - skipping replPropertyMetaData update\n"));
1706 unix_to_nt_time(&now, t);
1708 if (ldb_request_get_control(req, DSDB_CONTROL_CHANGEREPLMETADATA_OID)) {
1709 rmd_is_provided = true;
1710 if (ldb_request_get_control(req, DSDB_CONTROL_CHANGEREPLMETADATA_RESORT_OID)) {
1711 rmd_is_just_resorted = true;
1714 rmd_is_provided = false;
1717 /* if isDeleted is present and is TRUE, then we consider we are deleting,
1718 * otherwise we consider we are updating */
1719 if (ldb_msg_check_string_attribute(msg, "isDeleted", "TRUE")) {
1720 situation = REPL_URGENT_ON_DELETE;
1721 } else if (rename_attrs) {
1722 situation = REPL_URGENT_ON_CREATE | REPL_URGENT_ON_DELETE;
1724 situation = REPL_URGENT_ON_UPDATE;
1727 if (rmd_is_provided) {
1728 /* In this case the change_replmetadata control was supplied */
1729 /* We check that it's the only attribute that is provided
1730 * (it's a rare case so it's better to keep the code simplier)
1731 * We also check that the highest local_usn is bigger or the same as
1734 if( msg->num_elements != 1 ||
1735 strncmp(msg->elements[0].name,
1736 "replPropertyMetaData", 20) ) {
1737 DEBUG(0,(__location__ ": changereplmetada control called without "\
1738 "a specified replPropertyMetaData attribute or with others\n"));
1739 return LDB_ERR_OPERATIONS_ERROR;
1741 if (situation != REPL_URGENT_ON_UPDATE) {
1742 DEBUG(0,(__location__ ": changereplmetada control can't be called when deleting an object\n"));
1743 return LDB_ERR_OPERATIONS_ERROR;
1745 omd_value = ldb_msg_find_ldb_val(msg, "replPropertyMetaData");
1747 DEBUG(0,(__location__ ": replPropertyMetaData was not specified for Object %s\n",
1748 ldb_dn_get_linearized(msg->dn)));
1749 return LDB_ERR_OPERATIONS_ERROR;
1751 ndr_err = ndr_pull_struct_blob(omd_value, msg, &omd,
1752 (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
1753 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1754 DEBUG(0,(__location__ ": Failed to parse replPropertyMetaData for %s\n",
1755 ldb_dn_get_linearized(msg->dn)));
1756 return LDB_ERR_OPERATIONS_ERROR;
1759 ret = dsdb_module_search_dn(module, msg, &res, msg->dn, attrs2,
1760 DSDB_FLAG_NEXT_MODULE |
1761 DSDB_SEARCH_SHOW_RECYCLED |
1762 DSDB_SEARCH_SHOW_EXTENDED_DN |
1763 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT |
1764 DSDB_SEARCH_REVEAL_INTERNALS, req);
1766 if (ret != LDB_SUCCESS) {
1770 if (rmd_is_just_resorted == false) {
1771 *seq_num = find_max_local_usn(omd);
1773 db_seq = ldb_msg_find_attr_as_uint64(res->msgs[0], "uSNChanged", 0);
1776 * The test here now allows for a new
1777 * replPropertyMetaData with no change, if was
1778 * just dbcheck re-sorting the values.
1780 if (*seq_num <= db_seq) {
1781 DEBUG(0,(__location__ ": changereplmetada control provided but max(local_usn)" \
1782 " is less than uSNChanged (max = %lld uSNChanged = %lld)\n",
1783 (long long)*seq_num, (long long)db_seq));
1784 return LDB_ERR_OPERATIONS_ERROR;
1789 /* search for the existing replPropertyMetaDataBlob. We need
1790 * to use REVEAL and ask for DNs in storage format to support
1791 * the check for values being the same in
1792 * replmd_update_rpmd_element()
1794 ret = dsdb_module_search_dn(module, msg, &res, msg->dn, attrs,
1795 DSDB_FLAG_NEXT_MODULE |
1796 DSDB_SEARCH_SHOW_RECYCLED |
1797 DSDB_SEARCH_SHOW_EXTENDED_DN |
1798 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT |
1799 DSDB_SEARCH_REVEAL_INTERNALS, req);
1800 if (ret != LDB_SUCCESS) {
1804 omd_value = ldb_msg_find_ldb_val(res->msgs[0], "replPropertyMetaData");
1806 DEBUG(0,(__location__ ": Object %s does not have a replPropertyMetaData attribute\n",
1807 ldb_dn_get_linearized(msg->dn)));
1808 return LDB_ERR_OPERATIONS_ERROR;
1811 ndr_err = ndr_pull_struct_blob(omd_value, msg, &omd,
1812 (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
1813 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1814 DEBUG(0,(__location__ ": Failed to parse replPropertyMetaData for %s\n",
1815 ldb_dn_get_linearized(msg->dn)));
1816 return LDB_ERR_OPERATIONS_ERROR;
1819 if (omd.version != 1) {
1820 DEBUG(0,(__location__ ": bad version %u in replPropertyMetaData for %s\n",
1821 omd.version, ldb_dn_get_linearized(msg->dn)));
1822 return LDB_ERR_OPERATIONS_ERROR;
1825 for (i=0; i<msg->num_elements;) {
1826 struct ldb_message_element *el = &msg->elements[i];
1827 struct ldb_message_element *old_el;
1829 old_el = ldb_msg_find_element(res->msgs[0], el->name);
1830 ret = replmd_update_rpmd_element(ldb, msg, el, old_el,
1831 &omd, schema, seq_num,
1836 if (ret != LDB_SUCCESS) {
1840 if (!*is_urgent && (situation == REPL_URGENT_ON_UPDATE)) {
1841 *is_urgent = replmd_check_urgent_attribute(el);
1844 if (!(el->flags & DSDB_FLAG_INTERNAL_FORCE_META_DATA)) {
1849 el->flags &= ~DSDB_FLAG_INTERNAL_FORCE_META_DATA;
1851 if (el->num_values != 0) {
1856 ldb_msg_remove_element(msg, el);
1861 * Assert that we have an objectClass attribute - this is major
1862 * corruption if we don't have this!
1864 objectclass_el = ldb_msg_find_element(res->msgs[0], "objectClass");
1865 if (objectclass_el != NULL) {
1867 * Now check if this objectClass means we need to do urgent replication
1869 if (!*is_urgent && replmd_check_urgent_objectclass(objectclass_el,
1873 } else if (!ldb_request_get_control(req, DSDB_CONTROL_DBCHECK)) {
1874 ldb_asprintf_errstring(ldb, __location__
1875 ": objectClass missing on %s\n",
1876 ldb_dn_get_linearized(msg->dn));
1877 return LDB_ERR_OBJECT_CLASS_VIOLATION;
1881 * replmd_update_rpmd_element has done an update if the
1884 if (*seq_num != 0 || rmd_is_just_resorted == true) {
1885 struct ldb_val *md_value;
1886 struct ldb_message_element *el;
1888 /*if we are RODC and this is a DRSR update then its ok*/
1889 if (!ldb_request_get_control(req, DSDB_CONTROL_REPLICATED_UPDATE_OID)
1890 && !ldb_request_get_control(req, DSDB_CONTROL_DBCHECK_MODIFY_RO_REPLICA)
1891 && !is_forced_rodc) {
1892 unsigned instanceType;
1895 ldb_set_errstring(ldb, "RODC modify is forbidden!");
1896 return LDB_ERR_REFERRAL;
1899 instanceType = ldb_msg_find_attr_as_uint(res->msgs[0], "instanceType", INSTANCE_TYPE_WRITE);
1900 if (!(instanceType & INSTANCE_TYPE_WRITE)) {
1901 return ldb_error(ldb, LDB_ERR_UNWILLING_TO_PERFORM,
1902 "cannot change replicated attribute on partial replica");
1906 md_value = talloc(msg, struct ldb_val);
1907 if (md_value == NULL) {
1909 return LDB_ERR_OPERATIONS_ERROR;
1912 ret = replmd_replPropertyMetaDataCtr1_sort_and_verify(ldb, &omd.ctr.ctr1, msg->dn);
1913 if (ret != LDB_SUCCESS) {
1914 ldb_asprintf_errstring(ldb, "%s: %s", __func__, ldb_errstring(ldb));
1918 ndr_err = ndr_push_struct_blob(md_value, msg, &omd,
1919 (ndr_push_flags_fn_t)ndr_push_replPropertyMetaDataBlob);
1920 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1921 DEBUG(0,(__location__ ": Failed to marshall replPropertyMetaData for %s\n",
1922 ldb_dn_get_linearized(msg->dn)));
1923 return LDB_ERR_OPERATIONS_ERROR;
1926 ret = ldb_msg_add_empty(msg, "replPropertyMetaData", LDB_FLAG_MOD_REPLACE, &el);
1927 if (ret != LDB_SUCCESS) {
1928 DEBUG(0,(__location__ ": Failed to add updated replPropertyMetaData %s\n",
1929 ldb_dn_get_linearized(msg->dn)));
1934 el->values = md_value;
1940 static int parsed_dn_compare(struct parsed_dn *pdn1, struct parsed_dn *pdn2)
1942 int ret = ndr_guid_compare(&pdn1->guid, &pdn2->guid);
1944 return data_blob_cmp(&pdn1->dsdb_dn->extra_part,
1945 &pdn2->dsdb_dn->extra_part);
1951 get a series of message element values as an array of DNs and GUIDs
1952 the result is sorted by GUID
1954 static int get_parsed_dns(struct ldb_module *module, TALLOC_CTX *mem_ctx,
1955 struct ldb_message_element *el, struct parsed_dn **pdn,
1956 const char *ldap_oid, struct ldb_request *parent)
1959 bool values_are_sorted = true;
1960 struct ldb_context *ldb = ldb_module_get_ctx(module);
1967 (*pdn) = talloc_array(mem_ctx, struct parsed_dn, el->num_values);
1969 ldb_module_oom(module);
1970 return LDB_ERR_OPERATIONS_ERROR;
1973 for (i=0; i<el->num_values; i++) {
1974 struct ldb_val *v = &el->values[i];
1977 struct parsed_dn *p;
1981 p->dsdb_dn = dsdb_dn_parse(*pdn, ldb, v, ldap_oid);
1982 if (p->dsdb_dn == NULL) {
1983 return LDB_ERR_INVALID_DN_SYNTAX;
1986 dn = p->dsdb_dn->dn;
1988 status = dsdb_get_extended_dn_guid(dn, &p->guid, "GUID");
1989 if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND) ||
1990 unlikely(GUID_all_zero(&p->guid))) {
1991 /* we got a DN without a GUID - go find the GUID */
1992 int ret = dsdb_module_guid_by_dn(module, dn, &p->guid, parent);
1993 if (ret != LDB_SUCCESS) {
1994 ldb_asprintf_errstring(ldb, "Unable to find GUID for DN %s\n",
1995 ldb_dn_get_linearized(dn));
1996 if (ret == LDB_ERR_NO_SUCH_OBJECT &&
1997 LDB_FLAG_MOD_TYPE(el->flags) == LDB_FLAG_MOD_DELETE &&
1998 ldb_attr_cmp(el->name, "member") == 0) {
1999 return LDB_ERR_UNWILLING_TO_PERFORM;
2003 ret = dsdb_set_extended_dn_guid(dn, &p->guid, "GUID");
2004 if (ret != LDB_SUCCESS) {
2007 } else if (!NT_STATUS_IS_OK(status)) {
2008 return LDB_ERR_OPERATIONS_ERROR;
2010 if (i > 0 && values_are_sorted) {
2011 int cmp = parsed_dn_compare(p, &(*pdn)[i - 1]);
2013 values_are_sorted = false;
2016 /* keep a pointer to the original ldb_val */
2019 if (! values_are_sorted) {
2020 TYPESAFE_QSORT(*pdn, el->num_values, parsed_dn_compare);
2026 * Get a series of trusted message element values. The result is sorted by
2027 * GUID, even though the GUIDs might not be known. That works because we trust
2028 * the database to give us the elements like that if the
2029 * replmd_private->sorted_links flag is set.
2031 * We also ensure that the links are in the Functional Level 2003
2032 * linked attributes format.
2034 static int get_parsed_dns_trusted(struct ldb_module *module,
2035 struct replmd_private *replmd_private,
2036 TALLOC_CTX *mem_ctx,
2037 struct ldb_message_element *el,
2038 struct parsed_dn **pdn,
2039 const char *ldap_oid,
2040 struct ldb_request *parent)
2049 if (!replmd_private->sorted_links) {
2050 /* We need to sort the list. This is the slow old path we want
2053 ret = get_parsed_dns(module, mem_ctx, el, pdn, ldap_oid,
2055 if (ret != LDB_SUCCESS) {
2059 /* Here we get a list of 'struct parsed_dns' without the parsing */
2060 *pdn = talloc_zero_array(mem_ctx, struct parsed_dn,
2063 ldb_module_oom(module);
2064 return LDB_ERR_OPERATIONS_ERROR;
2067 for (i = 0; i < el->num_values; i++) {
2068 (*pdn)[i].v = &el->values[i];
2073 * This upgrades links to FL2003 style, and sorts the result
2074 * if that was needed.
2076 * TODO: Add a database feature that asserts we have no FL2000
2077 * style links to avoid this check or add a feature that
2078 * uses a similar check to find sorted/unsorted links
2079 * for an on-the-fly upgrade.
2082 ret = replmd_check_upgrade_links(ldb_module_get_ctx(module),
2083 *pdn, el->num_values,
2086 if (ret != LDB_SUCCESS) {
2094 build a new extended DN, including all meta data fields
2096 RMD_FLAGS = DSDB_RMD_FLAG_* bits
2097 RMD_ADDTIME = originating_add_time
2098 RMD_INVOCID = originating_invocation_id
2099 RMD_CHANGETIME = originating_change_time
2100 RMD_ORIGINATING_USN = originating_usn
2101 RMD_LOCAL_USN = local_usn
2102 RMD_VERSION = version
2104 static int replmd_build_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct dsdb_dn *dsdb_dn,
2105 const struct GUID *invocation_id, uint64_t seq_num,
2106 uint64_t local_usn, NTTIME nttime, uint32_t version, bool deleted)
2108 struct ldb_dn *dn = dsdb_dn->dn;
2109 const char *tstring, *usn_string, *flags_string;
2110 struct ldb_val tval;
2112 struct ldb_val usnv, local_usnv;
2113 struct ldb_val vers, flagsv;
2116 const char *dnstring;
2118 uint32_t rmd_flags = deleted?DSDB_RMD_FLAG_DELETED:0;
2120 tstring = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)nttime);
2122 return LDB_ERR_OPERATIONS_ERROR;
2124 tval = data_blob_string_const(tstring);
2126 usn_string = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)seq_num);
2128 return LDB_ERR_OPERATIONS_ERROR;
2130 usnv = data_blob_string_const(usn_string);
2132 usn_string = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)local_usn);
2134 return LDB_ERR_OPERATIONS_ERROR;
2136 local_usnv = data_blob_string_const(usn_string);
2138 vstring = talloc_asprintf(mem_ctx, "%lu", (unsigned long)version);
2140 return LDB_ERR_OPERATIONS_ERROR;
2142 vers = data_blob_string_const(vstring);
2144 status = GUID_to_ndr_blob(invocation_id, dn, &iid);
2145 if (!NT_STATUS_IS_OK(status)) {
2146 return LDB_ERR_OPERATIONS_ERROR;
2149 flags_string = talloc_asprintf(mem_ctx, "%u", rmd_flags);
2150 if (!flags_string) {
2151 return LDB_ERR_OPERATIONS_ERROR;
2153 flagsv = data_blob_string_const(flags_string);
2155 ret = ldb_dn_set_extended_component(dn, "RMD_FLAGS", &flagsv);
2156 if (ret != LDB_SUCCESS) return ret;
2157 ret = ldb_dn_set_extended_component(dn, "RMD_ADDTIME", &tval);
2158 if (ret != LDB_SUCCESS) return ret;
2159 ret = ldb_dn_set_extended_component(dn, "RMD_INVOCID", &iid);
2160 if (ret != LDB_SUCCESS) return ret;
2161 ret = ldb_dn_set_extended_component(dn, "RMD_CHANGETIME", &tval);
2162 if (ret != LDB_SUCCESS) return ret;
2163 ret = ldb_dn_set_extended_component(dn, "RMD_LOCAL_USN", &local_usnv);
2164 if (ret != LDB_SUCCESS) return ret;
2165 ret = ldb_dn_set_extended_component(dn, "RMD_ORIGINATING_USN", &usnv);
2166 if (ret != LDB_SUCCESS) return ret;
2167 ret = ldb_dn_set_extended_component(dn, "RMD_VERSION", &vers);
2168 if (ret != LDB_SUCCESS) return ret;
2170 dnstring = dsdb_dn_get_extended_linearized(mem_ctx, dsdb_dn, 1);
2171 if (dnstring == NULL) {
2172 return LDB_ERR_OPERATIONS_ERROR;
2174 *v = data_blob_string_const(dnstring);
2179 static int replmd_update_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct dsdb_dn *dsdb_dn,
2180 struct dsdb_dn *old_dsdb_dn, const struct GUID *invocation_id,
2181 uint64_t seq_num, uint64_t local_usn, NTTIME nttime,
2182 uint32_t version, bool deleted);
2185 check if any links need upgrading from w2k format
2187 static int replmd_check_upgrade_links(struct ldb_context *ldb,
2188 struct parsed_dn *dns, uint32_t count,
2189 struct ldb_message_element *el,
2190 const char *ldap_oid)
2193 const struct GUID *invocation_id = NULL;
2194 for (i=0; i<count; i++) {
2198 if (dns[i].dsdb_dn == NULL) {
2199 ret = really_parse_trusted_dn(dns, ldb, &dns[i],
2201 if (ret != LDB_SUCCESS) {
2202 return LDB_ERR_INVALID_DN_SYNTAX;
2206 status = dsdb_get_extended_dn_uint32(dns[i].dsdb_dn->dn,
2207 &version, "RMD_VERSION");
2208 if (!NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
2210 * We optimistically assume they are all the same; if
2211 * the first one is fixed, they are all fixed.
2213 * If the first one was *not* fixed and we find a
2214 * later one that is, that is an occasion to shout
2220 DEBUG(0, ("Mixed w2k and fixed format "
2221 "linked attributes\n"));
2225 if (invocation_id == NULL) {
2226 invocation_id = samdb_ntds_invocation_id(ldb);
2227 if (invocation_id == NULL) {
2228 return LDB_ERR_OPERATIONS_ERROR;
2233 /* it's an old one that needs upgrading */
2234 ret = replmd_update_la_val(el->values, dns[i].v,
2235 dns[i].dsdb_dn, dns[i].dsdb_dn,
2236 invocation_id, 1, 1, 0, 0, false);
2237 if (ret != LDB_SUCCESS) {
2243 * This sort() is critical for the operation of
2244 * get_parsed_dns_trusted() because callers of this function
2245 * expect a sorted list, and FL2000 style links are not
2246 * sorted. In particular, as well as the upgrade case,
2247 * get_parsed_dns_trusted() is called from
2248 * replmd_delete_remove_link() even in FL2000 mode
2250 * We do not normally pay the cost of the qsort() due to the
2251 * early return in the RMD_VERSION found case.
2253 TYPESAFE_QSORT(dns, count, parsed_dn_compare);
2258 update an extended DN, including all meta data fields
2260 see replmd_build_la_val for value names
2262 static int replmd_update_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct dsdb_dn *dsdb_dn,
2263 struct dsdb_dn *old_dsdb_dn, const struct GUID *invocation_id,
2264 uint64_t usn, uint64_t local_usn, NTTIME nttime,
2265 uint32_t version, bool deleted)
2267 struct ldb_dn *dn = dsdb_dn->dn;
2268 const char *tstring, *usn_string, *flags_string;
2269 struct ldb_val tval;
2271 struct ldb_val usnv, local_usnv;
2272 struct ldb_val vers, flagsv;
2273 const struct ldb_val *old_addtime;
2274 uint32_t old_version;
2277 const char *dnstring;
2279 uint32_t rmd_flags = deleted?DSDB_RMD_FLAG_DELETED:0;
2281 tstring = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)nttime);
2283 return LDB_ERR_OPERATIONS_ERROR;
2285 tval = data_blob_string_const(tstring);
2287 usn_string = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)usn);
2289 return LDB_ERR_OPERATIONS_ERROR;
2291 usnv = data_blob_string_const(usn_string);
2293 usn_string = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)local_usn);
2295 return LDB_ERR_OPERATIONS_ERROR;
2297 local_usnv = data_blob_string_const(usn_string);
2299 status = GUID_to_ndr_blob(invocation_id, dn, &iid);
2300 if (!NT_STATUS_IS_OK(status)) {
2301 return LDB_ERR_OPERATIONS_ERROR;
2304 flags_string = talloc_asprintf(mem_ctx, "%u", rmd_flags);
2305 if (!flags_string) {
2306 return LDB_ERR_OPERATIONS_ERROR;
2308 flagsv = data_blob_string_const(flags_string);
2310 ret = ldb_dn_set_extended_component(dn, "RMD_FLAGS", &flagsv);
2311 if (ret != LDB_SUCCESS) return ret;
2313 /* get the ADDTIME from the original */
2314 old_addtime = ldb_dn_get_extended_component(old_dsdb_dn->dn, "RMD_ADDTIME");
2315 if (old_addtime == NULL) {
2316 old_addtime = &tval;
2318 if (dsdb_dn != old_dsdb_dn ||
2319 ldb_dn_get_extended_component(dn, "RMD_ADDTIME") == NULL) {
2320 ret = ldb_dn_set_extended_component(dn, "RMD_ADDTIME", old_addtime);
2321 if (ret != LDB_SUCCESS) return ret;
2324 /* use our invocation id */
2325 ret = ldb_dn_set_extended_component(dn, "RMD_INVOCID", &iid);
2326 if (ret != LDB_SUCCESS) return ret;
2328 /* changetime is the current time */
2329 ret = ldb_dn_set_extended_component(dn, "RMD_CHANGETIME", &tval);
2330 if (ret != LDB_SUCCESS) return ret;
2332 /* update the USN */
2333 ret = ldb_dn_set_extended_component(dn, "RMD_ORIGINATING_USN", &usnv);
2334 if (ret != LDB_SUCCESS) return ret;
2336 ret = ldb_dn_set_extended_component(dn, "RMD_LOCAL_USN", &local_usnv);
2337 if (ret != LDB_SUCCESS) return ret;
2339 /* increase the version by 1 */
2340 status = dsdb_get_extended_dn_uint32(old_dsdb_dn->dn, &old_version, "RMD_VERSION");
2341 if (NT_STATUS_IS_OK(status) && old_version >= version) {
2342 version = old_version+1;
2344 vstring = talloc_asprintf(dn, "%lu", (unsigned long)version);
2345 vers = data_blob_string_const(vstring);
2346 ret = ldb_dn_set_extended_component(dn, "RMD_VERSION", &vers);
2347 if (ret != LDB_SUCCESS) return ret;
2349 dnstring = dsdb_dn_get_extended_linearized(mem_ctx, dsdb_dn, 1);
2350 if (dnstring == NULL) {
2351 return LDB_ERR_OPERATIONS_ERROR;
2353 *v = data_blob_string_const(dnstring);
2359 handle adding a linked attribute
2361 static int replmd_modify_la_add(struct ldb_module *module,
2362 struct replmd_private *replmd_private,
2363 const struct dsdb_schema *schema,
2364 struct ldb_message *msg,
2365 struct ldb_message_element *el,
2366 struct ldb_message_element *old_el,
2367 const struct dsdb_attribute *schema_attr,
2370 struct ldb_dn *msg_dn,
2371 struct ldb_request *parent)
2374 struct parsed_dn *dns, *old_dns;
2375 TALLOC_CTX *tmp_ctx = talloc_new(msg);
2377 struct ldb_val *new_values = NULL;
2378 unsigned old_num_values = old_el ? old_el->num_values : 0;
2379 unsigned num_values = 0;
2380 unsigned max_num_values;
2381 const struct GUID *invocation_id;
2382 struct ldb_context *ldb = ldb_module_get_ctx(module);
2384 unix_to_nt_time(&now, t);
2386 invocation_id = samdb_ntds_invocation_id(ldb);
2387 if (!invocation_id) {
2388 talloc_free(tmp_ctx);
2389 return LDB_ERR_OPERATIONS_ERROR;
2392 /* get the DNs to be added, fully parsed.
2394 * We need full parsing because they came off the wire and we don't
2395 * trust them, besides which we need their details to know where to put
2398 ret = get_parsed_dns(module, tmp_ctx, el, &dns,
2399 schema_attr->syntax->ldap_oid, parent);
2400 if (ret != LDB_SUCCESS) {
2401 talloc_free(tmp_ctx);
2405 /* get the existing DNs, lazily parsed */
2406 ret = get_parsed_dns_trusted(module, replmd_private,
2407 tmp_ctx, old_el, &old_dns,
2408 schema_attr->syntax->ldap_oid, parent);
2410 if (ret != LDB_SUCCESS) {
2411 talloc_free(tmp_ctx);
2415 max_num_values = old_num_values + el->num_values;
2416 if (max_num_values < old_num_values) {
2417 DEBUG(0, ("we seem to have overflow in replmd_modify_la_add. "
2418 "old values: %u, new values: %u, sum: %u",
2419 old_num_values, el->num_values, max_num_values));
2420 talloc_free(tmp_ctx);
2421 return LDB_ERR_OPERATIONS_ERROR;
2424 new_values = talloc_zero_array(tmp_ctx, struct ldb_val, max_num_values);
2426 if (new_values == NULL) {
2427 ldb_module_oom(module);
2428 talloc_free(tmp_ctx);
2429 return LDB_ERR_OPERATIONS_ERROR;
2433 * For each new value, find where it would go in the list. If there is
2434 * a matching GUID there, we update the existing value; otherwise we
2438 for (i = 0; i < el->num_values; i++) {
2439 struct parsed_dn *exact;
2440 struct parsed_dn *next;
2442 int err = parsed_dn_find(ldb, old_dns, old_num_values,
2445 dns[i].dsdb_dn->extra_part, 0,
2447 schema_attr->syntax->ldap_oid,
2449 if (err != LDB_SUCCESS) {
2450 talloc_free(tmp_ctx);
2454 if (exact != NULL) {
2456 * We are trying to add one that exists, which is only
2457 * allowed if it was previously deleted.
2459 * When we do undelete a link we change it in place.
2460 * It will be copied across into the right spot in due
2464 rmd_flags = dsdb_dn_rmd_flags(exact->dsdb_dn->dn);
2466 if (!(rmd_flags & DSDB_RMD_FLAG_DELETED)) {
2467 struct GUID_txt_buf guid_str;
2468 ldb_asprintf_errstring(ldb,
2469 "Attribute %s already "
2470 "exists for target GUID %s",
2472 GUID_buf_string(&exact->guid,
2474 talloc_free(tmp_ctx);
2475 /* error codes for 'member' need to be
2477 if (ldb_attr_cmp(el->name, "member") == 0) {
2478 return LDB_ERR_ENTRY_ALREADY_EXISTS;
2480 return LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS;
2484 ret = replmd_update_la_val(new_values, exact->v,
2487 invocation_id, seq_num,
2488 seq_num, now, 0, false);
2489 if (ret != LDB_SUCCESS) {
2490 talloc_free(tmp_ctx);
2494 ret = replmd_add_backlink(module, replmd_private,
2501 if (ret != LDB_SUCCESS) {
2502 talloc_free(tmp_ctx);
2508 * Here we don't have an exact match.
2510 * If next is NULL, this one goes beyond the end of the
2511 * existing list, so we need to add all of those ones first.
2513 * If next is not NULL, we need to add all the ones before
2517 offset = old_num_values;
2519 /* next should have been parsed, but let's make sure */
2520 if (next->dsdb_dn == NULL) {
2521 ret = really_parse_trusted_dn(tmp_ctx, ldb, next,
2522 schema_attr->syntax->ldap_oid);
2523 if (ret != LDB_SUCCESS) {
2527 offset = MIN(next - old_dns, old_num_values);
2530 /* put all the old ones before next on the list */
2531 for (; j < offset; j++) {
2532 new_values[num_values] = *old_dns[j].v;
2536 ret = replmd_add_backlink(module, replmd_private,
2541 /* Make the new linked attribute ldb_val. */
2542 ret = replmd_build_la_val(new_values, &new_values[num_values],
2543 dns[i].dsdb_dn, invocation_id,
2546 if (ret != LDB_SUCCESS) {
2547 talloc_free(tmp_ctx);
2551 if (ret != LDB_SUCCESS) {
2552 talloc_free(tmp_ctx);
2556 /* copy the rest of the old ones (if any) */
2557 for (; j < old_num_values; j++) {
2558 new_values[num_values] = *old_dns[j].v;
2562 talloc_steal(msg->elements, new_values);
2563 if (old_el != NULL) {
2564 talloc_steal(msg->elements, old_el->values);
2566 el->values = new_values;
2567 el->num_values = num_values;
2569 talloc_free(tmp_ctx);
2571 /* we now tell the backend to replace all existing values
2572 with the one we have constructed */
2573 el->flags = LDB_FLAG_MOD_REPLACE;
2580 handle deleting all active linked attributes
2582 static int replmd_modify_la_delete(struct ldb_module *module,
2583 struct replmd_private *replmd_private,
2584 const struct dsdb_schema *schema,
2585 struct ldb_message *msg,
2586 struct ldb_message_element *el,
2587 struct ldb_message_element *old_el,
2588 const struct dsdb_attribute *schema_attr,
2591 struct ldb_dn *msg_dn,
2592 struct ldb_request *parent)
2595 struct parsed_dn *dns, *old_dns;
2596 TALLOC_CTX *tmp_ctx = NULL;
2598 struct ldb_context *ldb = ldb_module_get_ctx(module);
2599 struct ldb_control *vanish_links_ctrl = NULL;
2600 bool vanish_links = false;
2601 unsigned int num_to_delete = el->num_values;
2603 const struct GUID *invocation_id;
2606 unix_to_nt_time(&now, t);
2608 invocation_id = samdb_ntds_invocation_id(ldb);
2609 if (!invocation_id) {
2610 return LDB_ERR_OPERATIONS_ERROR;
2613 if (old_el == NULL || old_el->num_values == 0) {
2614 /* there is nothing to delete... */
2615 if (num_to_delete == 0) {
2616 /* and we're deleting nothing, so that's OK */
2619 return LDB_ERR_NO_SUCH_ATTRIBUTE;
2622 tmp_ctx = talloc_new(msg);
2623 if (tmp_ctx == NULL) {
2624 return LDB_ERR_OPERATIONS_ERROR;
2627 ret = get_parsed_dns(module, tmp_ctx, el, &dns,
2628 schema_attr->syntax->ldap_oid, parent);
2629 if (ret != LDB_SUCCESS) {
2630 talloc_free(tmp_ctx);
2634 ret = get_parsed_dns_trusted(module, replmd_private,
2635 tmp_ctx, old_el, &old_dns,
2636 schema_attr->syntax->ldap_oid, parent);
2638 if (ret != LDB_SUCCESS) {
2639 talloc_free(tmp_ctx);
2644 vanish_links_ctrl = ldb_request_get_control(parent, DSDB_CONTROL_REPLMD_VANISH_LINKS);
2645 if (vanish_links_ctrl) {
2646 vanish_links = true;
2647 vanish_links_ctrl->critical = false;
2651 /* we empty out el->values here to avoid damage if we return early. */
2656 * If vanish links is set, we are actually removing members of
2657 * old_el->values; otherwise we are just marking them deleted.
2659 * There is a special case when no values are given: we remove them
2660 * all. When we have the vanish_links control we just have to remove
2661 * the backlinks and change our element to replace the existing values
2662 * with the empty list.
2665 if (num_to_delete == 0) {
2666 for (i = 0; i < old_el->num_values; i++) {
2667 struct parsed_dn *p = &old_dns[i];
2668 if (p->dsdb_dn == NULL) {
2669 ret = really_parse_trusted_dn(tmp_ctx, ldb, p,
2670 schema_attr->syntax->ldap_oid);
2671 if (ret != LDB_SUCCESS) {
2675 ret = replmd_add_backlink(module, replmd_private,
2676 schema, msg_dn, &p->guid,
2679 if (ret != LDB_SUCCESS) {
2680 talloc_free(tmp_ctx);
2687 rmd_flags = dsdb_dn_rmd_flags(p->dsdb_dn->dn);
2688 if (rmd_flags & DSDB_RMD_FLAG_DELETED) {
2692 ret = replmd_update_la_val(old_el->values, p->v,
2693 p->dsdb_dn, p->dsdb_dn,
2694 invocation_id, seq_num,
2695 seq_num, now, 0, true);
2696 if (ret != LDB_SUCCESS) {
2697 talloc_free(tmp_ctx);
2703 el->flags = LDB_FLAG_MOD_REPLACE;
2704 talloc_free(tmp_ctx);
2710 for (i = 0; i < num_to_delete; i++) {
2711 struct parsed_dn *p = &dns[i];
2712 struct parsed_dn *exact = NULL;
2713 struct parsed_dn *next = NULL;
2714 ret = parsed_dn_find(ldb, old_dns, old_el->num_values,
2717 p->dsdb_dn->extra_part, 0,
2719 schema_attr->syntax->ldap_oid,
2721 if (ret != LDB_SUCCESS) {
2722 talloc_free(tmp_ctx);
2725 if (exact == NULL) {
2726 struct GUID_txt_buf buf;
2727 ldb_asprintf_errstring(ldb, "Attribute %s doesn't "
2728 "exist for target GUID %s",
2730 GUID_buf_string(&p->guid, &buf));
2731 if (ldb_attr_cmp(el->name, "member") == 0) {
2732 talloc_free(tmp_ctx);
2733 return LDB_ERR_UNWILLING_TO_PERFORM;
2735 talloc_free(tmp_ctx);
2736 return LDB_ERR_NO_SUCH_ATTRIBUTE;
2741 if (CHECK_DEBUGLVL(5)) {
2742 rmd_flags = dsdb_dn_rmd_flags(exact->dsdb_dn->dn);
2743 if ((rmd_flags & DSDB_RMD_FLAG_DELETED)) {
2744 struct GUID_txt_buf buf;
2745 const char *guid_str = \
2746 GUID_buf_string(&p->guid, &buf);
2747 DEBUG(5, ("Deleting deleted linked "
2748 "attribute %s to %s, because "
2749 "vanish_links control is set\n",
2750 el->name, guid_str));
2754 /* remove the backlink */
2755 ret = replmd_add_backlink(module,
2762 if (ret != LDB_SUCCESS) {
2763 talloc_free(tmp_ctx);
2767 /* We flag the deletion and tidy it up later. */
2772 rmd_flags = dsdb_dn_rmd_flags(exact->dsdb_dn->dn);
2774 if (rmd_flags & DSDB_RMD_FLAG_DELETED) {
2775 struct GUID_txt_buf buf;
2776 const char *guid_str = GUID_buf_string(&p->guid, &buf);
2777 ldb_asprintf_errstring(ldb, "Attribute %s already "
2778 "deleted for target GUID %s",
2779 el->name, guid_str);
2780 if (ldb_attr_cmp(el->name, "member") == 0) {
2781 talloc_free(tmp_ctx);
2782 return LDB_ERR_UNWILLING_TO_PERFORM;
2784 talloc_free(tmp_ctx);
2785 return LDB_ERR_NO_SUCH_ATTRIBUTE;
2789 ret = replmd_update_la_val(old_el->values, exact->v,
2790 exact->dsdb_dn, exact->dsdb_dn,
2791 invocation_id, seq_num, seq_num,
2793 if (ret != LDB_SUCCESS) {
2794 talloc_free(tmp_ctx);
2797 ret = replmd_add_backlink(module, replmd_private,
2802 if (ret != LDB_SUCCESS) {
2803 talloc_free(tmp_ctx);
2810 for (i = 0; i < old_el->num_values; i++) {
2811 if (old_dns[i].v != NULL) {
2812 old_el->values[j] = *old_dns[i].v;
2816 old_el->num_values = j;
2819 el->values = talloc_steal(msg->elements, old_el->values);
2820 el->num_values = old_el->num_values;
2822 talloc_free(tmp_ctx);
2824 /* we now tell the backend to replace all existing values
2825 with the one we have constructed */
2826 el->flags = LDB_FLAG_MOD_REPLACE;
2832 handle replacing a linked attribute
2834 static int replmd_modify_la_replace(struct ldb_module *module,
2835 struct replmd_private *replmd_private,
2836 const struct dsdb_schema *schema,
2837 struct ldb_message *msg,
2838 struct ldb_message_element *el,
2839 struct ldb_message_element *old_el,
2840 const struct dsdb_attribute *schema_attr,
2843 struct ldb_dn *msg_dn,
2844 struct ldb_request *parent)
2846 unsigned int i, old_i, new_i;
2847 struct parsed_dn *dns, *old_dns;
2848 TALLOC_CTX *tmp_ctx = talloc_new(msg);
2850 const struct GUID *invocation_id;
2851 struct ldb_context *ldb = ldb_module_get_ctx(module);
2852 struct ldb_val *new_values = NULL;
2853 const char *ldap_oid = schema_attr->syntax->ldap_oid;
2854 unsigned int old_num_values;
2855 unsigned int repl_num_values;
2856 unsigned int max_num_values;
2859 unix_to_nt_time(&now, t);
2861 invocation_id = samdb_ntds_invocation_id(ldb);
2862 if (!invocation_id) {
2863 return LDB_ERR_OPERATIONS_ERROR;
2867 * The replace operation is unlike the replace and delete cases in that
2868 * we need to look at every existing link to see whether it is being
2869 * retained or deleted. In other words, we can't avoid parsing the GUIDs.
2871 * As we are trying to combine two sorted lists, the algorithm we use
2872 * is akin to the merge phase of a merge sort. We interleave the two
2873 * lists, doing different things depending on which side the current
2876 * There are three main cases, with some sub-cases.
2878 * - a DN is in the old list but not the new one. It needs to be
2879 * marked as deleted (but left in the list).
2880 * - maybe it is already deleted, and we have less to do.
2882 * - a DN is in both lists. The old data gets replaced by the new,
2883 * and the list doesn't grow. The old link may have been marked as
2884 * deleted, in which case we undelete it.
2886 * - a DN is in the new list only. We add it in the right place.
2889 old_num_values = old_el ? old_el->num_values : 0;
2890 repl_num_values = el->num_values;
2891 max_num_values = old_num_values + repl_num_values;
2893 if (max_num_values == 0) {
2894 /* There is nothing to do! */
2898 ret = get_parsed_dns(module, tmp_ctx, el, &dns, ldap_oid, parent);
2899 if (ret != LDB_SUCCESS) {
2900 talloc_free(tmp_ctx);
2904 ret = get_parsed_dns(module, tmp_ctx, old_el, &old_dns,
2906 if (ret != LDB_SUCCESS) {
2907 talloc_free(tmp_ctx);
2911 ret = replmd_check_upgrade_links(ldb, old_dns, old_num_values,
2913 if (ret != LDB_SUCCESS) {
2914 talloc_free(tmp_ctx);
2918 new_values = talloc_array(tmp_ctx, struct ldb_val, max_num_values);
2919 if (new_values == NULL) {
2920 ldb_module_oom(module);
2921 talloc_free(tmp_ctx);
2922 return LDB_ERR_OPERATIONS_ERROR;
2927 for (i = 0; i < max_num_values; i++) {
2929 struct parsed_dn *old_p, *new_p;
2930 if (old_i < old_num_values && new_i < repl_num_values) {
2931 old_p = &old_dns[old_i];
2932 new_p = &dns[new_i];
2933 cmp = parsed_dn_compare(old_p, new_p);
2934 } else if (old_i < old_num_values) {
2935 /* the new list is empty, read the old list */
2936 old_p = &old_dns[old_i];
2939 } else if (new_i < repl_num_values) {
2940 /* the old list is empty, read new list */
2942 new_p = &dns[new_i];
2950 * An old ones that come before the next replacement
2951 * (if any). We mark it as deleted and add it to the
2954 uint32_t rmd_flags = dsdb_dn_rmd_flags(old_p->dsdb_dn->dn);
2955 if ((rmd_flags & DSDB_RMD_FLAG_DELETED) == 0) {
2956 ret = replmd_update_la_val(new_values, old_p->v,
2962 if (ret != LDB_SUCCESS) {
2963 talloc_free(tmp_ctx);
2967 ret = replmd_add_backlink(module, replmd_private,
2970 &old_p->guid, false,
2973 if (ret != LDB_SUCCESS) {
2974 talloc_free(tmp_ctx);
2978 new_values[i] = *old_p->v;
2980 } else if (cmp == 0) {
2982 * We are overwriting one. If it was previously
2983 * deleted, we need to add a backlink.
2985 * Note that if any RMD_FLAGs in an extended new DN
2990 ret = replmd_update_la_val(new_values, old_p->v,
2996 if (ret != LDB_SUCCESS) {
2997 talloc_free(tmp_ctx);
3001 rmd_flags = dsdb_dn_rmd_flags(old_p->dsdb_dn->dn);
3002 if ((rmd_flags & DSDB_RMD_FLAG_DELETED) != 0) {
3003 ret = replmd_add_backlink(module, replmd_private,
3009 if (ret != LDB_SUCCESS) {
3010 talloc_free(tmp_ctx);
3015 new_values[i] = *old_p->v;
3020 * Replacements that don't match an existing one. We
3021 * just add them to the final list.
3023 ret = replmd_build_la_val(new_values,
3029 if (ret != LDB_SUCCESS) {
3030 talloc_free(tmp_ctx);
3033 ret = replmd_add_backlink(module, replmd_private,
3039 if (ret != LDB_SUCCESS) {
3040 talloc_free(tmp_ctx);
3043 new_values[i] = *new_p->v;
3047 if (old_el != NULL) {
3048 talloc_steal(msg->elements, old_el->values);
3050 el->values = talloc_steal(msg->elements, new_values);
3052 talloc_free(tmp_ctx);
3054 el->flags = LDB_FLAG_MOD_REPLACE;
3061 handle linked attributes in modify requests
3063 static int replmd_modify_handle_linked_attribs(struct ldb_module *module,
3064 struct replmd_private *replmd_private,
3065 struct ldb_message *msg,
3066 uint64_t seq_num, time_t t,
3067 struct ldb_request *parent)
3069 struct ldb_result *res;
3072 struct ldb_context *ldb = ldb_module_get_ctx(module);
3073 struct ldb_message *old_msg;
3075 const struct dsdb_schema *schema;
3077 if (dsdb_functional_level(ldb) == DS_DOMAIN_FUNCTION_2000) {
3079 * Nothing special is required for modifying or vanishing links
3080 * in fl2000 since they are just strings in a multi-valued
3083 struct ldb_control *ctrl = ldb_request_get_control(parent,
3084 DSDB_CONTROL_REPLMD_VANISH_LINKS);
3086 ctrl->critical = false;
3094 * We should restrict this to the intersection of the list of
3095 * linked attributes in the schema and the list of attributes
3098 * This will help performance a little, as otherwise we have
3099 * to allocate the entire object value-by-value.
3101 ret = dsdb_module_search_dn(module, msg, &res, msg->dn, NULL,
3102 DSDB_FLAG_NEXT_MODULE |
3103 DSDB_SEARCH_SHOW_RECYCLED |
3104 DSDB_SEARCH_REVEAL_INTERNALS |
3105 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT,
3107 if (ret != LDB_SUCCESS) {
3110 schema = dsdb_get_schema(ldb, res);
3112 return LDB_ERR_OPERATIONS_ERROR;
3115 old_msg = res->msgs[0];
3117 for (i=0; i<msg->num_elements; i++) {
3118 struct ldb_message_element *el = &msg->elements[i];
3119 struct ldb_message_element *old_el, *new_el;
3120 unsigned int mod_type = LDB_FLAG_MOD_TYPE(el->flags);
3121 const struct dsdb_attribute *schema_attr
3122 = dsdb_attribute_by_lDAPDisplayName(schema, el->name);
3124 ldb_asprintf_errstring(ldb,
3125 "%s: attribute %s is not a valid attribute in schema",
3126 __FUNCTION__, el->name);
3127 return LDB_ERR_OBJECT_CLASS_VIOLATION;
3129 if (schema_attr->linkID == 0) {
3132 if ((schema_attr->linkID & 1) == 1) {
3133 if (parent && ldb_request_get_control(parent, DSDB_CONTROL_DBCHECK)) {
3136 /* Odd is for the target. Illegal to modify */
3137 ldb_asprintf_errstring(ldb,
3138 "attribute %s must not be modified directly, it is a linked attribute", el->name);
3139 return LDB_ERR_UNWILLING_TO_PERFORM;
3141 old_el = ldb_msg_find_element(old_msg, el->name);
3143 case LDB_FLAG_MOD_REPLACE:
3144 ret = replmd_modify_la_replace(module, replmd_private,
3145 schema, msg, el, old_el,
3146 schema_attr, seq_num, t,
3150 case LDB_FLAG_MOD_DELETE:
3151 ret = replmd_modify_la_delete(module, replmd_private,
3152 schema, msg, el, old_el,
3153 schema_attr, seq_num, t,
3157 case LDB_FLAG_MOD_ADD:
3158 ret = replmd_modify_la_add(module, replmd_private,
3159 schema, msg, el, old_el,
3160 schema_attr, seq_num, t,
3165 ldb_asprintf_errstring(ldb,
3166 "invalid flags 0x%x for %s linked attribute",
3167 el->flags, el->name);
3168 return LDB_ERR_UNWILLING_TO_PERFORM;
3170 if (dsdb_check_single_valued_link(schema_attr, el) != LDB_SUCCESS) {
3171 ldb_asprintf_errstring(ldb,
3172 "Attribute %s is single valued but more than one value has been supplied",
3174 /* Return codes as found on Windows 2012r2 */
3175 if (mod_type == LDB_FLAG_MOD_REPLACE) {
3176 return LDB_ERR_CONSTRAINT_VIOLATION;
3178 return LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS;
3181 el->flags |= LDB_FLAG_INTERNAL_DISABLE_SINGLE_VALUE_CHECK;
3184 if (ret != LDB_SUCCESS) {
3188 ldb_msg_remove_attr(old_msg, el->name);
3190 ldb_msg_add_empty(old_msg, el->name, 0, &new_el);
3191 new_el->num_values = el->num_values;
3192 new_el->values = talloc_steal(msg->elements, el->values);
3194 /* TODO: this relises a bit too heavily on the exact
3195 behaviour of ldb_msg_find_element and
3196 ldb_msg_remove_element */
3197 old_el = ldb_msg_find_element(msg, el->name);
3199 ldb_msg_remove_element(msg, old_el);
3209 static int send_rodc_referral(struct ldb_request *req,
3210 struct ldb_context *ldb,
3213 char *referral = NULL;
3214 struct loadparm_context *lp_ctx = NULL;
3215 struct ldb_dn *fsmo_role_dn = NULL;
3216 struct ldb_dn *role_owner_dn = NULL;
3217 const char *domain = NULL;
3220 lp_ctx = talloc_get_type(ldb_get_opaque(ldb, "loadparm"),
3221 struct loadparm_context);
3223 werr = dsdb_get_fsmo_role_info(req, ldb, DREPL_PDC_MASTER,
3224 &fsmo_role_dn, &role_owner_dn);
3226 if (W_ERROR_IS_OK(werr)) {
3227 struct ldb_dn *server_dn = ldb_dn_copy(req, role_owner_dn);
3228 if (server_dn != NULL) {
3229 ldb_dn_remove_child_components(server_dn, 1);
3230 domain = samdb_dn_to_dnshostname(ldb, req,
3235 if (domain == NULL) {
3236 domain = lpcfg_dnsdomain(lp_ctx);
3239 referral = talloc_asprintf(req, "ldap://%s/%s",
3241 ldb_dn_get_linearized(dn));
3242 if (referral == NULL) {
3244 return LDB_ERR_OPERATIONS_ERROR;
3247 return ldb_module_send_referral(req, referral);
3251 static int replmd_modify(struct ldb_module *module, struct ldb_request *req)
3253 struct ldb_context *ldb;
3254 struct replmd_replicated_request *ac;
3255 struct ldb_request *down_req;
3256 struct ldb_message *msg;
3257 time_t t = time(NULL);
3259 bool is_urgent = false, rodc = false;
3260 bool is_schema_nc = false;
3261 unsigned int functional_level;
3262 const struct ldb_message_element *guid_el = NULL;
3263 struct ldb_control *sd_propagation_control;
3264 struct replmd_private *replmd_private =
3265 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
3267 /* do not manipulate our control entries */
3268 if (ldb_dn_is_special(req->op.mod.message->dn)) {
3269 return ldb_next_request(module, req);
3272 sd_propagation_control = ldb_request_get_control(req,
3273 DSDB_CONTROL_SEC_DESC_PROPAGATION_OID);
3274 if (sd_propagation_control != NULL) {
3275 if (req->op.mod.message->num_elements != 1) {
3276 return ldb_module_operr(module);
3278 ret = strcmp(req->op.mod.message->elements[0].name,
3279 "nTSecurityDescriptor");
3281 return ldb_module_operr(module);
3284 return ldb_next_request(module, req);
3287 ldb = ldb_module_get_ctx(module);
3289 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_modify\n");
3291 guid_el = ldb_msg_find_element(req->op.mod.message, "objectGUID");
3292 if (guid_el != NULL) {
3293 ldb_set_errstring(ldb,
3294 "replmd_modify: it's not allowed to change the objectGUID!");
3295 return LDB_ERR_CONSTRAINT_VIOLATION;
3298 ac = replmd_ctx_init(module, req);
3300 return ldb_module_oom(module);
3303 functional_level = dsdb_functional_level(ldb);
3305 /* we have to copy the message as the caller might have it as a const */
3306 msg = ldb_msg_copy_shallow(ac, req->op.mod.message);
3310 return LDB_ERR_OPERATIONS_ERROR;
3313 ldb_msg_remove_attr(msg, "whenChanged");
3314 ldb_msg_remove_attr(msg, "uSNChanged");
3316 is_schema_nc = ldb_dn_compare_base(replmd_private->schema_dn, msg->dn) == 0;
3318 ret = replmd_update_rpmd(module, ac->schema, req, NULL,
3319 msg, &ac->seq_num, t, is_schema_nc,
3321 if (rodc && (ret == LDB_ERR_REFERRAL)) {
3322 ret = send_rodc_referral(req, ldb, msg->dn);
3328 if (ret != LDB_SUCCESS) {
3333 ret = replmd_modify_handle_linked_attribs(module, replmd_private,
3334 msg, ac->seq_num, t, req);
3335 if (ret != LDB_SUCCESS) {
3341 * - replace the old object with the newly constructed one
3344 ac->is_urgent = is_urgent;
3346 ret = ldb_build_mod_req(&down_req, ldb, ac,
3349 ac, replmd_op_callback,
3351 LDB_REQ_SET_LOCATION(down_req);
3352 if (ret != LDB_SUCCESS) {
3357 /* current partition control is needed by "replmd_op_callback" */
3358 if (ldb_request_get_control(req, DSDB_CONTROL_CURRENT_PARTITION_OID) == NULL) {
3359 ret = ldb_request_add_control(down_req,
3360 DSDB_CONTROL_CURRENT_PARTITION_OID,
3362 if (ret != LDB_SUCCESS) {
3368 /* If we are in functional level 2000, then
3369 * replmd_modify_handle_linked_attribs will have done
3371 if (functional_level == DS_DOMAIN_FUNCTION_2000) {
3372 ret = ldb_request_add_control(down_req, DSDB_CONTROL_APPLY_LINKS, false, NULL);
3373 if (ret != LDB_SUCCESS) {
3379 talloc_steal(down_req, msg);
3381 /* we only change whenChanged and uSNChanged if the seq_num
3383 if (ac->seq_num != 0) {
3384 ret = add_time_element(msg, "whenChanged", t);
3385 if (ret != LDB_SUCCESS) {
3391 ret = add_uint64_element(ldb, msg, "uSNChanged", ac->seq_num);
3392 if (ret != LDB_SUCCESS) {
3399 /* go on with the call chain */
3400 return ldb_next_request(module, down_req);
3403 static int replmd_rename_callback(struct ldb_request *req, struct ldb_reply *ares);
3406 handle a rename request
3408 On a rename we need to do an extra ldb_modify which sets the
3409 whenChanged and uSNChanged attributes. We do this in a callback after the success.
3411 static int replmd_rename(struct ldb_module *module, struct ldb_request *req)
3413 struct ldb_context *ldb;
3414 struct replmd_replicated_request *ac;
3416 struct ldb_request *down_req;
3418 /* do not manipulate our control entries */
3419 if (ldb_dn_is_special(req->op.mod.message->dn)) {
3420 return ldb_next_request(module, req);
3423 ldb = ldb_module_get_ctx(module);
3425 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_rename\n");
3427 ac = replmd_ctx_init(module, req);
3429 return ldb_module_oom(module);
3432 ret = ldb_build_rename_req(&down_req, ldb, ac,
3433 ac->req->op.rename.olddn,
3434 ac->req->op.rename.newdn,
3436 ac, replmd_rename_callback,
3438 LDB_REQ_SET_LOCATION(down_req);
3439 if (ret != LDB_SUCCESS) {
3444 /* go on with the call chain */
3445 return ldb_next_request(module, down_req);
3448 /* After the rename is compleated, update the whenchanged etc */
3449 static int replmd_rename_callback(struct ldb_request *req, struct ldb_reply *ares)
3451 struct ldb_context *ldb;
3452 struct ldb_request *down_req;
3453 struct ldb_message *msg;
3454 const struct dsdb_attribute *rdn_attr;
3455 const char *rdn_name;
3456 const struct ldb_val *rdn_val;
3457 const char *attrs[5] = { NULL, };
3458 time_t t = time(NULL);
3460 bool is_urgent = false, rodc = false;
3462 struct replmd_replicated_request *ac =
3463 talloc_get_type(req->context, struct replmd_replicated_request);
3464 struct replmd_private *replmd_private =
3465 talloc_get_type(ldb_module_get_private(ac->module),
3466 struct replmd_private);
3468 ldb = ldb_module_get_ctx(ac->module);
3470 if (ares->error != LDB_SUCCESS) {
3471 return ldb_module_done(ac->req, ares->controls,
3472 ares->response, ares->error);
3475 if (ares->type != LDB_REPLY_DONE) {
3476 ldb_set_errstring(ldb,
3477 "invalid ldb_reply_type in callback");
3479 return ldb_module_done(ac->req, NULL, NULL,
3480 LDB_ERR_OPERATIONS_ERROR);
3484 * - replace the old object with the newly constructed one
3487 msg = ldb_msg_new(ac);
3490 return LDB_ERR_OPERATIONS_ERROR;
3493 msg->dn = ac->req->op.rename.newdn;
3495 is_schema_nc = ldb_dn_compare_base(replmd_private->schema_dn, msg->dn) == 0;
3497 rdn_name = ldb_dn_get_rdn_name(msg->dn);
3498 if (rdn_name == NULL) {
3500 return ldb_module_done(ac->req, NULL, NULL,
3504 /* normalize the rdn attribute name */
3505 rdn_attr = dsdb_attribute_by_lDAPDisplayName(ac->schema, rdn_name);
3506 if (rdn_attr == NULL) {
3508 return ldb_module_done(ac->req, NULL, NULL,
3511 rdn_name = rdn_attr->lDAPDisplayName;
3513 rdn_val = ldb_dn_get_rdn_val(msg->dn);
3514 if (rdn_val == NULL) {
3516 return ldb_module_done(ac->req, NULL, NULL,
3520 if (ldb_msg_add_empty(msg, rdn_name, LDB_FLAG_MOD_REPLACE, NULL) != 0) {
3522 return ldb_module_done(ac->req, NULL, NULL,
3525 if (ldb_msg_add_value(msg, rdn_name, rdn_val, NULL) != 0) {
3527 return ldb_module_done(ac->req, NULL, NULL,
3530 if (ldb_msg_add_empty(msg, "name", LDB_FLAG_MOD_REPLACE, NULL) != 0) {
3532 return ldb_module_done(ac->req, NULL, NULL,
3535 if (ldb_msg_add_value(msg, "name", rdn_val, NULL) != 0) {
3537 return ldb_module_done(ac->req, NULL, NULL,
3542 * here we let replmd_update_rpmd() only search for
3543 * the existing "replPropertyMetaData" and rdn_name attributes.
3545 * We do not want the existing "name" attribute as
3546 * the "name" attribute needs to get the version
3547 * updated on rename even if the rdn value hasn't changed.
3549 * This is the diff of the meta data, for a moved user
3550 * on a w2k8r2 server:
3553 * -dn: CN=sdf df,CN=Users,DC=bla,DC=base
3554 * +dn: CN=sdf df,OU=TestOU,DC=bla,DC=base
3555 * replPropertyMetaData: NDR: struct replPropertyMetaDataBlob
3556 * version : 0x00000001 (1)
3557 * reserved : 0x00000000 (0)
3558 * @@ -66,11 +66,11 @@ replPropertyMetaData: NDR: struct re
3559 * local_usn : 0x00000000000037a5 (14245)
3560 * array: struct replPropertyMetaData1
3561 * attid : DRSUAPI_ATTID_name (0x90001)
3562 * - version : 0x00000001 (1)
3563 * - originating_change_time : Wed Feb 9 17:20:49 2011 CET
3564 * + version : 0x00000002 (2)
3565 * + originating_change_time : Wed Apr 6 15:21:01 2011 CEST
3566 * originating_invocation_id: 0d36ca05-5507-4e62-aca3-354bab0d39e1
3567 * - originating_usn : 0x00000000000037a5 (14245)
3568 * - local_usn : 0x00000000000037a5 (14245)
3569 * + originating_usn : 0x0000000000003834 (14388)
3570 * + local_usn : 0x0000000000003834 (14388)
3571 * array: struct replPropertyMetaData1
3572 * attid : DRSUAPI_ATTID_userAccountControl (0x90008)
3573 * version : 0x00000004 (4)
3575 attrs[0] = "replPropertyMetaData";
3576 attrs[1] = "objectClass";
3577 attrs[2] = "instanceType";
3578 attrs[3] = rdn_name;
3581 ret = replmd_update_rpmd(ac->module, ac->schema, req, attrs,
3582 msg, &ac->seq_num, t,
3583 is_schema_nc, &is_urgent, &rodc);
3584 if (rodc && (ret == LDB_ERR_REFERRAL)) {
3585 ret = send_rodc_referral(req, ldb, ac->req->op.rename.olddn);
3587 return ldb_module_done(req, NULL, NULL, ret);
3590 if (ret != LDB_SUCCESS) {
3592 return ldb_module_done(ac->req, NULL, NULL, ret);
3595 if (ac->seq_num == 0) {
3597 return ldb_module_done(ac->req, NULL, NULL,
3599 "internal error seq_num == 0"));
3601 ac->is_urgent = is_urgent;
3603 ret = ldb_build_mod_req(&down_req, ldb, ac,
3606 ac, replmd_op_callback,
3608 LDB_REQ_SET_LOCATION(down_req);
3609 if (ret != LDB_SUCCESS) {
3614 /* current partition control is needed by "replmd_op_callback" */
3615 if (ldb_request_get_control(req, DSDB_CONTROL_CURRENT_PARTITION_OID) == NULL) {
3616 ret = ldb_request_add_control(down_req,
3617 DSDB_CONTROL_CURRENT_PARTITION_OID,
3619 if (ret != LDB_SUCCESS) {
3625 talloc_steal(down_req, msg);
3627 ret = add_time_element(msg, "whenChanged", t);
3628 if (ret != LDB_SUCCESS) {
3634 ret = add_uint64_element(ldb, msg, "uSNChanged", ac->seq_num);
3635 if (ret != LDB_SUCCESS) {
3641 /* go on with the call chain - do the modify after the rename */
3642 return ldb_next_request(ac->module, down_req);
3646 * remove links from objects that point at this object when an object
3647 * is deleted. We remove it from the NEXT module per MS-DRSR 5.160
3648 * RemoveObj which states that link removal due to the object being
3649 * deleted is NOT an originating update - they just go away!
3652 static int replmd_delete_remove_link(struct ldb_module *module,
3653 const struct dsdb_schema *schema,
3654 struct replmd_private *replmd_private,
3657 struct ldb_message_element *el,
3658 const struct dsdb_attribute *sa,
3659 struct ldb_request *parent)
3662 TALLOC_CTX *tmp_ctx = talloc_new(module);
3663 struct ldb_context *ldb = ldb_module_get_ctx(module);
3665 for (i=0; i<el->num_values; i++) {
3666 struct dsdb_dn *dsdb_dn;
3668 struct ldb_message *msg;
3669 const struct dsdb_attribute *target_attr;
3670 struct ldb_message_element *el2;
3672 struct ldb_val dn_val;
3673 uint32_t dsdb_flags = 0;
3674 const char *attrs[] = { NULL, NULL };
3675 struct ldb_result *link_res;
3676 struct ldb_message *link_msg;
3677 struct ldb_message_element *link_el;
3678 struct parsed_dn *link_dns;
3679 struct parsed_dn *p = NULL, *unused = NULL;
3681 if (dsdb_dn_is_deleted_val(&el->values[i])) {
3685 dsdb_dn = dsdb_dn_parse(tmp_ctx, ldb, &el->values[i], sa->syntax->ldap_oid);
3687 talloc_free(tmp_ctx);
3688 return LDB_ERR_OPERATIONS_ERROR;
3691 /* remove the link */
3692 msg = ldb_msg_new(tmp_ctx);
3694 ldb_module_oom(module);
3695 talloc_free(tmp_ctx);
3696 return LDB_ERR_OPERATIONS_ERROR;
3700 msg->dn = dsdb_dn->dn;
3702 target_attr = dsdb_attribute_by_linkID(schema, sa->linkID ^ 1);
3703 if (target_attr == NULL) {
3706 attrs[0] = target_attr->lDAPDisplayName;
3708 ret = ldb_msg_add_empty(msg, target_attr->lDAPDisplayName,
3709 LDB_FLAG_MOD_DELETE, &el2);
3710 if (ret != LDB_SUCCESS) {
3711 ldb_module_oom(module);
3712 talloc_free(tmp_ctx);
3713 return LDB_ERR_OPERATIONS_ERROR;
3716 ret = dsdb_module_search_dn(module, tmp_ctx, &link_res,
3718 DSDB_FLAG_NEXT_MODULE |
3719 DSDB_SEARCH_SHOW_EXTENDED_DN,
3722 if (ret != LDB_SUCCESS) {
3723 talloc_free(tmp_ctx);
3727 link_msg = link_res->msgs[0];
3728 link_el = ldb_msg_find_element(link_msg,
3729 target_attr->lDAPDisplayName);
3730 if (link_el == NULL) {
3731 talloc_free(tmp_ctx);
3732 return LDB_ERR_NO_SUCH_ATTRIBUTE;
3736 * This call 'upgrades' the links in link_dns, but we
3737 * do not commit the result back into the database, so
3738 * this is safe to call in FL2000 or on databases that
3739 * have been run at that level in the past.
3741 ret = get_parsed_dns_trusted(module, replmd_private, tmp_ctx,
3743 target_attr->syntax->ldap_oid, parent);
3744 if (ret != LDB_SUCCESS) {
3745 talloc_free(tmp_ctx);
3749 ret = parsed_dn_find(ldb, link_dns, link_el->num_values,
3753 target_attr->syntax->ldap_oid, false);
3754 if (ret != LDB_SUCCESS) {
3755 talloc_free(tmp_ctx);
3760 ldb_asprintf_errstring(ldb_module_get_ctx(module),
3761 "Failed to find forward link on %s "
3762 "as %s to remove backlink %s on %s",
3763 ldb_dn_get_linearized(msg->dn),
3764 target_attr->lDAPDisplayName,
3765 sa->lDAPDisplayName,
3766 ldb_dn_get_linearized(dn));
3767 talloc_free(tmp_ctx);
3768 return LDB_ERR_NO_SUCH_ATTRIBUTE;
3772 /* This needs to get the Binary DN, by first searching */
3773 dn_str = dsdb_dn_get_linearized(tmp_ctx,
3776 dn_val = data_blob_string_const(dn_str);
3777 el2->values = &dn_val;
3778 el2->num_values = 1;
3781 * Ensure that we tell the modification to vanish any linked
3782 * attributes (not simply mark them as isDeleted = TRUE)
3784 dsdb_flags |= DSDB_REPLMD_VANISH_LINKS;
3786 ret = dsdb_module_modify(module, msg, dsdb_flags|DSDB_FLAG_OWN_MODULE, parent);
3787 if (ret != LDB_SUCCESS) {
3788 talloc_free(tmp_ctx);
3792 talloc_free(tmp_ctx);
3798 handle update of replication meta data for deletion of objects
3800 This also handles the mapping of delete to a rename operation
3801 to allow deletes to be replicated.
3803 It also handles the incoming deleted objects, to ensure they are
3804 fully deleted here. In that case re_delete is true, and we do not
3805 use this as a signal to change the deleted state, just reinforce it.
3808 static int replmd_delete_internals(struct ldb_module *module, struct ldb_request *req, bool re_delete)
3810 int ret = LDB_ERR_OTHER;
3811 bool retb, disallow_move_on_delete;
3812 struct ldb_dn *old_dn, *new_dn;
3813 const char *rdn_name;
3814 const struct ldb_val *rdn_value, *new_rdn_value;
3816 struct ldb_context *ldb = ldb_module_get_ctx(module);
3817 const struct dsdb_schema *schema;
3818 struct ldb_message *msg, *old_msg;
3819 struct ldb_message_element *el;
3820 TALLOC_CTX *tmp_ctx;
3821 struct ldb_result *res, *parent_res;
3822 static const char * const preserved_attrs[] = {
3823 /* yes, this really is a hard coded list. See MS-ADTS
3824 section 3.1.1.5.5.1.1 */
3827 "dNReferenceUpdate",
3838 "msDS-LastKnownRDN",
3844 "distinguishedName",
3848 "proxiedObjectName",
3850 "nTSecurityDescriptor",
3851 "replPropertyMetaData",
3853 "securityIdentifier",
3861 "userAccountControl",
3868 static const char * const all_attrs[] = {
3869 DSDB_SECRET_ATTRIBUTES,
3873 unsigned int i, el_count = 0;
3874 uint32_t dsdb_flags = 0;
3875 struct replmd_private *replmd_private;
3876 enum deletion_state deletion_state, next_deletion_state;
3878 if (ldb_dn_is_special(req->op.del.dn)) {
3879 return ldb_next_request(module, req);
3883 * We have to allow dbcheck to remove an object that
3884 * is beyond repair, and to do so totally. This could
3885 * mean we we can get a partial object from the other
3886 * DC, causing havoc, so dbcheck suggests
3887 * re-replication first. dbcheck sets both DBCHECK
3888 * and RELAX in this situation.
3890 if (ldb_request_get_control(req, LDB_CONTROL_RELAX_OID)
3891 && ldb_request_get_control(req, DSDB_CONTROL_DBCHECK)) {
3892 /* really, really remove it */
3893 return ldb_next_request(module, req);
3896 tmp_ctx = talloc_new(ldb);
3899 return LDB_ERR_OPERATIONS_ERROR;
3902 schema = dsdb_get_schema(ldb, tmp_ctx);
3904 talloc_free(tmp_ctx);
3905 return LDB_ERR_OPERATIONS_ERROR;
3908 old_dn = ldb_dn_copy(tmp_ctx, req->op.del.dn);
3910 /* we need the complete msg off disk, so we can work out which
3911 attributes need to be removed */
3912 ret = dsdb_module_search_dn(module, tmp_ctx, &res, old_dn, all_attrs,
3913 DSDB_FLAG_NEXT_MODULE |
3914 DSDB_SEARCH_SHOW_RECYCLED |
3915 DSDB_SEARCH_REVEAL_INTERNALS |
3916 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT, req);
3917 if (ret != LDB_SUCCESS) {
3918 ldb_asprintf_errstring(ldb_module_get_ctx(module),
3919 "repmd_delete: Failed to %s %s, because we failed to find it: %s",
3920 re_delete ? "re-delete" : "delete",
3921 ldb_dn_get_linearized(old_dn),
3922 ldb_errstring(ldb_module_get_ctx(module)));
3923 talloc_free(tmp_ctx);
3926 old_msg = res->msgs[0];
3928 replmd_deletion_state(module, old_msg,
3930 &next_deletion_state);
3932 /* This supports us noticing an incoming isDeleted and acting on it */
3934 SMB_ASSERT(deletion_state > OBJECT_NOT_DELETED);
3935 next_deletion_state = deletion_state;
3938 if (next_deletion_state == OBJECT_REMOVED) {
3940 * We have to prevent objects being deleted, even if
3941 * the administrator really wants them gone, as
3942 * without the tombstone, we can get a partial object
3943 * from the other DC, causing havoc.
3945 * The only other valid case is when the 180 day
3946 * timeout has expired, when relax is specified.
3948 if (ldb_request_get_control(req, LDB_CONTROL_RELAX_OID)) {
3949 /* it is already deleted - really remove it this time */
3950 talloc_free(tmp_ctx);
3951 return ldb_next_request(module, req);
3954 ldb_asprintf_errstring(ldb, "Refusing to delete tombstone object %s. "
3955 "This check is to prevent corruption of the replicated state.",
3956 ldb_dn_get_linearized(old_msg->dn));
3957 return LDB_ERR_UNWILLING_TO_PERFORM;
3960 rdn_name = ldb_dn_get_rdn_name(old_dn);
3961 rdn_value = ldb_dn_get_rdn_val(old_dn);
3962 if ((rdn_name == NULL) || (rdn_value == NULL)) {
3963 talloc_free(tmp_ctx);
3964 return ldb_operr(ldb);
3967 msg = ldb_msg_new(tmp_ctx);
3969 ldb_module_oom(module);
3970 talloc_free(tmp_ctx);
3971 return LDB_ERR_OPERATIONS_ERROR;
3976 /* consider the SYSTEM_FLAG_DISALLOW_MOVE_ON_DELETE flag */
3977 disallow_move_on_delete =
3978 (ldb_msg_find_attr_as_int(old_msg, "systemFlags", 0)
3979 & SYSTEM_FLAG_DISALLOW_MOVE_ON_DELETE);
3981 /* work out where we will be renaming this object to */
3982 if (!disallow_move_on_delete) {
3983 struct ldb_dn *deleted_objects_dn;
3984 ret = dsdb_get_deleted_objects_dn(ldb, tmp_ctx, old_dn,
3985 &deleted_objects_dn);
3988 * We should not move objects if we can't find the
3989 * deleted objects DN. Not moving (or otherwise
3990 * harming) the Deleted Objects DN itself is handled
3993 if (re_delete && (ret != LDB_SUCCESS)) {
3994 new_dn = ldb_dn_get_parent(tmp_ctx, old_dn);
3995 if (new_dn == NULL) {
3996 ldb_module_oom(module);
3997 talloc_free(tmp_ctx);
3998 return LDB_ERR_OPERATIONS_ERROR;
4000 } else if (ret != LDB_SUCCESS) {
4001 /* this is probably an attempted delete on a partition
4002 * that doesn't allow delete operations, such as the
4003 * schema partition */
4004 ldb_asprintf_errstring(ldb, "No Deleted Objects container for DN %s",
4005 ldb_dn_get_linearized(old_dn));
4006 talloc_free(tmp_ctx);
4007 return LDB_ERR_UNWILLING_TO_PERFORM;
4009 new_dn = deleted_objects_dn;
4012 new_dn = ldb_dn_get_parent(tmp_ctx, old_dn);
4013 if (new_dn == NULL) {
4014 ldb_module_oom(module);
4015 talloc_free(tmp_ctx);
4016 return LDB_ERR_OPERATIONS_ERROR;
4020 /* get the objects GUID from the search we just did */
4021 guid = samdb_result_guid(old_msg, "objectGUID");
4023 if (deletion_state == OBJECT_NOT_DELETED) {
4024 /* Add a formatted child */
4025 retb = ldb_dn_add_child_fmt(new_dn, "%s=%s\\0ADEL:%s",
4027 ldb_dn_escape_value(tmp_ctx, *rdn_value),
4028 GUID_string(tmp_ctx, &guid));
4030 ldb_asprintf_errstring(ldb, __location__
4031 ": Unable to add a formatted child to dn: %s",
4032 ldb_dn_get_linearized(new_dn));
4033 talloc_free(tmp_ctx);
4034 return LDB_ERR_OPERATIONS_ERROR;
4037 ret = ldb_msg_add_string(msg, "isDeleted", "TRUE");
4038 if (ret != LDB_SUCCESS) {
4039 ldb_asprintf_errstring(ldb, __location__
4040 ": Failed to add isDeleted string to the msg");
4041 talloc_free(tmp_ctx);
4044 msg->elements[el_count++].flags = LDB_FLAG_MOD_REPLACE;
4047 * No matter what has happened with other renames etc, try again to
4048 * get this to be under the deleted DN. See MS-DRSR 5.160 RemoveObj
4051 struct ldb_dn *rdn = ldb_dn_copy(tmp_ctx, old_dn);
4052 retb = ldb_dn_remove_base_components(rdn, ldb_dn_get_comp_num(rdn) - 1);
4054 ldb_asprintf_errstring(ldb, __location__
4055 ": Unable to add a prepare rdn of %s",
4056 ldb_dn_get_linearized(rdn));
4057 talloc_free(tmp_ctx);
4058 return LDB_ERR_OPERATIONS_ERROR;
4060 SMB_ASSERT(ldb_dn_get_comp_num(rdn) == 1);
4062 retb = ldb_dn_add_child(new_dn, rdn);
4064 ldb_asprintf_errstring(ldb, __location__
4065 ": Unable to add rdn %s to base dn: %s",
4066 ldb_dn_get_linearized(rdn),
4067 ldb_dn_get_linearized(new_dn));
4068 talloc_free(tmp_ctx);
4069 return LDB_ERR_OPERATIONS_ERROR;
4074 now we need to modify the object in the following ways:
4076 - add isDeleted=TRUE
4077 - update rDN and name, with new rDN
4078 - remove linked attributes
4079 - remove objectCategory and sAMAccountType
4080 - remove attribs not on the preserved list
4081 - preserved if in above list, or is rDN
4082 - remove all linked attribs from this object
4083 - remove all links from other objects to this object
4084 - add lastKnownParent
4085 - update replPropertyMetaData?
4087 see MS-ADTS "Tombstone Requirements" section 3.1.1.5.5.1.1
4090 if (deletion_state == OBJECT_NOT_DELETED) {
4091 struct ldb_dn *parent_dn = ldb_dn_get_parent(tmp_ctx, old_dn);
4092 char *parent_dn_str = NULL;
4094 /* we need the storage form of the parent GUID */
4095 ret = dsdb_module_search_dn(module, tmp_ctx, &parent_res,
4097 DSDB_FLAG_NEXT_MODULE |
4098 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT |
4099 DSDB_SEARCH_REVEAL_INTERNALS|
4100 DSDB_SEARCH_SHOW_RECYCLED, req);
4101 if (ret != LDB_SUCCESS) {
4102 ldb_asprintf_errstring(ldb_module_get_ctx(module),
4103 "repmd_delete: Failed to %s %s, "
4104 "because we failed to find it's parent (%s): %s",
4105 re_delete ? "re-delete" : "delete",
4106 ldb_dn_get_linearized(old_dn),
4107 ldb_dn_get_linearized(parent_dn),
4108 ldb_errstring(ldb_module_get_ctx(module)));
4109 talloc_free(tmp_ctx);
4114 * Now we can use the DB version,
4115 * it will have the extended DN info in it
4117 parent_dn = parent_res->msgs[0]->dn;
4118 parent_dn_str = ldb_dn_get_extended_linearized(tmp_ctx,
4121 if (parent_dn_str == NULL) {
4122 talloc_free(tmp_ctx);
4123 return ldb_module_oom(module);
4126 ret = ldb_msg_add_steal_string(msg, "lastKnownParent",
4128 if (ret != LDB_SUCCESS) {
4129 ldb_asprintf_errstring(ldb, __location__
4130 ": Failed to add lastKnownParent "
4131 "string when deleting %s",
4132 ldb_dn_get_linearized(old_dn));
4133 talloc_free(tmp_ctx);
4136 msg->elements[el_count++].flags = LDB_FLAG_MOD_REPLACE;
4138 if (next_deletion_state == OBJECT_DELETED) {
4139 ret = ldb_msg_add_value(msg, "msDS-LastKnownRDN", rdn_value, NULL);
4140 if (ret != LDB_SUCCESS) {
4141 ldb_asprintf_errstring(ldb, __location__
4142 ": Failed to add msDS-LastKnownRDN "
4143 "string when deleting %s",
4144 ldb_dn_get_linearized(old_dn));
4145 talloc_free(tmp_ctx);
4148 msg->elements[el_count++].flags = LDB_FLAG_MOD_ADD;
4152 switch (next_deletion_state) {
4154 case OBJECT_RECYCLED:
4155 case OBJECT_TOMBSTONE:
4158 * MS-ADTS 3.1.1.5.5.1.1 Tombstone Requirements
4159 * describes what must be removed from a tombstone
4162 * MS-ADTS 3.1.1.5.5.1.3 Recycled-Object Requirements
4163 * describes what must be removed from a recycled
4169 * we also mark it as recycled, meaning this object can't be
4170 * recovered (we are stripping its attributes).
4171 * This is done only if we have this schema object of course ...
4172 * This behavior is identical to the one of Windows 2008R2 which
4173 * always set the isRecycled attribute, even if the recycle-bin is
4174 * not activated and what ever the forest level is.
4176 if (dsdb_attribute_by_lDAPDisplayName(schema, "isRecycled") != NULL) {
4177 ret = ldb_msg_add_string(msg, "isRecycled", "TRUE");
4178 if (ret != LDB_SUCCESS) {
4179 DEBUG(0,(__location__ ": Failed to add isRecycled string to the msg\n"));
4180 ldb_module_oom(module);
4181 talloc_free(tmp_ctx);
4184 msg->elements[el_count++].flags = LDB_FLAG_MOD_REPLACE;
4187 replmd_private = talloc_get_type(ldb_module_get_private(module),
4188 struct replmd_private);
4189 /* work out which of the old attributes we will be removing */
4190 for (i=0; i<old_msg->num_elements; i++) {
4191 const struct dsdb_attribute *sa;
4192 el = &old_msg->elements[i];
4193 sa = dsdb_attribute_by_lDAPDisplayName(schema, el->name);
4195 talloc_free(tmp_ctx);
4196 return LDB_ERR_OPERATIONS_ERROR;
4198 if (ldb_attr_cmp(el->name, rdn_name) == 0) {
4199 /* don't remove the rDN */
4202 if (sa->linkID & 1) {
4204 we have a backlink in this object
4205 that needs to be removed. We're not
4206 allowed to remove it directly
4207 however, so we instead setup a
4208 modify to delete the corresponding
4211 ret = replmd_delete_remove_link(module, schema,
4215 if (ret != LDB_SUCCESS) {
4216 const char *old_dn_str
4217 = ldb_dn_get_linearized(old_dn);
4218 ldb_asprintf_errstring(ldb,
4220 ": Failed to remove backlink of "
4221 "%s when deleting %s: %s",
4224 ldb_errstring(ldb));
4225 talloc_free(tmp_ctx);
4226 return LDB_ERR_OPERATIONS_ERROR;
4228 /* now we continue, which means we
4229 won't remove this backlink
4233 } else if (sa->linkID == 0) {
4234 if (ldb_attr_in_list(preserved_attrs, el->name)) {
4237 if (sa->searchFlags & SEARCH_FLAG_PRESERVEONDELETE) {
4242 * Ensure that we tell the modification to vanish any linked
4243 * attributes (not simply mark them as isDeleted = TRUE)
4245 dsdb_flags |= DSDB_REPLMD_VANISH_LINKS;
4247 ret = ldb_msg_add_empty(msg, el->name, LDB_FLAG_MOD_DELETE, &el);
4248 if (ret != LDB_SUCCESS) {
4249 talloc_free(tmp_ctx);
4250 ldb_module_oom(module);
4257 case OBJECT_DELETED:
4259 * MS-ADTS 3.1.1.5.5.1.2 Deleted-Object Requirements
4260 * describes what must be removed from a deleted
4264 ret = ldb_msg_add_empty(msg, "objectCategory", LDB_FLAG_MOD_REPLACE, NULL);
4265 if (ret != LDB_SUCCESS) {
4266 talloc_free(tmp_ctx);
4267 ldb_module_oom(module);
4271 ret = ldb_msg_add_empty(msg, "sAMAccountType", LDB_FLAG_MOD_REPLACE, NULL);
4272 if (ret != LDB_SUCCESS) {
4273 talloc_free(tmp_ctx);
4274 ldb_module_oom(module);
4284 if (deletion_state == OBJECT_NOT_DELETED) {
4285 const struct dsdb_attribute *sa;
4287 /* work out what the new rdn value is, for updating the
4288 rDN and name fields */
4289 new_rdn_value = ldb_dn_get_rdn_val(new_dn);
4290 if (new_rdn_value == NULL) {
4291 talloc_free(tmp_ctx);
4292 return ldb_operr(ldb);
4295 sa = dsdb_attribute_by_lDAPDisplayName(schema, rdn_name);
4297 talloc_free(tmp_ctx);
4298 return LDB_ERR_OPERATIONS_ERROR;
4301 ret = ldb_msg_add_value(msg, sa->lDAPDisplayName, new_rdn_value,
4303 if (ret != LDB_SUCCESS) {
4304 talloc_free(tmp_ctx);
4307 el->flags = LDB_FLAG_MOD_REPLACE;
4309 el = ldb_msg_find_element(old_msg, "name");
4311 ret = ldb_msg_add_value(msg, "name", new_rdn_value, &el);
4312 if (ret != LDB_SUCCESS) {
4313 talloc_free(tmp_ctx);
4316 el->flags = LDB_FLAG_MOD_REPLACE;
4321 * TODO: Per MS-DRSR 5.160 RemoveObj we should remove links directly, not as an originating update!
4326 * No matter what has happned with other renames, try again to
4327 * get this to be under the deleted DN.
4329 if (strcmp(ldb_dn_get_linearized(old_dn), ldb_dn_get_linearized(new_dn)) != 0) {
4330 /* now rename onto the new DN */
4331 ret = dsdb_module_rename(module, old_dn, new_dn, DSDB_FLAG_NEXT_MODULE, req);
4332 if (ret != LDB_SUCCESS){
4333 DEBUG(0,(__location__ ": Failed to rename object from '%s' to '%s' - %s\n",
4334 ldb_dn_get_linearized(old_dn),
4335 ldb_dn_get_linearized(new_dn),
4336 ldb_errstring(ldb)));
4337 talloc_free(tmp_ctx);
4343 ret = dsdb_module_modify(module, msg, dsdb_flags|DSDB_FLAG_OWN_MODULE, req);
4344 if (ret != LDB_SUCCESS) {
4345 ldb_asprintf_errstring(ldb, "replmd_delete: Failed to modify object %s in delete - %s",
4346 ldb_dn_get_linearized(old_dn), ldb_errstring(ldb));
4347 talloc_free(tmp_ctx);
4351 talloc_free(tmp_ctx);
4353 return ldb_module_done(req, NULL, NULL, LDB_SUCCESS);
4356 static int replmd_delete(struct ldb_module *module, struct ldb_request *req)
4358 return replmd_delete_internals(module, req, false);
4362 static int replmd_replicated_request_error(struct replmd_replicated_request *ar, int ret)
4367 static int replmd_replicated_request_werror(struct replmd_replicated_request *ar, WERROR status)
4369 int ret = LDB_ERR_OTHER;
4370 /* TODO: do some error mapping */
4372 /* Let the caller know the full WERROR */
4373 ar->objs->error = status;
4379 static struct replPropertyMetaData1 *
4380 replmd_replPropertyMetaData1_find_attid(struct replPropertyMetaDataBlob *md_blob,
4381 enum drsuapi_DsAttributeId attid)
4384 struct replPropertyMetaDataCtr1 *rpmd_ctr = &md_blob->ctr.ctr1;
4386 for (i = 0; i < rpmd_ctr->count; i++) {
4387 if (rpmd_ctr->array[i].attid == attid) {
4388 return &rpmd_ctr->array[i];
4396 return true if an update is newer than an existing entry
4397 see section 5.11 of MS-ADTS
4399 static bool replmd_update_is_newer(const struct GUID *current_invocation_id,
4400 const struct GUID *update_invocation_id,
4401 uint32_t current_version,
4402 uint32_t update_version,
4403 NTTIME current_change_time,
4404 NTTIME update_change_time)
4406 if (update_version != current_version) {
4407 return update_version > current_version;
4409 if (update_change_time != current_change_time) {
4410 return update_change_time > current_change_time;
4412 return GUID_compare(update_invocation_id, current_invocation_id) > 0;
4415 static bool replmd_replPropertyMetaData1_is_newer(struct replPropertyMetaData1 *cur_m,
4416 struct replPropertyMetaData1 *new_m)
4418 return replmd_update_is_newer(&cur_m->originating_invocation_id,
4419 &new_m->originating_invocation_id,
4422 cur_m->originating_change_time,
4423 new_m->originating_change_time);
4426 static bool replmd_replPropertyMetaData1_new_should_be_taken(uint32_t dsdb_repl_flags,
4427 struct replPropertyMetaData1 *cur_m,
4428 struct replPropertyMetaData1 *new_m)
4433 * If the new replPropertyMetaData entry for this attribute is
4434 * not provided (this happens in the case where we look for
4435 * ATTID_name, but the name was not changed), then the local
4436 * state is clearly still current, as the remote
4437 * server didn't send it due to being older the high watermark
4440 if (new_m == NULL) {
4444 if (dsdb_repl_flags & DSDB_REPL_FLAG_PRIORITISE_INCOMING) {
4446 * if we compare equal then do an
4447 * update. This is used when a client
4448 * asks for a FULL_SYNC, and can be
4449 * used to recover a corrupt
4452 * This call is a bit tricky, what we
4453 * are doing it turning the 'is_newer'
4454 * call into a 'not is older' by
4455 * swapping cur_m and new_m, and negating the
4458 cmp = !replmd_replPropertyMetaData1_is_newer(new_m,
4461 cmp = replmd_replPropertyMetaData1_is_newer(cur_m,
4471 static struct ldb_dn *replmd_conflict_dn(TALLOC_CTX *mem_ctx, struct ldb_dn *dn, struct GUID *guid)
4473 const struct ldb_val *rdn_val;
4474 const char *rdn_name;
4475 struct ldb_dn *new_dn;
4477 rdn_val = ldb_dn_get_rdn_val(dn);
4478 rdn_name = ldb_dn_get_rdn_name(dn);
4479 if (!rdn_val || !rdn_name) {
4483 new_dn = ldb_dn_copy(mem_ctx, dn);
4488 if (!ldb_dn_remove_child_components(new_dn, 1)) {
4492 if (!ldb_dn_add_child_fmt(new_dn, "%s=%s\\0ACNF:%s",
4494 ldb_dn_escape_value(new_dn, *rdn_val),
4495 GUID_string(new_dn, guid))) {
4504 perform a modify operation which sets the rDN and name attributes to
4505 their current values. This has the effect of changing these
4506 attributes to have been last updated by the current DC. This is
4507 needed to ensure that renames performed as part of conflict
4508 resolution are propogated to other DCs
4510 static int replmd_name_modify(struct replmd_replicated_request *ar,
4511 struct ldb_request *req, struct ldb_dn *dn)
4513 struct ldb_message *msg;
4514 const char *rdn_name;
4515 const struct ldb_val *rdn_val;
4516 const struct dsdb_attribute *rdn_attr;
4519 msg = ldb_msg_new(req);
4525 rdn_name = ldb_dn_get_rdn_name(dn);
4526 if (rdn_name == NULL) {
4530 /* normalize the rdn attribute name */
4531 rdn_attr = dsdb_attribute_by_lDAPDisplayName(ar->schema, rdn_name);
4532 if (rdn_attr == NULL) {
4535 rdn_name = rdn_attr->lDAPDisplayName;
4537 rdn_val = ldb_dn_get_rdn_val(dn);
4538 if (rdn_val == NULL) {
4542 if (ldb_msg_add_empty(msg, rdn_name, LDB_FLAG_MOD_REPLACE, NULL) != 0) {
4545 if (ldb_msg_add_value(msg, rdn_name, rdn_val, NULL) != 0) {
4548 if (ldb_msg_add_empty(msg, "name", LDB_FLAG_MOD_REPLACE, NULL) != 0) {
4551 if (ldb_msg_add_value(msg, "name", rdn_val, NULL) != 0) {
4556 * We have to mark this as a replicated update otherwise
4557 * schema_data may reject a rename in the schema partition
4560 ret = dsdb_module_modify(ar->module, msg,
4561 DSDB_FLAG_OWN_MODULE|DSDB_FLAG_REPLICATED_UPDATE,
4563 if (ret != LDB_SUCCESS) {
4564 DEBUG(0,(__location__ ": Failed to modify rDN/name of DN being DRS renamed '%s' - %s",
4565 ldb_dn_get_linearized(dn),
4566 ldb_errstring(ldb_module_get_ctx(ar->module))));
4576 DEBUG(0,(__location__ ": Failed to setup modify rDN/name of DN being DRS renamed '%s'",
4577 ldb_dn_get_linearized(dn)));
4578 return LDB_ERR_OPERATIONS_ERROR;
4583 callback for conflict DN handling where we have renamed the incoming
4584 record. After renaming it, we need to ensure the change of name and
4585 rDN for the incoming record is seen as an originating update by this DC.
4587 This also handles updating lastKnownParent for entries sent to lostAndFound
4589 static int replmd_op_name_modify_callback(struct ldb_request *req, struct ldb_reply *ares)
4591 struct replmd_replicated_request *ar =
4592 talloc_get_type_abort(req->context, struct replmd_replicated_request);
4593 struct ldb_dn *conflict_dn = NULL;
4596 if (ares->error != LDB_SUCCESS) {
4597 /* call the normal callback for everything except success */
4598 return replmd_op_callback(req, ares);
4601 switch (req->operation) {
4603 conflict_dn = req->op.add.message->dn;
4606 conflict_dn = req->op.mod.message->dn;
4609 smb_panic("replmd_op_name_modify_callback called in unknown circumstances");
4612 /* perform a modify of the rDN and name of the record */
4613 ret = replmd_name_modify(ar, req, conflict_dn);
4614 if (ret != LDB_SUCCESS) {
4616 return replmd_op_callback(req, ares);
4619 if (ar->objs->objects[ar->index_current].last_known_parent) {
4620 struct ldb_message *msg = ldb_msg_new(req);
4622 ldb_module_oom(ar->module);
4623 return LDB_ERR_OPERATIONS_ERROR;
4626 msg->dn = req->op.add.message->dn;
4628 ret = ldb_msg_add_steal_string(msg, "lastKnownParent",
4629 ldb_dn_get_extended_linearized(msg, ar->objs->objects[ar->index_current].last_known_parent, 1));
4630 if (ret != LDB_SUCCESS) {
4631 DEBUG(0,(__location__ ": Failed to add lastKnownParent string to the msg\n"));
4632 ldb_module_oom(ar->module);
4635 msg->elements[0].flags = LDB_FLAG_MOD_REPLACE;
4637 ret = dsdb_module_modify(ar->module, msg, DSDB_FLAG_OWN_MODULE, req);
4638 if (ret != LDB_SUCCESS) {
4639 DEBUG(0,(__location__ ": Failed to modify lastKnownParent of lostAndFound DN '%s' - %s",
4640 ldb_dn_get_linearized(msg->dn),
4641 ldb_errstring(ldb_module_get_ctx(ar->module))));
4647 return replmd_op_callback(req, ares);
4651 callback for replmd_replicated_apply_add()
4652 This copes with the creation of conflict records in the case where
4653 the DN exists, but with a different objectGUID
4655 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))
4657 struct ldb_dn *conflict_dn;
4658 struct replmd_replicated_request *ar =
4659 talloc_get_type_abort(req->context, struct replmd_replicated_request);
4660 struct ldb_result *res;
4661 const char *attrs[] = { "replPropertyMetaData", "objectGUID", NULL };
4663 const struct ldb_val *omd_value;
4664 struct replPropertyMetaDataBlob omd, *rmd;
4665 enum ndr_err_code ndr_err;
4666 bool rename_incoming_record, rodc;
4667 struct replPropertyMetaData1 *rmd_name, *omd_name;
4668 struct ldb_message *msg;
4669 struct ldb_request *down_req = NULL;
4671 /* call the normal callback for success */
4672 if (ares->error == LDB_SUCCESS) {
4673 return callback(req, ares);
4677 * we have a conflict, and need to decide if we will keep the
4678 * new record or the old record
4681 msg = ar->objs->objects[ar->index_current].msg;
4682 conflict_dn = msg->dn;
4684 /* For failures other than conflicts, fail the whole operation here */
4685 if (ares->error != LDB_ERR_ENTRY_ALREADY_EXISTS) {
4686 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module), "Failed to locally apply remote add of %s: %s",
4687 ldb_dn_get_linearized(conflict_dn),
4688 ldb_errstring(ldb_module_get_ctx(ar->module)));
4690 return ldb_module_done(ar->req, NULL, NULL,
4691 LDB_ERR_OPERATIONS_ERROR);
4694 ret = samdb_rodc(ldb_module_get_ctx(ar->module), &rodc);
4695 if (ret != LDB_SUCCESS) {
4696 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)));
4697 return ldb_module_done(ar->req, NULL, NULL,
4698 LDB_ERR_OPERATIONS_ERROR);
4704 * We are on an RODC, or were a GC for this
4705 * partition, so we have to fail this until
4706 * someone who owns the partition sorts it
4709 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
4710 "Conflict adding object '%s' from incoming replication as we are read only for the partition. \n"
4711 " - We must fail the operation until a master for this partition resolves the conflict",
4712 ldb_dn_get_linearized(conflict_dn));
4717 * first we need the replPropertyMetaData attribute from the
4718 * local, conflicting record
4720 ret = dsdb_module_search_dn(ar->module, req, &res, conflict_dn,
4722 DSDB_FLAG_NEXT_MODULE |
4723 DSDB_SEARCH_SHOW_DELETED |
4724 DSDB_SEARCH_SHOW_RECYCLED, req);
4725 if (ret != LDB_SUCCESS) {
4726 DEBUG(0,(__location__ ": Unable to find object for conflicting record '%s'\n",
4727 ldb_dn_get_linearized(conflict_dn)));
4731 omd_value = ldb_msg_find_ldb_val(res->msgs[0], "replPropertyMetaData");
4732 if (omd_value == NULL) {
4733 DEBUG(0,(__location__ ": Unable to find replPropertyMetaData for conflicting record '%s'\n",
4734 ldb_dn_get_linearized(conflict_dn)));
4738 ndr_err = ndr_pull_struct_blob(omd_value, res->msgs[0], &omd,
4739 (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
4740 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
4741 DEBUG(0,(__location__ ": Failed to parse old replPropertyMetaData for %s\n",
4742 ldb_dn_get_linearized(conflict_dn)));
4746 rmd = ar->objs->objects[ar->index_current].meta_data;
4749 * we decide which is newer based on the RPMD on the name
4750 * attribute. See [MS-DRSR] ResolveNameConflict.
4752 * We expect omd_name to be present, as this is from a local
4753 * search, but while rmd_name should have been given to us by
4754 * the remote server, if it is missing we just prefer the
4756 * replmd_replPropertyMetaData1_new_should_be_taken()
4758 rmd_name = replmd_replPropertyMetaData1_find_attid(rmd, DRSUAPI_ATTID_name);
4759 omd_name = replmd_replPropertyMetaData1_find_attid(&omd, DRSUAPI_ATTID_name);
4761 DEBUG(0,(__location__ ": Failed to find name attribute in local LDB replPropertyMetaData for %s\n",
4762 ldb_dn_get_linearized(conflict_dn)));
4767 * Should we preserve the current record, and so rename the
4768 * incoming record to be a conflict?
4770 rename_incoming_record
4771 = !replmd_replPropertyMetaData1_new_should_be_taken(ar->objs->dsdb_repl_flags & DSDB_REPL_FLAG_PRIORITISE_INCOMING,
4772 omd_name, rmd_name);
4774 if (rename_incoming_record) {
4776 struct ldb_dn *new_dn;
4778 guid = samdb_result_guid(msg, "objectGUID");
4779 if (GUID_all_zero(&guid)) {
4780 DEBUG(0,(__location__ ": Failed to find objectGUID for conflicting incoming record %s\n",
4781 ldb_dn_get_linearized(conflict_dn)));
4784 new_dn = replmd_conflict_dn(req, conflict_dn, &guid);
4785 if (new_dn == NULL) {
4786 DEBUG(0,(__location__ ": Failed to form conflict DN for %s\n",
4787 ldb_dn_get_linearized(conflict_dn)));
4791 DEBUG(2,(__location__ ": Resolving conflict record via incoming rename '%s' -> '%s'\n",
4792 ldb_dn_get_linearized(conflict_dn), ldb_dn_get_linearized(new_dn)));
4794 /* re-submit the request, but with the new DN */
4795 callback = replmd_op_name_modify_callback;
4798 /* we are renaming the existing record */
4800 struct ldb_dn *new_dn;
4802 guid = samdb_result_guid(res->msgs[0], "objectGUID");
4803 if (GUID_all_zero(&guid)) {
4804 DEBUG(0,(__location__ ": Failed to find objectGUID for existing conflict record %s\n",
4805 ldb_dn_get_linearized(conflict_dn)));
4809 new_dn = replmd_conflict_dn(req, conflict_dn, &guid);
4810 if (new_dn == NULL) {
4811 DEBUG(0,(__location__ ": Failed to form conflict DN for %s\n",
4812 ldb_dn_get_linearized(conflict_dn)));
4816 DEBUG(2,(__location__ ": Resolving conflict record via existing-record rename '%s' -> '%s'\n",
4817 ldb_dn_get_linearized(conflict_dn), ldb_dn_get_linearized(new_dn)));
4819 ret = dsdb_module_rename(ar->module, conflict_dn, new_dn,
4820 DSDB_FLAG_OWN_MODULE, req);
4821 if (ret != LDB_SUCCESS) {
4822 DEBUG(0,(__location__ ": Failed to rename conflict dn '%s' to '%s' - %s\n",
4823 ldb_dn_get_linearized(conflict_dn),
4824 ldb_dn_get_linearized(new_dn),
4825 ldb_errstring(ldb_module_get_ctx(ar->module))));
4830 * now we need to ensure that the rename is seen as an
4831 * originating update. We do that with a modify.
4833 ret = replmd_name_modify(ar, req, new_dn);
4834 if (ret != LDB_SUCCESS) {
4838 DEBUG(2,(__location__ ": With conflicting record renamed, re-apply replicated creation of '%s'\n",
4839 ldb_dn_get_linearized(req->op.add.message->dn)));
4842 ret = ldb_build_add_req(&down_req,
4843 ldb_module_get_ctx(ar->module),
4850 if (ret != LDB_SUCCESS) {
4853 LDB_REQ_SET_LOCATION(down_req);
4855 /* current partition control needed by "repmd_op_callback" */
4856 ret = ldb_request_add_control(down_req,
4857 DSDB_CONTROL_CURRENT_PARTITION_OID,
4859 if (ret != LDB_SUCCESS) {
4860 return replmd_replicated_request_error(ar, ret);
4863 if (ar->objs->dsdb_repl_flags & DSDB_REPL_FLAG_PARTIAL_REPLICA) {
4864 /* this tells the partition module to make it a
4865 partial replica if creating an NC */
4866 ret = ldb_request_add_control(down_req,
4867 DSDB_CONTROL_PARTIAL_REPLICA,
4869 if (ret != LDB_SUCCESS) {
4870 return replmd_replicated_request_error(ar, ret);
4875 * Finally we re-run the add, otherwise the new record won't
4876 * exist, as we are here because of that exact failure!
4878 return ldb_next_request(ar->module, down_req);
4881 /* on failure make the caller get the error. This means
4882 * replication will stop with an error, but there is not much
4885 return ldb_module_done(ar->req, NULL, NULL,
4890 callback for replmd_replicated_apply_add()
4891 This copes with the creation of conflict records in the case where
4892 the DN exists, but with a different objectGUID
4894 static int replmd_op_add_callback(struct ldb_request *req, struct ldb_reply *ares)
4896 struct replmd_replicated_request *ar =
4897 talloc_get_type_abort(req->context, struct replmd_replicated_request);
4899 if (ar->objs->objects[ar->index_current].last_known_parent) {
4900 /* This is like a conflict DN, where we put the object in LostAndFound
4901 see MS-DRSR 4.1.10.6.10 FindBestParentObject */
4902 return replmd_op_possible_conflict_callback(req, ares, replmd_op_name_modify_callback);
4905 return replmd_op_possible_conflict_callback(req, ares, replmd_op_callback);
4909 this is called when a new object comes in over DRS
4911 static int replmd_replicated_apply_add(struct replmd_replicated_request *ar)
4913 struct ldb_context *ldb;
4914 struct ldb_request *change_req;
4915 enum ndr_err_code ndr_err;
4916 struct ldb_message *msg;
4917 struct replPropertyMetaDataBlob *md;
4918 struct ldb_val md_value;
4921 bool remote_isDeleted = false;
4924 time_t t = time(NULL);
4925 const struct ldb_val *rdn_val;
4926 struct replmd_private *replmd_private =
4927 talloc_get_type(ldb_module_get_private(ar->module),
4928 struct replmd_private);
4929 unix_to_nt_time(&now, t);
4931 ldb = ldb_module_get_ctx(ar->module);
4932 msg = ar->objs->objects[ar->index_current].msg;
4933 md = ar->objs->objects[ar->index_current].meta_data;
4934 is_schema_nc = ldb_dn_compare_base(replmd_private->schema_dn, msg->dn) == 0;
4936 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &ar->seq_num);
4937 if (ret != LDB_SUCCESS) {
4938 return replmd_replicated_request_error(ar, ret);
4941 ret = dsdb_msg_add_guid(msg,
4942 &ar->objs->objects[ar->index_current].object_guid,
4944 if (ret != LDB_SUCCESS) {
4945 return replmd_replicated_request_error(ar, ret);
4948 ret = ldb_msg_add_string(msg, "whenChanged", ar->objs->objects[ar->index_current].when_changed);
4949 if (ret != LDB_SUCCESS) {
4950 return replmd_replicated_request_error(ar, ret);
4953 ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNCreated", ar->seq_num);
4954 if (ret != LDB_SUCCESS) {
4955 return replmd_replicated_request_error(ar, ret);
4958 ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNChanged", ar->seq_num);
4959 if (ret != LDB_SUCCESS) {
4960 return replmd_replicated_request_error(ar, ret);
4963 /* remove any message elements that have zero values */
4964 for (i=0; i<msg->num_elements; i++) {
4965 struct ldb_message_element *el = &msg->elements[i];
4967 if (el->num_values == 0) {
4968 if (ldb_attr_cmp(msg->elements[i].name, "objectClass") == 0) {
4969 ldb_asprintf_errstring(ldb, __location__
4970 ": empty objectClass sent on %s, aborting replication\n",
4971 ldb_dn_get_linearized(msg->dn));
4972 return replmd_replicated_request_error(ar, LDB_ERR_OBJECT_CLASS_VIOLATION);
4975 DEBUG(4,(__location__ ": Removing attribute %s with num_values==0\n",
4977 memmove(el, el+1, sizeof(*el)*(msg->num_elements - (i+1)));
4978 msg->num_elements--;
4985 struct GUID_txt_buf guid_txt;
4987 char *s = ldb_ldif_message_redacted_string(ldb, ar,
4990 DEBUG(4, ("DRS replication add message of %s:\n%s\n",
4991 GUID_buf_string(&ar->objs->objects[ar->index_current].object_guid, &guid_txt),
4996 remote_isDeleted = ldb_msg_find_attr_as_bool(msg,
4997 "isDeleted", false);
5000 * the meta data array is already sorted by the caller, except
5001 * for the RDN, which needs to be added.
5005 rdn_val = ldb_dn_get_rdn_val(msg->dn);
5006 ret = replmd_update_rpmd_rdn_attr(ldb, msg, rdn_val, NULL,
5007 md, ar, now, is_schema_nc,
5009 if (ret != LDB_SUCCESS) {
5010 ldb_asprintf_errstring(ldb, "%s: error during DRS repl ADD: %s", __func__, ldb_errstring(ldb));
5011 return replmd_replicated_request_error(ar, ret);
5014 ret = replmd_replPropertyMetaDataCtr1_sort_and_verify(ldb, &md->ctr.ctr1, msg->dn);
5015 if (ret != LDB_SUCCESS) {
5016 ldb_asprintf_errstring(ldb, "%s: error during DRS repl ADD: %s", __func__, ldb_errstring(ldb));
5017 return replmd_replicated_request_error(ar, ret);
5020 for (i=0; i < md->ctr.ctr1.count; i++) {
5021 md->ctr.ctr1.array[i].local_usn = ar->seq_num;
5023 ndr_err = ndr_push_struct_blob(&md_value, msg, md,
5024 (ndr_push_flags_fn_t)ndr_push_replPropertyMetaDataBlob);
5025 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
5026 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
5027 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
5029 ret = ldb_msg_add_value(msg, "replPropertyMetaData", &md_value, NULL);
5030 if (ret != LDB_SUCCESS) {
5031 return replmd_replicated_request_error(ar, ret);
5034 replmd_ldb_message_sort(msg, ar->schema);
5036 if (!remote_isDeleted) {
5037 ret = dsdb_module_schedule_sd_propagation(ar->module,
5038 ar->objs->partition_dn,
5040 if (ret != LDB_SUCCESS) {
5041 return replmd_replicated_request_error(ar, ret);
5045 ar->isDeleted = remote_isDeleted;
5047 ret = ldb_build_add_req(&change_req,
5053 replmd_op_add_callback,
5055 LDB_REQ_SET_LOCATION(change_req);
5056 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
5058 /* current partition control needed by "repmd_op_callback" */
5059 ret = ldb_request_add_control(change_req,
5060 DSDB_CONTROL_CURRENT_PARTITION_OID,
5062 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
5064 if (ar->objs->dsdb_repl_flags & DSDB_REPL_FLAG_PARTIAL_REPLICA) {
5065 /* this tells the partition module to make it a
5066 partial replica if creating an NC */
5067 ret = ldb_request_add_control(change_req,
5068 DSDB_CONTROL_PARTIAL_REPLICA,
5070 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
5073 return ldb_next_request(ar->module, change_req);
5076 static int replmd_replicated_apply_search_for_parent_callback(struct ldb_request *req,
5077 struct ldb_reply *ares)
5079 struct replmd_replicated_request *ar = talloc_get_type(req->context,
5080 struct replmd_replicated_request);
5084 return ldb_module_done(ar->req, NULL, NULL,
5085 LDB_ERR_OPERATIONS_ERROR);
5089 * The error NO_SUCH_OBJECT is not expected, unless the search
5090 * base is the partition DN, and that case doesn't happen here
5091 * because then we wouldn't get a parent_guid_value in any
5094 if (ares->error != LDB_SUCCESS) {
5095 return ldb_module_done(ar->req, ares->controls,
5096 ares->response, ares->error);
5099 switch (ares->type) {
5100 case LDB_REPLY_ENTRY:
5102 struct ldb_message *parent_msg = ares->message;
5103 struct ldb_message *msg = ar->objs->objects[ar->index_current].msg;
5104 struct ldb_dn *parent_dn;
5107 if (!ldb_msg_check_string_attribute(msg, "isDeleted", "TRUE")
5108 && ldb_msg_check_string_attribute(parent_msg, "isDeleted", "TRUE")) {
5109 /* Per MS-DRSR 4.1.10.6.10
5110 * FindBestParentObject we need to move this
5111 * new object under a deleted object to
5113 struct ldb_dn *nc_root;
5115 ret = dsdb_find_nc_root(ldb_module_get_ctx(ar->module), msg, msg->dn, &nc_root);
5116 if (ret == LDB_ERR_NO_SUCH_OBJECT) {
5117 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
5118 "No suitable NC root found for %s. "
5119 "We need to move this object because parent object %s "
5120 "is deleted, but this object is not.",
5121 ldb_dn_get_linearized(msg->dn),
5122 ldb_dn_get_linearized(parent_msg->dn));
5123 return ldb_module_done(ar->req, NULL, NULL, LDB_ERR_OPERATIONS_ERROR);
5124 } else if (ret != LDB_SUCCESS) {
5125 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
5126 "Unable to find NC root for %s: %s. "
5127 "We need to move this object because parent object %s "
5128 "is deleted, but this object is not.",
5129 ldb_dn_get_linearized(msg->dn),
5130 ldb_errstring(ldb_module_get_ctx(ar->module)),
5131 ldb_dn_get_linearized(parent_msg->dn));
5132 return ldb_module_done(ar->req, NULL, NULL, LDB_ERR_OPERATIONS_ERROR);
5135 ret = dsdb_wellknown_dn(ldb_module_get_ctx(ar->module), msg,
5137 DS_GUID_LOSTANDFOUND_CONTAINER,
5139 if (ret != LDB_SUCCESS) {
5140 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
5141 "Unable to find LostAndFound Container for %s "
5142 "in partition %s: %s. "
5143 "We need to move this object because parent object %s "
5144 "is deleted, but this object is not.",
5145 ldb_dn_get_linearized(msg->dn), ldb_dn_get_linearized(nc_root),
5146 ldb_errstring(ldb_module_get_ctx(ar->module)),
5147 ldb_dn_get_linearized(parent_msg->dn));
5148 return ldb_module_done(ar->req, NULL, NULL, LDB_ERR_OPERATIONS_ERROR);
5150 ar->objs->objects[ar->index_current].last_known_parent
5151 = talloc_steal(ar->objs->objects[ar->index_current].msg, parent_msg->dn);
5155 = talloc_steal(ar->objs->objects[ar->index_current].msg, parent_msg->dn);
5158 ar->objs->objects[ar->index_current].local_parent_dn = parent_dn;
5160 comp_num = ldb_dn_get_comp_num(msg->dn);
5162 if (!ldb_dn_remove_base_components(msg->dn, comp_num - 1)) {
5164 return ldb_module_done(ar->req, NULL, NULL, ldb_module_operr(ar->module));
5167 if (!ldb_dn_add_base(msg->dn, parent_dn)) {
5169 return ldb_module_done(ar->req, NULL, NULL, ldb_module_operr(ar->module));
5173 case LDB_REPLY_REFERRAL:
5174 /* we ignore referrals */
5177 case LDB_REPLY_DONE:
5179 if (ar->objs->objects[ar->index_current].local_parent_dn == NULL) {
5180 struct GUID_txt_buf str_buf;
5181 if (ar->search_msg != NULL) {
5182 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
5183 "No parent with GUID %s found for object locally known as %s",
5184 GUID_buf_string(ar->objs->objects[ar->index_current].parent_guid, &str_buf),
5185 ldb_dn_get_linearized(ar->search_msg->dn));
5187 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
5188 "No parent with GUID %s found for object remotely known as %s",
5189 GUID_buf_string(ar->objs->objects[ar->index_current].parent_guid, &str_buf),
5190 ldb_dn_get_linearized(ar->objs->objects[ar->index_current].msg->dn));
5194 * This error code is really important, as it
5195 * is the flag back to the callers to retry
5196 * this with DRSUAPI_DRS_GET_ANC, and so get
5197 * the parent objects before the child
5200 return ldb_module_done(ar->req, NULL, NULL,
5201 replmd_replicated_request_werror(ar, WERR_DS_DRA_MISSING_PARENT));
5204 if (ar->search_msg != NULL) {
5205 ret = replmd_replicated_apply_merge(ar);
5207 ret = replmd_replicated_apply_add(ar);
5209 if (ret != LDB_SUCCESS) {
5210 return ldb_module_done(ar->req, NULL, NULL, ret);
5219 * Look for the parent object, so we put the new object in the right
5220 * place This is akin to NameObject in MS-DRSR - this routine and the
5221 * callbacks find the right parent name, and correct name for this
5225 static int replmd_replicated_apply_search_for_parent(struct replmd_replicated_request *ar)
5227 struct ldb_context *ldb;
5231 struct ldb_request *search_req;
5232 static const char *attrs[] = {"isDeleted", NULL};
5233 struct GUID_txt_buf guid_str_buf;
5235 ldb = ldb_module_get_ctx(ar->module);
5237 if (ar->objs->objects[ar->index_current].parent_guid == NULL) {
5238 if (ar->search_msg != NULL) {
5239 return replmd_replicated_apply_merge(ar);
5241 return replmd_replicated_apply_add(ar);
5245 tmp_str = GUID_buf_string(ar->objs->objects[ar->index_current].parent_guid,
5248 filter = talloc_asprintf(ar, "(objectGUID=%s)", tmp_str);
5249 if (!filter) return replmd_replicated_request_werror(ar, WERR_NOT_ENOUGH_MEMORY);
5251 ret = ldb_build_search_req(&search_req,
5254 ar->objs->partition_dn,
5260 replmd_replicated_apply_search_for_parent_callback,
5262 LDB_REQ_SET_LOCATION(search_req);
5264 ret = dsdb_request_add_controls(search_req,
5265 DSDB_SEARCH_SHOW_RECYCLED|
5266 DSDB_SEARCH_SHOW_DELETED|
5267 DSDB_SEARCH_SHOW_EXTENDED_DN);
5268 if (ret != LDB_SUCCESS) {
5272 return ldb_next_request(ar->module, search_req);
5276 handle renames that come in over DRS replication
5278 static int replmd_replicated_handle_rename(struct replmd_replicated_request *ar,
5279 struct ldb_message *msg,
5280 struct ldb_request *parent,
5284 TALLOC_CTX *tmp_ctx = talloc_new(msg);
5285 struct ldb_result *res;
5286 struct ldb_dn *conflict_dn;
5287 const char *attrs[] = { "replPropertyMetaData", "objectGUID", NULL };
5288 const struct ldb_val *omd_value;
5289 struct replPropertyMetaDataBlob omd, *rmd;
5290 enum ndr_err_code ndr_err;
5291 bool rename_incoming_record, rodc;
5292 struct replPropertyMetaData1 *rmd_name, *omd_name;
5293 struct ldb_dn *new_dn;
5296 DEBUG(4,("replmd_replicated_request rename %s => %s\n",
5297 ldb_dn_get_linearized(ar->search_msg->dn),
5298 ldb_dn_get_linearized(msg->dn)));
5301 ret = dsdb_module_rename(ar->module, ar->search_msg->dn, msg->dn,
5302 DSDB_FLAG_NEXT_MODULE, ar->req);
5303 if (ret == LDB_SUCCESS) {
5304 talloc_free(tmp_ctx);
5309 if (ret != LDB_ERR_ENTRY_ALREADY_EXISTS) {
5310 talloc_free(tmp_ctx);
5311 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module), "Failed to locally apply remote rename from %s to %s: %s",
5312 ldb_dn_get_linearized(ar->search_msg->dn),
5313 ldb_dn_get_linearized(msg->dn),
5314 ldb_errstring(ldb_module_get_ctx(ar->module)));
5318 ret = samdb_rodc(ldb_module_get_ctx(ar->module), &rodc);
5319 if (ret != LDB_SUCCESS) {
5320 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
5321 "Failed to determine if we are an RODC when attempting to form conflict DN: %s",
5322 ldb_errstring(ldb_module_get_ctx(ar->module)));
5323 return LDB_ERR_OPERATIONS_ERROR;
5326 * we have a conflict, and need to decide if we will keep the
5327 * new record or the old record
5330 conflict_dn = msg->dn;
5334 * We are on an RODC, or were a GC for this
5335 * partition, so we have to fail this until
5336 * someone who owns the partition sorts it
5339 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
5340 "Conflict adding object '%s' from incoming replication but we are read only for the partition. \n"
5341 " - We must fail the operation until a master for this partition resolves the conflict",
5342 ldb_dn_get_linearized(conflict_dn));
5347 * first we need the replPropertyMetaData attribute from the
5350 ret = dsdb_module_search_dn(ar->module, tmp_ctx, &res, conflict_dn,
5352 DSDB_FLAG_NEXT_MODULE |
5353 DSDB_SEARCH_SHOW_DELETED |
5354 DSDB_SEARCH_SHOW_RECYCLED, ar->req);
5355 if (ret != LDB_SUCCESS) {
5356 DEBUG(0,(__location__ ": Unable to find object for conflicting record '%s'\n",
5357 ldb_dn_get_linearized(conflict_dn)));
5361 omd_value = ldb_msg_find_ldb_val(res->msgs[0], "replPropertyMetaData");
5362 if (omd_value == NULL) {
5363 DEBUG(0,(__location__ ": Unable to find replPropertyMetaData for conflicting record '%s'\n",
5364 ldb_dn_get_linearized(conflict_dn)));
5368 ndr_err = ndr_pull_struct_blob(omd_value, res->msgs[0], &omd,
5369 (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
5370 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
5371 DEBUG(0,(__location__ ": Failed to parse old replPropertyMetaData for %s\n",
5372 ldb_dn_get_linearized(conflict_dn)));
5376 rmd = ar->objs->objects[ar->index_current].meta_data;
5379 * we decide which is newer based on the RPMD on the name
5380 * attribute. See [MS-DRSR] ResolveNameConflict.
5382 * We expect omd_name to be present, as this is from a local
5383 * search, but while rmd_name should have been given to us by
5384 * the remote server, if it is missing we just prefer the
5386 * replmd_replPropertyMetaData1_new_should_be_taken()
5388 rmd_name = replmd_replPropertyMetaData1_find_attid(rmd, DRSUAPI_ATTID_name);
5389 omd_name = replmd_replPropertyMetaData1_find_attid(&omd, DRSUAPI_ATTID_name);
5391 DEBUG(0,(__location__ ": Failed to find name attribute in local LDB replPropertyMetaData for %s\n",
5392 ldb_dn_get_linearized(conflict_dn)));
5397 * Should we preserve the current record, and so rename the
5398 * incoming record to be a conflict?
5400 rename_incoming_record =
5401 !replmd_replPropertyMetaData1_new_should_be_taken(
5402 ar->objs->dsdb_repl_flags & DSDB_REPL_FLAG_PRIORITISE_INCOMING,
5403 omd_name, rmd_name);
5405 if (rename_incoming_record) {
5407 new_dn = replmd_conflict_dn(msg, msg->dn,
5408 &ar->objs->objects[ar->index_current].object_guid);
5409 if (new_dn == NULL) {
5410 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
5411 "Failed to form conflict DN for %s\n",
5412 ldb_dn_get_linearized(msg->dn));
5414 return replmd_replicated_request_werror(ar, WERR_NOT_ENOUGH_MEMORY);
5417 ret = dsdb_module_rename(ar->module, ar->search_msg->dn, new_dn,
5418 DSDB_FLAG_NEXT_MODULE, ar->req);
5419 if (ret != LDB_SUCCESS) {
5420 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
5421 "Failed to rename incoming conflicting dn '%s' (was '%s') to '%s' - %s\n",
5422 ldb_dn_get_linearized(conflict_dn),
5423 ldb_dn_get_linearized(ar->search_msg->dn),
5424 ldb_dn_get_linearized(new_dn),
5425 ldb_errstring(ldb_module_get_ctx(ar->module)));
5426 return replmd_replicated_request_werror(ar, WERR_DS_DRA_DB_ERROR);
5434 /* we are renaming the existing record */
5436 guid = samdb_result_guid(res->msgs[0], "objectGUID");
5437 if (GUID_all_zero(&guid)) {
5438 DEBUG(0,(__location__ ": Failed to find objectGUID for existing conflict record %s\n",
5439 ldb_dn_get_linearized(conflict_dn)));
5443 new_dn = replmd_conflict_dn(tmp_ctx, conflict_dn, &guid);
5444 if (new_dn == NULL) {
5445 DEBUG(0,(__location__ ": Failed to form conflict DN for %s\n",
5446 ldb_dn_get_linearized(conflict_dn)));
5450 DEBUG(2,(__location__ ": Resolving conflict record via existing-record rename '%s' -> '%s'\n",
5451 ldb_dn_get_linearized(conflict_dn), ldb_dn_get_linearized(new_dn)));
5453 ret = dsdb_module_rename(ar->module, conflict_dn, new_dn,
5454 DSDB_FLAG_OWN_MODULE, ar->req);
5455 if (ret != LDB_SUCCESS) {
5456 DEBUG(0,(__location__ ": Failed to rename conflict dn '%s' to '%s' - %s\n",
5457 ldb_dn_get_linearized(conflict_dn),
5458 ldb_dn_get_linearized(new_dn),
5459 ldb_errstring(ldb_module_get_ctx(ar->module))));
5464 * now we need to ensure that the rename is seen as an
5465 * originating update. We do that with a modify.
5467 ret = replmd_name_modify(ar, ar->req, new_dn);
5468 if (ret != LDB_SUCCESS) {
5472 DEBUG(2,(__location__ ": With conflicting record renamed, re-apply replicated rename '%s' -> '%s'\n",
5473 ldb_dn_get_linearized(ar->search_msg->dn),
5474 ldb_dn_get_linearized(msg->dn)));
5477 ret = dsdb_module_rename(ar->module, ar->search_msg->dn, msg->dn,
5478 DSDB_FLAG_NEXT_MODULE, ar->req);
5479 if (ret != LDB_SUCCESS) {
5480 DEBUG(0,(__location__ ": After conflict resolution, failed to rename dn '%s' to '%s' - %s\n",
5481 ldb_dn_get_linearized(ar->search_msg->dn),
5482 ldb_dn_get_linearized(msg->dn),
5483 ldb_errstring(ldb_module_get_ctx(ar->module))));
5489 * On failure make the caller get the error
5490 * This means replication will stop with an error,
5491 * but there is not much else we can do. In the
5492 * LDB_ERR_ENTRY_ALREADY_EXISTS case this is exactly what is
5496 talloc_free(tmp_ctx);
5501 static int replmd_replicated_apply_merge(struct replmd_replicated_request *ar)
5503 struct ldb_context *ldb;
5504 struct ldb_request *change_req;
5505 enum ndr_err_code ndr_err;
5506 struct ldb_message *msg;
5507 struct replPropertyMetaDataBlob *rmd;
5508 struct replPropertyMetaDataBlob omd;
5509 const struct ldb_val *omd_value;
5510 struct replPropertyMetaDataBlob nmd;
5511 struct ldb_val nmd_value;
5512 struct GUID remote_parent_guid;
5515 unsigned int removed_attrs = 0;
5517 int (*callback)(struct ldb_request *req, struct ldb_reply *ares) = replmd_op_callback;
5518 bool isDeleted = false;
5519 bool local_isDeleted = false;
5520 bool remote_isDeleted = false;
5521 bool take_remote_isDeleted = false;
5522 bool sd_updated = false;
5523 bool renamed = false;
5524 bool is_schema_nc = false;
5526 const struct ldb_val *old_rdn, *new_rdn;
5527 struct replmd_private *replmd_private =
5528 talloc_get_type(ldb_module_get_private(ar->module),
5529 struct replmd_private);
5531 time_t t = time(NULL);
5532 unix_to_nt_time(&now, t);
5534 ldb = ldb_module_get_ctx(ar->module);
5535 msg = ar->objs->objects[ar->index_current].msg;
5537 is_schema_nc = ldb_dn_compare_base(replmd_private->schema_dn, msg->dn) == 0;
5539 rmd = ar->objs->objects[ar->index_current].meta_data;
5543 /* find existing meta data */
5544 omd_value = ldb_msg_find_ldb_val(ar->search_msg, "replPropertyMetaData");
5546 ndr_err = ndr_pull_struct_blob(omd_value, ar, &omd,
5547 (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
5548 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
5549 nt_status = ndr_map_error2ntstatus(ndr_err);
5550 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
5553 if (omd.version != 1) {
5554 return replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
5559 struct GUID_txt_buf guid_txt;
5561 char *s = ldb_ldif_message_redacted_string(ldb, ar,
5562 LDB_CHANGETYPE_MODIFY, msg);
5563 DEBUG(5, ("Initial DRS replication modify message of %s is:\n%s\n"
5566 GUID_buf_string(&ar->objs->objects[ar->index_current].object_guid, &guid_txt),
5568 ndr_print_struct_string(s,
5569 (ndr_print_fn_t)ndr_print_replPropertyMetaDataBlob,
5570 "existing replPropertyMetaData",
5572 ndr_print_struct_string(s,
5573 (ndr_print_fn_t)ndr_print_replPropertyMetaDataBlob,
5574 "incoming replPropertyMetaData",
5579 local_isDeleted = ldb_msg_find_attr_as_bool(ar->search_msg,
5580 "isDeleted", false);
5581 remote_isDeleted = ldb_msg_find_attr_as_bool(msg,
5582 "isDeleted", false);
5585 * Fill in the remote_parent_guid with the GUID or an all-zero
5588 if (ar->objs->objects[ar->index_current].parent_guid != NULL) {
5589 remote_parent_guid = *ar->objs->objects[ar->index_current].parent_guid;
5591 remote_parent_guid = GUID_zero();
5595 * To ensure we follow a complex rename chain around, we have
5596 * to confirm that the DN is the same (mostly to confirm the
5597 * RDN) and the parentGUID is the same.
5599 * This ensures we keep things under the correct parent, which
5600 * replmd_replicated_handle_rename() will do.
5603 if (strcmp(ldb_dn_get_linearized(msg->dn), ldb_dn_get_linearized(ar->search_msg->dn)) == 0
5604 && GUID_equal(&remote_parent_guid, &ar->local_parent_guid)) {
5608 * handle renames, even just by case that come in over
5609 * DRS. Changes in the parent DN don't hit us here,
5610 * because the search for a parent will clean up those
5613 * We also have already filtered out the case where
5614 * the peer has an older name to what we have (see
5615 * replmd_replicated_apply_search_callback())
5617 ret = replmd_replicated_handle_rename(ar, msg, ar->req, &renamed);
5620 if (ret != LDB_SUCCESS) {
5621 ldb_debug(ldb, LDB_DEBUG_FATAL,
5622 "replmd_replicated_request rename %s => %s failed - %s\n",
5623 ldb_dn_get_linearized(ar->search_msg->dn),
5624 ldb_dn_get_linearized(msg->dn),
5625 ldb_errstring(ldb));
5626 return replmd_replicated_request_werror(ar, WERR_DS_DRA_DB_ERROR);
5629 if (renamed == true) {
5631 * Set the callback to one that will fix up the name
5632 * metadata on the new conflict DN
5634 callback = replmd_op_name_modify_callback;
5639 nmd.ctr.ctr1.count = omd.ctr.ctr1.count + rmd->ctr.ctr1.count;
5640 nmd.ctr.ctr1.array = talloc_array(ar,
5641 struct replPropertyMetaData1,
5642 nmd.ctr.ctr1.count);
5643 if (!nmd.ctr.ctr1.array) return replmd_replicated_request_werror(ar, WERR_NOT_ENOUGH_MEMORY);
5645 /* first copy the old meta data */
5646 for (i=0; i < omd.ctr.ctr1.count; i++) {
5647 nmd.ctr.ctr1.array[ni] = omd.ctr.ctr1.array[i];
5652 /* now merge in the new meta data */
5653 for (i=0; i < rmd->ctr.ctr1.count; i++) {
5656 for (j=0; j < ni; j++) {
5659 if (rmd->ctr.ctr1.array[i].attid != nmd.ctr.ctr1.array[j].attid) {
5663 cmp = replmd_replPropertyMetaData1_new_should_be_taken(
5664 ar->objs->dsdb_repl_flags,
5665 &nmd.ctr.ctr1.array[j],
5666 &rmd->ctr.ctr1.array[i]);
5668 /* replace the entry */
5669 nmd.ctr.ctr1.array[j] = rmd->ctr.ctr1.array[i];
5670 if (ar->seq_num == 0) {
5671 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &ar->seq_num);
5672 if (ret != LDB_SUCCESS) {
5673 return replmd_replicated_request_error(ar, ret);
5676 nmd.ctr.ctr1.array[j].local_usn = ar->seq_num;
5677 switch (nmd.ctr.ctr1.array[j].attid) {
5678 case DRSUAPI_ATTID_ntSecurityDescriptor:
5681 case DRSUAPI_ATTID_isDeleted:
5682 take_remote_isDeleted = true;
5691 if (rmd->ctr.ctr1.array[i].attid != DRSUAPI_ATTID_instanceType) {
5692 DEBUG(3,("Discarding older DRS attribute update to %s on %s from %s\n",
5693 msg->elements[i-removed_attrs].name,
5694 ldb_dn_get_linearized(msg->dn),
5695 GUID_string(ar, &rmd->ctr.ctr1.array[i].originating_invocation_id)));
5698 /* we don't want to apply this change so remove the attribute */
5699 ldb_msg_remove_element(msg, &msg->elements[i-removed_attrs]);
5706 if (found) continue;
5708 nmd.ctr.ctr1.array[ni] = rmd->ctr.ctr1.array[i];
5709 if (ar->seq_num == 0) {
5710 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &ar->seq_num);
5711 if (ret != LDB_SUCCESS) {
5712 return replmd_replicated_request_error(ar, ret);
5715 nmd.ctr.ctr1.array[ni].local_usn = ar->seq_num;
5716 switch (nmd.ctr.ctr1.array[ni].attid) {
5717 case DRSUAPI_ATTID_ntSecurityDescriptor:
5720 case DRSUAPI_ATTID_isDeleted:
5721 take_remote_isDeleted = true;
5730 * finally correct the size of the meta_data array
5732 nmd.ctr.ctr1.count = ni;
5734 new_rdn = ldb_dn_get_rdn_val(msg->dn);
5735 old_rdn = ldb_dn_get_rdn_val(ar->search_msg->dn);
5738 ret = replmd_update_rpmd_rdn_attr(ldb, msg, new_rdn, old_rdn,
5739 &nmd, ar, now, is_schema_nc,
5741 if (ret != LDB_SUCCESS) {
5742 ldb_asprintf_errstring(ldb, "%s: error during DRS repl merge: %s", __func__, ldb_errstring(ldb));
5743 return replmd_replicated_request_error(ar, ret);
5747 * sort the new meta data array
5749 ret = replmd_replPropertyMetaDataCtr1_sort_and_verify(ldb, &nmd.ctr.ctr1, msg->dn);
5750 if (ret != LDB_SUCCESS) {
5751 ldb_asprintf_errstring(ldb, "%s: error during DRS repl merge: %s", __func__, ldb_errstring(ldb));
5756 * Work out if this object is deleted, so we can prune any extra attributes. See MS-DRSR 4.1.10.6.9
5759 * This also controls SD propagation below
5761 if (take_remote_isDeleted) {
5762 isDeleted = remote_isDeleted;
5764 isDeleted = local_isDeleted;
5767 ar->isDeleted = isDeleted;
5770 * check if some replicated attributes left, otherwise skip the ldb_modify() call
5772 if (msg->num_elements == 0) {
5773 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_replicated_apply_merge[%u]: skip replace\n",
5776 return replmd_replicated_apply_isDeleted(ar);
5779 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_replicated_apply_merge[%u]: replace %u attributes\n",
5780 ar->index_current, msg->num_elements);
5786 if (sd_updated && !isDeleted) {
5787 ret = dsdb_module_schedule_sd_propagation(ar->module,
5788 ar->objs->partition_dn,
5790 if (ret != LDB_SUCCESS) {
5791 return ldb_operr(ldb);
5795 /* create the meta data value */
5796 ndr_err = ndr_push_struct_blob(&nmd_value, msg, &nmd,
5797 (ndr_push_flags_fn_t)ndr_push_replPropertyMetaDataBlob);
5798 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
5799 nt_status = ndr_map_error2ntstatus(ndr_err);
5800 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
5804 * when we know that we'll modify the record, add the whenChanged, uSNChanged
5805 * and replPopertyMetaData attributes
5807 ret = ldb_msg_add_string(msg, "whenChanged", ar->objs->objects[ar->index_current].when_changed);
5808 if (ret != LDB_SUCCESS) {
5809 return replmd_replicated_request_error(ar, ret);
5811 ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNChanged", ar->seq_num);
5812 if (ret != LDB_SUCCESS) {
5813 return replmd_replicated_request_error(ar, ret);
5815 ret = ldb_msg_add_value(msg, "replPropertyMetaData", &nmd_value, NULL);
5816 if (ret != LDB_SUCCESS) {
5817 return replmd_replicated_request_error(ar, ret);
5820 replmd_ldb_message_sort(msg, ar->schema);
5822 /* we want to replace the old values */
5823 for (i=0; i < msg->num_elements; i++) {
5824 msg->elements[i].flags = LDB_FLAG_MOD_REPLACE;
5825 if (ldb_attr_cmp(msg->elements[i].name, "objectClass") == 0) {
5826 if (msg->elements[i].num_values == 0) {
5827 ldb_asprintf_errstring(ldb, __location__
5828 ": objectClass removed on %s, aborting replication\n",
5829 ldb_dn_get_linearized(msg->dn));
5830 return replmd_replicated_request_error(ar, LDB_ERR_OBJECT_CLASS_VIOLATION);
5836 struct GUID_txt_buf guid_txt;
5838 char *s = ldb_ldif_message_redacted_string(ldb, ar,
5839 LDB_CHANGETYPE_MODIFY,
5841 DEBUG(4, ("Final DRS replication modify message of %s:\n%s\n",
5842 GUID_buf_string(&ar->objs->objects[ar->index_current].object_guid, &guid_txt),
5847 ret = ldb_build_mod_req(&change_req,
5855 LDB_REQ_SET_LOCATION(change_req);
5856 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
5858 /* current partition control needed by "repmd_op_callback" */
5859 ret = ldb_request_add_control(change_req,
5860 DSDB_CONTROL_CURRENT_PARTITION_OID,
5862 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
5864 return ldb_next_request(ar->module, change_req);
5867 static int replmd_replicated_apply_search_callback(struct ldb_request *req,
5868 struct ldb_reply *ares)
5870 struct replmd_replicated_request *ar = talloc_get_type(req->context,
5871 struct replmd_replicated_request);
5875 return ldb_module_done(ar->req, NULL, NULL,
5876 LDB_ERR_OPERATIONS_ERROR);
5878 if (ares->error != LDB_SUCCESS &&
5879 ares->error != LDB_ERR_NO_SUCH_OBJECT) {
5880 return ldb_module_done(ar->req, ares->controls,
5881 ares->response, ares->error);
5884 switch (ares->type) {
5885 case LDB_REPLY_ENTRY:
5886 ar->search_msg = talloc_steal(ar, ares->message);
5889 case LDB_REPLY_REFERRAL:
5890 /* we ignore referrals */
5893 case LDB_REPLY_DONE:
5895 struct replPropertyMetaData1 *md_remote;
5896 struct replPropertyMetaData1 *md_local;
5898 struct replPropertyMetaDataBlob omd;
5899 const struct ldb_val *omd_value;
5900 struct replPropertyMetaDataBlob *rmd;
5901 struct ldb_message *msg;
5903 ar->objs->objects[ar->index_current].local_parent_dn = NULL;
5904 ar->objs->objects[ar->index_current].last_known_parent = NULL;
5907 * This is the ADD case, find the appropriate parent,
5908 * as this object doesn't exist locally:
5910 if (ar->search_msg == NULL) {
5911 ret = replmd_replicated_apply_search_for_parent(ar);
5912 if (ret != LDB_SUCCESS) {
5913 return ldb_module_done(ar->req, NULL, NULL, ret);
5920 * Otherwise, in the MERGE case, work out if we are
5921 * attempting a rename, and if so find the parent the
5922 * newly renamed object wants to belong under (which
5923 * may not be the parent in it's attached string DN
5925 rmd = ar->objs->objects[ar->index_current].meta_data;
5929 /* find existing meta data */
5930 omd_value = ldb_msg_find_ldb_val(ar->search_msg, "replPropertyMetaData");
5932 enum ndr_err_code ndr_err;
5933 ndr_err = ndr_pull_struct_blob(omd_value, ar, &omd,
5934 (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
5935 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
5936 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
5937 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
5940 if (omd.version != 1) {
5941 return replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
5945 ar->local_parent_guid = samdb_result_guid(ar->search_msg, "parentGUID");
5947 instanceType = ldb_msg_find_attr_as_int(ar->search_msg, "instanceType", 0);
5948 if (((instanceType & INSTANCE_TYPE_IS_NC_HEAD) == 0)
5949 && GUID_all_zero(&ar->local_parent_guid)) {
5950 DEBUG(0, ("Refusing to replicate new version of %s "
5951 "as local object has an all-zero parentGUID attribute, "
5952 "despite not being an NC root\n",
5953 ldb_dn_get_linearized(ar->search_msg->dn)));
5954 return replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
5958 * now we need to check for double renames. We could have a
5959 * local rename pending which our replication partner hasn't
5960 * received yet. We choose which one wins by looking at the
5961 * attribute stamps on the two objects, the newer one wins.
5963 * This also simply applies the correct algorithms for
5964 * determining if a change was made to name at all, or
5965 * if the object has just been renamed under the same
5968 md_remote = replmd_replPropertyMetaData1_find_attid(rmd, DRSUAPI_ATTID_name);
5969 md_local = replmd_replPropertyMetaData1_find_attid(&omd, DRSUAPI_ATTID_name);
5971 DEBUG(0,(__location__ ": Failed to find name attribute in local LDB replPropertyMetaData for %s\n",
5972 ldb_dn_get_linearized(ar->search_msg->dn)));
5973 return replmd_replicated_request_werror(ar, WERR_DS_DRA_DB_ERROR);
5977 * if there is no name attribute given then we have to assume the
5978 * object we've received has the older name
5980 if (replmd_replPropertyMetaData1_new_should_be_taken(
5981 ar->objs->dsdb_repl_flags & DSDB_REPL_FLAG_PRIORITISE_INCOMING,
5982 md_local, md_remote)) {
5983 struct GUID_txt_buf p_guid_local;
5984 struct GUID_txt_buf p_guid_remote;
5985 msg = ar->objs->objects[ar->index_current].msg;
5987 /* Merge on the existing object, with rename */
5989 DEBUG(4,(__location__ ": Looking for new parent for object %s currently under %s "
5990 "as incoming object changing to %s under %s\n",
5991 ldb_dn_get_linearized(ar->search_msg->dn),
5992 GUID_buf_string(&ar->local_parent_guid, &p_guid_local),
5993 ldb_dn_get_linearized(msg->dn),
5994 GUID_buf_string(ar->objs->objects[ar->index_current].parent_guid,
5996 ret = replmd_replicated_apply_search_for_parent(ar);
5998 struct GUID_txt_buf p_guid_local;
5999 struct GUID_txt_buf p_guid_remote;
6000 msg = ar->objs->objects[ar->index_current].msg;
6003 * Merge on the existing object, force no
6004 * rename (code below just to explain why in
6008 if (strcmp(ldb_dn_get_linearized(ar->search_msg->dn),
6009 ldb_dn_get_linearized(msg->dn)) == 0) {
6010 if (ar->objs->objects[ar->index_current].parent_guid != NULL &&
6011 GUID_equal(&ar->local_parent_guid,
6012 ar->objs->objects[ar->index_current].parent_guid)
6014 DEBUG(4,(__location__ ": Keeping object %s at under %s "
6015 "despite incoming object changing parent to %s\n",
6016 ldb_dn_get_linearized(ar->search_msg->dn),
6017 GUID_buf_string(&ar->local_parent_guid, &p_guid_local),
6018 GUID_buf_string(ar->objs->objects[ar->index_current].parent_guid,
6022 DEBUG(4,(__location__ ": Keeping object %s at under %s "
6023 " and rejecting older rename to %s under %s\n",
6024 ldb_dn_get_linearized(ar->search_msg->dn),
6025 GUID_buf_string(&ar->local_parent_guid, &p_guid_local),
6026 ldb_dn_get_linearized(msg->dn),
6027 GUID_buf_string(ar->objs->objects[ar->index_current].parent_guid,
6031 * This assignment ensures that the strcmp()
6032 * and GUID_equal() calls in
6033 * replmd_replicated_apply_merge() avoids the
6036 ar->objs->objects[ar->index_current].parent_guid =
6037 &ar->local_parent_guid;
6039 msg->dn = ar->search_msg->dn;
6040 ret = replmd_replicated_apply_merge(ar);
6042 if (ret != LDB_SUCCESS) {
6043 return ldb_module_done(ar->req, NULL, NULL, ret);
6053 * Stores the linked attributes received in the replication chunk - these get
6054 * applied at the end of the transaction. We also check that each linked
6055 * attribute is valid, i.e. source and target objects are known.
6057 static int replmd_store_linked_attributes(struct replmd_replicated_request *ar)
6059 int ret = LDB_SUCCESS;
6061 struct ldb_module *module = ar->module;
6062 struct replmd_private *replmd_private =
6063 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
6064 struct ldb_context *ldb;
6066 ldb = ldb_module_get_ctx(module);
6068 DEBUG(4,("linked_attributes_count=%u\n", ar->objs->linked_attributes_count));
6070 /* save away the linked attributes for the end of the transaction */
6071 for (i = 0; i < ar->objs->linked_attributes_count; i++) {
6072 struct la_entry *la_entry;
6074 if (replmd_private->la_ctx == NULL) {
6075 replmd_private->la_ctx = talloc_new(replmd_private);
6077 la_entry = talloc(replmd_private->la_ctx, struct la_entry);
6078 if (la_entry == NULL) {
6080 return LDB_ERR_OPERATIONS_ERROR;
6082 la_entry->la = talloc(la_entry, struct drsuapi_DsReplicaLinkedAttribute);
6083 if (la_entry->la == NULL) {
6084 talloc_free(la_entry);
6086 return LDB_ERR_OPERATIONS_ERROR;
6088 *la_entry->la = ar->objs->linked_attributes[i];
6089 la_entry->dsdb_repl_flags = ar->objs->dsdb_repl_flags;
6091 /* we need to steal the non-scalars so they stay
6092 around until the end of the transaction */
6093 talloc_steal(la_entry->la, la_entry->la->identifier);
6094 talloc_steal(la_entry->la, la_entry->la->value.blob);
6096 ret = replmd_verify_linked_attribute(ar, la_entry);
6098 if (ret != LDB_SUCCESS) {
6102 DLIST_ADD(replmd_private->la_list, la_entry);
6108 static int replmd_replicated_uptodate_vector(struct replmd_replicated_request *ar);
6110 static int replmd_replicated_apply_next(struct replmd_replicated_request *ar)
6112 struct ldb_context *ldb;
6116 struct ldb_request *search_req;
6117 static const char *attrs[] = { "repsFrom", "replUpToDateVector",
6118 "parentGUID", "instanceType",
6119 "replPropertyMetaData", "nTSecurityDescriptor",
6120 "isDeleted", NULL };
6121 struct GUID_txt_buf guid_str_buf;
6123 if (ar->index_current >= ar->objs->num_objects) {
6126 * Now that we've applied all the objects, check the new linked
6127 * attributes and store them (we apply them in .prepare_commit)
6129 ret = replmd_store_linked_attributes(ar);
6131 if (ret != LDB_SUCCESS) {
6135 /* done applying objects, move on to the next stage */
6136 return replmd_replicated_uptodate_vector(ar);
6139 ldb = ldb_module_get_ctx(ar->module);
6140 ar->search_msg = NULL;
6141 ar->isDeleted = false;
6143 tmp_str = GUID_buf_string(&ar->objs->objects[ar->index_current].object_guid,
6146 filter = talloc_asprintf(ar, "(objectGUID=%s)", tmp_str);
6147 if (!filter) return replmd_replicated_request_werror(ar, WERR_NOT_ENOUGH_MEMORY);
6149 ret = ldb_build_search_req(&search_req,
6152 ar->objs->partition_dn,
6158 replmd_replicated_apply_search_callback,
6160 LDB_REQ_SET_LOCATION(search_req);
6162 ret = dsdb_request_add_controls(search_req, DSDB_SEARCH_SHOW_RECYCLED);
6164 if (ret != LDB_SUCCESS) {
6168 return ldb_next_request(ar->module, search_req);
6172 * This is essentially a wrapper for replmd_replicated_apply_next()
6174 * This is needed to ensure that both codepaths call this handler.
6176 static int replmd_replicated_apply_isDeleted(struct replmd_replicated_request *ar)
6178 struct ldb_dn *deleted_objects_dn;
6179 struct ldb_message *msg = ar->objs->objects[ar->index_current].msg;
6180 int ret = dsdb_get_deleted_objects_dn(ldb_module_get_ctx(ar->module), msg, msg->dn,
6181 &deleted_objects_dn);
6182 if (ar->isDeleted && (ret != LDB_SUCCESS || ldb_dn_compare(msg->dn, deleted_objects_dn) != 0)) {
6184 * Do a delete here again, so that if there is
6185 * anything local that conflicts with this
6186 * object being deleted, it is removed. This
6187 * includes links. See MS-DRSR 4.1.10.6.9
6190 * If the object is already deleted, and there
6191 * is no more work required, it doesn't do
6195 /* This has been updated to point to the DN we eventually did the modify on */
6197 struct ldb_request *del_req;
6198 struct ldb_result *res;
6200 TALLOC_CTX *tmp_ctx = talloc_new(ar);
6202 ret = ldb_oom(ldb_module_get_ctx(ar->module));
6206 res = talloc_zero(tmp_ctx, struct ldb_result);
6208 ret = ldb_oom(ldb_module_get_ctx(ar->module));
6209 talloc_free(tmp_ctx);
6213 /* Build a delete request, which hopefully will artually turn into nothing */
6214 ret = ldb_build_del_req(&del_req, ldb_module_get_ctx(ar->module), tmp_ctx,
6218 ldb_modify_default_callback,
6220 LDB_REQ_SET_LOCATION(del_req);
6221 if (ret != LDB_SUCCESS) {
6222 talloc_free(tmp_ctx);
6227 * This is the guts of the call, call back
6228 * into our delete code, but setting the
6229 * re_delete flag so we delete anything that
6230 * shouldn't be there on a deleted or recycled
6233 ret = replmd_delete_internals(ar->module, del_req, true);
6234 if (ret == LDB_SUCCESS) {
6235 ret = ldb_wait(del_req->handle, LDB_WAIT_ALL);
6238 talloc_free(tmp_ctx);
6239 if (ret != LDB_SUCCESS) {
6244 ar->index_current++;
6245 return replmd_replicated_apply_next(ar);
6248 static int replmd_replicated_uptodate_modify_callback(struct ldb_request *req,
6249 struct ldb_reply *ares)
6251 struct ldb_context *ldb;
6252 struct replmd_replicated_request *ar = talloc_get_type(req->context,
6253 struct replmd_replicated_request);
6254 ldb = ldb_module_get_ctx(ar->module);
6257 return ldb_module_done(ar->req, NULL, NULL,
6258 LDB_ERR_OPERATIONS_ERROR);
6260 if (ares->error != LDB_SUCCESS) {
6261 return ldb_module_done(ar->req, ares->controls,
6262 ares->response, ares->error);
6265 if (ares->type != LDB_REPLY_DONE) {
6266 ldb_asprintf_errstring(ldb, "Invalid LDB reply type %d", ares->type);
6267 return ldb_module_done(ar->req, NULL, NULL,
6268 LDB_ERR_OPERATIONS_ERROR);
6273 return ldb_module_done(ar->req, NULL, NULL, LDB_SUCCESS);
6276 static int replmd_replicated_uptodate_modify(struct replmd_replicated_request *ar)
6278 struct ldb_context *ldb;
6279 struct ldb_request *change_req;
6280 enum ndr_err_code ndr_err;
6281 struct ldb_message *msg;
6282 struct replUpToDateVectorBlob ouv;
6283 const struct ldb_val *ouv_value;
6284 const struct drsuapi_DsReplicaCursor2CtrEx *ruv;
6285 struct replUpToDateVectorBlob nuv;
6286 struct ldb_val nuv_value;
6287 struct ldb_message_element *nuv_el = NULL;
6288 struct ldb_message_element *orf_el = NULL;
6289 struct repsFromToBlob nrf;
6290 struct ldb_val *nrf_value = NULL;
6291 struct ldb_message_element *nrf_el = NULL;
6295 time_t t = time(NULL);
6298 uint32_t instanceType;
6300 ldb = ldb_module_get_ctx(ar->module);
6301 ruv = ar->objs->uptodateness_vector;
6307 unix_to_nt_time(&now, t);
6309 if (ar->search_msg == NULL) {
6310 /* this happens for a REPL_OBJ call where we are
6311 creating the target object by replicating it. The
6312 subdomain join code does this for the partition DN
6314 DEBUG(4,(__location__ ": Skipping UDV and repsFrom update as no target DN\n"));
6315 return ldb_module_done(ar->req, NULL, NULL, LDB_SUCCESS);
6318 instanceType = ldb_msg_find_attr_as_uint(ar->search_msg, "instanceType", 0);
6319 if (! (instanceType & INSTANCE_TYPE_IS_NC_HEAD)) {
6320 DEBUG(4,(__location__ ": Skipping UDV and repsFrom update as not NC root: %s\n",
6321 ldb_dn_get_linearized(ar->search_msg->dn)));
6322 return ldb_module_done(ar->req, NULL, NULL, LDB_SUCCESS);
6326 * first create the new replUpToDateVector
6328 ouv_value = ldb_msg_find_ldb_val(ar->search_msg, "replUpToDateVector");
6330 ndr_err = ndr_pull_struct_blob(ouv_value, ar, &ouv,
6331 (ndr_pull_flags_fn_t)ndr_pull_replUpToDateVectorBlob);
6332 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
6333 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
6334 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
6337 if (ouv.version != 2) {
6338 return replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
6343 * the new uptodateness vector will at least
6344 * contain 1 entry, one for the source_dsa
6346 * plus optional values from our old vector and the one from the source_dsa
6348 nuv.ctr.ctr2.count = ouv.ctr.ctr2.count;
6349 if (ruv) nuv.ctr.ctr2.count += ruv->count;
6350 nuv.ctr.ctr2.cursors = talloc_array(ar,
6351 struct drsuapi_DsReplicaCursor2,
6352 nuv.ctr.ctr2.count);
6353 if (!nuv.ctr.ctr2.cursors) return replmd_replicated_request_werror(ar, WERR_NOT_ENOUGH_MEMORY);
6355 /* first copy the old vector */
6356 for (i=0; i < ouv.ctr.ctr2.count; i++) {
6357 nuv.ctr.ctr2.cursors[ni] = ouv.ctr.ctr2.cursors[i];
6361 /* merge in the source_dsa vector is available */
6362 for (i=0; (ruv && i < ruv->count); i++) {
6365 if (GUID_equal(&ruv->cursors[i].source_dsa_invocation_id,
6366 &ar->our_invocation_id)) {
6370 for (j=0; j < ni; j++) {
6371 if (!GUID_equal(&ruv->cursors[i].source_dsa_invocation_id,
6372 &nuv.ctr.ctr2.cursors[j].source_dsa_invocation_id)) {
6378 if (ruv->cursors[i].highest_usn > nuv.ctr.ctr2.cursors[j].highest_usn) {
6379 nuv.ctr.ctr2.cursors[j] = ruv->cursors[i];
6384 if (found) continue;
6386 /* if it's not there yet, add it */
6387 nuv.ctr.ctr2.cursors[ni] = ruv->cursors[i];
6392 * finally correct the size of the cursors array
6394 nuv.ctr.ctr2.count = ni;
6399 TYPESAFE_QSORT(nuv.ctr.ctr2.cursors, nuv.ctr.ctr2.count, drsuapi_DsReplicaCursor2_compare);
6402 * create the change ldb_message
6404 msg = ldb_msg_new(ar);
6405 if (!msg) return replmd_replicated_request_werror(ar, WERR_NOT_ENOUGH_MEMORY);
6406 msg->dn = ar->search_msg->dn;
6408 ndr_err = ndr_push_struct_blob(&nuv_value, msg, &nuv,
6409 (ndr_push_flags_fn_t)ndr_push_replUpToDateVectorBlob);
6410 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
6411 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
6412 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
6414 ret = ldb_msg_add_value(msg, "replUpToDateVector", &nuv_value, &nuv_el);
6415 if (ret != LDB_SUCCESS) {
6416 return replmd_replicated_request_error(ar, ret);
6418 nuv_el->flags = LDB_FLAG_MOD_REPLACE;
6421 * now create the new repsFrom value from the given repsFromTo1 structure
6425 nrf.ctr.ctr1 = *ar->objs->source_dsa;
6426 nrf.ctr.ctr1.last_attempt = now;
6427 nrf.ctr.ctr1.last_success = now;
6428 nrf.ctr.ctr1.result_last_attempt = WERR_OK;
6431 * first see if we already have a repsFrom value for the current source dsa
6432 * if so we'll later replace this value
6434 orf_el = ldb_msg_find_element(ar->search_msg, "repsFrom");
6436 for (i=0; i < orf_el->num_values; i++) {
6437 struct repsFromToBlob *trf;
6439 trf = talloc(ar, struct repsFromToBlob);
6440 if (!trf) return replmd_replicated_request_werror(ar, WERR_NOT_ENOUGH_MEMORY);
6442 ndr_err = ndr_pull_struct_blob(&orf_el->values[i], trf, trf,
6443 (ndr_pull_flags_fn_t)ndr_pull_repsFromToBlob);
6444 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
6445 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
6446 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
6449 if (trf->version != 1) {
6450 return replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
6454 * we compare the source dsa objectGUID not the invocation_id
6455 * because we want only one repsFrom value per source dsa
6456 * and when the invocation_id of the source dsa has changed we don't need
6457 * the old repsFrom with the old invocation_id
6459 if (!GUID_equal(&trf->ctr.ctr1.source_dsa_obj_guid,
6460 &ar->objs->source_dsa->source_dsa_obj_guid)) {
6466 nrf_value = &orf_el->values[i];
6471 * copy over all old values to the new ldb_message
6473 ret = ldb_msg_add_empty(msg, "repsFrom", 0, &nrf_el);
6474 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
6479 * if we haven't found an old repsFrom value for the current source dsa
6480 * we'll add a new value
6483 struct ldb_val zero_value;
6484 ZERO_STRUCT(zero_value);
6485 ret = ldb_msg_add_value(msg, "repsFrom", &zero_value, &nrf_el);
6486 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
6488 nrf_value = &nrf_el->values[nrf_el->num_values - 1];
6491 /* we now fill the value which is already attached to ldb_message */
6492 ndr_err = ndr_push_struct_blob(nrf_value, msg,
6494 (ndr_push_flags_fn_t)ndr_push_repsFromToBlob);
6495 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
6496 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
6497 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
6501 * the ldb_message_element for the attribute, has all the old values and the new one
6502 * so we'll replace the whole attribute with all values
6504 nrf_el->flags = LDB_FLAG_MOD_REPLACE;
6506 if (CHECK_DEBUGLVL(4)) {
6507 char *s = ldb_ldif_message_redacted_string(ldb, ar,
6508 LDB_CHANGETYPE_MODIFY,
6510 DEBUG(4, ("DRS replication uptodate modify message:\n%s\n", s));
6514 /* prepare the ldb_modify() request */
6515 ret = ldb_build_mod_req(&change_req,
6521 replmd_replicated_uptodate_modify_callback,
6523 LDB_REQ_SET_LOCATION(change_req);
6524 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
6526 return ldb_next_request(ar->module, change_req);
6529 static int replmd_replicated_uptodate_search_callback(struct ldb_request *req,
6530 struct ldb_reply *ares)
6532 struct replmd_replicated_request *ar = talloc_get_type(req->context,
6533 struct replmd_replicated_request);
6537 return ldb_module_done(ar->req, NULL, NULL,
6538 LDB_ERR_OPERATIONS_ERROR);
6540 if (ares->error != LDB_SUCCESS &&
6541 ares->error != LDB_ERR_NO_SUCH_OBJECT) {
6542 return ldb_module_done(ar->req, ares->controls,
6543 ares->response, ares->error);
6546 switch (ares->type) {
6547 case LDB_REPLY_ENTRY:
6548 ar->search_msg = talloc_steal(ar, ares->message);
6551 case LDB_REPLY_REFERRAL:
6552 /* we ignore referrals */
6555 case LDB_REPLY_DONE:
6556 ret = replmd_replicated_uptodate_modify(ar);
6557 if (ret != LDB_SUCCESS) {
6558 return ldb_module_done(ar->req, NULL, NULL, ret);
6567 static int replmd_replicated_uptodate_vector(struct replmd_replicated_request *ar)
6569 struct ldb_context *ldb = ldb_module_get_ctx(ar->module);
6570 struct replmd_private *replmd_private =
6571 talloc_get_type_abort(ldb_module_get_private(ar->module),
6572 struct replmd_private);
6574 static const char *attrs[] = {
6575 "replUpToDateVector",
6580 struct ldb_request *search_req;
6582 ar->search_msg = NULL;
6585 * Let the caller know that we did an originating updates
6587 ar->objs->originating_updates = replmd_private->originating_updates;
6589 ret = ldb_build_search_req(&search_req,
6592 ar->objs->partition_dn,
6598 replmd_replicated_uptodate_search_callback,
6600 LDB_REQ_SET_LOCATION(search_req);
6601 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
6603 return ldb_next_request(ar->module, search_req);
6608 static int replmd_extended_replicated_objects(struct ldb_module *module, struct ldb_request *req)
6610 struct ldb_context *ldb;
6611 struct dsdb_extended_replicated_objects *objs;
6612 struct replmd_replicated_request *ar;
6613 struct ldb_control **ctrls;
6616 ldb = ldb_module_get_ctx(module);
6618 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_extended_replicated_objects\n");
6620 objs = talloc_get_type(req->op.extended.data, struct dsdb_extended_replicated_objects);
6622 ldb_debug(ldb, LDB_DEBUG_FATAL, "replmd_extended_replicated_objects: invalid extended data\n");
6623 return LDB_ERR_PROTOCOL_ERROR;
6626 if (objs->version != DSDB_EXTENDED_REPLICATED_OBJECTS_VERSION) {
6627 ldb_debug(ldb, LDB_DEBUG_FATAL, "replmd_extended_replicated_objects: extended data invalid version [%u != %u]\n",
6628 objs->version, DSDB_EXTENDED_REPLICATED_OBJECTS_VERSION);
6629 return LDB_ERR_PROTOCOL_ERROR;
6632 ar = replmd_ctx_init(module, req);
6634 return LDB_ERR_OPERATIONS_ERROR;
6636 /* Set the flags to have the replmd_op_callback run over the full set of objects */
6637 ar->apply_mode = true;
6639 ar->schema = dsdb_get_schema(ldb, ar);
6641 ldb_debug_set(ldb, LDB_DEBUG_FATAL, "replmd_ctx_init: no loaded schema found\n");
6643 DEBUG(0,(__location__ ": %s\n", ldb_errstring(ldb)));
6644 return LDB_ERR_CONSTRAINT_VIOLATION;
6647 ctrls = req->controls;
6649 if (req->controls) {
6650 req->controls = talloc_memdup(ar, req->controls,
6651 talloc_get_size(req->controls));
6652 if (!req->controls) return replmd_replicated_request_werror(ar, WERR_NOT_ENOUGH_MEMORY);
6655 ret = ldb_request_add_control(req, DSDB_CONTROL_REPLICATED_UPDATE_OID, false, NULL);
6656 if (ret != LDB_SUCCESS) {
6660 /* If this change contained linked attributes in the body
6661 * (rather than in the links section) we need to update
6662 * backlinks in linked_attributes */
6663 ret = ldb_request_add_control(req, DSDB_CONTROL_APPLY_LINKS, false, NULL);
6664 if (ret != LDB_SUCCESS) {
6668 ar->controls = req->controls;
6669 req->controls = ctrls;
6671 return replmd_replicated_apply_next(ar);
6675 * Returns True if the source and target DNs both have the same naming context,
6676 * i.e. they're both in the same partition.
6678 static bool replmd_objects_have_same_nc(struct ldb_context *ldb,
6679 TALLOC_CTX *mem_ctx,
6680 struct ldb_dn *source_dn,
6681 struct ldb_dn *target_dn)
6683 TALLOC_CTX *tmp_ctx;
6684 struct ldb_dn *source_nc;
6685 struct ldb_dn *target_nc;
6687 bool same_nc = true;
6689 tmp_ctx = talloc_new(mem_ctx);
6691 ret = dsdb_find_nc_root(ldb, tmp_ctx, source_dn, &source_nc);
6692 if (ret != LDB_SUCCESS) {
6693 DBG_ERR("Failed to find base DN for source %s\n",
6694 ldb_dn_get_linearized(source_dn));
6695 talloc_free(tmp_ctx);
6699 ret = dsdb_find_nc_root(ldb, tmp_ctx, target_dn, &target_nc);
6700 if (ret != LDB_SUCCESS) {
6701 DBG_ERR("Failed to find base DN for target %s\n",
6702 ldb_dn_get_linearized(target_dn));
6703 talloc_free(tmp_ctx);
6707 same_nc = (ldb_dn_compare(source_nc, target_nc) == 0);
6709 talloc_free(tmp_ctx);
6715 * Checks that the target object for a linked attribute exists.
6716 * @param guid returns the target object's GUID (is returned)if it exists)
6717 * @param ignore_link set to true if the linked attribute should be ignored
6718 * (i.e. the target doesn't exist, but that it's OK to skip the link)
6720 static int replmd_check_target_exists(struct ldb_module *module,
6721 struct dsdb_dn *dsdb_dn,
6722 struct la_entry *la_entry,
6723 struct ldb_dn *source_dn,
6727 struct drsuapi_DsReplicaLinkedAttribute *la = la_entry->la;
6728 struct ldb_context *ldb = ldb_module_get_ctx(module);
6729 struct ldb_result *target_res;
6730 TALLOC_CTX *tmp_ctx = talloc_new(la_entry);
6731 const char *attrs[] = { "isDeleted", "isRecycled", NULL };
6734 enum deletion_state target_deletion_state = OBJECT_REMOVED;
6735 bool active = (la->flags & DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE) ? true : false;
6737 *ignore_link = false;
6738 ntstatus = dsdb_get_extended_dn_guid(dsdb_dn->dn, guid, "GUID");
6740 if (!NT_STATUS_IS_OK(ntstatus) && !active) {
6743 * This strange behaviour (allowing a NULL/missing
6744 * GUID) originally comes from:
6746 * commit e3054ce0fe0f8f62d2f5b2a77893e7a1479128bd
6747 * Author: Andrew Tridgell <tridge@samba.org>
6748 * Date: Mon Dec 21 21:21:55 2009 +1100
6750 * s4-drs: cope better with NULL GUIDS from DRS
6752 * It is valid to get a NULL GUID over DRS for a deleted forward link. We
6753 * need to match by DN if possible when seeing if we should update an
6756 * Pair-Programmed-With: Andrew Bartlett <abartlet@samba.org>
6758 ret = dsdb_module_search_dn(module, tmp_ctx, &target_res,
6760 DSDB_FLAG_NEXT_MODULE |
6761 DSDB_SEARCH_SHOW_RECYCLED |
6762 DSDB_SEARCH_SEARCH_ALL_PARTITIONS |
6763 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT,
6765 } else if (!NT_STATUS_IS_OK(ntstatus)) {
6766 ldb_asprintf_errstring(ldb, "Failed to find GUID in linked attribute 0x%x blob for %s from %s",
6768 ldb_dn_get_linearized(dsdb_dn->dn),
6769 ldb_dn_get_linearized(source_dn));
6770 talloc_free(tmp_ctx);
6771 return LDB_ERR_OPERATIONS_ERROR;
6773 ret = dsdb_module_search(module, tmp_ctx, &target_res,
6774 NULL, LDB_SCOPE_SUBTREE,
6776 DSDB_FLAG_NEXT_MODULE |
6777 DSDB_SEARCH_SHOW_RECYCLED |
6778 DSDB_SEARCH_SEARCH_ALL_PARTITIONS |
6779 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT,
6782 GUID_string(tmp_ctx, guid));
6785 if (ret != LDB_SUCCESS) {
6786 ldb_asprintf_errstring(ldb, "Failed to re-resolve GUID %s: %s\n",
6787 GUID_string(tmp_ctx, guid),
6788 ldb_errstring(ldb));
6789 talloc_free(tmp_ctx);
6793 if (target_res->count == 0) {
6796 * we may not be able to resolve link targets properly when
6797 * dealing with subsets of objects, e.g. the source is a
6798 * critical object and the target isn't
6801 * When we implement Trusted Domains we need to consider
6802 * whether they get treated as an incomplete replica here or not
6804 if (la_entry->dsdb_repl_flags & DSDB_REPL_FLAG_OBJECT_SUBSET) {
6807 * We don't increase the highwater-mark in the object
6808 * subset cases, so subsequent replications should
6809 * resolve any missing links
6811 DEBUG(2,(__location__
6812 ": Failed to find target %s linked from %s\n",
6813 ldb_dn_get_linearized(dsdb_dn->dn),
6814 ldb_dn_get_linearized(source_dn)));
6815 *ignore_link = true;
6817 } else if (replmd_objects_have_same_nc(ldb, tmp_ctx, source_dn,
6819 ldb_asprintf_errstring(ldb, "Unknown target %s GUID %s linked from %s\n",
6820 ldb_dn_get_linearized(dsdb_dn->dn),
6821 GUID_string(tmp_ctx, guid),
6822 ldb_dn_get_linearized(source_dn));
6823 ret = LDB_ERR_NO_SUCH_OBJECT;
6827 * The target of the cross-partition link is missing.
6828 * Continue and try to at least add the forward-link.
6829 * This isn't great, but if we can add a partial link
6830 * then it's better than nothing.
6832 DEBUG(2,("Failed to resolve cross-partition link between %s and %s\n",
6833 ldb_dn_get_linearized(source_dn),
6834 ldb_dn_get_linearized(dsdb_dn->dn)));
6836 } else if (target_res->count != 1) {
6837 ldb_asprintf_errstring(ldb, "More than one object found matching objectGUID %s\n",
6838 GUID_string(tmp_ctx, guid));
6839 ret = LDB_ERR_OPERATIONS_ERROR;
6841 struct ldb_message *target_msg = target_res->msgs[0];
6843 dsdb_dn->dn = talloc_steal(dsdb_dn, target_msg->dn);
6845 /* Get the object's state (i.e. Not Deleted, Tombstone, etc) */
6846 replmd_deletion_state(module, target_msg,
6847 &target_deletion_state, NULL);
6850 * Check for deleted objects as per MS-DRSR 4.1.10.6.14
6851 * ProcessLinkValue(). Link updates should not be sent for
6852 * recycled and tombstone objects (deleting the links should
6853 * happen when we delete the object). This probably means our
6854 * copy of the target object isn't up to date.
6856 if (target_deletion_state >= OBJECT_RECYCLED) {
6858 if (la_entry->dsdb_repl_flags & DSDB_REPL_FLAG_TARGETS_UPTODATE) {
6861 * target should already be uptodate so there's no
6862 * point retrying - it's probably just bad timing
6864 *ignore_link = true;
6865 DEBUG(0, ("%s is deleted but up to date. "
6866 "Ignoring link from %s\n",
6867 ldb_dn_get_linearized(dsdb_dn->dn),
6868 ldb_dn_get_linearized(source_dn)));
6871 ldb_asprintf_errstring(ldb,
6872 "Deleted target %s GUID %s linked from %s",
6873 ldb_dn_get_linearized(dsdb_dn->dn),
6874 GUID_string(tmp_ctx, guid),
6875 ldb_dn_get_linearized(source_dn));
6876 ret = LDB_ERR_NO_SUCH_OBJECT;
6881 talloc_free(tmp_ctx);
6886 * Extracts the key details about the source/target object for a
6887 * linked-attribute entry.
6888 * This returns the following details:
6889 * @param ret_attr the schema details for the linked attribute
6890 * @param source_msg the search result for the source object
6891 * @param target_dsdb_dn the unpacked DN info for the target object
6893 static int replmd_extract_la_entry_details(struct ldb_module *module,
6894 struct la_entry *la_entry,
6895 TALLOC_CTX *mem_ctx,
6896 const struct dsdb_attribute **ret_attr,
6897 struct ldb_message **source_msg,
6898 struct dsdb_dn **target_dsdb_dn)
6900 struct drsuapi_DsReplicaLinkedAttribute *la = la_entry->la;
6901 struct ldb_context *ldb = ldb_module_get_ctx(module);
6902 const struct dsdb_schema *schema = dsdb_get_schema(ldb, mem_ctx);
6904 const struct dsdb_attribute *attr;
6906 struct ldb_result *res;
6907 const char *attrs[4];
6910 linked_attributes[0]:
6911 &objs->linked_attributes[i]: struct drsuapi_DsReplicaLinkedAttribute
6913 identifier: struct drsuapi_DsReplicaObjectIdentifier
6914 __ndr_size : 0x0000003a (58)
6915 __ndr_size_sid : 0x00000000 (0)
6916 guid : 8e95b6a9-13dd-4158-89db-3220a5be5cc7
6918 __ndr_size_dn : 0x00000000 (0)
6920 attid : DRSUAPI_ATTID_member (0x1F)
6921 value: struct drsuapi_DsAttributeValue
6922 __ndr_size : 0x0000007e (126)
6924 blob : DATA_BLOB length=126
6925 flags : 0x00000001 (1)
6926 1: DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE
6927 originating_add_time : Wed Sep 2 22:20:01 2009 EST
6928 meta_data: struct drsuapi_DsReplicaMetaData
6929 version : 0x00000015 (21)
6930 originating_change_time : Wed Sep 2 23:39:07 2009 EST
6931 originating_invocation_id: 794640f3-18cf-40ee-a211-a93992b67a64
6932 originating_usn : 0x000000000001e19c (123292)
6934 (for cases where the link is to a normal DN)
6935 &target: struct drsuapi_DsReplicaObjectIdentifier3
6936 __ndr_size : 0x0000007e (126)
6937 __ndr_size_sid : 0x0000001c (28)
6938 guid : 7639e594-db75-4086-b0d4-67890ae46031
6939 sid : S-1-5-21-2848215498-2472035911-1947525656-19924
6940 __ndr_size_dn : 0x00000022 (34)
6941 dn : 'CN=UOne,OU=TestOU,DC=vsofs8,DC=com'
6944 /* find the attribute being modified */
6945 attr = dsdb_attribute_by_attributeID_id(schema, la->attid);
6947 struct GUID_txt_buf guid_str;
6948 ldb_asprintf_errstring(ldb, "Unable to find attributeID 0x%x for link on <GUID=%s>",
6950 GUID_buf_string(&la->identifier->guid,
6952 return LDB_ERR_OPERATIONS_ERROR;
6955 attrs[0] = attr->lDAPDisplayName;
6956 attrs[1] = "isDeleted";
6957 attrs[2] = "isRecycled";
6961 * get the existing message from the db for the object with
6962 * this GUID, returning attribute being modified. We will then
6963 * use this msg as the basis for a modify call
6965 ret = dsdb_module_search(module, mem_ctx, &res, NULL, LDB_SCOPE_SUBTREE, attrs,
6966 DSDB_FLAG_NEXT_MODULE |
6967 DSDB_SEARCH_SEARCH_ALL_PARTITIONS |
6968 DSDB_SEARCH_SHOW_RECYCLED |
6969 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT |
6970 DSDB_SEARCH_REVEAL_INTERNALS,
6972 "objectGUID=%s", GUID_string(mem_ctx, &la->identifier->guid));
6973 if (ret != LDB_SUCCESS) {
6976 if (res->count != 1) {
6977 ldb_asprintf_errstring(ldb, "DRS linked attribute for GUID %s - DN not found",
6978 GUID_string(mem_ctx, &la->identifier->guid));
6979 return LDB_ERR_NO_SUCH_OBJECT;
6982 *source_msg = res->msgs[0];
6984 /* the value blob for the attribute holds the target object DN */
6985 status = dsdb_dn_la_from_blob(ldb, attr, schema, mem_ctx, la->value.blob, target_dsdb_dn);
6986 if (!W_ERROR_IS_OK(status)) {
6987 ldb_asprintf_errstring(ldb, "Failed to parsed linked attribute blob for %s on %s - %s\n",
6988 attr->lDAPDisplayName,
6989 ldb_dn_get_linearized(res->msgs[0]->dn),
6990 win_errstr(status));
6991 return LDB_ERR_OPERATIONS_ERROR;
7000 * Verifies the source and target objects are known for a linked attribute
7002 static int replmd_verify_linked_attribute(struct replmd_replicated_request *ar,
7003 struct la_entry *la)
7005 int ret = LDB_SUCCESS;
7006 TALLOC_CTX *tmp_ctx = talloc_new(la);
7007 struct ldb_module *module = ar->module;
7008 struct ldb_message *src_msg;
7009 const struct dsdb_attribute *attr;
7010 struct dsdb_dn *tgt_dsdb_dn;
7011 struct GUID guid = GUID_zero();
7014 ret = replmd_extract_la_entry_details(module, la, tmp_ctx, &attr,
7015 &src_msg, &tgt_dsdb_dn);
7018 * When we fail to find the source object, the error code we pass
7019 * back here is really important. It flags back to the callers to
7020 * retry this request with DRSUAPI_DRS_GET_ANC. This case should
7021 * never happen if we're replicating from a Samba DC, but it is
7022 * needed to talk to a Windows DC
7024 if (ret == LDB_ERR_NO_SUCH_OBJECT) {
7025 ret = replmd_replicated_request_werror(ar, WERR_DS_DRA_MISSING_PARENT);
7028 if (ret != LDB_SUCCESS) {
7029 talloc_free(tmp_ctx);
7033 ret = replmd_check_target_exists(module, tgt_dsdb_dn, la,
7034 src_msg->dn, &guid, &dummy);
7037 * When we fail to find the target object, the error code we pass
7038 * back here is really important. It flags back to the callers to
7039 * retry this request with DRSUAPI_DRS_GET_TGT
7041 if (ret == LDB_ERR_NO_SUCH_OBJECT) {
7042 ret = replmd_replicated_request_werror(ar, WERR_DS_DRA_RECYCLED_TARGET);
7045 talloc_free(tmp_ctx);
7050 process one linked attribute structure
7052 static int replmd_process_linked_attribute(struct ldb_module *module,
7053 struct replmd_private *replmd_private,
7054 struct la_entry *la_entry,
7055 struct ldb_request *parent)
7057 struct drsuapi_DsReplicaLinkedAttribute *la = la_entry->la;
7058 struct ldb_context *ldb = ldb_module_get_ctx(module);
7059 struct ldb_message *msg;
7060 TALLOC_CTX *tmp_ctx = talloc_new(la_entry);
7061 const struct dsdb_schema *schema = dsdb_get_schema(ldb, tmp_ctx);
7063 const struct dsdb_attribute *attr;
7064 struct dsdb_dn *dsdb_dn;
7065 uint64_t seq_num = 0;
7066 struct ldb_message_element *old_el;
7067 time_t t = time(NULL);
7068 struct parsed_dn *pdn_list, *pdn, *next;
7069 struct GUID guid = GUID_zero();
7070 bool active = (la->flags & DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE)?true:false;
7072 enum deletion_state deletion_state = OBJECT_NOT_DELETED;
7075 * get the attribute being modified, the search result for the source object,
7076 * and the target object's DN details
7078 ret = replmd_extract_la_entry_details(module, la_entry, tmp_ctx, &attr,
7081 if (ret != LDB_SUCCESS) {
7082 talloc_free(tmp_ctx);
7087 * Check for deleted objects per MS-DRSR 4.1.10.6.14
7088 * ProcessLinkValue, because link updates are not applied to
7089 * recycled and tombstone objects. We don't have to delete
7090 * any existing link, that should have happened when the
7091 * object deletion was replicated or initiated.
7093 replmd_deletion_state(module, msg, &deletion_state, NULL);
7095 if (deletion_state >= OBJECT_RECYCLED) {
7096 talloc_free(tmp_ctx);
7100 old_el = ldb_msg_find_element(msg, attr->lDAPDisplayName);
7101 if (old_el == NULL) {
7102 ret = ldb_msg_add_empty(msg, attr->lDAPDisplayName, LDB_FLAG_MOD_REPLACE, &old_el);
7103 if (ret != LDB_SUCCESS) {
7104 ldb_module_oom(module);
7105 talloc_free(tmp_ctx);
7106 return LDB_ERR_OPERATIONS_ERROR;
7109 old_el->flags = LDB_FLAG_MOD_REPLACE;
7112 /* parse the existing links */
7113 ret = get_parsed_dns_trusted(module, replmd_private, tmp_ctx, old_el, &pdn_list,
7114 attr->syntax->ldap_oid, parent);
7116 if (ret != LDB_SUCCESS) {
7117 talloc_free(tmp_ctx);
7121 ret = replmd_check_target_exists(module, dsdb_dn, la_entry, msg->dn,
7122 &guid, &ignore_link);
7124 if (ret != LDB_SUCCESS) {
7125 talloc_free(tmp_ctx);
7130 * there are some cases where the target object doesn't exist, but it's
7131 * OK to ignore the linked attribute
7134 talloc_free(tmp_ctx);
7138 /* see if this link already exists */
7139 ret = parsed_dn_find(ldb, pdn_list, old_el->num_values,
7142 dsdb_dn->extra_part, 0,
7144 attr->syntax->ldap_oid,
7146 if (ret != LDB_SUCCESS) {
7147 talloc_free(tmp_ctx);
7153 /* see if this update is newer than what we have already */
7154 struct GUID invocation_id = GUID_zero();
7155 uint32_t version = 0;
7156 uint32_t originating_usn = 0;
7157 NTTIME change_time = 0;
7158 uint32_t rmd_flags = dsdb_dn_rmd_flags(pdn->dsdb_dn->dn);
7160 dsdb_get_extended_dn_guid(pdn->dsdb_dn->dn, &invocation_id, "RMD_INVOCID");
7161 dsdb_get_extended_dn_uint32(pdn->dsdb_dn->dn, &version, "RMD_VERSION");
7162 dsdb_get_extended_dn_uint32(pdn->dsdb_dn->dn, &originating_usn, "RMD_ORIGINATING_USN");
7163 dsdb_get_extended_dn_nttime(pdn->dsdb_dn->dn, &change_time, "RMD_CHANGETIME");
7165 if (!replmd_update_is_newer(&invocation_id,
7166 &la->meta_data.originating_invocation_id,
7168 la->meta_data.version,
7170 la->meta_data.originating_change_time)) {
7171 DEBUG(3,("Discarding older DRS linked attribute update to %s on %s from %s\n",
7172 old_el->name, ldb_dn_get_linearized(msg->dn),
7173 GUID_string(tmp_ctx, &la->meta_data.originating_invocation_id)));
7174 talloc_free(tmp_ctx);
7178 /* get a seq_num for this change */
7179 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &seq_num);
7180 if (ret != LDB_SUCCESS) {
7181 talloc_free(tmp_ctx);
7185 if (!(rmd_flags & DSDB_RMD_FLAG_DELETED)) {
7186 /* remove the existing backlink */
7187 ret = replmd_add_backlink(module, replmd_private,
7192 if (ret != LDB_SUCCESS) {
7193 talloc_free(tmp_ctx);
7198 ret = replmd_update_la_val(tmp_ctx, pdn->v, dsdb_dn, pdn->dsdb_dn,
7199 &la->meta_data.originating_invocation_id,
7200 la->meta_data.originating_usn, seq_num,
7201 la->meta_data.originating_change_time,
7202 la->meta_data.version,
7204 if (ret != LDB_SUCCESS) {
7205 talloc_free(tmp_ctx);
7210 /* add the new backlink */
7211 ret = replmd_add_backlink(module, replmd_private,
7216 if (ret != LDB_SUCCESS) {
7217 talloc_free(tmp_ctx);
7223 /* get a seq_num for this change */
7224 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &seq_num);
7225 if (ret != LDB_SUCCESS) {
7226 talloc_free(tmp_ctx);
7230 * We know where the new one needs to be, from the *next
7231 * pointer into pdn_list.
7234 offset = old_el->num_values;
7236 if (next->dsdb_dn == NULL) {
7237 ret = really_parse_trusted_dn(tmp_ctx, ldb, next,
7238 attr->syntax->ldap_oid);
7239 if (ret != LDB_SUCCESS) {
7243 offset = next - pdn_list;
7244 if (offset > old_el->num_values) {
7245 talloc_free(tmp_ctx);
7246 return LDB_ERR_OPERATIONS_ERROR;
7250 old_el->values = talloc_realloc(msg->elements, old_el->values,
7251 struct ldb_val, old_el->num_values+1);
7252 if (!old_el->values) {
7253 ldb_module_oom(module);
7254 return LDB_ERR_OPERATIONS_ERROR;
7257 if (offset != old_el->num_values) {
7258 memmove(&old_el->values[offset + 1], &old_el->values[offset],
7259 (old_el->num_values - offset) * sizeof(old_el->values[0]));
7262 old_el->num_values++;
7264 ret = replmd_build_la_val(tmp_ctx, &old_el->values[offset], dsdb_dn,
7265 &la->meta_data.originating_invocation_id,
7266 la->meta_data.originating_usn, seq_num,
7267 la->meta_data.originating_change_time,
7268 la->meta_data.version,
7270 if (ret != LDB_SUCCESS) {
7271 talloc_free(tmp_ctx);
7276 ret = replmd_add_backlink(module, replmd_private,
7281 if (ret != LDB_SUCCESS) {
7282 talloc_free(tmp_ctx);
7288 /* we only change whenChanged and uSNChanged if the seq_num
7290 ret = add_time_element(msg, "whenChanged", t);
7291 if (ret != LDB_SUCCESS) {
7292 talloc_free(tmp_ctx);
7297 ret = add_uint64_element(ldb, msg, "uSNChanged", seq_num);
7298 if (ret != LDB_SUCCESS) {
7299 talloc_free(tmp_ctx);
7304 old_el = ldb_msg_find_element(msg, attr->lDAPDisplayName);
7305 if (old_el == NULL) {
7306 talloc_free(tmp_ctx);
7307 return ldb_operr(ldb);
7310 ret = dsdb_check_single_valued_link(attr, old_el);
7311 if (ret != LDB_SUCCESS) {
7312 talloc_free(tmp_ctx);
7316 old_el->flags |= LDB_FLAG_INTERNAL_DISABLE_SINGLE_VALUE_CHECK;
7318 ret = linked_attr_modify(module, msg, parent);
7319 if (ret != LDB_SUCCESS) {
7320 ldb_debug(ldb, LDB_DEBUG_WARNING, "Failed to apply linked attribute change '%s'\n%s\n",
7322 ldb_ldif_message_redacted_string(ldb,
7324 LDB_CHANGETYPE_MODIFY,
7326 talloc_free(tmp_ctx);
7330 talloc_free(tmp_ctx);
7335 static int replmd_extended(struct ldb_module *module, struct ldb_request *req)
7337 if (strcmp(req->op.extended.oid, DSDB_EXTENDED_REPLICATED_OBJECTS_OID) == 0) {
7338 return replmd_extended_replicated_objects(module, req);
7341 return ldb_next_request(module, req);
7346 we hook into the transaction operations to allow us to
7347 perform the linked attribute updates at the end of the whole
7348 transaction. This allows a forward linked attribute to be created
7349 before the object is created. During a vampire, w2k8 sends us linked
7350 attributes before the objects they are part of.
7352 static int replmd_start_transaction(struct ldb_module *module)
7354 /* create our private structure for this transaction */
7355 struct replmd_private *replmd_private = talloc_get_type(ldb_module_get_private(module),
7356 struct replmd_private);
7357 replmd_txn_cleanup(replmd_private);
7359 /* free any leftover mod_usn records from cancelled
7361 while (replmd_private->ncs) {
7362 struct nc_entry *e = replmd_private->ncs;
7363 DLIST_REMOVE(replmd_private->ncs, e);
7367 replmd_private->originating_updates = false;
7369 return ldb_next_start_trans(module);
7373 on prepare commit we loop over our queued la_context structures and
7376 static int replmd_prepare_commit(struct ldb_module *module)
7378 struct replmd_private *replmd_private =
7379 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
7380 struct la_entry *la, *prev;
7384 * Walk the list of linked attributes from DRS replication.
7386 * We walk backwards, to do the first entry first, as we
7387 * added the entries with DLIST_ADD() which puts them at the
7390 for (la = DLIST_TAIL(replmd_private->la_list); la; la=prev) {
7391 prev = DLIST_PREV(la);
7392 DLIST_REMOVE(replmd_private->la_list, la);
7393 ret = replmd_process_linked_attribute(module, replmd_private,
7395 if (ret != LDB_SUCCESS) {
7396 replmd_txn_cleanup(replmd_private);
7401 replmd_txn_cleanup(replmd_private);
7403 /* possibly change @REPLCHANGED */
7404 ret = replmd_notify_store(module, NULL);
7405 if (ret != LDB_SUCCESS) {
7409 return ldb_next_prepare_commit(module);
7412 static int replmd_del_transaction(struct ldb_module *module)
7414 struct replmd_private *replmd_private =
7415 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
7416 replmd_txn_cleanup(replmd_private);
7418 return ldb_next_del_trans(module);
7422 static const struct ldb_module_ops ldb_repl_meta_data_module_ops = {
7423 .name = "repl_meta_data",
7424 .init_context = replmd_init,
7426 .modify = replmd_modify,
7427 .rename = replmd_rename,
7428 .del = replmd_delete,
7429 .extended = replmd_extended,
7430 .start_transaction = replmd_start_transaction,
7431 .prepare_commit = replmd_prepare_commit,
7432 .del_transaction = replmd_del_transaction,
7435 int ldb_repl_meta_data_module_init(const char *version)
7437 LDB_MODULE_CHECK_VERSION(version);
7438 return ldb_register_module(&ldb_repl_meta_data_module_ops);