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 bool incomplete_replica;
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_attributes(struct replmd_replicated_request *ar);
119 enum urgent_situation {
120 REPL_URGENT_ON_CREATE = 1,
121 REPL_URGENT_ON_UPDATE = 2,
122 REPL_URGENT_ON_DELETE = 4
125 enum deletion_state {
126 OBJECT_NOT_DELETED=1,
133 static void replmd_deletion_state(struct ldb_module *module,
134 const struct ldb_message *msg,
135 enum deletion_state *current_state,
136 enum deletion_state *next_state)
139 bool enabled = false;
142 *current_state = OBJECT_REMOVED;
143 if (next_state != NULL) {
144 *next_state = OBJECT_REMOVED;
149 ret = dsdb_recyclebin_enabled(module, &enabled);
150 if (ret != LDB_SUCCESS) {
154 if (ldb_msg_check_string_attribute(msg, "isDeleted", "TRUE")) {
156 *current_state = OBJECT_TOMBSTONE;
157 if (next_state != NULL) {
158 *next_state = OBJECT_REMOVED;
163 if (ldb_msg_check_string_attribute(msg, "isRecycled", "TRUE")) {
164 *current_state = OBJECT_RECYCLED;
165 if (next_state != NULL) {
166 *next_state = OBJECT_REMOVED;
171 *current_state = OBJECT_DELETED;
172 if (next_state != NULL) {
173 *next_state = OBJECT_RECYCLED;
178 *current_state = OBJECT_NOT_DELETED;
179 if (next_state == NULL) {
184 *next_state = OBJECT_DELETED;
186 *next_state = OBJECT_TOMBSTONE;
190 static const struct {
191 const char *update_name;
192 enum urgent_situation repl_situation;
193 } urgent_objects[] = {
194 {"nTDSDSA", (REPL_URGENT_ON_CREATE | REPL_URGENT_ON_DELETE)},
195 {"crossRef", (REPL_URGENT_ON_CREATE | REPL_URGENT_ON_DELETE)},
196 {"attributeSchema", (REPL_URGENT_ON_CREATE | REPL_URGENT_ON_UPDATE)},
197 {"classSchema", (REPL_URGENT_ON_CREATE | REPL_URGENT_ON_UPDATE)},
198 {"secret", (REPL_URGENT_ON_CREATE | REPL_URGENT_ON_UPDATE)},
199 {"rIDManager", (REPL_URGENT_ON_CREATE | REPL_URGENT_ON_UPDATE)},
203 /* Attributes looked for when updating or deleting, to check for a urgent replication needed */
204 static const char *urgent_attrs[] = {
207 "userAccountControl",
212 static bool replmd_check_urgent_objectclass(const struct ldb_message_element *objectclass_el,
213 enum urgent_situation situation)
216 for (i=0; urgent_objects[i].update_name; i++) {
218 if ((situation & urgent_objects[i].repl_situation) == 0) {
222 for (j=0; j<objectclass_el->num_values; j++) {
223 const struct ldb_val *v = &objectclass_el->values[j];
224 if (ldb_attr_cmp((const char *)v->data, urgent_objects[i].update_name) == 0) {
232 static bool replmd_check_urgent_attribute(const struct ldb_message_element *el)
234 if (ldb_attr_in_list(urgent_attrs, el->name)) {
240 static int replmd_replicated_apply_isDeleted(struct replmd_replicated_request *ar);
243 initialise the module
244 allocate the private structure and build the list
245 of partition DNs for use by replmd_notify()
247 static int replmd_init(struct ldb_module *module)
249 struct replmd_private *replmd_private;
250 struct ldb_context *ldb = ldb_module_get_ctx(module);
251 static const char *samba_dsdb_attrs[] = { SAMBA_COMPATIBLE_FEATURES_ATTR, NULL };
252 struct ldb_dn *samba_dsdb_dn;
253 struct ldb_result *res;
255 TALLOC_CTX *frame = talloc_stackframe();
256 replmd_private = talloc_zero(module, struct replmd_private);
257 if (replmd_private == NULL) {
260 return LDB_ERR_OPERATIONS_ERROR;
262 ldb_module_set_private(module, replmd_private);
264 replmd_private->schema_dn = ldb_get_schema_basedn(ldb);
266 samba_dsdb_dn = ldb_dn_new(frame, ldb, "@SAMBA_DSDB");
267 if (!samba_dsdb_dn) {
272 ret = dsdb_module_search_dn(module, frame, &res, samba_dsdb_dn,
273 samba_dsdb_attrs, DSDB_FLAG_NEXT_MODULE, NULL);
274 if (ret == LDB_SUCCESS) {
275 replmd_private->sorted_links
276 = ldb_msg_check_string_attribute(res->msgs[0],
277 SAMBA_COMPATIBLE_FEATURES_ATTR,
278 SAMBA_SORTED_LINKS_FEATURE);
282 return ldb_next_init(module);
286 cleanup our per-transaction contexts
288 static void replmd_txn_cleanup(struct replmd_private *replmd_private)
290 talloc_free(replmd_private->la_ctx);
291 replmd_private->la_list = NULL;
292 replmd_private->la_ctx = NULL;
298 struct la_backlink *next, *prev;
299 const char *attr_name;
300 struct ldb_dn *forward_dn;
301 struct GUID target_guid;
306 a ldb_modify request operating on modules below the
309 static int linked_attr_modify(struct ldb_module *module,
310 const struct ldb_message *message,
311 struct ldb_request *parent)
313 struct ldb_request *mod_req;
315 struct ldb_context *ldb = ldb_module_get_ctx(module);
316 TALLOC_CTX *tmp_ctx = talloc_new(module);
317 struct ldb_result *res;
319 res = talloc_zero(tmp_ctx, struct ldb_result);
321 talloc_free(tmp_ctx);
322 return ldb_oom(ldb_module_get_ctx(module));
325 ret = ldb_build_mod_req(&mod_req, ldb, tmp_ctx,
329 ldb_modify_default_callback,
331 LDB_REQ_SET_LOCATION(mod_req);
332 if (ret != LDB_SUCCESS) {
333 talloc_free(tmp_ctx);
337 ret = ldb_request_add_control(mod_req, DSDB_CONTROL_REPLICATED_UPDATE_OID,
339 if (ret != LDB_SUCCESS) {
343 /* Run the new request */
344 ret = ldb_next_request(module, mod_req);
346 if (ret == LDB_SUCCESS) {
347 ret = ldb_wait(mod_req->handle, LDB_WAIT_ALL);
350 talloc_free(tmp_ctx);
355 process a backlinks we accumulated during a transaction, adding and
356 deleting the backlinks from the target objects
358 static int replmd_process_backlink(struct ldb_module *module, struct la_backlink *bl, struct ldb_request *parent)
360 struct ldb_dn *target_dn, *source_dn;
362 struct ldb_context *ldb = ldb_module_get_ctx(module);
363 struct ldb_message *msg;
364 TALLOC_CTX *frame = talloc_stackframe();
370 - construct ldb_message
371 - either an add or a delete
373 ret = dsdb_module_dn_by_guid(module, frame, &bl->target_guid, &target_dn, parent);
374 if (ret != LDB_SUCCESS) {
375 struct GUID_txt_buf guid_str;
376 DEBUG(2,(__location__ ": WARNING: Failed to find target DN for linked attribute with GUID %s\n",
377 GUID_buf_string(&bl->target_guid, &guid_str)));
382 msg = ldb_msg_new(frame);
384 ldb_module_oom(module);
386 return LDB_ERR_OPERATIONS_ERROR;
389 source_dn = ldb_dn_copy(frame, bl->forward_dn);
391 ldb_module_oom(module);
393 return LDB_ERR_OPERATIONS_ERROR;
395 /* Filter down to the attributes we want in the backlink */
396 const char *accept[] = { "GUID", "SID", NULL };
397 ldb_dn_extended_filter(source_dn, accept);
400 /* construct a ldb_message for adding/deleting the backlink */
402 dn_string = ldb_dn_get_extended_linearized(frame, bl->forward_dn, 1);
404 ldb_module_oom(module);
406 return LDB_ERR_OPERATIONS_ERROR;
408 ret = ldb_msg_add_steal_string(msg, bl->attr_name, dn_string);
409 if (ret != LDB_SUCCESS) {
413 msg->elements[0].flags = bl->active?LDB_FLAG_MOD_ADD:LDB_FLAG_MOD_DELETE;
415 /* a backlink should never be single valued. Unfortunately the
416 exchange schema has a attribute
417 msExchBridgeheadedLocalConnectorsDNBL which is single
418 valued and a backlink. We need to cope with that by
419 ignoring the single value flag */
420 msg->elements[0].flags |= LDB_FLAG_INTERNAL_DISABLE_SINGLE_VALUE_CHECK;
422 ret = dsdb_module_modify(module, msg, DSDB_FLAG_NEXT_MODULE, parent);
423 if (ret == LDB_ERR_NO_SUCH_ATTRIBUTE && !bl->active) {
424 /* we allow LDB_ERR_NO_SUCH_ATTRIBUTE as success to
425 cope with possible corruption where the backlink has
426 already been removed */
427 DEBUG(3,("WARNING: backlink from %s already removed from %s - %s\n",
428 ldb_dn_get_linearized(target_dn),
429 ldb_dn_get_linearized(source_dn),
430 ldb_errstring(ldb)));
432 } else if (ret != LDB_SUCCESS) {
433 ldb_asprintf_errstring(ldb, "Failed to %s backlink from %s to %s - %s",
434 bl->active?"add":"remove",
435 ldb_dn_get_linearized(source_dn),
436 ldb_dn_get_linearized(target_dn),
446 add a backlink to the list of backlinks to add/delete in the prepare
449 forward_dn is stolen onto the defereed context
451 static int replmd_defer_add_backlink(struct ldb_module *module,
452 struct replmd_private *replmd_private,
453 const struct dsdb_schema *schema,
454 struct replmd_replicated_request *ac,
455 struct ldb_dn *forward_dn,
456 struct GUID *target_guid, bool active,
457 const struct dsdb_attribute *schema_attr,
458 struct ldb_request *parent)
460 const struct dsdb_attribute *target_attr;
461 struct la_backlink *bl;
463 bl = talloc(ac, struct la_backlink);
465 ldb_module_oom(module);
466 return LDB_ERR_OPERATIONS_ERROR;
469 target_attr = dsdb_attribute_by_linkID(schema, schema_attr->linkID ^ 1);
472 * windows 2003 has a broken schema where the
473 * definition of msDS-IsDomainFor is missing (which is
474 * supposed to be the backlink of the
475 * msDS-HasDomainNCs attribute
480 bl->attr_name = target_attr->lDAPDisplayName;
481 bl->forward_dn = talloc_steal(bl, forward_dn);
482 bl->target_guid = *target_guid;
485 DLIST_ADD(ac->la_backlinks, bl);
491 add a backlink to the list of backlinks to add/delete in the prepare
494 static int replmd_add_backlink(struct ldb_module *module,
495 struct replmd_private *replmd_private,
496 const struct dsdb_schema *schema,
497 struct ldb_dn *forward_dn,
498 struct GUID *target_guid, bool active,
499 const struct dsdb_attribute *schema_attr,
500 struct ldb_request *parent)
502 const struct dsdb_attribute *target_attr;
503 struct la_backlink bl;
506 target_attr = dsdb_attribute_by_linkID(schema, schema_attr->linkID ^ 1);
509 * windows 2003 has a broken schema where the
510 * definition of msDS-IsDomainFor is missing (which is
511 * supposed to be the backlink of the
512 * msDS-HasDomainNCs attribute
517 bl.attr_name = target_attr->lDAPDisplayName;
518 bl.forward_dn = forward_dn;
519 bl.target_guid = *target_guid;
522 ret = replmd_process_backlink(module, &bl, parent);
528 * Callback for most write operations in this module:
530 * notify the repl task that a object has changed. The notifies are
531 * gathered up in the replmd_private structure then written to the
532 * @REPLCHANGED object in each partition during the prepare_commit
534 static int replmd_op_callback(struct ldb_request *req, struct ldb_reply *ares)
537 struct replmd_replicated_request *ac =
538 talloc_get_type_abort(req->context, struct replmd_replicated_request);
539 struct replmd_private *replmd_private =
540 talloc_get_type_abort(ldb_module_get_private(ac->module), struct replmd_private);
541 struct nc_entry *modified_partition;
542 struct ldb_control *partition_ctrl;
543 const struct dsdb_control_current_partition *partition;
545 struct ldb_control **controls;
547 partition_ctrl = ldb_reply_get_control(ares, DSDB_CONTROL_CURRENT_PARTITION_OID);
549 controls = ares->controls;
550 if (ldb_request_get_control(ac->req,
551 DSDB_CONTROL_CURRENT_PARTITION_OID) == NULL) {
553 * Remove the current partition control from what we pass up
554 * the chain if it hasn't been requested manually.
556 controls = ldb_controls_except_specified(ares->controls, ares,
560 if (ares->error != LDB_SUCCESS) {
561 DEBUG(5,("%s failure. Error is: %s\n", __FUNCTION__, ldb_strerror(ares->error)));
562 return ldb_module_done(ac->req, controls,
563 ares->response, ares->error);
566 if (ares->type != LDB_REPLY_DONE) {
567 ldb_set_errstring(ldb_module_get_ctx(ac->module), "Invalid reply type for notify\n!");
568 return ldb_module_done(ac->req, NULL,
569 NULL, LDB_ERR_OPERATIONS_ERROR);
572 if (ac->apply_mode == false) {
573 struct la_backlink *bl;
575 * process our backlink list after an replmd_add(),
576 * creating and deleting backlinks as necessary (this
577 * code is sync). The other cases are handled inline
580 for (bl=ac->la_backlinks; bl; bl=bl->next) {
581 ret = replmd_process_backlink(ac->module, bl, ac->req);
582 if (ret != LDB_SUCCESS) {
583 return ldb_module_done(ac->req, NULL,
589 if (!partition_ctrl) {
590 ldb_set_errstring(ldb_module_get_ctx(ac->module),"No partition control on reply");
591 return ldb_module_done(ac->req, NULL,
592 NULL, LDB_ERR_OPERATIONS_ERROR);
595 partition = talloc_get_type_abort(partition_ctrl->data,
596 struct dsdb_control_current_partition);
598 if (ac->seq_num > 0) {
599 for (modified_partition = replmd_private->ncs; modified_partition;
600 modified_partition = modified_partition->next) {
601 if (ldb_dn_compare(modified_partition->dn, partition->dn) == 0) {
606 if (modified_partition == NULL) {
607 modified_partition = talloc_zero(replmd_private, struct nc_entry);
608 if (!modified_partition) {
609 ldb_oom(ldb_module_get_ctx(ac->module));
610 return ldb_module_done(ac->req, NULL,
611 NULL, LDB_ERR_OPERATIONS_ERROR);
613 modified_partition->dn = ldb_dn_copy(modified_partition, partition->dn);
614 if (!modified_partition->dn) {
615 ldb_oom(ldb_module_get_ctx(ac->module));
616 return ldb_module_done(ac->req, NULL,
617 NULL, LDB_ERR_OPERATIONS_ERROR);
619 DLIST_ADD(replmd_private->ncs, modified_partition);
622 if (ac->seq_num > modified_partition->mod_usn) {
623 modified_partition->mod_usn = ac->seq_num;
625 modified_partition->mod_usn_urgent = ac->seq_num;
628 if (!ac->apply_mode) {
629 replmd_private->originating_updates = true;
633 if (ac->apply_mode) {
634 ret = replmd_replicated_apply_isDeleted(ac);
635 if (ret != LDB_SUCCESS) {
636 return ldb_module_done(ac->req, NULL, NULL, ret);
640 /* free the partition control container here, for the
641 * common path. Other cases will have it cleaned up
642 * eventually with the ares */
643 talloc_free(partition_ctrl);
644 return ldb_module_done(ac->req, controls,
645 ares->response, LDB_SUCCESS);
651 * update a @REPLCHANGED record in each partition if there have been
652 * any writes of replicated data in the partition
654 static int replmd_notify_store(struct ldb_module *module, struct ldb_request *parent)
656 struct replmd_private *replmd_private =
657 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
659 while (replmd_private->ncs) {
661 struct nc_entry *modified_partition = replmd_private->ncs;
663 ret = dsdb_module_save_partition_usn(module, modified_partition->dn,
664 modified_partition->mod_usn,
665 modified_partition->mod_usn_urgent, parent);
666 if (ret != LDB_SUCCESS) {
667 DEBUG(0,(__location__ ": Failed to save partition uSN for %s\n",
668 ldb_dn_get_linearized(modified_partition->dn)));
672 if (ldb_dn_compare(modified_partition->dn,
673 replmd_private->schema_dn) == 0) {
674 struct ldb_result *ext_res;
675 ret = dsdb_module_extended(module,
676 replmd_private->schema_dn,
678 DSDB_EXTENDED_SCHEMA_UPDATE_NOW_OID,
680 DSDB_FLAG_NEXT_MODULE,
682 if (ret != LDB_SUCCESS) {
685 talloc_free(ext_res);
688 DLIST_REMOVE(replmd_private->ncs, modified_partition);
689 talloc_free(modified_partition);
697 created a replmd_replicated_request context
699 static struct replmd_replicated_request *replmd_ctx_init(struct ldb_module *module,
700 struct ldb_request *req)
702 struct ldb_context *ldb;
703 struct replmd_replicated_request *ac;
704 const struct GUID *our_invocation_id;
706 ldb = ldb_module_get_ctx(module);
708 ac = talloc_zero(req, struct replmd_replicated_request);
717 ac->schema = dsdb_get_schema(ldb, ac);
719 ldb_debug_set(ldb, LDB_DEBUG_FATAL,
720 "replmd_modify: no dsdb_schema loaded");
721 DEBUG(0,(__location__ ": %s\n", ldb_errstring(ldb)));
726 /* get our invocationId */
727 our_invocation_id = samdb_ntds_invocation_id(ldb);
728 if (!our_invocation_id) {
729 ldb_debug_set(ldb, LDB_DEBUG_FATAL,
730 "replmd_add: unable to find invocationId\n");
734 ac->our_invocation_id = *our_invocation_id;
740 add a time element to a record
742 static int add_time_element(struct ldb_message *msg, const char *attr, time_t t)
744 struct ldb_message_element *el;
748 if (ldb_msg_find_element(msg, attr) != NULL) {
752 s = ldb_timestring(msg, t);
754 return LDB_ERR_OPERATIONS_ERROR;
757 ret = ldb_msg_add_string(msg, attr, s);
758 if (ret != LDB_SUCCESS) {
762 el = ldb_msg_find_element(msg, attr);
763 /* always set as replace. This works because on add ops, the flag
765 el->flags = LDB_FLAG_MOD_REPLACE;
771 add a uint64_t element to a record
773 static int add_uint64_element(struct ldb_context *ldb, struct ldb_message *msg,
774 const char *attr, uint64_t v)
776 struct ldb_message_element *el;
779 if (ldb_msg_find_element(msg, attr) != NULL) {
783 ret = samdb_msg_add_uint64(ldb, msg, msg, attr, v);
784 if (ret != LDB_SUCCESS) {
788 el = ldb_msg_find_element(msg, attr);
789 /* always set as replace. This works because on add ops, the flag
791 el->flags = LDB_FLAG_MOD_REPLACE;
796 static int replmd_replPropertyMetaData1_attid_sort(const struct replPropertyMetaData1 *m1,
797 const struct replPropertyMetaData1 *m2,
798 const uint32_t *rdn_attid)
801 * This assignment seems inoccous, but it is critical for the
802 * system, as we need to do the comparisons as a unsigned
803 * quantity, not signed (enums are signed integers)
805 uint32_t attid_1 = m1->attid;
806 uint32_t attid_2 = m2->attid;
808 if (attid_1 == attid_2) {
813 * See above regarding this being an unsigned comparison.
814 * Otherwise when the high bit is set on non-standard
815 * attributes, they would end up first, before objectClass
818 return attid_1 > attid_2 ? 1 : -1;
821 static int replmd_replPropertyMetaDataCtr1_verify(struct ldb_context *ldb,
822 struct replPropertyMetaDataCtr1 *ctr1,
825 if (ctr1->count == 0) {
826 ldb_debug_set(ldb, LDB_DEBUG_FATAL,
827 "No elements found in replPropertyMetaData for %s!\n",
828 ldb_dn_get_linearized(dn));
829 return LDB_ERR_CONSTRAINT_VIOLATION;
832 /* the objectClass attribute is value 0x00000000, so must be first */
833 if (ctr1->array[0].attid != DRSUAPI_ATTID_objectClass) {
834 ldb_debug_set(ldb, LDB_DEBUG_FATAL,
835 "No objectClass found in replPropertyMetaData for %s!\n",
836 ldb_dn_get_linearized(dn));
837 return LDB_ERR_OBJECT_CLASS_VIOLATION;
843 static int replmd_replPropertyMetaDataCtr1_sort_and_verify(struct ldb_context *ldb,
844 struct replPropertyMetaDataCtr1 *ctr1,
847 /* Note this is O(n^2) for the almost-sorted case, which this is */
848 LDB_TYPESAFE_QSORT(ctr1->array, ctr1->count, NULL,
849 replmd_replPropertyMetaData1_attid_sort);
850 return replmd_replPropertyMetaDataCtr1_verify(ldb, ctr1, dn);
853 static int replmd_ldb_message_element_attid_sort(const struct ldb_message_element *e1,
854 const struct ldb_message_element *e2,
855 const struct dsdb_schema *schema)
857 const struct dsdb_attribute *a1;
858 const struct dsdb_attribute *a2;
861 * TODO: make this faster by caching the dsdb_attribute pointer
862 * on the ldb_messag_element
865 a1 = dsdb_attribute_by_lDAPDisplayName(schema, e1->name);
866 a2 = dsdb_attribute_by_lDAPDisplayName(schema, e2->name);
869 * TODO: remove this check, we should rely on e1 and e2 having valid attribute names
873 return strcasecmp(e1->name, e2->name);
875 if (a1->attributeID_id == a2->attributeID_id) {
878 return a1->attributeID_id > a2->attributeID_id ? 1 : -1;
881 static void replmd_ldb_message_sort(struct ldb_message *msg,
882 const struct dsdb_schema *schema)
884 LDB_TYPESAFE_QSORT(msg->elements, msg->num_elements, schema, replmd_ldb_message_element_attid_sort);
887 static int replmd_build_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct dsdb_dn *dsdb_dn,
888 const struct GUID *invocation_id, uint64_t seq_num,
889 uint64_t local_usn, NTTIME nttime, uint32_t version, bool deleted);
891 static int parsed_dn_compare(struct parsed_dn *pdn1, struct parsed_dn *pdn2);
893 static int get_parsed_dns(struct ldb_module *module, TALLOC_CTX *mem_ctx,
894 struct ldb_message_element *el, struct parsed_dn **pdn,
895 const char *ldap_oid, struct ldb_request *parent);
898 fix up linked attributes in replmd_add.
899 This involves setting up the right meta-data in extended DN
900 components, and creating backlinks to the object
902 static int replmd_add_fix_la(struct ldb_module *module, TALLOC_CTX *mem_ctx,
903 struct replmd_private *replmd_private,
904 struct ldb_message_element *el,
905 struct replmd_replicated_request *ac,
907 struct ldb_dn *forward_dn,
908 const struct dsdb_attribute *sa,
909 struct ldb_request *parent)
912 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
913 struct ldb_context *ldb = ldb_module_get_ctx(module);
914 struct parsed_dn *pdn;
915 /* We will take a reference to the schema in replmd_add_backlink */
916 const struct dsdb_schema *schema = dsdb_get_schema(ldb, NULL);
917 struct ldb_val *new_values = NULL;
920 if (dsdb_check_single_valued_link(sa, el) == LDB_SUCCESS) {
921 el->flags |= LDB_FLAG_INTERNAL_DISABLE_SINGLE_VALUE_CHECK;
923 ldb_asprintf_errstring(ldb,
924 "Attribute %s is single valued but "
925 "more than one value has been supplied",
927 talloc_free(tmp_ctx);
928 return LDB_ERR_CONSTRAINT_VIOLATION;
931 ret = get_parsed_dns(module, tmp_ctx, el, &pdn,
932 sa->syntax->ldap_oid, parent);
933 if (ret != LDB_SUCCESS) {
934 talloc_free(tmp_ctx);
938 new_values = talloc_array(tmp_ctx, struct ldb_val, el->num_values);
939 if (new_values == NULL) {
940 ldb_module_oom(module);
941 talloc_free(tmp_ctx);
942 return LDB_ERR_OPERATIONS_ERROR;
945 for (i = 0; i < el->num_values; i++) {
946 struct parsed_dn *p = &pdn[i];
947 if (i > 0 && parsed_dn_compare(p, &pdn[i - 1]) == 0) {
948 ldb_asprintf_errstring(ldb,
949 "Linked attribute %s has "
950 "multiple identical values", el->name);
951 talloc_free(tmp_ctx);
952 if (ldb_attr_cmp(el->name, "member") == 0) {
953 return LDB_ERR_ENTRY_ALREADY_EXISTS;
955 return LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS;
958 ret = replmd_build_la_val(el->values, p->v, p->dsdb_dn,
959 &ac->our_invocation_id,
960 ac->seq_num, ac->seq_num, now, 0, false);
961 if (ret != LDB_SUCCESS) {
962 talloc_free(tmp_ctx);
966 ret = replmd_defer_add_backlink(module, replmd_private,
968 forward_dn, &p->guid, true, sa,
970 if (ret != LDB_SUCCESS) {
971 talloc_free(tmp_ctx);
975 new_values[i] = *p->v;
977 el->values = talloc_steal(mem_ctx, new_values);
979 talloc_free(tmp_ctx);
983 static int replmd_add_make_extended_dn(struct ldb_request *req,
984 const DATA_BLOB *guid_blob,
985 struct ldb_dn **_extended_dn)
988 const DATA_BLOB *sid_blob;
989 /* Calculate an extended DN for any linked attributes */
990 struct ldb_dn *extended_dn = ldb_dn_copy(req, req->op.add.message->dn);
992 return LDB_ERR_OPERATIONS_ERROR;
994 ret = ldb_dn_set_extended_component(extended_dn, "GUID", guid_blob);
995 if (ret != LDB_SUCCESS) {
999 sid_blob = ldb_msg_find_ldb_val(req->op.add.message, "objectSID");
1000 if (sid_blob != NULL) {
1001 ret = ldb_dn_set_extended_component(extended_dn, "SID", sid_blob);
1002 if (ret != LDB_SUCCESS) {
1006 *_extended_dn = extended_dn;
1011 intercept add requests
1013 static int replmd_add(struct ldb_module *module, struct ldb_request *req)
1015 struct ldb_context *ldb;
1016 struct ldb_control *control;
1017 struct replmd_replicated_request *ac;
1018 enum ndr_err_code ndr_err;
1019 struct ldb_request *down_req;
1020 struct ldb_message *msg;
1021 const DATA_BLOB *guid_blob;
1022 DATA_BLOB guid_blob_stack;
1024 uint8_t guid_data[16];
1025 struct replPropertyMetaDataBlob nmd;
1026 struct ldb_val nmd_value;
1027 struct ldb_dn *extended_dn = NULL;
1030 * The use of a time_t here seems odd, but as the NTTIME
1031 * elements are actually declared as NTTIME_1sec in the IDL,
1032 * getting a higher resolution timestamp is not required.
1034 time_t t = time(NULL);
1039 unsigned int functional_level;
1041 bool allow_add_guid = false;
1042 bool remove_current_guid = false;
1043 bool is_urgent = false;
1044 bool is_schema_nc = false;
1045 struct ldb_message_element *objectclass_el;
1046 struct replmd_private *replmd_private =
1047 talloc_get_type_abort(ldb_module_get_private(module), struct replmd_private);
1049 /* check if there's a show relax control (used by provision to say 'I know what I'm doing') */
1050 control = ldb_request_get_control(req, LDB_CONTROL_RELAX_OID);
1052 allow_add_guid = true;
1055 /* do not manipulate our control entries */
1056 if (ldb_dn_is_special(req->op.add.message->dn)) {
1057 return ldb_next_request(module, req);
1060 ldb = ldb_module_get_ctx(module);
1062 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_add\n");
1064 guid_blob = ldb_msg_find_ldb_val(req->op.add.message, "objectGUID");
1065 if (guid_blob != NULL) {
1066 if (!allow_add_guid) {
1067 ldb_set_errstring(ldb,
1068 "replmd_add: it's not allowed to add an object with objectGUID!");
1069 return LDB_ERR_UNWILLING_TO_PERFORM;
1071 NTSTATUS status = GUID_from_data_blob(guid_blob,&guid);
1072 if (!NT_STATUS_IS_OK(status)) {
1073 ldb_set_errstring(ldb,
1074 "replmd_add: Unable to parse the 'objectGUID' as a GUID!");
1075 return LDB_ERR_UNWILLING_TO_PERFORM;
1077 /* we remove this attribute as it can be a string and
1078 * will not be treated correctly and then we will re-add
1079 * it later on in the good format */
1080 remove_current_guid = true;
1084 guid = GUID_random();
1086 guid_blob_stack = data_blob_const(guid_data, sizeof(guid_data));
1088 /* This can't fail */
1089 ndr_push_struct_into_fixed_blob(&guid_blob_stack, &guid,
1090 (ndr_push_flags_fn_t)ndr_push_GUID);
1091 guid_blob = &guid_blob_stack;
1094 ac = replmd_ctx_init(module, req);
1096 return ldb_module_oom(module);
1099 functional_level = dsdb_functional_level(ldb);
1101 /* Get a sequence number from the backend */
1102 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &ac->seq_num);
1103 if (ret != LDB_SUCCESS) {
1108 /* we have to copy the message as the caller might have it as a const */
1109 msg = ldb_msg_copy_shallow(ac, req->op.add.message);
1113 return LDB_ERR_OPERATIONS_ERROR;
1116 /* generated times */
1117 unix_to_nt_time(&now, t);
1118 time_str = ldb_timestring(msg, t);
1122 return LDB_ERR_OPERATIONS_ERROR;
1124 if (remove_current_guid) {
1125 ldb_msg_remove_attr(msg,"objectGUID");
1129 * remove autogenerated attributes
1131 ldb_msg_remove_attr(msg, "whenCreated");
1132 ldb_msg_remove_attr(msg, "whenChanged");
1133 ldb_msg_remove_attr(msg, "uSNCreated");
1134 ldb_msg_remove_attr(msg, "uSNChanged");
1135 ldb_msg_remove_attr(msg, "replPropertyMetaData");
1138 * readd replicated attributes
1140 ret = ldb_msg_add_string(msg, "whenCreated", time_str);
1141 if (ret != LDB_SUCCESS) {
1147 /* build the replication meta_data */
1150 nmd.ctr.ctr1.count = msg->num_elements;
1151 nmd.ctr.ctr1.array = talloc_array(msg,
1152 struct replPropertyMetaData1,
1153 nmd.ctr.ctr1.count);
1154 if (!nmd.ctr.ctr1.array) {
1157 return LDB_ERR_OPERATIONS_ERROR;
1160 is_schema_nc = ldb_dn_compare_base(replmd_private->schema_dn, msg->dn) == 0;
1162 for (i=0; i < msg->num_elements;) {
1163 struct ldb_message_element *e = &msg->elements[i];
1164 struct replPropertyMetaData1 *m = &nmd.ctr.ctr1.array[ni];
1165 const struct dsdb_attribute *sa;
1167 if (e->name[0] == '@') {
1172 sa = dsdb_attribute_by_lDAPDisplayName(ac->schema, e->name);
1174 ldb_debug_set(ldb, LDB_DEBUG_ERROR,
1175 "replmd_add: attribute '%s' not defined in schema\n",
1178 return LDB_ERR_NO_SUCH_ATTRIBUTE;
1181 if ((sa->systemFlags & DS_FLAG_ATTR_NOT_REPLICATED) || (sa->systemFlags & DS_FLAG_ATTR_IS_CONSTRUCTED)) {
1182 /* if the attribute is not replicated (0x00000001)
1183 * or constructed (0x00000004) it has no metadata
1189 if (sa->linkID != 0 && functional_level > DS_DOMAIN_FUNCTION_2000) {
1190 if (extended_dn == NULL) {
1191 ret = replmd_add_make_extended_dn(req,
1194 if (ret != LDB_SUCCESS) {
1201 * Prepare the context for the backlinks and
1202 * create metadata for the forward links. The
1203 * backlinks are created in
1204 * replmd_op_callback() after the successful
1205 * ADD of the object.
1207 ret = replmd_add_fix_la(module, msg->elements,
1212 if (ret != LDB_SUCCESS) {
1216 /* linked attributes are not stored in
1217 replPropertyMetaData in FL above w2k */
1222 m->attid = dsdb_attribute_get_attid(sa, is_schema_nc);
1224 if (m->attid == DRSUAPI_ATTID_isDeleted) {
1225 const struct ldb_val *rdn_val = ldb_dn_get_rdn_val(msg->dn);
1228 if (rdn_val == NULL) {
1231 return LDB_ERR_OPERATIONS_ERROR;
1234 rdn = (const char*)rdn_val->data;
1235 if (strcmp(rdn, "Deleted Objects") == 0) {
1237 * Set the originating_change_time to 29/12/9999 at 23:59:59
1238 * as specified in MS-ADTS 7.1.1.4.2 Deleted Objects Container
1240 m->originating_change_time = DELETED_OBJECT_CONTAINER_CHANGE_TIME;
1242 m->originating_change_time = now;
1245 m->originating_change_time = now;
1247 m->originating_invocation_id = ac->our_invocation_id;
1248 m->originating_usn = ac->seq_num;
1249 m->local_usn = ac->seq_num;
1252 if (!(e->flags & DSDB_FLAG_INTERNAL_FORCE_META_DATA)) {
1257 e->flags &= ~DSDB_FLAG_INTERNAL_FORCE_META_DATA;
1259 if (e->num_values != 0) {
1264 ldb_msg_remove_element(msg, e);
1267 /* fix meta data count */
1268 nmd.ctr.ctr1.count = ni;
1271 * sort meta data array
1273 ret = replmd_replPropertyMetaDataCtr1_sort_and_verify(ldb, &nmd.ctr.ctr1, msg->dn);
1274 if (ret != LDB_SUCCESS) {
1275 ldb_asprintf_errstring(ldb, "%s: error during direct ADD: %s", __func__, ldb_errstring(ldb));
1280 /* generated NDR encoded values */
1281 ndr_err = ndr_push_struct_blob(&nmd_value, msg,
1283 (ndr_push_flags_fn_t)ndr_push_replPropertyMetaDataBlob);
1284 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1287 return LDB_ERR_OPERATIONS_ERROR;
1291 * add the autogenerated values
1293 ret = dsdb_msg_add_guid(msg, &guid, "objectGUID");
1294 if (ret != LDB_SUCCESS) {
1299 ret = ldb_msg_add_string(msg, "whenChanged", time_str);
1300 if (ret != LDB_SUCCESS) {
1305 ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNCreated", ac->seq_num);
1306 if (ret != LDB_SUCCESS) {
1311 ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNChanged", ac->seq_num);
1312 if (ret != LDB_SUCCESS) {
1317 ret = ldb_msg_add_value(msg, "replPropertyMetaData", &nmd_value, NULL);
1318 if (ret != LDB_SUCCESS) {
1325 * sort the attributes by attid before storing the object
1327 replmd_ldb_message_sort(msg, ac->schema);
1330 * Assert that we do have an objectClass
1332 objectclass_el = ldb_msg_find_element(msg, "objectClass");
1333 if (objectclass_el == NULL) {
1334 ldb_asprintf_errstring(ldb, __location__
1335 ": objectClass missing on %s\n",
1336 ldb_dn_get_linearized(msg->dn));
1338 return LDB_ERR_OBJECT_CLASS_VIOLATION;
1340 is_urgent = replmd_check_urgent_objectclass(objectclass_el,
1341 REPL_URGENT_ON_CREATE);
1343 ac->is_urgent = is_urgent;
1344 ret = ldb_build_add_req(&down_req, ldb, ac,
1347 ac, replmd_op_callback,
1350 LDB_REQ_SET_LOCATION(down_req);
1351 if (ret != LDB_SUCCESS) {
1356 /* current partition control is needed by "replmd_op_callback" */
1357 if (ldb_request_get_control(req, DSDB_CONTROL_CURRENT_PARTITION_OID) == NULL) {
1358 ret = ldb_request_add_control(down_req,
1359 DSDB_CONTROL_CURRENT_PARTITION_OID,
1361 if (ret != LDB_SUCCESS) {
1367 if (functional_level == DS_DOMAIN_FUNCTION_2000) {
1368 ret = ldb_request_add_control(down_req, DSDB_CONTROL_APPLY_LINKS, false, NULL);
1369 if (ret != LDB_SUCCESS) {
1375 /* mark the control done */
1377 control->critical = 0;
1379 /* go on with the call chain */
1380 return ldb_next_request(module, down_req);
1385 * update the replPropertyMetaData for one element
1387 static int replmd_update_rpmd_element(struct ldb_context *ldb,
1388 struct ldb_message *msg,
1389 struct ldb_message_element *el,
1390 struct ldb_message_element *old_el,
1391 struct replPropertyMetaDataBlob *omd,
1392 const struct dsdb_schema *schema,
1394 const struct GUID *our_invocation_id,
1397 bool is_forced_rodc,
1398 struct ldb_request *req)
1401 const struct dsdb_attribute *a;
1402 struct replPropertyMetaData1 *md1;
1403 bool may_skip = false;
1406 a = dsdb_attribute_by_lDAPDisplayName(schema, el->name);
1408 if (ldb_request_get_control(req, LDB_CONTROL_RELAX_OID)) {
1409 /* allow this to make it possible for dbcheck
1410 to remove bad attributes */
1414 DEBUG(0,(__location__ ": Unable to find attribute %s in schema\n",
1416 return LDB_ERR_OPERATIONS_ERROR;
1419 attid = dsdb_attribute_get_attid(a, is_schema_nc);
1421 if ((a->systemFlags & DS_FLAG_ATTR_NOT_REPLICATED) || (a->systemFlags & DS_FLAG_ATTR_IS_CONSTRUCTED)) {
1426 * if the attribute's value haven't changed, and this isn't
1427 * just a delete of everything then return LDB_SUCCESS Unless
1428 * we have the provision control or if the attribute is
1429 * interSiteTopologyGenerator as this page explain:
1430 * http://support.microsoft.com/kb/224815 this attribute is
1431 * periodicaly written by the DC responsible for the intersite
1432 * generation in a given site
1434 * Unchanged could be deleting or replacing an already-gone
1435 * thing with an unconstrained delete/empty replace or a
1436 * replace with the same value, but not an add with the same
1437 * value because that could be about adding a duplicate (which
1438 * is for someone else to error out on).
1440 if (old_el != NULL && ldb_msg_element_equal_ordered(el, old_el)) {
1441 if (LDB_FLAG_MOD_TYPE(el->flags) == LDB_FLAG_MOD_REPLACE) {
1444 } else if (old_el == NULL && el->num_values == 0) {
1445 if (LDB_FLAG_MOD_TYPE(el->flags) == LDB_FLAG_MOD_REPLACE) {
1447 } else if (LDB_FLAG_MOD_TYPE(el->flags) == LDB_FLAG_MOD_DELETE) {
1450 } else if (a->linkID != 0 && LDB_FLAG_MOD_TYPE(el->flags) == LDB_FLAG_MOD_DELETE &&
1451 ldb_request_get_control(req, DSDB_CONTROL_REPLMD_VANISH_LINKS) != NULL) {
1453 * We intentionally skip the version bump when attempting to
1456 * The control is set by dbcheck and expunge-tombstones which
1457 * both attempt to be non-replicating. Otherwise, making an
1458 * alteration to the replication state would trigger a
1459 * broadcast of all expunged objects.
1464 if (el->flags & DSDB_FLAG_INTERNAL_FORCE_META_DATA) {
1466 el->flags &= ~DSDB_FLAG_INTERNAL_FORCE_META_DATA;
1470 if (strcmp(el->name, "interSiteTopologyGenerator") != 0 &&
1471 !ldb_request_get_control(req, LDB_CONTROL_PROVISION_OID)) {
1473 * allow this to make it possible for dbcheck
1474 * to rebuild broken metadata
1480 for (i=0; i<omd->ctr.ctr1.count; i++) {
1482 * First check if we find it under the msDS-IntID,
1483 * then check if we find it under the OID and
1486 * This allows the administrator to simply re-write
1487 * the attributes and so restore replication, which is
1488 * likely what they will try to do.
1490 if (attid == omd->ctr.ctr1.array[i].attid) {
1494 if (a->attributeID_id == omd->ctr.ctr1.array[i].attid) {
1499 if (a->linkID != 0 && dsdb_functional_level(ldb) > DS_DOMAIN_FUNCTION_2000) {
1500 /* linked attributes are not stored in
1501 replPropertyMetaData in FL above w2k, but we do
1502 raise the seqnum for the object */
1503 if (*seq_num == 0 &&
1504 ldb_sequence_number(ldb, LDB_SEQ_NEXT, seq_num) != LDB_SUCCESS) {
1505 return LDB_ERR_OPERATIONS_ERROR;
1510 if (i == omd->ctr.ctr1.count) {
1511 /* we need to add a new one */
1512 omd->ctr.ctr1.array = talloc_realloc(msg, omd->ctr.ctr1.array,
1513 struct replPropertyMetaData1, omd->ctr.ctr1.count+1);
1514 if (omd->ctr.ctr1.array == NULL) {
1516 return LDB_ERR_OPERATIONS_ERROR;
1518 omd->ctr.ctr1.count++;
1519 ZERO_STRUCT(omd->ctr.ctr1.array[i]);
1522 /* Get a new sequence number from the backend. We only do this
1523 * if we have a change that requires a new
1524 * replPropertyMetaData element
1526 if (*seq_num == 0) {
1527 int ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, seq_num);
1528 if (ret != LDB_SUCCESS) {
1529 return LDB_ERR_OPERATIONS_ERROR;
1533 md1 = &omd->ctr.ctr1.array[i];
1537 if (md1->attid == DRSUAPI_ATTID_isDeleted) {
1538 const struct ldb_val *rdn_val = ldb_dn_get_rdn_val(msg->dn);
1541 if (rdn_val == NULL) {
1543 return LDB_ERR_OPERATIONS_ERROR;
1546 rdn = (const char*)rdn_val->data;
1547 if (strcmp(rdn, "Deleted Objects") == 0) {
1549 * Set the originating_change_time to 29/12/9999 at 23:59:59
1550 * as specified in MS-ADTS 7.1.1.4.2 Deleted Objects Container
1552 md1->originating_change_time = DELETED_OBJECT_CONTAINER_CHANGE_TIME;
1554 md1->originating_change_time = now;
1557 md1->originating_change_time = now;
1559 md1->originating_invocation_id = *our_invocation_id;
1560 md1->originating_usn = *seq_num;
1561 md1->local_usn = *seq_num;
1563 if (is_forced_rodc) {
1564 /* Force version to 0 to be overriden later via replication */
1572 * Bump the replPropertyMetaData version on an attribute, and if it
1573 * has changed (or forced by leaving rdn_old NULL), update the value
1576 * This is important, as calling a modify operation may not change the
1577 * version number if the values appear unchanged, but a rename between
1578 * parents bumps this value.
1581 static int replmd_update_rpmd_rdn_attr(struct ldb_context *ldb,
1582 struct ldb_message *msg,
1583 const struct ldb_val *rdn_new,
1584 const struct ldb_val *rdn_old,
1585 struct replPropertyMetaDataBlob *omd,
1586 struct replmd_replicated_request *ar,
1589 bool is_forced_rodc)
1591 const char *rdn_name = ldb_dn_get_rdn_name(msg->dn);
1592 const struct dsdb_attribute *rdn_attr =
1593 dsdb_attribute_by_lDAPDisplayName(ar->schema, rdn_name);
1594 const char *attr_name = rdn_attr != NULL ?
1595 rdn_attr->lDAPDisplayName :
1597 struct ldb_message_element new_el = {
1598 .flags = LDB_FLAG_MOD_REPLACE,
1601 .values = discard_const_p(struct ldb_val, rdn_new)
1603 struct ldb_message_element old_el = {
1604 .flags = LDB_FLAG_MOD_REPLACE,
1606 .num_values = rdn_old ? 1 : 0,
1607 .values = discard_const_p(struct ldb_val, rdn_old)
1610 if (ldb_msg_element_equal_ordered(&new_el, &old_el) == false) {
1611 int ret = ldb_msg_add(msg, &new_el, LDB_FLAG_MOD_REPLACE);
1612 if (ret != LDB_SUCCESS) {
1613 return ldb_oom(ldb);
1617 return replmd_update_rpmd_element(ldb, msg, &new_el, NULL,
1618 omd, ar->schema, &ar->seq_num,
1619 &ar->our_invocation_id,
1620 now, is_schema_nc, is_forced_rodc,
1625 static uint64_t find_max_local_usn(struct replPropertyMetaDataBlob omd)
1627 uint32_t count = omd.ctr.ctr1.count;
1630 for (i=0; i < count; i++) {
1631 struct replPropertyMetaData1 m = omd.ctr.ctr1.array[i];
1632 if (max < m.local_usn) {
1640 * update the replPropertyMetaData object each time we modify an
1641 * object. This is needed for DRS replication, as the merge on the
1642 * client is based on this object
1644 static int replmd_update_rpmd(struct ldb_module *module,
1645 const struct dsdb_schema *schema,
1646 struct ldb_request *req,
1647 const char * const *rename_attrs,
1648 struct ldb_message *msg, uint64_t *seq_num,
1649 time_t t, bool is_schema_nc,
1650 bool *is_urgent, bool *rodc)
1652 const struct ldb_val *omd_value;
1653 enum ndr_err_code ndr_err;
1654 struct replPropertyMetaDataBlob omd;
1657 const struct GUID *our_invocation_id;
1659 const char * const *attrs = NULL;
1660 const char * const attrs2[] = { "uSNChanged", "objectClass", "instanceType", NULL };
1661 struct ldb_result *res;
1662 struct ldb_context *ldb;
1663 struct ldb_message_element *objectclass_el;
1664 enum urgent_situation situation;
1665 bool rmd_is_provided;
1666 bool rmd_is_just_resorted = false;
1667 const char *not_rename_attrs[4 + msg->num_elements];
1668 bool is_forced_rodc = false;
1671 attrs = rename_attrs;
1673 for (i = 0; i < msg->num_elements; i++) {
1674 not_rename_attrs[i] = msg->elements[i].name;
1676 not_rename_attrs[i] = "replPropertyMetaData";
1677 not_rename_attrs[i+1] = "objectClass";
1678 not_rename_attrs[i+2] = "instanceType";
1679 not_rename_attrs[i+3] = NULL;
1680 attrs = not_rename_attrs;
1683 ldb = ldb_module_get_ctx(module);
1685 ret = samdb_rodc(ldb, rodc);
1686 if (ret != LDB_SUCCESS) {
1687 DEBUG(4, (__location__ ": unable to tell if we are an RODC\n"));
1692 ldb_request_get_control(req, DSDB_CONTROL_FORCE_RODC_LOCAL_CHANGE)) {
1693 is_forced_rodc = true;
1696 our_invocation_id = samdb_ntds_invocation_id(ldb);
1697 if (!our_invocation_id) {
1698 /* this happens during an initial vampire while
1699 updating the schema */
1700 DEBUG(5,("No invocationID - skipping replPropertyMetaData update\n"));
1704 unix_to_nt_time(&now, t);
1706 if (ldb_request_get_control(req, DSDB_CONTROL_CHANGEREPLMETADATA_OID)) {
1707 rmd_is_provided = true;
1708 if (ldb_request_get_control(req, DSDB_CONTROL_CHANGEREPLMETADATA_RESORT_OID)) {
1709 rmd_is_just_resorted = true;
1712 rmd_is_provided = false;
1715 /* if isDeleted is present and is TRUE, then we consider we are deleting,
1716 * otherwise we consider we are updating */
1717 if (ldb_msg_check_string_attribute(msg, "isDeleted", "TRUE")) {
1718 situation = REPL_URGENT_ON_DELETE;
1719 } else if (rename_attrs) {
1720 situation = REPL_URGENT_ON_CREATE | REPL_URGENT_ON_DELETE;
1722 situation = REPL_URGENT_ON_UPDATE;
1725 if (rmd_is_provided) {
1726 /* In this case the change_replmetadata control was supplied */
1727 /* We check that it's the only attribute that is provided
1728 * (it's a rare case so it's better to keep the code simplier)
1729 * We also check that the highest local_usn is bigger or the same as
1732 if( msg->num_elements != 1 ||
1733 strncmp(msg->elements[0].name,
1734 "replPropertyMetaData", 20) ) {
1735 DEBUG(0,(__location__ ": changereplmetada control called without "\
1736 "a specified replPropertyMetaData attribute or with others\n"));
1737 return LDB_ERR_OPERATIONS_ERROR;
1739 if (situation != REPL_URGENT_ON_UPDATE) {
1740 DEBUG(0,(__location__ ": changereplmetada control can't be called when deleting an object\n"));
1741 return LDB_ERR_OPERATIONS_ERROR;
1743 omd_value = ldb_msg_find_ldb_val(msg, "replPropertyMetaData");
1745 DEBUG(0,(__location__ ": replPropertyMetaData was not specified for Object %s\n",
1746 ldb_dn_get_linearized(msg->dn)));
1747 return LDB_ERR_OPERATIONS_ERROR;
1749 ndr_err = ndr_pull_struct_blob(omd_value, msg, &omd,
1750 (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
1751 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1752 DEBUG(0,(__location__ ": Failed to parse replPropertyMetaData for %s\n",
1753 ldb_dn_get_linearized(msg->dn)));
1754 return LDB_ERR_OPERATIONS_ERROR;
1757 ret = dsdb_module_search_dn(module, msg, &res, msg->dn, attrs2,
1758 DSDB_FLAG_NEXT_MODULE |
1759 DSDB_SEARCH_SHOW_RECYCLED |
1760 DSDB_SEARCH_SHOW_EXTENDED_DN |
1761 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT |
1762 DSDB_SEARCH_REVEAL_INTERNALS, req);
1764 if (ret != LDB_SUCCESS) {
1768 if (rmd_is_just_resorted == false) {
1769 *seq_num = find_max_local_usn(omd);
1771 db_seq = ldb_msg_find_attr_as_uint64(res->msgs[0], "uSNChanged", 0);
1774 * The test here now allows for a new
1775 * replPropertyMetaData with no change, if was
1776 * just dbcheck re-sorting the values.
1778 if (*seq_num <= db_seq) {
1779 DEBUG(0,(__location__ ": changereplmetada control provided but max(local_usn)" \
1780 " is less than uSNChanged (max = %lld uSNChanged = %lld)\n",
1781 (long long)*seq_num, (long long)db_seq));
1782 return LDB_ERR_OPERATIONS_ERROR;
1787 /* search for the existing replPropertyMetaDataBlob. We need
1788 * to use REVEAL and ask for DNs in storage format to support
1789 * the check for values being the same in
1790 * replmd_update_rpmd_element()
1792 ret = dsdb_module_search_dn(module, msg, &res, msg->dn, attrs,
1793 DSDB_FLAG_NEXT_MODULE |
1794 DSDB_SEARCH_SHOW_RECYCLED |
1795 DSDB_SEARCH_SHOW_EXTENDED_DN |
1796 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT |
1797 DSDB_SEARCH_REVEAL_INTERNALS, req);
1798 if (ret != LDB_SUCCESS) {
1802 omd_value = ldb_msg_find_ldb_val(res->msgs[0], "replPropertyMetaData");
1804 DEBUG(0,(__location__ ": Object %s does not have a replPropertyMetaData attribute\n",
1805 ldb_dn_get_linearized(msg->dn)));
1806 return LDB_ERR_OPERATIONS_ERROR;
1809 ndr_err = ndr_pull_struct_blob(omd_value, msg, &omd,
1810 (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
1811 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1812 DEBUG(0,(__location__ ": Failed to parse replPropertyMetaData for %s\n",
1813 ldb_dn_get_linearized(msg->dn)));
1814 return LDB_ERR_OPERATIONS_ERROR;
1817 if (omd.version != 1) {
1818 DEBUG(0,(__location__ ": bad version %u in replPropertyMetaData for %s\n",
1819 omd.version, ldb_dn_get_linearized(msg->dn)));
1820 return LDB_ERR_OPERATIONS_ERROR;
1823 for (i=0; i<msg->num_elements;) {
1824 struct ldb_message_element *el = &msg->elements[i];
1825 struct ldb_message_element *old_el;
1827 old_el = ldb_msg_find_element(res->msgs[0], el->name);
1828 ret = replmd_update_rpmd_element(ldb, msg, el, old_el,
1829 &omd, schema, seq_num,
1834 if (ret != LDB_SUCCESS) {
1838 if (!*is_urgent && (situation == REPL_URGENT_ON_UPDATE)) {
1839 *is_urgent = replmd_check_urgent_attribute(el);
1842 if (!(el->flags & DSDB_FLAG_INTERNAL_FORCE_META_DATA)) {
1847 el->flags &= ~DSDB_FLAG_INTERNAL_FORCE_META_DATA;
1849 if (el->num_values != 0) {
1854 ldb_msg_remove_element(msg, el);
1859 * Assert that we have an objectClass attribute - this is major
1860 * corruption if we don't have this!
1862 objectclass_el = ldb_msg_find_element(res->msgs[0], "objectClass");
1863 if (objectclass_el != NULL) {
1865 * Now check if this objectClass means we need to do urgent replication
1867 if (!*is_urgent && replmd_check_urgent_objectclass(objectclass_el,
1871 } else if (!ldb_request_get_control(req, DSDB_CONTROL_DBCHECK)) {
1872 ldb_asprintf_errstring(ldb, __location__
1873 ": objectClass missing on %s\n",
1874 ldb_dn_get_linearized(msg->dn));
1875 return LDB_ERR_OBJECT_CLASS_VIOLATION;
1879 * replmd_update_rpmd_element has done an update if the
1882 if (*seq_num != 0 || rmd_is_just_resorted == true) {
1883 struct ldb_val *md_value;
1884 struct ldb_message_element *el;
1886 /*if we are RODC and this is a DRSR update then its ok*/
1887 if (!ldb_request_get_control(req, DSDB_CONTROL_REPLICATED_UPDATE_OID)
1888 && !ldb_request_get_control(req, DSDB_CONTROL_DBCHECK_MODIFY_RO_REPLICA)
1889 && !is_forced_rodc) {
1890 unsigned instanceType;
1893 ldb_set_errstring(ldb, "RODC modify is forbidden!");
1894 return LDB_ERR_REFERRAL;
1897 instanceType = ldb_msg_find_attr_as_uint(res->msgs[0], "instanceType", INSTANCE_TYPE_WRITE);
1898 if (!(instanceType & INSTANCE_TYPE_WRITE)) {
1899 return ldb_error(ldb, LDB_ERR_UNWILLING_TO_PERFORM,
1900 "cannot change replicated attribute on partial replica");
1904 md_value = talloc(msg, struct ldb_val);
1905 if (md_value == NULL) {
1907 return LDB_ERR_OPERATIONS_ERROR;
1910 ret = replmd_replPropertyMetaDataCtr1_sort_and_verify(ldb, &omd.ctr.ctr1, msg->dn);
1911 if (ret != LDB_SUCCESS) {
1912 ldb_asprintf_errstring(ldb, "%s: %s", __func__, ldb_errstring(ldb));
1916 ndr_err = ndr_push_struct_blob(md_value, msg, &omd,
1917 (ndr_push_flags_fn_t)ndr_push_replPropertyMetaDataBlob);
1918 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1919 DEBUG(0,(__location__ ": Failed to marshall replPropertyMetaData for %s\n",
1920 ldb_dn_get_linearized(msg->dn)));
1921 return LDB_ERR_OPERATIONS_ERROR;
1924 ret = ldb_msg_add_empty(msg, "replPropertyMetaData", LDB_FLAG_MOD_REPLACE, &el);
1925 if (ret != LDB_SUCCESS) {
1926 DEBUG(0,(__location__ ": Failed to add updated replPropertyMetaData %s\n",
1927 ldb_dn_get_linearized(msg->dn)));
1932 el->values = md_value;
1938 static int parsed_dn_compare(struct parsed_dn *pdn1, struct parsed_dn *pdn2)
1940 int ret = ndr_guid_compare(&pdn1->guid, &pdn2->guid);
1942 return data_blob_cmp(&pdn1->dsdb_dn->extra_part,
1943 &pdn2->dsdb_dn->extra_part);
1949 get a series of message element values as an array of DNs and GUIDs
1950 the result is sorted by GUID
1952 static int get_parsed_dns(struct ldb_module *module, TALLOC_CTX *mem_ctx,
1953 struct ldb_message_element *el, struct parsed_dn **pdn,
1954 const char *ldap_oid, struct ldb_request *parent)
1957 bool values_are_sorted = true;
1958 struct ldb_context *ldb = ldb_module_get_ctx(module);
1965 (*pdn) = talloc_array(mem_ctx, struct parsed_dn, el->num_values);
1967 ldb_module_oom(module);
1968 return LDB_ERR_OPERATIONS_ERROR;
1971 for (i=0; i<el->num_values; i++) {
1972 struct ldb_val *v = &el->values[i];
1975 struct parsed_dn *p;
1979 p->dsdb_dn = dsdb_dn_parse(*pdn, ldb, v, ldap_oid);
1980 if (p->dsdb_dn == NULL) {
1981 return LDB_ERR_INVALID_DN_SYNTAX;
1984 dn = p->dsdb_dn->dn;
1986 status = dsdb_get_extended_dn_guid(dn, &p->guid, "GUID");
1987 if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND) ||
1988 unlikely(GUID_all_zero(&p->guid))) {
1989 /* we got a DN without a GUID - go find the GUID */
1990 int ret = dsdb_module_guid_by_dn(module, dn, &p->guid, parent);
1991 if (ret != LDB_SUCCESS) {
1992 ldb_asprintf_errstring(ldb, "Unable to find GUID for DN %s\n",
1993 ldb_dn_get_linearized(dn));
1994 if (ret == LDB_ERR_NO_SUCH_OBJECT &&
1995 LDB_FLAG_MOD_TYPE(el->flags) == LDB_FLAG_MOD_DELETE &&
1996 ldb_attr_cmp(el->name, "member") == 0) {
1997 return LDB_ERR_UNWILLING_TO_PERFORM;
2001 ret = dsdb_set_extended_dn_guid(dn, &p->guid, "GUID");
2002 if (ret != LDB_SUCCESS) {
2005 } else if (!NT_STATUS_IS_OK(status)) {
2006 return LDB_ERR_OPERATIONS_ERROR;
2008 if (i > 0 && values_are_sorted) {
2009 int cmp = parsed_dn_compare(p, &(*pdn)[i - 1]);
2011 values_are_sorted = false;
2014 /* keep a pointer to the original ldb_val */
2017 if (! values_are_sorted) {
2018 TYPESAFE_QSORT(*pdn, el->num_values, parsed_dn_compare);
2024 * Get a series of trusted message element values. The result is sorted by
2025 * GUID, even though the GUIDs might not be known. That works because we trust
2026 * the database to give us the elements like that if the
2027 * replmd_private->sorted_links flag is set.
2029 * We also ensure that the links are in the Functional Level 2003
2030 * linked attributes format.
2032 static int get_parsed_dns_trusted(struct ldb_module *module,
2033 struct replmd_private *replmd_private,
2034 TALLOC_CTX *mem_ctx,
2035 struct ldb_message_element *el,
2036 struct parsed_dn **pdn,
2037 const char *ldap_oid,
2038 struct ldb_request *parent)
2047 if (!replmd_private->sorted_links) {
2048 /* We need to sort the list. This is the slow old path we want
2051 ret = get_parsed_dns(module, mem_ctx, el, pdn, ldap_oid,
2053 if (ret != LDB_SUCCESS) {
2057 /* Here we get a list of 'struct parsed_dns' without the parsing */
2058 *pdn = talloc_zero_array(mem_ctx, struct parsed_dn,
2061 ldb_module_oom(module);
2062 return LDB_ERR_OPERATIONS_ERROR;
2065 for (i = 0; i < el->num_values; i++) {
2066 (*pdn)[i].v = &el->values[i];
2071 * This upgrades links to FL2003 style, and sorts the result
2072 * if that was needed.
2074 * TODO: Add a database feature that asserts we have no FL2000
2075 * style links to avoid this check or add a feature that
2076 * uses a similar check to find sorted/unsorted links
2077 * for an on-the-fly upgrade.
2080 ret = replmd_check_upgrade_links(ldb_module_get_ctx(module),
2081 *pdn, el->num_values,
2084 if (ret != LDB_SUCCESS) {
2092 build a new extended DN, including all meta data fields
2094 RMD_FLAGS = DSDB_RMD_FLAG_* bits
2095 RMD_ADDTIME = originating_add_time
2096 RMD_INVOCID = originating_invocation_id
2097 RMD_CHANGETIME = originating_change_time
2098 RMD_ORIGINATING_USN = originating_usn
2099 RMD_LOCAL_USN = local_usn
2100 RMD_VERSION = version
2102 static int replmd_build_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct dsdb_dn *dsdb_dn,
2103 const struct GUID *invocation_id, uint64_t seq_num,
2104 uint64_t local_usn, NTTIME nttime, uint32_t version, bool deleted)
2106 struct ldb_dn *dn = dsdb_dn->dn;
2107 const char *tstring, *usn_string, *flags_string;
2108 struct ldb_val tval;
2110 struct ldb_val usnv, local_usnv;
2111 struct ldb_val vers, flagsv;
2114 const char *dnstring;
2116 uint32_t rmd_flags = deleted?DSDB_RMD_FLAG_DELETED:0;
2118 tstring = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)nttime);
2120 return LDB_ERR_OPERATIONS_ERROR;
2122 tval = data_blob_string_const(tstring);
2124 usn_string = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)seq_num);
2126 return LDB_ERR_OPERATIONS_ERROR;
2128 usnv = data_blob_string_const(usn_string);
2130 usn_string = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)local_usn);
2132 return LDB_ERR_OPERATIONS_ERROR;
2134 local_usnv = data_blob_string_const(usn_string);
2136 vstring = talloc_asprintf(mem_ctx, "%lu", (unsigned long)version);
2138 return LDB_ERR_OPERATIONS_ERROR;
2140 vers = data_blob_string_const(vstring);
2142 status = GUID_to_ndr_blob(invocation_id, dn, &iid);
2143 if (!NT_STATUS_IS_OK(status)) {
2144 return LDB_ERR_OPERATIONS_ERROR;
2147 flags_string = talloc_asprintf(mem_ctx, "%u", rmd_flags);
2148 if (!flags_string) {
2149 return LDB_ERR_OPERATIONS_ERROR;
2151 flagsv = data_blob_string_const(flags_string);
2153 ret = ldb_dn_set_extended_component(dn, "RMD_FLAGS", &flagsv);
2154 if (ret != LDB_SUCCESS) return ret;
2155 ret = ldb_dn_set_extended_component(dn, "RMD_ADDTIME", &tval);
2156 if (ret != LDB_SUCCESS) return ret;
2157 ret = ldb_dn_set_extended_component(dn, "RMD_INVOCID", &iid);
2158 if (ret != LDB_SUCCESS) return ret;
2159 ret = ldb_dn_set_extended_component(dn, "RMD_CHANGETIME", &tval);
2160 if (ret != LDB_SUCCESS) return ret;
2161 ret = ldb_dn_set_extended_component(dn, "RMD_LOCAL_USN", &local_usnv);
2162 if (ret != LDB_SUCCESS) return ret;
2163 ret = ldb_dn_set_extended_component(dn, "RMD_ORIGINATING_USN", &usnv);
2164 if (ret != LDB_SUCCESS) return ret;
2165 ret = ldb_dn_set_extended_component(dn, "RMD_VERSION", &vers);
2166 if (ret != LDB_SUCCESS) return ret;
2168 dnstring = dsdb_dn_get_extended_linearized(mem_ctx, dsdb_dn, 1);
2169 if (dnstring == NULL) {
2170 return LDB_ERR_OPERATIONS_ERROR;
2172 *v = data_blob_string_const(dnstring);
2177 static int replmd_update_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct dsdb_dn *dsdb_dn,
2178 struct dsdb_dn *old_dsdb_dn, const struct GUID *invocation_id,
2179 uint64_t seq_num, uint64_t local_usn, NTTIME nttime,
2180 uint32_t version, bool deleted);
2183 check if any links need upgrading from w2k format
2185 static int replmd_check_upgrade_links(struct ldb_context *ldb,
2186 struct parsed_dn *dns, uint32_t count,
2187 struct ldb_message_element *el,
2188 const char *ldap_oid)
2191 const struct GUID *invocation_id = NULL;
2192 for (i=0; i<count; i++) {
2196 if (dns[i].dsdb_dn == NULL) {
2197 ret = really_parse_trusted_dn(dns, ldb, &dns[i],
2199 if (ret != LDB_SUCCESS) {
2200 return LDB_ERR_INVALID_DN_SYNTAX;
2204 status = dsdb_get_extended_dn_uint32(dns[i].dsdb_dn->dn,
2205 &version, "RMD_VERSION");
2206 if (!NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
2208 * We optimistically assume they are all the same; if
2209 * the first one is fixed, they are all fixed.
2211 * If the first one was *not* fixed and we find a
2212 * later one that is, that is an occasion to shout
2218 DEBUG(0, ("Mixed w2k and fixed format "
2219 "linked attributes\n"));
2223 if (invocation_id == NULL) {
2224 invocation_id = samdb_ntds_invocation_id(ldb);
2225 if (invocation_id == NULL) {
2226 return LDB_ERR_OPERATIONS_ERROR;
2231 /* it's an old one that needs upgrading */
2232 ret = replmd_update_la_val(el->values, dns[i].v,
2233 dns[i].dsdb_dn, dns[i].dsdb_dn,
2234 invocation_id, 1, 1, 0, 0, false);
2235 if (ret != LDB_SUCCESS) {
2241 * This sort() is critical for the operation of
2242 * get_parsed_dns_trusted() because callers of this function
2243 * expect a sorted list, and FL2000 style links are not
2244 * sorted. In particular, as well as the upgrade case,
2245 * get_parsed_dns_trusted() is called from
2246 * replmd_delete_remove_link() even in FL2000 mode
2248 * We do not normally pay the cost of the qsort() due to the
2249 * early return in the RMD_VERSION found case.
2251 TYPESAFE_QSORT(dns, count, parsed_dn_compare);
2256 update an extended DN, including all meta data fields
2258 see replmd_build_la_val for value names
2260 static int replmd_update_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct dsdb_dn *dsdb_dn,
2261 struct dsdb_dn *old_dsdb_dn, const struct GUID *invocation_id,
2262 uint64_t usn, uint64_t local_usn, NTTIME nttime,
2263 uint32_t version, bool deleted)
2265 struct ldb_dn *dn = dsdb_dn->dn;
2266 const char *tstring, *usn_string, *flags_string;
2267 struct ldb_val tval;
2269 struct ldb_val usnv, local_usnv;
2270 struct ldb_val vers, flagsv;
2271 const struct ldb_val *old_addtime;
2272 uint32_t old_version;
2275 const char *dnstring;
2277 uint32_t rmd_flags = deleted?DSDB_RMD_FLAG_DELETED:0;
2279 tstring = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)nttime);
2281 return LDB_ERR_OPERATIONS_ERROR;
2283 tval = data_blob_string_const(tstring);
2285 usn_string = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)usn);
2287 return LDB_ERR_OPERATIONS_ERROR;
2289 usnv = data_blob_string_const(usn_string);
2291 usn_string = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)local_usn);
2293 return LDB_ERR_OPERATIONS_ERROR;
2295 local_usnv = data_blob_string_const(usn_string);
2297 status = GUID_to_ndr_blob(invocation_id, dn, &iid);
2298 if (!NT_STATUS_IS_OK(status)) {
2299 return LDB_ERR_OPERATIONS_ERROR;
2302 flags_string = talloc_asprintf(mem_ctx, "%u", rmd_flags);
2303 if (!flags_string) {
2304 return LDB_ERR_OPERATIONS_ERROR;
2306 flagsv = data_blob_string_const(flags_string);
2308 ret = ldb_dn_set_extended_component(dn, "RMD_FLAGS", &flagsv);
2309 if (ret != LDB_SUCCESS) return ret;
2311 /* get the ADDTIME from the original */
2312 old_addtime = ldb_dn_get_extended_component(old_dsdb_dn->dn, "RMD_ADDTIME");
2313 if (old_addtime == NULL) {
2314 old_addtime = &tval;
2316 if (dsdb_dn != old_dsdb_dn ||
2317 ldb_dn_get_extended_component(dn, "RMD_ADDTIME") == NULL) {
2318 ret = ldb_dn_set_extended_component(dn, "RMD_ADDTIME", old_addtime);
2319 if (ret != LDB_SUCCESS) return ret;
2322 /* use our invocation id */
2323 ret = ldb_dn_set_extended_component(dn, "RMD_INVOCID", &iid);
2324 if (ret != LDB_SUCCESS) return ret;
2326 /* changetime is the current time */
2327 ret = ldb_dn_set_extended_component(dn, "RMD_CHANGETIME", &tval);
2328 if (ret != LDB_SUCCESS) return ret;
2330 /* update the USN */
2331 ret = ldb_dn_set_extended_component(dn, "RMD_ORIGINATING_USN", &usnv);
2332 if (ret != LDB_SUCCESS) return ret;
2334 ret = ldb_dn_set_extended_component(dn, "RMD_LOCAL_USN", &local_usnv);
2335 if (ret != LDB_SUCCESS) return ret;
2337 /* increase the version by 1 */
2338 status = dsdb_get_extended_dn_uint32(old_dsdb_dn->dn, &old_version, "RMD_VERSION");
2339 if (NT_STATUS_IS_OK(status) && old_version >= version) {
2340 version = old_version+1;
2342 vstring = talloc_asprintf(dn, "%lu", (unsigned long)version);
2343 vers = data_blob_string_const(vstring);
2344 ret = ldb_dn_set_extended_component(dn, "RMD_VERSION", &vers);
2345 if (ret != LDB_SUCCESS) return ret;
2347 dnstring = dsdb_dn_get_extended_linearized(mem_ctx, dsdb_dn, 1);
2348 if (dnstring == NULL) {
2349 return LDB_ERR_OPERATIONS_ERROR;
2351 *v = data_blob_string_const(dnstring);
2357 handle adding a linked attribute
2359 static int replmd_modify_la_add(struct ldb_module *module,
2360 struct replmd_private *replmd_private,
2361 const struct dsdb_schema *schema,
2362 struct ldb_message *msg,
2363 struct ldb_message_element *el,
2364 struct ldb_message_element *old_el,
2365 const struct dsdb_attribute *schema_attr,
2368 struct ldb_dn *msg_dn,
2369 struct ldb_request *parent)
2372 struct parsed_dn *dns, *old_dns;
2373 TALLOC_CTX *tmp_ctx = talloc_new(msg);
2375 struct ldb_val *new_values = NULL;
2376 unsigned old_num_values = old_el ? old_el->num_values : 0;
2377 unsigned num_values = 0;
2378 unsigned max_num_values;
2379 const struct GUID *invocation_id;
2380 struct ldb_context *ldb = ldb_module_get_ctx(module);
2382 unix_to_nt_time(&now, t);
2384 invocation_id = samdb_ntds_invocation_id(ldb);
2385 if (!invocation_id) {
2386 talloc_free(tmp_ctx);
2387 return LDB_ERR_OPERATIONS_ERROR;
2390 /* get the DNs to be added, fully parsed.
2392 * We need full parsing because they came off the wire and we don't
2393 * trust them, besides which we need their details to know where to put
2396 ret = get_parsed_dns(module, tmp_ctx, el, &dns,
2397 schema_attr->syntax->ldap_oid, parent);
2398 if (ret != LDB_SUCCESS) {
2399 talloc_free(tmp_ctx);
2403 /* get the existing DNs, lazily parsed */
2404 ret = get_parsed_dns_trusted(module, replmd_private,
2405 tmp_ctx, old_el, &old_dns,
2406 schema_attr->syntax->ldap_oid, parent);
2408 if (ret != LDB_SUCCESS) {
2409 talloc_free(tmp_ctx);
2413 max_num_values = old_num_values + el->num_values;
2414 if (max_num_values < old_num_values) {
2415 DEBUG(0, ("we seem to have overflow in replmd_modify_la_add. "
2416 "old values: %u, new values: %u, sum: %u",
2417 old_num_values, el->num_values, max_num_values));
2418 talloc_free(tmp_ctx);
2419 return LDB_ERR_OPERATIONS_ERROR;
2422 new_values = talloc_zero_array(tmp_ctx, struct ldb_val, max_num_values);
2424 if (new_values == NULL) {
2425 ldb_module_oom(module);
2426 talloc_free(tmp_ctx);
2427 return LDB_ERR_OPERATIONS_ERROR;
2431 * For each new value, find where it would go in the list. If there is
2432 * a matching GUID there, we update the existing value; otherwise we
2436 for (i = 0; i < el->num_values; i++) {
2437 struct parsed_dn *exact;
2438 struct parsed_dn *next;
2440 int err = parsed_dn_find(ldb, old_dns, old_num_values,
2443 dns[i].dsdb_dn->extra_part, 0,
2445 schema_attr->syntax->ldap_oid,
2447 if (err != LDB_SUCCESS) {
2448 talloc_free(tmp_ctx);
2452 if (exact != NULL) {
2454 * We are trying to add one that exists, which is only
2455 * allowed if it was previously deleted.
2457 * When we do undelete a link we change it in place.
2458 * It will be copied across into the right spot in due
2462 rmd_flags = dsdb_dn_rmd_flags(exact->dsdb_dn->dn);
2464 if (!(rmd_flags & DSDB_RMD_FLAG_DELETED)) {
2465 struct GUID_txt_buf guid_str;
2466 ldb_asprintf_errstring(ldb,
2467 "Attribute %s already "
2468 "exists for target GUID %s",
2470 GUID_buf_string(&exact->guid,
2472 talloc_free(tmp_ctx);
2473 /* error codes for 'member' need to be
2475 if (ldb_attr_cmp(el->name, "member") == 0) {
2476 return LDB_ERR_ENTRY_ALREADY_EXISTS;
2478 return LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS;
2482 ret = replmd_update_la_val(new_values, exact->v,
2485 invocation_id, seq_num,
2486 seq_num, now, 0, false);
2487 if (ret != LDB_SUCCESS) {
2488 talloc_free(tmp_ctx);
2492 ret = replmd_add_backlink(module, replmd_private,
2499 if (ret != LDB_SUCCESS) {
2500 talloc_free(tmp_ctx);
2506 * Here we don't have an exact match.
2508 * If next is NULL, this one goes beyond the end of the
2509 * existing list, so we need to add all of those ones first.
2511 * If next is not NULL, we need to add all the ones before
2515 offset = old_num_values;
2517 /* next should have been parsed, but let's make sure */
2518 if (next->dsdb_dn == NULL) {
2519 ret = really_parse_trusted_dn(tmp_ctx, ldb, next,
2520 schema_attr->syntax->ldap_oid);
2521 if (ret != LDB_SUCCESS) {
2525 offset = MIN(next - old_dns, old_num_values);
2528 /* put all the old ones before next on the list */
2529 for (; j < offset; j++) {
2530 new_values[num_values] = *old_dns[j].v;
2534 ret = replmd_add_backlink(module, replmd_private,
2539 /* Make the new linked attribute ldb_val. */
2540 ret = replmd_build_la_val(new_values, &new_values[num_values],
2541 dns[i].dsdb_dn, invocation_id,
2544 if (ret != LDB_SUCCESS) {
2545 talloc_free(tmp_ctx);
2549 if (ret != LDB_SUCCESS) {
2550 talloc_free(tmp_ctx);
2554 /* copy the rest of the old ones (if any) */
2555 for (; j < old_num_values; j++) {
2556 new_values[num_values] = *old_dns[j].v;
2560 talloc_steal(msg->elements, new_values);
2561 if (old_el != NULL) {
2562 talloc_steal(msg->elements, old_el->values);
2564 el->values = new_values;
2565 el->num_values = num_values;
2567 talloc_free(tmp_ctx);
2569 /* we now tell the backend to replace all existing values
2570 with the one we have constructed */
2571 el->flags = LDB_FLAG_MOD_REPLACE;
2578 handle deleting all active linked attributes
2580 static int replmd_modify_la_delete(struct ldb_module *module,
2581 struct replmd_private *replmd_private,
2582 const struct dsdb_schema *schema,
2583 struct ldb_message *msg,
2584 struct ldb_message_element *el,
2585 struct ldb_message_element *old_el,
2586 const struct dsdb_attribute *schema_attr,
2589 struct ldb_dn *msg_dn,
2590 struct ldb_request *parent)
2593 struct parsed_dn *dns, *old_dns;
2594 TALLOC_CTX *tmp_ctx = NULL;
2596 struct ldb_context *ldb = ldb_module_get_ctx(module);
2597 struct ldb_control *vanish_links_ctrl = NULL;
2598 bool vanish_links = false;
2599 unsigned int num_to_delete = el->num_values;
2601 const struct GUID *invocation_id;
2604 unix_to_nt_time(&now, t);
2606 invocation_id = samdb_ntds_invocation_id(ldb);
2607 if (!invocation_id) {
2608 return LDB_ERR_OPERATIONS_ERROR;
2611 if (old_el == NULL || old_el->num_values == 0) {
2612 /* there is nothing to delete... */
2613 if (num_to_delete == 0) {
2614 /* and we're deleting nothing, so that's OK */
2617 return LDB_ERR_NO_SUCH_ATTRIBUTE;
2620 tmp_ctx = talloc_new(msg);
2621 if (tmp_ctx == NULL) {
2622 return LDB_ERR_OPERATIONS_ERROR;
2625 ret = get_parsed_dns(module, tmp_ctx, el, &dns,
2626 schema_attr->syntax->ldap_oid, parent);
2627 if (ret != LDB_SUCCESS) {
2628 talloc_free(tmp_ctx);
2632 ret = get_parsed_dns_trusted(module, replmd_private,
2633 tmp_ctx, old_el, &old_dns,
2634 schema_attr->syntax->ldap_oid, parent);
2636 if (ret != LDB_SUCCESS) {
2637 talloc_free(tmp_ctx);
2642 vanish_links_ctrl = ldb_request_get_control(parent, DSDB_CONTROL_REPLMD_VANISH_LINKS);
2643 if (vanish_links_ctrl) {
2644 vanish_links = true;
2645 vanish_links_ctrl->critical = false;
2649 /* we empty out el->values here to avoid damage if we return early. */
2654 * If vanish links is set, we are actually removing members of
2655 * old_el->values; otherwise we are just marking them deleted.
2657 * There is a special case when no values are given: we remove them
2658 * all. When we have the vanish_links control we just have to remove
2659 * the backlinks and change our element to replace the existing values
2660 * with the empty list.
2663 if (num_to_delete == 0) {
2664 for (i = 0; i < old_el->num_values; i++) {
2665 struct parsed_dn *p = &old_dns[i];
2666 if (p->dsdb_dn == NULL) {
2667 ret = really_parse_trusted_dn(tmp_ctx, ldb, p,
2668 schema_attr->syntax->ldap_oid);
2669 if (ret != LDB_SUCCESS) {
2673 ret = replmd_add_backlink(module, replmd_private,
2674 schema, msg_dn, &p->guid,
2677 if (ret != LDB_SUCCESS) {
2678 talloc_free(tmp_ctx);
2685 rmd_flags = dsdb_dn_rmd_flags(p->dsdb_dn->dn);
2686 if (rmd_flags & DSDB_RMD_FLAG_DELETED) {
2690 ret = replmd_update_la_val(old_el->values, p->v,
2691 p->dsdb_dn, p->dsdb_dn,
2692 invocation_id, seq_num,
2693 seq_num, now, 0, true);
2694 if (ret != LDB_SUCCESS) {
2695 talloc_free(tmp_ctx);
2701 el->flags = LDB_FLAG_MOD_REPLACE;
2702 talloc_free(tmp_ctx);
2708 for (i = 0; i < num_to_delete; i++) {
2709 struct parsed_dn *p = &dns[i];
2710 struct parsed_dn *exact = NULL;
2711 struct parsed_dn *next = NULL;
2712 ret = parsed_dn_find(ldb, old_dns, old_el->num_values,
2715 p->dsdb_dn->extra_part, 0,
2717 schema_attr->syntax->ldap_oid,
2719 if (ret != LDB_SUCCESS) {
2720 talloc_free(tmp_ctx);
2723 if (exact == NULL) {
2724 struct GUID_txt_buf buf;
2725 ldb_asprintf_errstring(ldb, "Attribute %s doesn't "
2726 "exist for target GUID %s",
2728 GUID_buf_string(&p->guid, &buf));
2729 if (ldb_attr_cmp(el->name, "member") == 0) {
2730 talloc_free(tmp_ctx);
2731 return LDB_ERR_UNWILLING_TO_PERFORM;
2733 talloc_free(tmp_ctx);
2734 return LDB_ERR_NO_SUCH_ATTRIBUTE;
2739 if (CHECK_DEBUGLVL(5)) {
2740 rmd_flags = dsdb_dn_rmd_flags(exact->dsdb_dn->dn);
2741 if ((rmd_flags & DSDB_RMD_FLAG_DELETED)) {
2742 struct GUID_txt_buf buf;
2743 const char *guid_str = \
2744 GUID_buf_string(&p->guid, &buf);
2745 DEBUG(5, ("Deleting deleted linked "
2746 "attribute %s to %s, because "
2747 "vanish_links control is set\n",
2748 el->name, guid_str));
2752 /* remove the backlink */
2753 ret = replmd_add_backlink(module,
2760 if (ret != LDB_SUCCESS) {
2761 talloc_free(tmp_ctx);
2765 /* We flag the deletion and tidy it up later. */
2770 rmd_flags = dsdb_dn_rmd_flags(exact->dsdb_dn->dn);
2772 if (rmd_flags & DSDB_RMD_FLAG_DELETED) {
2773 struct GUID_txt_buf buf;
2774 const char *guid_str = GUID_buf_string(&p->guid, &buf);
2775 ldb_asprintf_errstring(ldb, "Attribute %s already "
2776 "deleted for target GUID %s",
2777 el->name, guid_str);
2778 if (ldb_attr_cmp(el->name, "member") == 0) {
2779 talloc_free(tmp_ctx);
2780 return LDB_ERR_UNWILLING_TO_PERFORM;
2782 talloc_free(tmp_ctx);
2783 return LDB_ERR_NO_SUCH_ATTRIBUTE;
2787 ret = replmd_update_la_val(old_el->values, exact->v,
2788 exact->dsdb_dn, exact->dsdb_dn,
2789 invocation_id, seq_num, seq_num,
2791 if (ret != LDB_SUCCESS) {
2792 talloc_free(tmp_ctx);
2795 ret = replmd_add_backlink(module, replmd_private,
2800 if (ret != LDB_SUCCESS) {
2801 talloc_free(tmp_ctx);
2808 for (i = 0; i < old_el->num_values; i++) {
2809 if (old_dns[i].v != NULL) {
2810 old_el->values[j] = *old_dns[i].v;
2814 old_el->num_values = j;
2817 el->values = talloc_steal(msg->elements, old_el->values);
2818 el->num_values = old_el->num_values;
2820 talloc_free(tmp_ctx);
2822 /* we now tell the backend to replace all existing values
2823 with the one we have constructed */
2824 el->flags = LDB_FLAG_MOD_REPLACE;
2830 handle replacing a linked attribute
2832 static int replmd_modify_la_replace(struct ldb_module *module,
2833 struct replmd_private *replmd_private,
2834 const struct dsdb_schema *schema,
2835 struct ldb_message *msg,
2836 struct ldb_message_element *el,
2837 struct ldb_message_element *old_el,
2838 const struct dsdb_attribute *schema_attr,
2841 struct ldb_dn *msg_dn,
2842 struct ldb_request *parent)
2844 unsigned int i, old_i, new_i;
2845 struct parsed_dn *dns, *old_dns;
2846 TALLOC_CTX *tmp_ctx = talloc_new(msg);
2848 const struct GUID *invocation_id;
2849 struct ldb_context *ldb = ldb_module_get_ctx(module);
2850 struct ldb_val *new_values = NULL;
2851 const char *ldap_oid = schema_attr->syntax->ldap_oid;
2852 unsigned int old_num_values;
2853 unsigned int repl_num_values;
2854 unsigned int max_num_values;
2857 unix_to_nt_time(&now, t);
2859 invocation_id = samdb_ntds_invocation_id(ldb);
2860 if (!invocation_id) {
2861 return LDB_ERR_OPERATIONS_ERROR;
2865 * The replace operation is unlike the replace and delete cases in that
2866 * we need to look at every existing link to see whether it is being
2867 * retained or deleted. In other words, we can't avoid parsing the GUIDs.
2869 * As we are trying to combine two sorted lists, the algorithm we use
2870 * is akin to the merge phase of a merge sort. We interleave the two
2871 * lists, doing different things depending on which side the current
2874 * There are three main cases, with some sub-cases.
2876 * - a DN is in the old list but not the new one. It needs to be
2877 * marked as deleted (but left in the list).
2878 * - maybe it is already deleted, and we have less to do.
2880 * - a DN is in both lists. The old data gets replaced by the new,
2881 * and the list doesn't grow. The old link may have been marked as
2882 * deleted, in which case we undelete it.
2884 * - a DN is in the new list only. We add it in the right place.
2887 old_num_values = old_el ? old_el->num_values : 0;
2888 repl_num_values = el->num_values;
2889 max_num_values = old_num_values + repl_num_values;
2891 if (max_num_values == 0) {
2892 /* There is nothing to do! */
2896 ret = get_parsed_dns(module, tmp_ctx, el, &dns, ldap_oid, parent);
2897 if (ret != LDB_SUCCESS) {
2898 talloc_free(tmp_ctx);
2902 ret = get_parsed_dns(module, tmp_ctx, old_el, &old_dns,
2904 if (ret != LDB_SUCCESS) {
2905 talloc_free(tmp_ctx);
2909 ret = replmd_check_upgrade_links(ldb, old_dns, old_num_values,
2911 if (ret != LDB_SUCCESS) {
2912 talloc_free(tmp_ctx);
2916 new_values = talloc_array(tmp_ctx, struct ldb_val, max_num_values);
2917 if (new_values == NULL) {
2918 ldb_module_oom(module);
2919 talloc_free(tmp_ctx);
2920 return LDB_ERR_OPERATIONS_ERROR;
2925 for (i = 0; i < max_num_values; i++) {
2927 struct parsed_dn *old_p, *new_p;
2928 if (old_i < old_num_values && new_i < repl_num_values) {
2929 old_p = &old_dns[old_i];
2930 new_p = &dns[new_i];
2931 cmp = parsed_dn_compare(old_p, new_p);
2932 } else if (old_i < old_num_values) {
2933 /* the new list is empty, read the old list */
2934 old_p = &old_dns[old_i];
2937 } else if (new_i < repl_num_values) {
2938 /* the old list is empty, read new list */
2940 new_p = &dns[new_i];
2948 * An old ones that come before the next replacement
2949 * (if any). We mark it as deleted and add it to the
2952 uint32_t rmd_flags = dsdb_dn_rmd_flags(old_p->dsdb_dn->dn);
2953 if ((rmd_flags & DSDB_RMD_FLAG_DELETED) == 0) {
2954 ret = replmd_update_la_val(new_values, old_p->v,
2960 if (ret != LDB_SUCCESS) {
2961 talloc_free(tmp_ctx);
2965 ret = replmd_add_backlink(module, replmd_private,
2968 &old_p->guid, false,
2971 if (ret != LDB_SUCCESS) {
2972 talloc_free(tmp_ctx);
2976 new_values[i] = *old_p->v;
2978 } else if (cmp == 0) {
2980 * We are overwriting one. If it was previously
2981 * deleted, we need to add a backlink.
2983 * Note that if any RMD_FLAGs in an extended new DN
2988 ret = replmd_update_la_val(new_values, old_p->v,
2994 if (ret != LDB_SUCCESS) {
2995 talloc_free(tmp_ctx);
2999 rmd_flags = dsdb_dn_rmd_flags(old_p->dsdb_dn->dn);
3000 if ((rmd_flags & DSDB_RMD_FLAG_DELETED) != 0) {
3001 ret = replmd_add_backlink(module, replmd_private,
3007 if (ret != LDB_SUCCESS) {
3008 talloc_free(tmp_ctx);
3013 new_values[i] = *old_p->v;
3018 * Replacements that don't match an existing one. We
3019 * just add them to the final list.
3021 ret = replmd_build_la_val(new_values,
3027 if (ret != LDB_SUCCESS) {
3028 talloc_free(tmp_ctx);
3031 ret = replmd_add_backlink(module, replmd_private,
3037 if (ret != LDB_SUCCESS) {
3038 talloc_free(tmp_ctx);
3041 new_values[i] = *new_p->v;
3045 if (old_el != NULL) {
3046 talloc_steal(msg->elements, old_el->values);
3048 el->values = talloc_steal(msg->elements, new_values);
3050 talloc_free(tmp_ctx);
3052 el->flags = LDB_FLAG_MOD_REPLACE;
3059 handle linked attributes in modify requests
3061 static int replmd_modify_handle_linked_attribs(struct ldb_module *module,
3062 struct replmd_private *replmd_private,
3063 struct ldb_message *msg,
3064 uint64_t seq_num, time_t t,
3065 struct ldb_request *parent)
3067 struct ldb_result *res;
3070 struct ldb_context *ldb = ldb_module_get_ctx(module);
3071 struct ldb_message *old_msg;
3073 const struct dsdb_schema *schema;
3075 if (dsdb_functional_level(ldb) == DS_DOMAIN_FUNCTION_2000) {
3077 * Nothing special is required for modifying or vanishing links
3078 * in fl2000 since they are just strings in a multi-valued
3081 struct ldb_control *ctrl = ldb_request_get_control(parent,
3082 DSDB_CONTROL_REPLMD_VANISH_LINKS);
3084 ctrl->critical = false;
3092 * We should restrict this to the intersection of the list of
3093 * linked attributes in the schema and the list of attributes
3096 * This will help performance a little, as otherwise we have
3097 * to allocate the entire object value-by-value.
3099 ret = dsdb_module_search_dn(module, msg, &res, msg->dn, NULL,
3100 DSDB_FLAG_NEXT_MODULE |
3101 DSDB_SEARCH_SHOW_RECYCLED |
3102 DSDB_SEARCH_REVEAL_INTERNALS |
3103 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT,
3105 if (ret != LDB_SUCCESS) {
3108 schema = dsdb_get_schema(ldb, res);
3110 return LDB_ERR_OPERATIONS_ERROR;
3113 old_msg = res->msgs[0];
3115 for (i=0; i<msg->num_elements; i++) {
3116 struct ldb_message_element *el = &msg->elements[i];
3117 struct ldb_message_element *old_el, *new_el;
3118 unsigned int mod_type = LDB_FLAG_MOD_TYPE(el->flags);
3119 const struct dsdb_attribute *schema_attr
3120 = dsdb_attribute_by_lDAPDisplayName(schema, el->name);
3122 ldb_asprintf_errstring(ldb,
3123 "%s: attribute %s is not a valid attribute in schema",
3124 __FUNCTION__, el->name);
3125 return LDB_ERR_OBJECT_CLASS_VIOLATION;
3127 if (schema_attr->linkID == 0) {
3130 if ((schema_attr->linkID & 1) == 1) {
3131 if (parent && ldb_request_get_control(parent, DSDB_CONTROL_DBCHECK)) {
3134 /* Odd is for the target. Illegal to modify */
3135 ldb_asprintf_errstring(ldb,
3136 "attribute %s must not be modified directly, it is a linked attribute", el->name);
3137 return LDB_ERR_UNWILLING_TO_PERFORM;
3139 old_el = ldb_msg_find_element(old_msg, el->name);
3141 case LDB_FLAG_MOD_REPLACE:
3142 ret = replmd_modify_la_replace(module, replmd_private,
3143 schema, msg, el, old_el,
3144 schema_attr, seq_num, t,
3148 case LDB_FLAG_MOD_DELETE:
3149 ret = replmd_modify_la_delete(module, replmd_private,
3150 schema, msg, el, old_el,
3151 schema_attr, seq_num, t,
3155 case LDB_FLAG_MOD_ADD:
3156 ret = replmd_modify_la_add(module, replmd_private,
3157 schema, msg, el, old_el,
3158 schema_attr, seq_num, t,
3163 ldb_asprintf_errstring(ldb,
3164 "invalid flags 0x%x for %s linked attribute",
3165 el->flags, el->name);
3166 return LDB_ERR_UNWILLING_TO_PERFORM;
3168 if (dsdb_check_single_valued_link(schema_attr, el) != LDB_SUCCESS) {
3169 ldb_asprintf_errstring(ldb,
3170 "Attribute %s is single valued but more than one value has been supplied",
3172 /* Return codes as found on Windows 2012r2 */
3173 if (mod_type == LDB_FLAG_MOD_REPLACE) {
3174 return LDB_ERR_CONSTRAINT_VIOLATION;
3176 return LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS;
3179 el->flags |= LDB_FLAG_INTERNAL_DISABLE_SINGLE_VALUE_CHECK;
3182 if (ret != LDB_SUCCESS) {
3186 ldb_msg_remove_attr(old_msg, el->name);
3188 ldb_msg_add_empty(old_msg, el->name, 0, &new_el);
3189 new_el->num_values = el->num_values;
3190 new_el->values = talloc_steal(msg->elements, el->values);
3192 /* TODO: this relises a bit too heavily on the exact
3193 behaviour of ldb_msg_find_element and
3194 ldb_msg_remove_element */
3195 old_el = ldb_msg_find_element(msg, el->name);
3197 ldb_msg_remove_element(msg, old_el);
3207 static int send_rodc_referral(struct ldb_request *req,
3208 struct ldb_context *ldb,
3211 char *referral = NULL;
3212 struct loadparm_context *lp_ctx = NULL;
3213 struct ldb_dn *fsmo_role_dn = NULL;
3214 struct ldb_dn *role_owner_dn = NULL;
3215 const char *domain = NULL;
3218 lp_ctx = talloc_get_type(ldb_get_opaque(ldb, "loadparm"),
3219 struct loadparm_context);
3221 werr = dsdb_get_fsmo_role_info(req, ldb, DREPL_PDC_MASTER,
3222 &fsmo_role_dn, &role_owner_dn);
3224 if (W_ERROR_IS_OK(werr)) {
3225 struct ldb_dn *server_dn = ldb_dn_copy(req, role_owner_dn);
3226 if (server_dn != NULL) {
3227 ldb_dn_remove_child_components(server_dn, 1);
3228 domain = samdb_dn_to_dnshostname(ldb, req,
3233 if (domain == NULL) {
3234 domain = lpcfg_dnsdomain(lp_ctx);
3237 referral = talloc_asprintf(req, "ldap://%s/%s",
3239 ldb_dn_get_linearized(dn));
3240 if (referral == NULL) {
3242 return LDB_ERR_OPERATIONS_ERROR;
3245 return ldb_module_send_referral(req, referral);
3249 static int replmd_modify(struct ldb_module *module, struct ldb_request *req)
3251 struct ldb_context *ldb;
3252 struct replmd_replicated_request *ac;
3253 struct ldb_request *down_req;
3254 struct ldb_message *msg;
3255 time_t t = time(NULL);
3257 bool is_urgent = false, rodc = false;
3258 bool is_schema_nc = false;
3259 unsigned int functional_level;
3260 const struct ldb_message_element *guid_el = NULL;
3261 struct ldb_control *sd_propagation_control;
3262 struct replmd_private *replmd_private =
3263 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
3265 /* do not manipulate our control entries */
3266 if (ldb_dn_is_special(req->op.mod.message->dn)) {
3267 return ldb_next_request(module, req);
3270 sd_propagation_control = ldb_request_get_control(req,
3271 DSDB_CONTROL_SEC_DESC_PROPAGATION_OID);
3272 if (sd_propagation_control != NULL) {
3273 if (req->op.mod.message->num_elements != 1) {
3274 return ldb_module_operr(module);
3276 ret = strcmp(req->op.mod.message->elements[0].name,
3277 "nTSecurityDescriptor");
3279 return ldb_module_operr(module);
3282 return ldb_next_request(module, req);
3285 ldb = ldb_module_get_ctx(module);
3287 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_modify\n");
3289 guid_el = ldb_msg_find_element(req->op.mod.message, "objectGUID");
3290 if (guid_el != NULL) {
3291 ldb_set_errstring(ldb,
3292 "replmd_modify: it's not allowed to change the objectGUID!");
3293 return LDB_ERR_CONSTRAINT_VIOLATION;
3296 ac = replmd_ctx_init(module, req);
3298 return ldb_module_oom(module);
3301 functional_level = dsdb_functional_level(ldb);
3303 /* we have to copy the message as the caller might have it as a const */
3304 msg = ldb_msg_copy_shallow(ac, req->op.mod.message);
3308 return LDB_ERR_OPERATIONS_ERROR;
3311 ldb_msg_remove_attr(msg, "whenChanged");
3312 ldb_msg_remove_attr(msg, "uSNChanged");
3314 is_schema_nc = ldb_dn_compare_base(replmd_private->schema_dn, msg->dn) == 0;
3316 ret = replmd_update_rpmd(module, ac->schema, req, NULL,
3317 msg, &ac->seq_num, t, is_schema_nc,
3319 if (rodc && (ret == LDB_ERR_REFERRAL)) {
3320 ret = send_rodc_referral(req, ldb, msg->dn);
3326 if (ret != LDB_SUCCESS) {
3331 ret = replmd_modify_handle_linked_attribs(module, replmd_private,
3332 msg, ac->seq_num, t, req);
3333 if (ret != LDB_SUCCESS) {
3339 * - replace the old object with the newly constructed one
3342 ac->is_urgent = is_urgent;
3344 ret = ldb_build_mod_req(&down_req, ldb, ac,
3347 ac, replmd_op_callback,
3349 LDB_REQ_SET_LOCATION(down_req);
3350 if (ret != LDB_SUCCESS) {
3355 /* current partition control is needed by "replmd_op_callback" */
3356 if (ldb_request_get_control(req, DSDB_CONTROL_CURRENT_PARTITION_OID) == NULL) {
3357 ret = ldb_request_add_control(down_req,
3358 DSDB_CONTROL_CURRENT_PARTITION_OID,
3360 if (ret != LDB_SUCCESS) {
3366 /* If we are in functional level 2000, then
3367 * replmd_modify_handle_linked_attribs will have done
3369 if (functional_level == DS_DOMAIN_FUNCTION_2000) {
3370 ret = ldb_request_add_control(down_req, DSDB_CONTROL_APPLY_LINKS, false, NULL);
3371 if (ret != LDB_SUCCESS) {
3377 talloc_steal(down_req, msg);
3379 /* we only change whenChanged and uSNChanged if the seq_num
3381 if (ac->seq_num != 0) {
3382 ret = add_time_element(msg, "whenChanged", t);
3383 if (ret != LDB_SUCCESS) {
3389 ret = add_uint64_element(ldb, msg, "uSNChanged", ac->seq_num);
3390 if (ret != LDB_SUCCESS) {
3397 /* go on with the call chain */
3398 return ldb_next_request(module, down_req);
3401 static int replmd_rename_callback(struct ldb_request *req, struct ldb_reply *ares);
3404 handle a rename request
3406 On a rename we need to do an extra ldb_modify which sets the
3407 whenChanged and uSNChanged attributes. We do this in a callback after the success.
3409 static int replmd_rename(struct ldb_module *module, struct ldb_request *req)
3411 struct ldb_context *ldb;
3412 struct replmd_replicated_request *ac;
3414 struct ldb_request *down_req;
3416 /* do not manipulate our control entries */
3417 if (ldb_dn_is_special(req->op.mod.message->dn)) {
3418 return ldb_next_request(module, req);
3421 ldb = ldb_module_get_ctx(module);
3423 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_rename\n");
3425 ac = replmd_ctx_init(module, req);
3427 return ldb_module_oom(module);
3430 ret = ldb_build_rename_req(&down_req, ldb, ac,
3431 ac->req->op.rename.olddn,
3432 ac->req->op.rename.newdn,
3434 ac, replmd_rename_callback,
3436 LDB_REQ_SET_LOCATION(down_req);
3437 if (ret != LDB_SUCCESS) {
3442 /* go on with the call chain */
3443 return ldb_next_request(module, down_req);
3446 /* After the rename is compleated, update the whenchanged etc */
3447 static int replmd_rename_callback(struct ldb_request *req, struct ldb_reply *ares)
3449 struct ldb_context *ldb;
3450 struct ldb_request *down_req;
3451 struct ldb_message *msg;
3452 const struct dsdb_attribute *rdn_attr;
3453 const char *rdn_name;
3454 const struct ldb_val *rdn_val;
3455 const char *attrs[5] = { NULL, };
3456 time_t t = time(NULL);
3458 bool is_urgent = false, rodc = false;
3460 struct replmd_replicated_request *ac =
3461 talloc_get_type(req->context, struct replmd_replicated_request);
3462 struct replmd_private *replmd_private =
3463 talloc_get_type(ldb_module_get_private(ac->module),
3464 struct replmd_private);
3466 ldb = ldb_module_get_ctx(ac->module);
3468 if (ares->error != LDB_SUCCESS) {
3469 return ldb_module_done(ac->req, ares->controls,
3470 ares->response, ares->error);
3473 if (ares->type != LDB_REPLY_DONE) {
3474 ldb_set_errstring(ldb,
3475 "invalid ldb_reply_type in callback");
3477 return ldb_module_done(ac->req, NULL, NULL,
3478 LDB_ERR_OPERATIONS_ERROR);
3482 * - replace the old object with the newly constructed one
3485 msg = ldb_msg_new(ac);
3488 return LDB_ERR_OPERATIONS_ERROR;
3491 msg->dn = ac->req->op.rename.newdn;
3493 is_schema_nc = ldb_dn_compare_base(replmd_private->schema_dn, msg->dn) == 0;
3495 rdn_name = ldb_dn_get_rdn_name(msg->dn);
3496 if (rdn_name == NULL) {
3498 return ldb_module_done(ac->req, NULL, NULL,
3502 /* normalize the rdn attribute name */
3503 rdn_attr = dsdb_attribute_by_lDAPDisplayName(ac->schema, rdn_name);
3504 if (rdn_attr == NULL) {
3506 return ldb_module_done(ac->req, NULL, NULL,
3509 rdn_name = rdn_attr->lDAPDisplayName;
3511 rdn_val = ldb_dn_get_rdn_val(msg->dn);
3512 if (rdn_val == NULL) {
3514 return ldb_module_done(ac->req, NULL, NULL,
3518 if (ldb_msg_add_empty(msg, rdn_name, LDB_FLAG_MOD_REPLACE, NULL) != 0) {
3520 return ldb_module_done(ac->req, NULL, NULL,
3523 if (ldb_msg_add_value(msg, rdn_name, rdn_val, NULL) != 0) {
3525 return ldb_module_done(ac->req, NULL, NULL,
3528 if (ldb_msg_add_empty(msg, "name", LDB_FLAG_MOD_REPLACE, NULL) != 0) {
3530 return ldb_module_done(ac->req, NULL, NULL,
3533 if (ldb_msg_add_value(msg, "name", rdn_val, NULL) != 0) {
3535 return ldb_module_done(ac->req, NULL, NULL,
3540 * here we let replmd_update_rpmd() only search for
3541 * the existing "replPropertyMetaData" and rdn_name attributes.
3543 * We do not want the existing "name" attribute as
3544 * the "name" attribute needs to get the version
3545 * updated on rename even if the rdn value hasn't changed.
3547 * This is the diff of the meta data, for a moved user
3548 * on a w2k8r2 server:
3551 * -dn: CN=sdf df,CN=Users,DC=bla,DC=base
3552 * +dn: CN=sdf df,OU=TestOU,DC=bla,DC=base
3553 * replPropertyMetaData: NDR: struct replPropertyMetaDataBlob
3554 * version : 0x00000001 (1)
3555 * reserved : 0x00000000 (0)
3556 * @@ -66,11 +66,11 @@ replPropertyMetaData: NDR: struct re
3557 * local_usn : 0x00000000000037a5 (14245)
3558 * array: struct replPropertyMetaData1
3559 * attid : DRSUAPI_ATTID_name (0x90001)
3560 * - version : 0x00000001 (1)
3561 * - originating_change_time : Wed Feb 9 17:20:49 2011 CET
3562 * + version : 0x00000002 (2)
3563 * + originating_change_time : Wed Apr 6 15:21:01 2011 CEST
3564 * originating_invocation_id: 0d36ca05-5507-4e62-aca3-354bab0d39e1
3565 * - originating_usn : 0x00000000000037a5 (14245)
3566 * - local_usn : 0x00000000000037a5 (14245)
3567 * + originating_usn : 0x0000000000003834 (14388)
3568 * + local_usn : 0x0000000000003834 (14388)
3569 * array: struct replPropertyMetaData1
3570 * attid : DRSUAPI_ATTID_userAccountControl (0x90008)
3571 * version : 0x00000004 (4)
3573 attrs[0] = "replPropertyMetaData";
3574 attrs[1] = "objectClass";
3575 attrs[2] = "instanceType";
3576 attrs[3] = rdn_name;
3579 ret = replmd_update_rpmd(ac->module, ac->schema, req, attrs,
3580 msg, &ac->seq_num, t,
3581 is_schema_nc, &is_urgent, &rodc);
3582 if (rodc && (ret == LDB_ERR_REFERRAL)) {
3583 ret = send_rodc_referral(req, ldb, ac->req->op.rename.olddn);
3585 return ldb_module_done(req, NULL, NULL, ret);
3588 if (ret != LDB_SUCCESS) {
3590 return ldb_module_done(ac->req, NULL, NULL, ret);
3593 if (ac->seq_num == 0) {
3595 return ldb_module_done(ac->req, NULL, NULL,
3597 "internal error seq_num == 0"));
3599 ac->is_urgent = is_urgent;
3601 ret = ldb_build_mod_req(&down_req, ldb, ac,
3604 ac, replmd_op_callback,
3606 LDB_REQ_SET_LOCATION(down_req);
3607 if (ret != LDB_SUCCESS) {
3612 /* current partition control is needed by "replmd_op_callback" */
3613 if (ldb_request_get_control(req, DSDB_CONTROL_CURRENT_PARTITION_OID) == NULL) {
3614 ret = ldb_request_add_control(down_req,
3615 DSDB_CONTROL_CURRENT_PARTITION_OID,
3617 if (ret != LDB_SUCCESS) {
3623 talloc_steal(down_req, msg);
3625 ret = add_time_element(msg, "whenChanged", t);
3626 if (ret != LDB_SUCCESS) {
3632 ret = add_uint64_element(ldb, msg, "uSNChanged", ac->seq_num);
3633 if (ret != LDB_SUCCESS) {
3639 /* go on with the call chain - do the modify after the rename */
3640 return ldb_next_request(ac->module, down_req);
3644 * remove links from objects that point at this object when an object
3645 * is deleted. We remove it from the NEXT module per MS-DRSR 5.160
3646 * RemoveObj which states that link removal due to the object being
3647 * deleted is NOT an originating update - they just go away!
3650 static int replmd_delete_remove_link(struct ldb_module *module,
3651 const struct dsdb_schema *schema,
3652 struct replmd_private *replmd_private,
3655 struct ldb_message_element *el,
3656 const struct dsdb_attribute *sa,
3657 struct ldb_request *parent)
3660 TALLOC_CTX *tmp_ctx = talloc_new(module);
3661 struct ldb_context *ldb = ldb_module_get_ctx(module);
3663 for (i=0; i<el->num_values; i++) {
3664 struct dsdb_dn *dsdb_dn;
3666 struct ldb_message *msg;
3667 const struct dsdb_attribute *target_attr;
3668 struct ldb_message_element *el2;
3670 struct ldb_val dn_val;
3671 uint32_t dsdb_flags = 0;
3672 const char *attrs[] = { NULL, NULL };
3673 struct ldb_result *link_res;
3674 struct ldb_message *link_msg;
3675 struct ldb_message_element *link_el;
3676 struct parsed_dn *link_dns;
3677 struct parsed_dn *p = NULL, *unused = NULL;
3679 if (dsdb_dn_is_deleted_val(&el->values[i])) {
3683 dsdb_dn = dsdb_dn_parse(tmp_ctx, ldb, &el->values[i], sa->syntax->ldap_oid);
3685 talloc_free(tmp_ctx);
3686 return LDB_ERR_OPERATIONS_ERROR;
3689 /* remove the link */
3690 msg = ldb_msg_new(tmp_ctx);
3692 ldb_module_oom(module);
3693 talloc_free(tmp_ctx);
3694 return LDB_ERR_OPERATIONS_ERROR;
3698 msg->dn = dsdb_dn->dn;
3700 target_attr = dsdb_attribute_by_linkID(schema, sa->linkID ^ 1);
3701 if (target_attr == NULL) {
3704 attrs[0] = target_attr->lDAPDisplayName;
3706 ret = ldb_msg_add_empty(msg, target_attr->lDAPDisplayName,
3707 LDB_FLAG_MOD_DELETE, &el2);
3708 if (ret != LDB_SUCCESS) {
3709 ldb_module_oom(module);
3710 talloc_free(tmp_ctx);
3711 return LDB_ERR_OPERATIONS_ERROR;
3714 ret = dsdb_module_search_dn(module, tmp_ctx, &link_res,
3716 DSDB_FLAG_NEXT_MODULE |
3717 DSDB_SEARCH_SHOW_EXTENDED_DN,
3720 if (ret != LDB_SUCCESS) {
3721 talloc_free(tmp_ctx);
3725 link_msg = link_res->msgs[0];
3726 link_el = ldb_msg_find_element(link_msg,
3727 target_attr->lDAPDisplayName);
3728 if (link_el == NULL) {
3729 talloc_free(tmp_ctx);
3730 return LDB_ERR_NO_SUCH_ATTRIBUTE;
3734 * This call 'upgrades' the links in link_dns, but we
3735 * do not commit the result back into the database, so
3736 * this is safe to call in FL2000 or on databases that
3737 * have been run at that level in the past.
3739 ret = get_parsed_dns_trusted(module, replmd_private, tmp_ctx,
3741 target_attr->syntax->ldap_oid, parent);
3742 if (ret != LDB_SUCCESS) {
3743 talloc_free(tmp_ctx);
3747 ret = parsed_dn_find(ldb, link_dns, link_el->num_values,
3751 target_attr->syntax->ldap_oid, false);
3752 if (ret != LDB_SUCCESS) {
3753 talloc_free(tmp_ctx);
3758 ldb_asprintf_errstring(ldb_module_get_ctx(module),
3759 "Failed to find forward link on %s "
3760 "as %s to remove backlink %s on %s",
3761 ldb_dn_get_linearized(msg->dn),
3762 target_attr->lDAPDisplayName,
3763 sa->lDAPDisplayName,
3764 ldb_dn_get_linearized(dn));
3765 talloc_free(tmp_ctx);
3766 return LDB_ERR_NO_SUCH_ATTRIBUTE;
3770 /* This needs to get the Binary DN, by first searching */
3771 dn_str = dsdb_dn_get_linearized(tmp_ctx,
3774 dn_val = data_blob_string_const(dn_str);
3775 el2->values = &dn_val;
3776 el2->num_values = 1;
3779 * Ensure that we tell the modification to vanish any linked
3780 * attributes (not simply mark them as isDeleted = TRUE)
3782 dsdb_flags |= DSDB_REPLMD_VANISH_LINKS;
3784 ret = dsdb_module_modify(module, msg, dsdb_flags|DSDB_FLAG_OWN_MODULE, parent);
3785 if (ret != LDB_SUCCESS) {
3786 talloc_free(tmp_ctx);
3790 talloc_free(tmp_ctx);
3796 handle update of replication meta data for deletion of objects
3798 This also handles the mapping of delete to a rename operation
3799 to allow deletes to be replicated.
3801 It also handles the incoming deleted objects, to ensure they are
3802 fully deleted here. In that case re_delete is true, and we do not
3803 use this as a signal to change the deleted state, just reinforce it.
3806 static int replmd_delete_internals(struct ldb_module *module, struct ldb_request *req, bool re_delete)
3808 int ret = LDB_ERR_OTHER;
3809 bool retb, disallow_move_on_delete;
3810 struct ldb_dn *old_dn, *new_dn;
3811 const char *rdn_name;
3812 const struct ldb_val *rdn_value, *new_rdn_value;
3814 struct ldb_context *ldb = ldb_module_get_ctx(module);
3815 const struct dsdb_schema *schema;
3816 struct ldb_message *msg, *old_msg;
3817 struct ldb_message_element *el;
3818 TALLOC_CTX *tmp_ctx;
3819 struct ldb_result *res, *parent_res;
3820 static const char * const preserved_attrs[] = {
3821 /* yes, this really is a hard coded list. See MS-ADTS
3822 section 3.1.1.5.5.1.1 */
3825 "dNReferenceUpdate",
3836 "msDS-LastKnownRDN",
3842 "distinguishedName",
3846 "proxiedObjectName",
3848 "nTSecurityDescriptor",
3849 "replPropertyMetaData",
3851 "securityIdentifier",
3859 "userAccountControl",
3866 static const char * const all_attrs[] = {
3867 DSDB_SECRET_ATTRIBUTES,
3871 unsigned int i, el_count = 0;
3872 uint32_t dsdb_flags = 0;
3873 struct replmd_private *replmd_private;
3874 enum deletion_state deletion_state, next_deletion_state;
3876 if (ldb_dn_is_special(req->op.del.dn)) {
3877 return ldb_next_request(module, req);
3881 * We have to allow dbcheck to remove an object that
3882 * is beyond repair, and to do so totally. This could
3883 * mean we we can get a partial object from the other
3884 * DC, causing havoc, so dbcheck suggests
3885 * re-replication first. dbcheck sets both DBCHECK
3886 * and RELAX in this situation.
3888 if (ldb_request_get_control(req, LDB_CONTROL_RELAX_OID)
3889 && ldb_request_get_control(req, DSDB_CONTROL_DBCHECK)) {
3890 /* really, really remove it */
3891 return ldb_next_request(module, req);
3894 tmp_ctx = talloc_new(ldb);
3897 return LDB_ERR_OPERATIONS_ERROR;
3900 schema = dsdb_get_schema(ldb, tmp_ctx);
3902 talloc_free(tmp_ctx);
3903 return LDB_ERR_OPERATIONS_ERROR;
3906 old_dn = ldb_dn_copy(tmp_ctx, req->op.del.dn);
3908 /* we need the complete msg off disk, so we can work out which
3909 attributes need to be removed */
3910 ret = dsdb_module_search_dn(module, tmp_ctx, &res, old_dn, all_attrs,
3911 DSDB_FLAG_NEXT_MODULE |
3912 DSDB_SEARCH_SHOW_RECYCLED |
3913 DSDB_SEARCH_REVEAL_INTERNALS |
3914 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT, req);
3915 if (ret != LDB_SUCCESS) {
3916 ldb_asprintf_errstring(ldb_module_get_ctx(module),
3917 "repmd_delete: Failed to %s %s, because we failed to find it: %s",
3918 re_delete ? "re-delete" : "delete",
3919 ldb_dn_get_linearized(old_dn),
3920 ldb_errstring(ldb_module_get_ctx(module)));
3921 talloc_free(tmp_ctx);
3924 old_msg = res->msgs[0];
3926 replmd_deletion_state(module, old_msg,
3928 &next_deletion_state);
3930 /* This supports us noticing an incoming isDeleted and acting on it */
3932 SMB_ASSERT(deletion_state > OBJECT_NOT_DELETED);
3933 next_deletion_state = deletion_state;
3936 if (next_deletion_state == OBJECT_REMOVED) {
3938 * We have to prevent objects being deleted, even if
3939 * the administrator really wants them gone, as
3940 * without the tombstone, we can get a partial object
3941 * from the other DC, causing havoc.
3943 * The only other valid case is when the 180 day
3944 * timeout has expired, when relax is specified.
3946 if (ldb_request_get_control(req, LDB_CONTROL_RELAX_OID)) {
3947 /* it is already deleted - really remove it this time */
3948 talloc_free(tmp_ctx);
3949 return ldb_next_request(module, req);
3952 ldb_asprintf_errstring(ldb, "Refusing to delete tombstone object %s. "
3953 "This check is to prevent corruption of the replicated state.",
3954 ldb_dn_get_linearized(old_msg->dn));
3955 return LDB_ERR_UNWILLING_TO_PERFORM;
3958 rdn_name = ldb_dn_get_rdn_name(old_dn);
3959 rdn_value = ldb_dn_get_rdn_val(old_dn);
3960 if ((rdn_name == NULL) || (rdn_value == NULL)) {
3961 talloc_free(tmp_ctx);
3962 return ldb_operr(ldb);
3965 msg = ldb_msg_new(tmp_ctx);
3967 ldb_module_oom(module);
3968 talloc_free(tmp_ctx);
3969 return LDB_ERR_OPERATIONS_ERROR;
3974 /* consider the SYSTEM_FLAG_DISALLOW_MOVE_ON_DELETE flag */
3975 disallow_move_on_delete =
3976 (ldb_msg_find_attr_as_int(old_msg, "systemFlags", 0)
3977 & SYSTEM_FLAG_DISALLOW_MOVE_ON_DELETE);
3979 /* work out where we will be renaming this object to */
3980 if (!disallow_move_on_delete) {
3981 struct ldb_dn *deleted_objects_dn;
3982 ret = dsdb_get_deleted_objects_dn(ldb, tmp_ctx, old_dn,
3983 &deleted_objects_dn);
3986 * We should not move objects if we can't find the
3987 * deleted objects DN. Not moving (or otherwise
3988 * harming) the Deleted Objects DN itself is handled
3991 if (re_delete && (ret != LDB_SUCCESS)) {
3992 new_dn = ldb_dn_get_parent(tmp_ctx, old_dn);
3993 if (new_dn == NULL) {
3994 ldb_module_oom(module);
3995 talloc_free(tmp_ctx);
3996 return LDB_ERR_OPERATIONS_ERROR;
3998 } else if (ret != LDB_SUCCESS) {
3999 /* this is probably an attempted delete on a partition
4000 * that doesn't allow delete operations, such as the
4001 * schema partition */
4002 ldb_asprintf_errstring(ldb, "No Deleted Objects container for DN %s",
4003 ldb_dn_get_linearized(old_dn));
4004 talloc_free(tmp_ctx);
4005 return LDB_ERR_UNWILLING_TO_PERFORM;
4007 new_dn = deleted_objects_dn;
4010 new_dn = ldb_dn_get_parent(tmp_ctx, old_dn);
4011 if (new_dn == NULL) {
4012 ldb_module_oom(module);
4013 talloc_free(tmp_ctx);
4014 return LDB_ERR_OPERATIONS_ERROR;
4018 /* get the objects GUID from the search we just did */
4019 guid = samdb_result_guid(old_msg, "objectGUID");
4021 if (deletion_state == OBJECT_NOT_DELETED) {
4022 /* Add a formatted child */
4023 retb = ldb_dn_add_child_fmt(new_dn, "%s=%s\\0ADEL:%s",
4025 ldb_dn_escape_value(tmp_ctx, *rdn_value),
4026 GUID_string(tmp_ctx, &guid));
4028 ldb_asprintf_errstring(ldb, __location__
4029 ": Unable to add a formatted child to dn: %s",
4030 ldb_dn_get_linearized(new_dn));
4031 talloc_free(tmp_ctx);
4032 return LDB_ERR_OPERATIONS_ERROR;
4035 ret = ldb_msg_add_string(msg, "isDeleted", "TRUE");
4036 if (ret != LDB_SUCCESS) {
4037 ldb_asprintf_errstring(ldb, __location__
4038 ": Failed to add isDeleted string to the msg");
4039 talloc_free(tmp_ctx);
4042 msg->elements[el_count++].flags = LDB_FLAG_MOD_REPLACE;
4045 * No matter what has happened with other renames etc, try again to
4046 * get this to be under the deleted DN. See MS-DRSR 5.160 RemoveObj
4049 struct ldb_dn *rdn = ldb_dn_copy(tmp_ctx, old_dn);
4050 retb = ldb_dn_remove_base_components(rdn, ldb_dn_get_comp_num(rdn) - 1);
4052 ldb_asprintf_errstring(ldb, __location__
4053 ": Unable to add a prepare rdn of %s",
4054 ldb_dn_get_linearized(rdn));
4055 talloc_free(tmp_ctx);
4056 return LDB_ERR_OPERATIONS_ERROR;
4058 SMB_ASSERT(ldb_dn_get_comp_num(rdn) == 1);
4060 retb = ldb_dn_add_child(new_dn, rdn);
4062 ldb_asprintf_errstring(ldb, __location__
4063 ": Unable to add rdn %s to base dn: %s",
4064 ldb_dn_get_linearized(rdn),
4065 ldb_dn_get_linearized(new_dn));
4066 talloc_free(tmp_ctx);
4067 return LDB_ERR_OPERATIONS_ERROR;
4072 now we need to modify the object in the following ways:
4074 - add isDeleted=TRUE
4075 - update rDN and name, with new rDN
4076 - remove linked attributes
4077 - remove objectCategory and sAMAccountType
4078 - remove attribs not on the preserved list
4079 - preserved if in above list, or is rDN
4080 - remove all linked attribs from this object
4081 - remove all links from other objects to this object
4082 - add lastKnownParent
4083 - update replPropertyMetaData?
4085 see MS-ADTS "Tombstone Requirements" section 3.1.1.5.5.1.1
4088 if (deletion_state == OBJECT_NOT_DELETED) {
4089 struct ldb_dn *parent_dn = ldb_dn_get_parent(tmp_ctx, old_dn);
4090 char *parent_dn_str = NULL;
4092 /* we need the storage form of the parent GUID */
4093 ret = dsdb_module_search_dn(module, tmp_ctx, &parent_res,
4095 DSDB_FLAG_NEXT_MODULE |
4096 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT |
4097 DSDB_SEARCH_REVEAL_INTERNALS|
4098 DSDB_SEARCH_SHOW_RECYCLED, req);
4099 if (ret != LDB_SUCCESS) {
4100 ldb_asprintf_errstring(ldb_module_get_ctx(module),
4101 "repmd_delete: Failed to %s %s, "
4102 "because we failed to find it's parent (%s): %s",
4103 re_delete ? "re-delete" : "delete",
4104 ldb_dn_get_linearized(old_dn),
4105 ldb_dn_get_linearized(parent_dn),
4106 ldb_errstring(ldb_module_get_ctx(module)));
4107 talloc_free(tmp_ctx);
4112 * Now we can use the DB version,
4113 * it will have the extended DN info in it
4115 parent_dn = parent_res->msgs[0]->dn;
4116 parent_dn_str = ldb_dn_get_extended_linearized(tmp_ctx,
4119 if (parent_dn_str == NULL) {
4120 talloc_free(tmp_ctx);
4121 return ldb_module_oom(module);
4124 ret = ldb_msg_add_steal_string(msg, "lastKnownParent",
4126 if (ret != LDB_SUCCESS) {
4127 ldb_asprintf_errstring(ldb, __location__
4128 ": Failed to add lastKnownParent "
4129 "string when deleting %s",
4130 ldb_dn_get_linearized(old_dn));
4131 talloc_free(tmp_ctx);
4134 msg->elements[el_count++].flags = LDB_FLAG_MOD_REPLACE;
4136 if (next_deletion_state == OBJECT_DELETED) {
4137 ret = ldb_msg_add_value(msg, "msDS-LastKnownRDN", rdn_value, NULL);
4138 if (ret != LDB_SUCCESS) {
4139 ldb_asprintf_errstring(ldb, __location__
4140 ": Failed to add msDS-LastKnownRDN "
4141 "string when deleting %s",
4142 ldb_dn_get_linearized(old_dn));
4143 talloc_free(tmp_ctx);
4146 msg->elements[el_count++].flags = LDB_FLAG_MOD_ADD;
4150 switch (next_deletion_state) {
4152 case OBJECT_RECYCLED:
4153 case OBJECT_TOMBSTONE:
4156 * MS-ADTS 3.1.1.5.5.1.1 Tombstone Requirements
4157 * describes what must be removed from a tombstone
4160 * MS-ADTS 3.1.1.5.5.1.3 Recycled-Object Requirements
4161 * describes what must be removed from a recycled
4167 * we also mark it as recycled, meaning this object can't be
4168 * recovered (we are stripping its attributes).
4169 * This is done only if we have this schema object of course ...
4170 * This behavior is identical to the one of Windows 2008R2 which
4171 * always set the isRecycled attribute, even if the recycle-bin is
4172 * not activated and what ever the forest level is.
4174 if (dsdb_attribute_by_lDAPDisplayName(schema, "isRecycled") != NULL) {
4175 ret = ldb_msg_add_string(msg, "isRecycled", "TRUE");
4176 if (ret != LDB_SUCCESS) {
4177 DEBUG(0,(__location__ ": Failed to add isRecycled string to the msg\n"));
4178 ldb_module_oom(module);
4179 talloc_free(tmp_ctx);
4182 msg->elements[el_count++].flags = LDB_FLAG_MOD_REPLACE;
4185 replmd_private = talloc_get_type(ldb_module_get_private(module),
4186 struct replmd_private);
4187 /* work out which of the old attributes we will be removing */
4188 for (i=0; i<old_msg->num_elements; i++) {
4189 const struct dsdb_attribute *sa;
4190 el = &old_msg->elements[i];
4191 sa = dsdb_attribute_by_lDAPDisplayName(schema, el->name);
4193 talloc_free(tmp_ctx);
4194 return LDB_ERR_OPERATIONS_ERROR;
4196 if (ldb_attr_cmp(el->name, rdn_name) == 0) {
4197 /* don't remove the rDN */
4200 if (sa->linkID & 1) {
4202 we have a backlink in this object
4203 that needs to be removed. We're not
4204 allowed to remove it directly
4205 however, so we instead setup a
4206 modify to delete the corresponding
4209 ret = replmd_delete_remove_link(module, schema,
4213 if (ret != LDB_SUCCESS) {
4214 const char *old_dn_str
4215 = ldb_dn_get_linearized(old_dn);
4216 ldb_asprintf_errstring(ldb,
4218 ": Failed to remove backlink of "
4219 "%s when deleting %s: %s",
4222 ldb_errstring(ldb));
4223 talloc_free(tmp_ctx);
4224 return LDB_ERR_OPERATIONS_ERROR;
4226 /* now we continue, which means we
4227 won't remove this backlink
4231 } else if (sa->linkID == 0) {
4232 if (ldb_attr_in_list(preserved_attrs, el->name)) {
4235 if (sa->searchFlags & SEARCH_FLAG_PRESERVEONDELETE) {
4240 * Ensure that we tell the modification to vanish any linked
4241 * attributes (not simply mark them as isDeleted = TRUE)
4243 dsdb_flags |= DSDB_REPLMD_VANISH_LINKS;
4245 ret = ldb_msg_add_empty(msg, el->name, LDB_FLAG_MOD_DELETE, &el);
4246 if (ret != LDB_SUCCESS) {
4247 talloc_free(tmp_ctx);
4248 ldb_module_oom(module);
4255 case OBJECT_DELETED:
4257 * MS-ADTS 3.1.1.5.5.1.2 Deleted-Object Requirements
4258 * describes what must be removed from a deleted
4262 ret = ldb_msg_add_empty(msg, "objectCategory", LDB_FLAG_MOD_REPLACE, NULL);
4263 if (ret != LDB_SUCCESS) {
4264 talloc_free(tmp_ctx);
4265 ldb_module_oom(module);
4269 ret = ldb_msg_add_empty(msg, "sAMAccountType", LDB_FLAG_MOD_REPLACE, NULL);
4270 if (ret != LDB_SUCCESS) {
4271 talloc_free(tmp_ctx);
4272 ldb_module_oom(module);
4282 if (deletion_state == OBJECT_NOT_DELETED) {
4283 const struct dsdb_attribute *sa;
4285 /* work out what the new rdn value is, for updating the
4286 rDN and name fields */
4287 new_rdn_value = ldb_dn_get_rdn_val(new_dn);
4288 if (new_rdn_value == NULL) {
4289 talloc_free(tmp_ctx);
4290 return ldb_operr(ldb);
4293 sa = dsdb_attribute_by_lDAPDisplayName(schema, rdn_name);
4295 talloc_free(tmp_ctx);
4296 return LDB_ERR_OPERATIONS_ERROR;
4299 ret = ldb_msg_add_value(msg, sa->lDAPDisplayName, new_rdn_value,
4301 if (ret != LDB_SUCCESS) {
4302 talloc_free(tmp_ctx);
4305 el->flags = LDB_FLAG_MOD_REPLACE;
4307 el = ldb_msg_find_element(old_msg, "name");
4309 ret = ldb_msg_add_value(msg, "name", new_rdn_value, &el);
4310 if (ret != LDB_SUCCESS) {
4311 talloc_free(tmp_ctx);
4314 el->flags = LDB_FLAG_MOD_REPLACE;
4319 * TODO: Per MS-DRSR 5.160 RemoveObj we should remove links directly, not as an originating update!
4324 * No matter what has happned with other renames, try again to
4325 * get this to be under the deleted DN.
4327 if (strcmp(ldb_dn_get_linearized(old_dn), ldb_dn_get_linearized(new_dn)) != 0) {
4328 /* now rename onto the new DN */
4329 ret = dsdb_module_rename(module, old_dn, new_dn, DSDB_FLAG_NEXT_MODULE, req);
4330 if (ret != LDB_SUCCESS){
4331 DEBUG(0,(__location__ ": Failed to rename object from '%s' to '%s' - %s\n",
4332 ldb_dn_get_linearized(old_dn),
4333 ldb_dn_get_linearized(new_dn),
4334 ldb_errstring(ldb)));
4335 talloc_free(tmp_ctx);
4341 ret = dsdb_module_modify(module, msg, dsdb_flags|DSDB_FLAG_OWN_MODULE, req);
4342 if (ret != LDB_SUCCESS) {
4343 ldb_asprintf_errstring(ldb, "replmd_delete: Failed to modify object %s in delete - %s",
4344 ldb_dn_get_linearized(old_dn), ldb_errstring(ldb));
4345 talloc_free(tmp_ctx);
4349 talloc_free(tmp_ctx);
4351 return ldb_module_done(req, NULL, NULL, LDB_SUCCESS);
4354 static int replmd_delete(struct ldb_module *module, struct ldb_request *req)
4356 return replmd_delete_internals(module, req, false);
4360 static int replmd_replicated_request_error(struct replmd_replicated_request *ar, int ret)
4365 static int replmd_replicated_request_werror(struct replmd_replicated_request *ar, WERROR status)
4367 int ret = LDB_ERR_OTHER;
4368 /* TODO: do some error mapping */
4370 /* Let the caller know the full WERROR */
4371 ar->objs->error = status;
4377 static struct replPropertyMetaData1 *
4378 replmd_replPropertyMetaData1_find_attid(struct replPropertyMetaDataBlob *md_blob,
4379 enum drsuapi_DsAttributeId attid)
4382 struct replPropertyMetaDataCtr1 *rpmd_ctr = &md_blob->ctr.ctr1;
4384 for (i = 0; i < rpmd_ctr->count; i++) {
4385 if (rpmd_ctr->array[i].attid == attid) {
4386 return &rpmd_ctr->array[i];
4394 return true if an update is newer than an existing entry
4395 see section 5.11 of MS-ADTS
4397 static bool replmd_update_is_newer(const struct GUID *current_invocation_id,
4398 const struct GUID *update_invocation_id,
4399 uint32_t current_version,
4400 uint32_t update_version,
4401 NTTIME current_change_time,
4402 NTTIME update_change_time)
4404 if (update_version != current_version) {
4405 return update_version > current_version;
4407 if (update_change_time != current_change_time) {
4408 return update_change_time > current_change_time;
4410 return GUID_compare(update_invocation_id, current_invocation_id) > 0;
4413 static bool replmd_replPropertyMetaData1_is_newer(struct replPropertyMetaData1 *cur_m,
4414 struct replPropertyMetaData1 *new_m)
4416 return replmd_update_is_newer(&cur_m->originating_invocation_id,
4417 &new_m->originating_invocation_id,
4420 cur_m->originating_change_time,
4421 new_m->originating_change_time);
4424 static bool replmd_replPropertyMetaData1_new_should_be_taken(uint32_t dsdb_repl_flags,
4425 struct replPropertyMetaData1 *cur_m,
4426 struct replPropertyMetaData1 *new_m)
4431 * If the new replPropertyMetaData entry for this attribute is
4432 * not provided (this happens in the case where we look for
4433 * ATTID_name, but the name was not changed), then the local
4434 * state is clearly still current, as the remote
4435 * server didn't send it due to being older the high watermark
4438 if (new_m == NULL) {
4442 if (dsdb_repl_flags & DSDB_REPL_FLAG_PRIORITISE_INCOMING) {
4444 * if we compare equal then do an
4445 * update. This is used when a client
4446 * asks for a FULL_SYNC, and can be
4447 * used to recover a corrupt
4450 * This call is a bit tricky, what we
4451 * are doing it turning the 'is_newer'
4452 * call into a 'not is older' by
4453 * swapping cur_m and new_m, and negating the
4456 cmp = !replmd_replPropertyMetaData1_is_newer(new_m,
4459 cmp = replmd_replPropertyMetaData1_is_newer(cur_m,
4469 static struct ldb_dn *replmd_conflict_dn(TALLOC_CTX *mem_ctx, struct ldb_dn *dn, struct GUID *guid)
4471 const struct ldb_val *rdn_val;
4472 const char *rdn_name;
4473 struct ldb_dn *new_dn;
4475 rdn_val = ldb_dn_get_rdn_val(dn);
4476 rdn_name = ldb_dn_get_rdn_name(dn);
4477 if (!rdn_val || !rdn_name) {
4481 new_dn = ldb_dn_copy(mem_ctx, dn);
4486 if (!ldb_dn_remove_child_components(new_dn, 1)) {
4490 if (!ldb_dn_add_child_fmt(new_dn, "%s=%s\\0ACNF:%s",
4492 ldb_dn_escape_value(new_dn, *rdn_val),
4493 GUID_string(new_dn, guid))) {
4502 perform a modify operation which sets the rDN and name attributes to
4503 their current values. This has the effect of changing these
4504 attributes to have been last updated by the current DC. This is
4505 needed to ensure that renames performed as part of conflict
4506 resolution are propogated to other DCs
4508 static int replmd_name_modify(struct replmd_replicated_request *ar,
4509 struct ldb_request *req, struct ldb_dn *dn)
4511 struct ldb_message *msg;
4512 const char *rdn_name;
4513 const struct ldb_val *rdn_val;
4514 const struct dsdb_attribute *rdn_attr;
4517 msg = ldb_msg_new(req);
4523 rdn_name = ldb_dn_get_rdn_name(dn);
4524 if (rdn_name == NULL) {
4528 /* normalize the rdn attribute name */
4529 rdn_attr = dsdb_attribute_by_lDAPDisplayName(ar->schema, rdn_name);
4530 if (rdn_attr == NULL) {
4533 rdn_name = rdn_attr->lDAPDisplayName;
4535 rdn_val = ldb_dn_get_rdn_val(dn);
4536 if (rdn_val == NULL) {
4540 if (ldb_msg_add_empty(msg, rdn_name, LDB_FLAG_MOD_REPLACE, NULL) != 0) {
4543 if (ldb_msg_add_value(msg, rdn_name, rdn_val, NULL) != 0) {
4546 if (ldb_msg_add_empty(msg, "name", LDB_FLAG_MOD_REPLACE, NULL) != 0) {
4549 if (ldb_msg_add_value(msg, "name", rdn_val, NULL) != 0) {
4554 * We have to mark this as a replicated update otherwise
4555 * schema_data may reject a rename in the schema partition
4558 ret = dsdb_module_modify(ar->module, msg,
4559 DSDB_FLAG_OWN_MODULE|DSDB_FLAG_REPLICATED_UPDATE,
4561 if (ret != LDB_SUCCESS) {
4562 DEBUG(0,(__location__ ": Failed to modify rDN/name of DN being DRS renamed '%s' - %s",
4563 ldb_dn_get_linearized(dn),
4564 ldb_errstring(ldb_module_get_ctx(ar->module))));
4574 DEBUG(0,(__location__ ": Failed to setup modify rDN/name of DN being DRS renamed '%s'",
4575 ldb_dn_get_linearized(dn)));
4576 return LDB_ERR_OPERATIONS_ERROR;
4581 callback for conflict DN handling where we have renamed the incoming
4582 record. After renaming it, we need to ensure the change of name and
4583 rDN for the incoming record is seen as an originating update by this DC.
4585 This also handles updating lastKnownParent for entries sent to lostAndFound
4587 static int replmd_op_name_modify_callback(struct ldb_request *req, struct ldb_reply *ares)
4589 struct replmd_replicated_request *ar =
4590 talloc_get_type_abort(req->context, struct replmd_replicated_request);
4591 struct ldb_dn *conflict_dn = NULL;
4594 if (ares->error != LDB_SUCCESS) {
4595 /* call the normal callback for everything except success */
4596 return replmd_op_callback(req, ares);
4599 switch (req->operation) {
4601 conflict_dn = req->op.add.message->dn;
4604 conflict_dn = req->op.mod.message->dn;
4607 smb_panic("replmd_op_name_modify_callback called in unknown circumstances");
4610 /* perform a modify of the rDN and name of the record */
4611 ret = replmd_name_modify(ar, req, conflict_dn);
4612 if (ret != LDB_SUCCESS) {
4614 return replmd_op_callback(req, ares);
4617 if (ar->objs->objects[ar->index_current].last_known_parent) {
4618 struct ldb_message *msg = ldb_msg_new(req);
4620 ldb_module_oom(ar->module);
4621 return LDB_ERR_OPERATIONS_ERROR;
4624 msg->dn = req->op.add.message->dn;
4626 ret = ldb_msg_add_steal_string(msg, "lastKnownParent",
4627 ldb_dn_get_extended_linearized(msg, ar->objs->objects[ar->index_current].last_known_parent, 1));
4628 if (ret != LDB_SUCCESS) {
4629 DEBUG(0,(__location__ ": Failed to add lastKnownParent string to the msg\n"));
4630 ldb_module_oom(ar->module);
4633 msg->elements[0].flags = LDB_FLAG_MOD_REPLACE;
4635 ret = dsdb_module_modify(ar->module, msg, DSDB_FLAG_OWN_MODULE, req);
4636 if (ret != LDB_SUCCESS) {
4637 DEBUG(0,(__location__ ": Failed to modify lastKnownParent of lostAndFound DN '%s' - %s",
4638 ldb_dn_get_linearized(msg->dn),
4639 ldb_errstring(ldb_module_get_ctx(ar->module))));
4645 return replmd_op_callback(req, ares);
4649 callback for replmd_replicated_apply_add()
4650 This copes with the creation of conflict records in the case where
4651 the DN exists, but with a different objectGUID
4653 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))
4655 struct ldb_dn *conflict_dn;
4656 struct replmd_replicated_request *ar =
4657 talloc_get_type_abort(req->context, struct replmd_replicated_request);
4658 struct ldb_result *res;
4659 const char *attrs[] = { "replPropertyMetaData", "objectGUID", NULL };
4661 const struct ldb_val *omd_value;
4662 struct replPropertyMetaDataBlob omd, *rmd;
4663 enum ndr_err_code ndr_err;
4664 bool rename_incoming_record, rodc;
4665 struct replPropertyMetaData1 *rmd_name, *omd_name;
4666 struct ldb_message *msg;
4667 struct ldb_request *down_req = NULL;
4669 /* call the normal callback for success */
4670 if (ares->error == LDB_SUCCESS) {
4671 return callback(req, ares);
4675 * we have a conflict, and need to decide if we will keep the
4676 * new record or the old record
4679 msg = ar->objs->objects[ar->index_current].msg;
4680 conflict_dn = msg->dn;
4682 /* For failures other than conflicts, fail the whole operation here */
4683 if (ares->error != LDB_ERR_ENTRY_ALREADY_EXISTS) {
4684 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module), "Failed to locally apply remote add of %s: %s",
4685 ldb_dn_get_linearized(conflict_dn),
4686 ldb_errstring(ldb_module_get_ctx(ar->module)));
4688 return ldb_module_done(ar->req, NULL, NULL,
4689 LDB_ERR_OPERATIONS_ERROR);
4692 ret = samdb_rodc(ldb_module_get_ctx(ar->module), &rodc);
4693 if (ret != LDB_SUCCESS) {
4694 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)));
4695 return ldb_module_done(ar->req, NULL, NULL,
4696 LDB_ERR_OPERATIONS_ERROR);
4702 * We are on an RODC, or were a GC for this
4703 * partition, so we have to fail this until
4704 * someone who owns the partition sorts it
4707 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
4708 "Conflict adding object '%s' from incoming replication as we are read only for the partition. \n"
4709 " - We must fail the operation until a master for this partition resolves the conflict",
4710 ldb_dn_get_linearized(conflict_dn));
4715 * first we need the replPropertyMetaData attribute from the
4716 * local, conflicting record
4718 ret = dsdb_module_search_dn(ar->module, req, &res, conflict_dn,
4720 DSDB_FLAG_NEXT_MODULE |
4721 DSDB_SEARCH_SHOW_DELETED |
4722 DSDB_SEARCH_SHOW_RECYCLED, req);
4723 if (ret != LDB_SUCCESS) {
4724 DEBUG(0,(__location__ ": Unable to find object for conflicting record '%s'\n",
4725 ldb_dn_get_linearized(conflict_dn)));
4729 omd_value = ldb_msg_find_ldb_val(res->msgs[0], "replPropertyMetaData");
4730 if (omd_value == NULL) {
4731 DEBUG(0,(__location__ ": Unable to find replPropertyMetaData for conflicting record '%s'\n",
4732 ldb_dn_get_linearized(conflict_dn)));
4736 ndr_err = ndr_pull_struct_blob(omd_value, res->msgs[0], &omd,
4737 (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
4738 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
4739 DEBUG(0,(__location__ ": Failed to parse old replPropertyMetaData for %s\n",
4740 ldb_dn_get_linearized(conflict_dn)));
4744 rmd = ar->objs->objects[ar->index_current].meta_data;
4747 * we decide which is newer based on the RPMD on the name
4748 * attribute. See [MS-DRSR] ResolveNameConflict.
4750 * We expect omd_name to be present, as this is from a local
4751 * search, but while rmd_name should have been given to us by
4752 * the remote server, if it is missing we just prefer the
4754 * replmd_replPropertyMetaData1_new_should_be_taken()
4756 rmd_name = replmd_replPropertyMetaData1_find_attid(rmd, DRSUAPI_ATTID_name);
4757 omd_name = replmd_replPropertyMetaData1_find_attid(&omd, DRSUAPI_ATTID_name);
4759 DEBUG(0,(__location__ ": Failed to find name attribute in local LDB replPropertyMetaData for %s\n",
4760 ldb_dn_get_linearized(conflict_dn)));
4765 * Should we preserve the current record, and so rename the
4766 * incoming record to be a conflict?
4768 rename_incoming_record
4769 = !replmd_replPropertyMetaData1_new_should_be_taken(ar->objs->dsdb_repl_flags & DSDB_REPL_FLAG_PRIORITISE_INCOMING,
4770 omd_name, rmd_name);
4772 if (rename_incoming_record) {
4774 struct ldb_dn *new_dn;
4776 guid = samdb_result_guid(msg, "objectGUID");
4777 if (GUID_all_zero(&guid)) {
4778 DEBUG(0,(__location__ ": Failed to find objectGUID for conflicting incoming record %s\n",
4779 ldb_dn_get_linearized(conflict_dn)));
4782 new_dn = replmd_conflict_dn(req, conflict_dn, &guid);
4783 if (new_dn == NULL) {
4784 DEBUG(0,(__location__ ": Failed to form conflict DN for %s\n",
4785 ldb_dn_get_linearized(conflict_dn)));
4789 DEBUG(2,(__location__ ": Resolving conflict record via incoming rename '%s' -> '%s'\n",
4790 ldb_dn_get_linearized(conflict_dn), ldb_dn_get_linearized(new_dn)));
4792 /* re-submit the request, but with the new DN */
4793 callback = replmd_op_name_modify_callback;
4796 /* we are renaming the existing record */
4798 struct ldb_dn *new_dn;
4800 guid = samdb_result_guid(res->msgs[0], "objectGUID");
4801 if (GUID_all_zero(&guid)) {
4802 DEBUG(0,(__location__ ": Failed to find objectGUID for existing conflict record %s\n",
4803 ldb_dn_get_linearized(conflict_dn)));
4807 new_dn = replmd_conflict_dn(req, conflict_dn, &guid);
4808 if (new_dn == NULL) {
4809 DEBUG(0,(__location__ ": Failed to form conflict DN for %s\n",
4810 ldb_dn_get_linearized(conflict_dn)));
4814 DEBUG(2,(__location__ ": Resolving conflict record via existing-record rename '%s' -> '%s'\n",
4815 ldb_dn_get_linearized(conflict_dn), ldb_dn_get_linearized(new_dn)));
4817 ret = dsdb_module_rename(ar->module, conflict_dn, new_dn,
4818 DSDB_FLAG_OWN_MODULE, req);
4819 if (ret != LDB_SUCCESS) {
4820 DEBUG(0,(__location__ ": Failed to rename conflict dn '%s' to '%s' - %s\n",
4821 ldb_dn_get_linearized(conflict_dn),
4822 ldb_dn_get_linearized(new_dn),
4823 ldb_errstring(ldb_module_get_ctx(ar->module))));
4828 * now we need to ensure that the rename is seen as an
4829 * originating update. We do that with a modify.
4831 ret = replmd_name_modify(ar, req, new_dn);
4832 if (ret != LDB_SUCCESS) {
4836 DEBUG(2,(__location__ ": With conflicting record renamed, re-apply replicated creation of '%s'\n",
4837 ldb_dn_get_linearized(req->op.add.message->dn)));
4840 ret = ldb_build_add_req(&down_req,
4841 ldb_module_get_ctx(ar->module),
4848 if (ret != LDB_SUCCESS) {
4851 LDB_REQ_SET_LOCATION(down_req);
4853 /* current partition control needed by "repmd_op_callback" */
4854 ret = ldb_request_add_control(down_req,
4855 DSDB_CONTROL_CURRENT_PARTITION_OID,
4857 if (ret != LDB_SUCCESS) {
4858 return replmd_replicated_request_error(ar, ret);
4861 if (ar->objs->dsdb_repl_flags & DSDB_REPL_FLAG_PARTIAL_REPLICA) {
4862 /* this tells the partition module to make it a
4863 partial replica if creating an NC */
4864 ret = ldb_request_add_control(down_req,
4865 DSDB_CONTROL_PARTIAL_REPLICA,
4867 if (ret != LDB_SUCCESS) {
4868 return replmd_replicated_request_error(ar, ret);
4873 * Finally we re-run the add, otherwise the new record won't
4874 * exist, as we are here because of that exact failure!
4876 return ldb_next_request(ar->module, down_req);
4879 /* on failure make the caller get the error. This means
4880 * replication will stop with an error, but there is not much
4883 return ldb_module_done(ar->req, NULL, NULL,
4888 callback for replmd_replicated_apply_add()
4889 This copes with the creation of conflict records in the case where
4890 the DN exists, but with a different objectGUID
4892 static int replmd_op_add_callback(struct ldb_request *req, struct ldb_reply *ares)
4894 struct replmd_replicated_request *ar =
4895 talloc_get_type_abort(req->context, struct replmd_replicated_request);
4897 if (ar->objs->objects[ar->index_current].last_known_parent) {
4898 /* This is like a conflict DN, where we put the object in LostAndFound
4899 see MS-DRSR 4.1.10.6.10 FindBestParentObject */
4900 return replmd_op_possible_conflict_callback(req, ares, replmd_op_name_modify_callback);
4903 return replmd_op_possible_conflict_callback(req, ares, replmd_op_callback);
4907 this is called when a new object comes in over DRS
4909 static int replmd_replicated_apply_add(struct replmd_replicated_request *ar)
4911 struct ldb_context *ldb;
4912 struct ldb_request *change_req;
4913 enum ndr_err_code ndr_err;
4914 struct ldb_message *msg;
4915 struct replPropertyMetaDataBlob *md;
4916 struct ldb_val md_value;
4919 bool remote_isDeleted = false;
4922 time_t t = time(NULL);
4923 const struct ldb_val *rdn_val;
4924 struct replmd_private *replmd_private =
4925 talloc_get_type(ldb_module_get_private(ar->module),
4926 struct replmd_private);
4927 unix_to_nt_time(&now, t);
4929 ldb = ldb_module_get_ctx(ar->module);
4930 msg = ar->objs->objects[ar->index_current].msg;
4931 md = ar->objs->objects[ar->index_current].meta_data;
4932 is_schema_nc = ldb_dn_compare_base(replmd_private->schema_dn, msg->dn) == 0;
4934 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &ar->seq_num);
4935 if (ret != LDB_SUCCESS) {
4936 return replmd_replicated_request_error(ar, ret);
4939 ret = dsdb_msg_add_guid(msg,
4940 &ar->objs->objects[ar->index_current].object_guid,
4942 if (ret != LDB_SUCCESS) {
4943 return replmd_replicated_request_error(ar, ret);
4946 ret = ldb_msg_add_string(msg, "whenChanged", ar->objs->objects[ar->index_current].when_changed);
4947 if (ret != LDB_SUCCESS) {
4948 return replmd_replicated_request_error(ar, ret);
4951 ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNCreated", ar->seq_num);
4952 if (ret != LDB_SUCCESS) {
4953 return replmd_replicated_request_error(ar, ret);
4956 ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNChanged", ar->seq_num);
4957 if (ret != LDB_SUCCESS) {
4958 return replmd_replicated_request_error(ar, ret);
4961 /* remove any message elements that have zero values */
4962 for (i=0; i<msg->num_elements; i++) {
4963 struct ldb_message_element *el = &msg->elements[i];
4965 if (el->num_values == 0) {
4966 if (ldb_attr_cmp(msg->elements[i].name, "objectClass") == 0) {
4967 ldb_asprintf_errstring(ldb, __location__
4968 ": empty objectClass sent on %s, aborting replication\n",
4969 ldb_dn_get_linearized(msg->dn));
4970 return replmd_replicated_request_error(ar, LDB_ERR_OBJECT_CLASS_VIOLATION);
4973 DEBUG(4,(__location__ ": Removing attribute %s with num_values==0\n",
4975 memmove(el, el+1, sizeof(*el)*(msg->num_elements - (i+1)));
4976 msg->num_elements--;
4983 struct GUID_txt_buf guid_txt;
4985 char *s = ldb_ldif_message_string(ldb, ar, LDB_CHANGETYPE_ADD, msg);
4986 DEBUG(4, ("DRS replication add message of %s:\n%s\n",
4987 GUID_buf_string(&ar->objs->objects[ar->index_current].object_guid, &guid_txt),
4992 remote_isDeleted = ldb_msg_find_attr_as_bool(msg,
4993 "isDeleted", false);
4996 * the meta data array is already sorted by the caller, except
4997 * for the RDN, which needs to be added.
5001 rdn_val = ldb_dn_get_rdn_val(msg->dn);
5002 ret = replmd_update_rpmd_rdn_attr(ldb, msg, rdn_val, NULL,
5003 md, ar, now, is_schema_nc,
5005 if (ret != LDB_SUCCESS) {
5006 ldb_asprintf_errstring(ldb, "%s: error during DRS repl ADD: %s", __func__, ldb_errstring(ldb));
5007 return replmd_replicated_request_error(ar, ret);
5010 ret = replmd_replPropertyMetaDataCtr1_sort_and_verify(ldb, &md->ctr.ctr1, msg->dn);
5011 if (ret != LDB_SUCCESS) {
5012 ldb_asprintf_errstring(ldb, "%s: error during DRS repl ADD: %s", __func__, ldb_errstring(ldb));
5013 return replmd_replicated_request_error(ar, ret);
5016 for (i=0; i < md->ctr.ctr1.count; i++) {
5017 md->ctr.ctr1.array[i].local_usn = ar->seq_num;
5019 ndr_err = ndr_push_struct_blob(&md_value, msg, md,
5020 (ndr_push_flags_fn_t)ndr_push_replPropertyMetaDataBlob);
5021 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
5022 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
5023 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
5025 ret = ldb_msg_add_value(msg, "replPropertyMetaData", &md_value, NULL);
5026 if (ret != LDB_SUCCESS) {
5027 return replmd_replicated_request_error(ar, ret);
5030 replmd_ldb_message_sort(msg, ar->schema);
5032 if (!remote_isDeleted) {
5033 ret = dsdb_module_schedule_sd_propagation(ar->module,
5034 ar->objs->partition_dn,
5036 if (ret != LDB_SUCCESS) {
5037 return replmd_replicated_request_error(ar, ret);
5041 ar->isDeleted = remote_isDeleted;
5043 ret = ldb_build_add_req(&change_req,
5049 replmd_op_add_callback,
5051 LDB_REQ_SET_LOCATION(change_req);
5052 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
5054 /* current partition control needed by "repmd_op_callback" */
5055 ret = ldb_request_add_control(change_req,
5056 DSDB_CONTROL_CURRENT_PARTITION_OID,
5058 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
5060 if (ar->objs->dsdb_repl_flags & DSDB_REPL_FLAG_PARTIAL_REPLICA) {
5061 /* this tells the partition module to make it a
5062 partial replica if creating an NC */
5063 ret = ldb_request_add_control(change_req,
5064 DSDB_CONTROL_PARTIAL_REPLICA,
5066 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
5069 return ldb_next_request(ar->module, change_req);
5072 static int replmd_replicated_apply_search_for_parent_callback(struct ldb_request *req,
5073 struct ldb_reply *ares)
5075 struct replmd_replicated_request *ar = talloc_get_type(req->context,
5076 struct replmd_replicated_request);
5080 return ldb_module_done(ar->req, NULL, NULL,
5081 LDB_ERR_OPERATIONS_ERROR);
5085 * The error NO_SUCH_OBJECT is not expected, unless the search
5086 * base is the partition DN, and that case doesn't happen here
5087 * because then we wouldn't get a parent_guid_value in any
5090 if (ares->error != LDB_SUCCESS) {
5091 return ldb_module_done(ar->req, ares->controls,
5092 ares->response, ares->error);
5095 switch (ares->type) {
5096 case LDB_REPLY_ENTRY:
5098 struct ldb_message *parent_msg = ares->message;
5099 struct ldb_message *msg = ar->objs->objects[ar->index_current].msg;
5100 struct ldb_dn *parent_dn;
5103 if (!ldb_msg_check_string_attribute(msg, "isDeleted", "TRUE")
5104 && ldb_msg_check_string_attribute(parent_msg, "isDeleted", "TRUE")) {
5105 /* Per MS-DRSR 4.1.10.6.10
5106 * FindBestParentObject we need to move this
5107 * new object under a deleted object to
5109 struct ldb_dn *nc_root;
5111 ret = dsdb_find_nc_root(ldb_module_get_ctx(ar->module), msg, msg->dn, &nc_root);
5112 if (ret == LDB_ERR_NO_SUCH_OBJECT) {
5113 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
5114 "No suitable NC root found for %s. "
5115 "We need to move this object because parent object %s "
5116 "is deleted, but this object is not.",
5117 ldb_dn_get_linearized(msg->dn),
5118 ldb_dn_get_linearized(parent_msg->dn));
5119 return ldb_module_done(ar->req, NULL, NULL, LDB_ERR_OPERATIONS_ERROR);
5120 } else if (ret != LDB_SUCCESS) {
5121 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
5122 "Unable to find NC root for %s: %s. "
5123 "We need to move this object because parent object %s "
5124 "is deleted, but this object is not.",
5125 ldb_dn_get_linearized(msg->dn),
5126 ldb_errstring(ldb_module_get_ctx(ar->module)),
5127 ldb_dn_get_linearized(parent_msg->dn));
5128 return ldb_module_done(ar->req, NULL, NULL, LDB_ERR_OPERATIONS_ERROR);
5131 ret = dsdb_wellknown_dn(ldb_module_get_ctx(ar->module), msg,
5133 DS_GUID_LOSTANDFOUND_CONTAINER,
5135 if (ret != LDB_SUCCESS) {
5136 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
5137 "Unable to find LostAndFound Container for %s "
5138 "in partition %s: %s. "
5139 "We need to move this object because parent object %s "
5140 "is deleted, but this object is not.",
5141 ldb_dn_get_linearized(msg->dn), ldb_dn_get_linearized(nc_root),
5142 ldb_errstring(ldb_module_get_ctx(ar->module)),
5143 ldb_dn_get_linearized(parent_msg->dn));
5144 return ldb_module_done(ar->req, NULL, NULL, LDB_ERR_OPERATIONS_ERROR);
5146 ar->objs->objects[ar->index_current].last_known_parent
5147 = talloc_steal(ar->objs->objects[ar->index_current].msg, parent_msg->dn);
5151 = talloc_steal(ar->objs->objects[ar->index_current].msg, parent_msg->dn);
5154 ar->objs->objects[ar->index_current].local_parent_dn = parent_dn;
5156 comp_num = ldb_dn_get_comp_num(msg->dn);
5158 if (!ldb_dn_remove_base_components(msg->dn, comp_num - 1)) {
5160 return ldb_module_done(ar->req, NULL, NULL, ldb_module_operr(ar->module));
5163 if (!ldb_dn_add_base(msg->dn, parent_dn)) {
5165 return ldb_module_done(ar->req, NULL, NULL, ldb_module_operr(ar->module));
5169 case LDB_REPLY_REFERRAL:
5170 /* we ignore referrals */
5173 case LDB_REPLY_DONE:
5175 if (ar->objs->objects[ar->index_current].local_parent_dn == NULL) {
5176 struct GUID_txt_buf str_buf;
5177 if (ar->search_msg != NULL) {
5178 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
5179 "No parent with GUID %s found for object locally known as %s",
5180 GUID_buf_string(ar->objs->objects[ar->index_current].parent_guid, &str_buf),
5181 ldb_dn_get_linearized(ar->search_msg->dn));
5183 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
5184 "No parent with GUID %s found for object remotely known as %s",
5185 GUID_buf_string(ar->objs->objects[ar->index_current].parent_guid, &str_buf),
5186 ldb_dn_get_linearized(ar->objs->objects[ar->index_current].msg->dn));
5190 * This error code is really important, as it
5191 * is the flag back to the callers to retry
5192 * this with DRSUAPI_DRS_GET_ANC, and so get
5193 * the parent objects before the child
5196 return ldb_module_done(ar->req, NULL, NULL,
5197 replmd_replicated_request_werror(ar, WERR_DS_DRA_MISSING_PARENT));
5200 if (ar->search_msg != NULL) {
5201 ret = replmd_replicated_apply_merge(ar);
5203 ret = replmd_replicated_apply_add(ar);
5205 if (ret != LDB_SUCCESS) {
5206 return ldb_module_done(ar->req, NULL, NULL, ret);
5215 * Look for the parent object, so we put the new object in the right
5216 * place This is akin to NameObject in MS-DRSR - this routine and the
5217 * callbacks find the right parent name, and correct name for this
5221 static int replmd_replicated_apply_search_for_parent(struct replmd_replicated_request *ar)
5223 struct ldb_context *ldb;
5227 struct ldb_request *search_req;
5228 static const char *attrs[] = {"isDeleted", NULL};
5229 struct GUID_txt_buf guid_str_buf;
5231 ldb = ldb_module_get_ctx(ar->module);
5233 if (ar->objs->objects[ar->index_current].parent_guid == NULL) {
5234 if (ar->search_msg != NULL) {
5235 return replmd_replicated_apply_merge(ar);
5237 return replmd_replicated_apply_add(ar);
5241 tmp_str = GUID_buf_string(ar->objs->objects[ar->index_current].parent_guid,
5244 filter = talloc_asprintf(ar, "(objectGUID=%s)", tmp_str);
5245 if (!filter) return replmd_replicated_request_werror(ar, WERR_NOT_ENOUGH_MEMORY);
5247 ret = ldb_build_search_req(&search_req,
5250 ar->objs->partition_dn,
5256 replmd_replicated_apply_search_for_parent_callback,
5258 LDB_REQ_SET_LOCATION(search_req);
5260 ret = dsdb_request_add_controls(search_req,
5261 DSDB_SEARCH_SHOW_RECYCLED|
5262 DSDB_SEARCH_SHOW_DELETED|
5263 DSDB_SEARCH_SHOW_EXTENDED_DN);
5264 if (ret != LDB_SUCCESS) {
5268 return ldb_next_request(ar->module, search_req);
5272 handle renames that come in over DRS replication
5274 static int replmd_replicated_handle_rename(struct replmd_replicated_request *ar,
5275 struct ldb_message *msg,
5276 struct ldb_request *parent,
5280 TALLOC_CTX *tmp_ctx = talloc_new(msg);
5281 struct ldb_result *res;
5282 struct ldb_dn *conflict_dn;
5283 const char *attrs[] = { "replPropertyMetaData", "objectGUID", NULL };
5284 const struct ldb_val *omd_value;
5285 struct replPropertyMetaDataBlob omd, *rmd;
5286 enum ndr_err_code ndr_err;
5287 bool rename_incoming_record, rodc;
5288 struct replPropertyMetaData1 *rmd_name, *omd_name;
5289 struct ldb_dn *new_dn;
5292 DEBUG(4,("replmd_replicated_request rename %s => %s\n",
5293 ldb_dn_get_linearized(ar->search_msg->dn),
5294 ldb_dn_get_linearized(msg->dn)));
5297 ret = dsdb_module_rename(ar->module, ar->search_msg->dn, msg->dn,
5298 DSDB_FLAG_NEXT_MODULE, ar->req);
5299 if (ret == LDB_SUCCESS) {
5300 talloc_free(tmp_ctx);
5305 if (ret != LDB_ERR_ENTRY_ALREADY_EXISTS) {
5306 talloc_free(tmp_ctx);
5307 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module), "Failed to locally apply remote rename from %s to %s: %s",
5308 ldb_dn_get_linearized(ar->search_msg->dn),
5309 ldb_dn_get_linearized(msg->dn),
5310 ldb_errstring(ldb_module_get_ctx(ar->module)));
5314 ret = samdb_rodc(ldb_module_get_ctx(ar->module), &rodc);
5315 if (ret != LDB_SUCCESS) {
5316 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
5317 "Failed to determine if we are an RODC when attempting to form conflict DN: %s",
5318 ldb_errstring(ldb_module_get_ctx(ar->module)));
5319 return LDB_ERR_OPERATIONS_ERROR;
5322 * we have a conflict, and need to decide if we will keep the
5323 * new record or the old record
5326 conflict_dn = msg->dn;
5330 * We are on an RODC, or were a GC for this
5331 * partition, so we have to fail this until
5332 * someone who owns the partition sorts it
5335 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
5336 "Conflict adding object '%s' from incoming replication but we are read only for the partition. \n"
5337 " - We must fail the operation until a master for this partition resolves the conflict",
5338 ldb_dn_get_linearized(conflict_dn));
5343 * first we need the replPropertyMetaData attribute from the
5346 ret = dsdb_module_search_dn(ar->module, tmp_ctx, &res, conflict_dn,
5348 DSDB_FLAG_NEXT_MODULE |
5349 DSDB_SEARCH_SHOW_DELETED |
5350 DSDB_SEARCH_SHOW_RECYCLED, ar->req);
5351 if (ret != LDB_SUCCESS) {
5352 DEBUG(0,(__location__ ": Unable to find object for conflicting record '%s'\n",
5353 ldb_dn_get_linearized(conflict_dn)));
5357 omd_value = ldb_msg_find_ldb_val(res->msgs[0], "replPropertyMetaData");
5358 if (omd_value == NULL) {
5359 DEBUG(0,(__location__ ": Unable to find replPropertyMetaData for conflicting record '%s'\n",
5360 ldb_dn_get_linearized(conflict_dn)));
5364 ndr_err = ndr_pull_struct_blob(omd_value, res->msgs[0], &omd,
5365 (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
5366 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
5367 DEBUG(0,(__location__ ": Failed to parse old replPropertyMetaData for %s\n",
5368 ldb_dn_get_linearized(conflict_dn)));
5372 rmd = ar->objs->objects[ar->index_current].meta_data;
5375 * we decide which is newer based on the RPMD on the name
5376 * attribute. See [MS-DRSR] ResolveNameConflict.
5378 * We expect omd_name to be present, as this is from a local
5379 * search, but while rmd_name should have been given to us by
5380 * the remote server, if it is missing we just prefer the
5382 * replmd_replPropertyMetaData1_new_should_be_taken()
5384 rmd_name = replmd_replPropertyMetaData1_find_attid(rmd, DRSUAPI_ATTID_name);
5385 omd_name = replmd_replPropertyMetaData1_find_attid(&omd, DRSUAPI_ATTID_name);
5387 DEBUG(0,(__location__ ": Failed to find name attribute in local LDB replPropertyMetaData for %s\n",
5388 ldb_dn_get_linearized(conflict_dn)));
5393 * Should we preserve the current record, and so rename the
5394 * incoming record to be a conflict?
5396 rename_incoming_record =
5397 !replmd_replPropertyMetaData1_new_should_be_taken(
5398 ar->objs->dsdb_repl_flags & DSDB_REPL_FLAG_PRIORITISE_INCOMING,
5399 omd_name, rmd_name);
5401 if (rename_incoming_record) {
5403 new_dn = replmd_conflict_dn(msg, msg->dn,
5404 &ar->objs->objects[ar->index_current].object_guid);
5405 if (new_dn == NULL) {
5406 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
5407 "Failed to form conflict DN for %s\n",
5408 ldb_dn_get_linearized(msg->dn));
5410 return replmd_replicated_request_werror(ar, WERR_NOT_ENOUGH_MEMORY);
5413 ret = dsdb_module_rename(ar->module, ar->search_msg->dn, new_dn,
5414 DSDB_FLAG_NEXT_MODULE, ar->req);
5415 if (ret != LDB_SUCCESS) {
5416 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
5417 "Failed to rename incoming conflicting dn '%s' (was '%s') to '%s' - %s\n",
5418 ldb_dn_get_linearized(conflict_dn),
5419 ldb_dn_get_linearized(ar->search_msg->dn),
5420 ldb_dn_get_linearized(new_dn),
5421 ldb_errstring(ldb_module_get_ctx(ar->module)));
5422 return replmd_replicated_request_werror(ar, WERR_DS_DRA_DB_ERROR);
5430 /* we are renaming the existing record */
5432 guid = samdb_result_guid(res->msgs[0], "objectGUID");
5433 if (GUID_all_zero(&guid)) {
5434 DEBUG(0,(__location__ ": Failed to find objectGUID for existing conflict record %s\n",
5435 ldb_dn_get_linearized(conflict_dn)));
5439 new_dn = replmd_conflict_dn(tmp_ctx, conflict_dn, &guid);
5440 if (new_dn == NULL) {
5441 DEBUG(0,(__location__ ": Failed to form conflict DN for %s\n",
5442 ldb_dn_get_linearized(conflict_dn)));
5446 DEBUG(2,(__location__ ": Resolving conflict record via existing-record rename '%s' -> '%s'\n",
5447 ldb_dn_get_linearized(conflict_dn), ldb_dn_get_linearized(new_dn)));
5449 ret = dsdb_module_rename(ar->module, conflict_dn, new_dn,
5450 DSDB_FLAG_OWN_MODULE, ar->req);
5451 if (ret != LDB_SUCCESS) {
5452 DEBUG(0,(__location__ ": Failed to rename conflict dn '%s' to '%s' - %s\n",
5453 ldb_dn_get_linearized(conflict_dn),
5454 ldb_dn_get_linearized(new_dn),
5455 ldb_errstring(ldb_module_get_ctx(ar->module))));
5460 * now we need to ensure that the rename is seen as an
5461 * originating update. We do that with a modify.
5463 ret = replmd_name_modify(ar, ar->req, new_dn);
5464 if (ret != LDB_SUCCESS) {
5468 DEBUG(2,(__location__ ": With conflicting record renamed, re-apply replicated rename '%s' -> '%s'\n",
5469 ldb_dn_get_linearized(ar->search_msg->dn),
5470 ldb_dn_get_linearized(msg->dn)));
5473 ret = dsdb_module_rename(ar->module, ar->search_msg->dn, msg->dn,
5474 DSDB_FLAG_NEXT_MODULE, ar->req);
5475 if (ret != LDB_SUCCESS) {
5476 DEBUG(0,(__location__ ": After conflict resolution, failed to rename dn '%s' to '%s' - %s\n",
5477 ldb_dn_get_linearized(ar->search_msg->dn),
5478 ldb_dn_get_linearized(msg->dn),
5479 ldb_errstring(ldb_module_get_ctx(ar->module))));
5485 * On failure make the caller get the error
5486 * This means replication will stop with an error,
5487 * but there is not much else we can do. In the
5488 * LDB_ERR_ENTRY_ALREADY_EXISTS case this is exactly what is
5492 talloc_free(tmp_ctx);
5497 static int replmd_replicated_apply_merge(struct replmd_replicated_request *ar)
5499 struct ldb_context *ldb;
5500 struct ldb_request *change_req;
5501 enum ndr_err_code ndr_err;
5502 struct ldb_message *msg;
5503 struct replPropertyMetaDataBlob *rmd;
5504 struct replPropertyMetaDataBlob omd;
5505 const struct ldb_val *omd_value;
5506 struct replPropertyMetaDataBlob nmd;
5507 struct ldb_val nmd_value;
5508 struct GUID remote_parent_guid;
5511 unsigned int removed_attrs = 0;
5513 int (*callback)(struct ldb_request *req, struct ldb_reply *ares) = replmd_op_callback;
5514 bool isDeleted = false;
5515 bool local_isDeleted = false;
5516 bool remote_isDeleted = false;
5517 bool take_remote_isDeleted = false;
5518 bool sd_updated = false;
5519 bool renamed = false;
5520 bool is_schema_nc = false;
5522 const struct ldb_val *old_rdn, *new_rdn;
5523 struct replmd_private *replmd_private =
5524 talloc_get_type(ldb_module_get_private(ar->module),
5525 struct replmd_private);
5527 time_t t = time(NULL);
5528 unix_to_nt_time(&now, t);
5530 ldb = ldb_module_get_ctx(ar->module);
5531 msg = ar->objs->objects[ar->index_current].msg;
5533 is_schema_nc = ldb_dn_compare_base(replmd_private->schema_dn, msg->dn) == 0;
5535 rmd = ar->objs->objects[ar->index_current].meta_data;
5539 /* find existing meta data */
5540 omd_value = ldb_msg_find_ldb_val(ar->search_msg, "replPropertyMetaData");
5542 ndr_err = ndr_pull_struct_blob(omd_value, ar, &omd,
5543 (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
5544 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
5545 nt_status = ndr_map_error2ntstatus(ndr_err);
5546 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
5549 if (omd.version != 1) {
5550 return replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
5555 struct GUID_txt_buf guid_txt;
5557 char *s = ldb_ldif_message_string(ldb, ar, LDB_CHANGETYPE_MODIFY, msg);
5558 DEBUG(5, ("Initial DRS replication modify message of %s is:\n%s\n"
5561 GUID_buf_string(&ar->objs->objects[ar->index_current].object_guid, &guid_txt),
5563 ndr_print_struct_string(s,
5564 (ndr_print_fn_t)ndr_print_replPropertyMetaDataBlob,
5565 "existing replPropertyMetaData",
5567 ndr_print_struct_string(s,
5568 (ndr_print_fn_t)ndr_print_replPropertyMetaDataBlob,
5569 "incoming replPropertyMetaData",
5574 local_isDeleted = ldb_msg_find_attr_as_bool(ar->search_msg,
5575 "isDeleted", false);
5576 remote_isDeleted = ldb_msg_find_attr_as_bool(msg,
5577 "isDeleted", false);
5580 * Fill in the remote_parent_guid with the GUID or an all-zero
5583 if (ar->objs->objects[ar->index_current].parent_guid != NULL) {
5584 remote_parent_guid = *ar->objs->objects[ar->index_current].parent_guid;
5586 remote_parent_guid = GUID_zero();
5590 * To ensure we follow a complex rename chain around, we have
5591 * to confirm that the DN is the same (mostly to confirm the
5592 * RDN) and the parentGUID is the same.
5594 * This ensures we keep things under the correct parent, which
5595 * replmd_replicated_handle_rename() will do.
5598 if (strcmp(ldb_dn_get_linearized(msg->dn), ldb_dn_get_linearized(ar->search_msg->dn)) == 0
5599 && GUID_equal(&remote_parent_guid, &ar->local_parent_guid)) {
5603 * handle renames, even just by case that come in over
5604 * DRS. Changes in the parent DN don't hit us here,
5605 * because the search for a parent will clean up those
5608 * We also have already filtered out the case where
5609 * the peer has an older name to what we have (see
5610 * replmd_replicated_apply_search_callback())
5612 ret = replmd_replicated_handle_rename(ar, msg, ar->req, &renamed);
5615 if (ret != LDB_SUCCESS) {
5616 ldb_debug(ldb, LDB_DEBUG_FATAL,
5617 "replmd_replicated_request rename %s => %s failed - %s\n",
5618 ldb_dn_get_linearized(ar->search_msg->dn),
5619 ldb_dn_get_linearized(msg->dn),
5620 ldb_errstring(ldb));
5621 return replmd_replicated_request_werror(ar, WERR_DS_DRA_DB_ERROR);
5624 if (renamed == true) {
5626 * Set the callback to one that will fix up the name
5627 * metadata on the new conflict DN
5629 callback = replmd_op_name_modify_callback;
5634 nmd.ctr.ctr1.count = omd.ctr.ctr1.count + rmd->ctr.ctr1.count;
5635 nmd.ctr.ctr1.array = talloc_array(ar,
5636 struct replPropertyMetaData1,
5637 nmd.ctr.ctr1.count);
5638 if (!nmd.ctr.ctr1.array) return replmd_replicated_request_werror(ar, WERR_NOT_ENOUGH_MEMORY);
5640 /* first copy the old meta data */
5641 for (i=0; i < omd.ctr.ctr1.count; i++) {
5642 nmd.ctr.ctr1.array[ni] = omd.ctr.ctr1.array[i];
5647 /* now merge in the new meta data */
5648 for (i=0; i < rmd->ctr.ctr1.count; i++) {
5651 for (j=0; j < ni; j++) {
5654 if (rmd->ctr.ctr1.array[i].attid != nmd.ctr.ctr1.array[j].attid) {
5658 cmp = replmd_replPropertyMetaData1_new_should_be_taken(
5659 ar->objs->dsdb_repl_flags,
5660 &nmd.ctr.ctr1.array[j],
5661 &rmd->ctr.ctr1.array[i]);
5663 /* replace the entry */
5664 nmd.ctr.ctr1.array[j] = rmd->ctr.ctr1.array[i];
5665 if (ar->seq_num == 0) {
5666 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &ar->seq_num);
5667 if (ret != LDB_SUCCESS) {
5668 return replmd_replicated_request_error(ar, ret);
5671 nmd.ctr.ctr1.array[j].local_usn = ar->seq_num;
5672 switch (nmd.ctr.ctr1.array[j].attid) {
5673 case DRSUAPI_ATTID_ntSecurityDescriptor:
5676 case DRSUAPI_ATTID_isDeleted:
5677 take_remote_isDeleted = true;
5686 if (rmd->ctr.ctr1.array[i].attid != DRSUAPI_ATTID_instanceType) {
5687 DEBUG(3,("Discarding older DRS attribute update to %s on %s from %s\n",
5688 msg->elements[i-removed_attrs].name,
5689 ldb_dn_get_linearized(msg->dn),
5690 GUID_string(ar, &rmd->ctr.ctr1.array[i].originating_invocation_id)));
5693 /* we don't want to apply this change so remove the attribute */
5694 ldb_msg_remove_element(msg, &msg->elements[i-removed_attrs]);
5701 if (found) continue;
5703 nmd.ctr.ctr1.array[ni] = rmd->ctr.ctr1.array[i];
5704 if (ar->seq_num == 0) {
5705 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &ar->seq_num);
5706 if (ret != LDB_SUCCESS) {
5707 return replmd_replicated_request_error(ar, ret);
5710 nmd.ctr.ctr1.array[ni].local_usn = ar->seq_num;
5711 switch (nmd.ctr.ctr1.array[ni].attid) {
5712 case DRSUAPI_ATTID_ntSecurityDescriptor:
5715 case DRSUAPI_ATTID_isDeleted:
5716 take_remote_isDeleted = true;
5725 * finally correct the size of the meta_data array
5727 nmd.ctr.ctr1.count = ni;
5729 new_rdn = ldb_dn_get_rdn_val(msg->dn);
5730 old_rdn = ldb_dn_get_rdn_val(ar->search_msg->dn);
5733 ret = replmd_update_rpmd_rdn_attr(ldb, msg, new_rdn, old_rdn,
5734 &nmd, ar, now, is_schema_nc,
5736 if (ret != LDB_SUCCESS) {
5737 ldb_asprintf_errstring(ldb, "%s: error during DRS repl merge: %s", __func__, ldb_errstring(ldb));
5738 return replmd_replicated_request_error(ar, ret);
5742 * sort the new meta data array
5744 ret = replmd_replPropertyMetaDataCtr1_sort_and_verify(ldb, &nmd.ctr.ctr1, msg->dn);
5745 if (ret != LDB_SUCCESS) {
5746 ldb_asprintf_errstring(ldb, "%s: error during DRS repl merge: %s", __func__, ldb_errstring(ldb));
5751 * Work out if this object is deleted, so we can prune any extra attributes. See MS-DRSR 4.1.10.6.9
5754 * This also controls SD propagation below
5756 if (take_remote_isDeleted) {
5757 isDeleted = remote_isDeleted;
5759 isDeleted = local_isDeleted;
5762 ar->isDeleted = isDeleted;
5765 * check if some replicated attributes left, otherwise skip the ldb_modify() call
5767 if (msg->num_elements == 0) {
5768 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_replicated_apply_merge[%u]: skip replace\n",
5771 return replmd_replicated_apply_isDeleted(ar);
5774 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_replicated_apply_merge[%u]: replace %u attributes\n",
5775 ar->index_current, msg->num_elements);
5781 if (sd_updated && !isDeleted) {
5782 ret = dsdb_module_schedule_sd_propagation(ar->module,
5783 ar->objs->partition_dn,
5785 if (ret != LDB_SUCCESS) {
5786 return ldb_operr(ldb);
5790 /* create the meta data value */
5791 ndr_err = ndr_push_struct_blob(&nmd_value, msg, &nmd,
5792 (ndr_push_flags_fn_t)ndr_push_replPropertyMetaDataBlob);
5793 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
5794 nt_status = ndr_map_error2ntstatus(ndr_err);
5795 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
5799 * when we know that we'll modify the record, add the whenChanged, uSNChanged
5800 * and replPopertyMetaData attributes
5802 ret = ldb_msg_add_string(msg, "whenChanged", ar->objs->objects[ar->index_current].when_changed);
5803 if (ret != LDB_SUCCESS) {
5804 return replmd_replicated_request_error(ar, ret);
5806 ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNChanged", ar->seq_num);
5807 if (ret != LDB_SUCCESS) {
5808 return replmd_replicated_request_error(ar, ret);
5810 ret = ldb_msg_add_value(msg, "replPropertyMetaData", &nmd_value, NULL);
5811 if (ret != LDB_SUCCESS) {
5812 return replmd_replicated_request_error(ar, ret);
5815 replmd_ldb_message_sort(msg, ar->schema);
5817 /* we want to replace the old values */
5818 for (i=0; i < msg->num_elements; i++) {
5819 msg->elements[i].flags = LDB_FLAG_MOD_REPLACE;
5820 if (ldb_attr_cmp(msg->elements[i].name, "objectClass") == 0) {
5821 if (msg->elements[i].num_values == 0) {
5822 ldb_asprintf_errstring(ldb, __location__
5823 ": objectClass removed on %s, aborting replication\n",
5824 ldb_dn_get_linearized(msg->dn));
5825 return replmd_replicated_request_error(ar, LDB_ERR_OBJECT_CLASS_VIOLATION);
5831 struct GUID_txt_buf guid_txt;
5833 char *s = ldb_ldif_message_string(ldb, ar, LDB_CHANGETYPE_MODIFY, msg);
5834 DEBUG(4, ("Final DRS replication modify message of %s:\n%s\n",
5835 GUID_buf_string(&ar->objs->objects[ar->index_current].object_guid, &guid_txt),
5840 ret = ldb_build_mod_req(&change_req,
5848 LDB_REQ_SET_LOCATION(change_req);
5849 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
5851 /* current partition control needed by "repmd_op_callback" */
5852 ret = ldb_request_add_control(change_req,
5853 DSDB_CONTROL_CURRENT_PARTITION_OID,
5855 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
5857 return ldb_next_request(ar->module, change_req);
5860 static int replmd_replicated_apply_search_callback(struct ldb_request *req,
5861 struct ldb_reply *ares)
5863 struct replmd_replicated_request *ar = talloc_get_type(req->context,
5864 struct replmd_replicated_request);
5868 return ldb_module_done(ar->req, NULL, NULL,
5869 LDB_ERR_OPERATIONS_ERROR);
5871 if (ares->error != LDB_SUCCESS &&
5872 ares->error != LDB_ERR_NO_SUCH_OBJECT) {
5873 return ldb_module_done(ar->req, ares->controls,
5874 ares->response, ares->error);
5877 switch (ares->type) {
5878 case LDB_REPLY_ENTRY:
5879 ar->search_msg = talloc_steal(ar, ares->message);
5882 case LDB_REPLY_REFERRAL:
5883 /* we ignore referrals */
5886 case LDB_REPLY_DONE:
5888 struct replPropertyMetaData1 *md_remote;
5889 struct replPropertyMetaData1 *md_local;
5891 struct replPropertyMetaDataBlob omd;
5892 const struct ldb_val *omd_value;
5893 struct replPropertyMetaDataBlob *rmd;
5894 struct ldb_message *msg;
5896 ar->objs->objects[ar->index_current].local_parent_dn = NULL;
5897 ar->objs->objects[ar->index_current].last_known_parent = NULL;
5900 * This is the ADD case, find the appropriate parent,
5901 * as this object doesn't exist locally:
5903 if (ar->search_msg == NULL) {
5904 ret = replmd_replicated_apply_search_for_parent(ar);
5905 if (ret != LDB_SUCCESS) {
5906 return ldb_module_done(ar->req, NULL, NULL, ret);
5913 * Otherwise, in the MERGE case, work out if we are
5914 * attempting a rename, and if so find the parent the
5915 * newly renamed object wants to belong under (which
5916 * may not be the parent in it's attached string DN
5918 rmd = ar->objs->objects[ar->index_current].meta_data;
5922 /* find existing meta data */
5923 omd_value = ldb_msg_find_ldb_val(ar->search_msg, "replPropertyMetaData");
5925 enum ndr_err_code ndr_err;
5926 ndr_err = ndr_pull_struct_blob(omd_value, ar, &omd,
5927 (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
5928 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
5929 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
5930 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
5933 if (omd.version != 1) {
5934 return replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
5938 ar->local_parent_guid = samdb_result_guid(ar->search_msg, "parentGUID");
5940 instanceType = ldb_msg_find_attr_as_int(ar->search_msg, "instanceType", 0);
5941 if (((instanceType & INSTANCE_TYPE_IS_NC_HEAD) == 0)
5942 && GUID_all_zero(&ar->local_parent_guid)) {
5943 DEBUG(0, ("Refusing to replicate new version of %s "
5944 "as local object has an all-zero parentGUID attribute, "
5945 "despite not being an NC root\n",
5946 ldb_dn_get_linearized(ar->search_msg->dn)));
5947 return replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
5951 * now we need to check for double renames. We could have a
5952 * local rename pending which our replication partner hasn't
5953 * received yet. We choose which one wins by looking at the
5954 * attribute stamps on the two objects, the newer one wins.
5956 * This also simply applies the correct algorithms for
5957 * determining if a change was made to name at all, or
5958 * if the object has just been renamed under the same
5961 md_remote = replmd_replPropertyMetaData1_find_attid(rmd, DRSUAPI_ATTID_name);
5962 md_local = replmd_replPropertyMetaData1_find_attid(&omd, DRSUAPI_ATTID_name);
5964 DEBUG(0,(__location__ ": Failed to find name attribute in local LDB replPropertyMetaData for %s\n",
5965 ldb_dn_get_linearized(ar->search_msg->dn)));
5966 return replmd_replicated_request_werror(ar, WERR_DS_DRA_DB_ERROR);
5970 * if there is no name attribute given then we have to assume the
5971 * object we've received has the older name
5973 if (replmd_replPropertyMetaData1_new_should_be_taken(
5974 ar->objs->dsdb_repl_flags & DSDB_REPL_FLAG_PRIORITISE_INCOMING,
5975 md_local, md_remote)) {
5976 struct GUID_txt_buf p_guid_local;
5977 struct GUID_txt_buf p_guid_remote;
5978 msg = ar->objs->objects[ar->index_current].msg;
5980 /* Merge on the existing object, with rename */
5982 DEBUG(4,(__location__ ": Looking for new parent for object %s currently under %s "
5983 "as incoming object changing to %s under %s\n",
5984 ldb_dn_get_linearized(ar->search_msg->dn),
5985 GUID_buf_string(&ar->local_parent_guid, &p_guid_local),
5986 ldb_dn_get_linearized(msg->dn),
5987 GUID_buf_string(ar->objs->objects[ar->index_current].parent_guid,
5989 ret = replmd_replicated_apply_search_for_parent(ar);
5991 struct GUID_txt_buf p_guid_local;
5992 struct GUID_txt_buf p_guid_remote;
5993 msg = ar->objs->objects[ar->index_current].msg;
5996 * Merge on the existing object, force no
5997 * rename (code below just to explain why in
6001 if (strcmp(ldb_dn_get_linearized(ar->search_msg->dn),
6002 ldb_dn_get_linearized(msg->dn)) == 0) {
6003 if (ar->objs->objects[ar->index_current].parent_guid != NULL &&
6004 GUID_equal(&ar->local_parent_guid,
6005 ar->objs->objects[ar->index_current].parent_guid)
6007 DEBUG(4,(__location__ ": Keeping object %s at under %s "
6008 "despite incoming object changing parent to %s\n",
6009 ldb_dn_get_linearized(ar->search_msg->dn),
6010 GUID_buf_string(&ar->local_parent_guid, &p_guid_local),
6011 GUID_buf_string(ar->objs->objects[ar->index_current].parent_guid,
6015 DEBUG(4,(__location__ ": Keeping object %s at under %s "
6016 " and rejecting older rename to %s under %s\n",
6017 ldb_dn_get_linearized(ar->search_msg->dn),
6018 GUID_buf_string(&ar->local_parent_guid, &p_guid_local),
6019 ldb_dn_get_linearized(msg->dn),
6020 GUID_buf_string(ar->objs->objects[ar->index_current].parent_guid,
6024 * This assignment ensures that the strcmp()
6025 * and GUID_equal() calls in
6026 * replmd_replicated_apply_merge() avoids the
6029 ar->objs->objects[ar->index_current].parent_guid =
6030 &ar->local_parent_guid;
6032 msg->dn = ar->search_msg->dn;
6033 ret = replmd_replicated_apply_merge(ar);
6035 if (ret != LDB_SUCCESS) {
6036 return ldb_module_done(ar->req, NULL, NULL, ret);
6045 static int replmd_replicated_uptodate_vector(struct replmd_replicated_request *ar);
6047 static int replmd_replicated_apply_next(struct replmd_replicated_request *ar)
6049 struct ldb_context *ldb;
6053 struct ldb_request *search_req;
6054 static const char *attrs[] = { "repsFrom", "replUpToDateVector",
6055 "parentGUID", "instanceType",
6056 "replPropertyMetaData", "nTSecurityDescriptor",
6057 "isDeleted", NULL };
6058 struct GUID_txt_buf guid_str_buf;
6060 if (ar->index_current >= ar->objs->num_objects) {
6063 * Now that we've applied all the objects, check that the new
6064 * linked attributes only reference objects we know about
6066 ret = replmd_verify_linked_attributes(ar);
6068 if (ret != LDB_SUCCESS) {
6072 /* done applying objects, move on to the next stage */
6073 return replmd_replicated_uptodate_vector(ar);
6076 ldb = ldb_module_get_ctx(ar->module);
6077 ar->search_msg = NULL;
6078 ar->isDeleted = false;
6080 tmp_str = GUID_buf_string(&ar->objs->objects[ar->index_current].object_guid,
6083 filter = talloc_asprintf(ar, "(objectGUID=%s)", tmp_str);
6084 if (!filter) return replmd_replicated_request_werror(ar, WERR_NOT_ENOUGH_MEMORY);
6086 ret = ldb_build_search_req(&search_req,
6089 ar->objs->partition_dn,
6095 replmd_replicated_apply_search_callback,
6097 LDB_REQ_SET_LOCATION(search_req);
6099 ret = dsdb_request_add_controls(search_req, DSDB_SEARCH_SHOW_RECYCLED);
6101 if (ret != LDB_SUCCESS) {
6105 return ldb_next_request(ar->module, search_req);
6109 * This is essentially a wrapper for replmd_replicated_apply_next()
6111 * This is needed to ensure that both codepaths call this handler.
6113 static int replmd_replicated_apply_isDeleted(struct replmd_replicated_request *ar)
6115 struct ldb_dn *deleted_objects_dn;
6116 struct ldb_message *msg = ar->objs->objects[ar->index_current].msg;
6117 int ret = dsdb_get_deleted_objects_dn(ldb_module_get_ctx(ar->module), msg, msg->dn,
6118 &deleted_objects_dn);
6119 if (ar->isDeleted && (ret != LDB_SUCCESS || ldb_dn_compare(msg->dn, deleted_objects_dn) != 0)) {
6121 * Do a delete here again, so that if there is
6122 * anything local that conflicts with this
6123 * object being deleted, it is removed. This
6124 * includes links. See MS-DRSR 4.1.10.6.9
6127 * If the object is already deleted, and there
6128 * is no more work required, it doesn't do
6132 /* This has been updated to point to the DN we eventually did the modify on */
6134 struct ldb_request *del_req;
6135 struct ldb_result *res;
6137 TALLOC_CTX *tmp_ctx = talloc_new(ar);
6139 ret = ldb_oom(ldb_module_get_ctx(ar->module));
6143 res = talloc_zero(tmp_ctx, struct ldb_result);
6145 ret = ldb_oom(ldb_module_get_ctx(ar->module));
6146 talloc_free(tmp_ctx);
6150 /* Build a delete request, which hopefully will artually turn into nothing */
6151 ret = ldb_build_del_req(&del_req, ldb_module_get_ctx(ar->module), tmp_ctx,
6155 ldb_modify_default_callback,
6157 LDB_REQ_SET_LOCATION(del_req);
6158 if (ret != LDB_SUCCESS) {
6159 talloc_free(tmp_ctx);
6164 * This is the guts of the call, call back
6165 * into our delete code, but setting the
6166 * re_delete flag so we delete anything that
6167 * shouldn't be there on a deleted or recycled
6170 ret = replmd_delete_internals(ar->module, del_req, true);
6171 if (ret == LDB_SUCCESS) {
6172 ret = ldb_wait(del_req->handle, LDB_WAIT_ALL);
6175 talloc_free(tmp_ctx);
6176 if (ret != LDB_SUCCESS) {
6181 ar->index_current++;
6182 return replmd_replicated_apply_next(ar);
6185 static int replmd_replicated_uptodate_modify_callback(struct ldb_request *req,
6186 struct ldb_reply *ares)
6188 struct ldb_context *ldb;
6189 struct replmd_replicated_request *ar = talloc_get_type(req->context,
6190 struct replmd_replicated_request);
6191 ldb = ldb_module_get_ctx(ar->module);
6194 return ldb_module_done(ar->req, NULL, NULL,
6195 LDB_ERR_OPERATIONS_ERROR);
6197 if (ares->error != LDB_SUCCESS) {
6198 return ldb_module_done(ar->req, ares->controls,
6199 ares->response, ares->error);
6202 if (ares->type != LDB_REPLY_DONE) {
6203 ldb_asprintf_errstring(ldb, "Invalid LDB reply type %d", ares->type);
6204 return ldb_module_done(ar->req, NULL, NULL,
6205 LDB_ERR_OPERATIONS_ERROR);
6210 return ldb_module_done(ar->req, NULL, NULL, LDB_SUCCESS);
6213 static int replmd_replicated_uptodate_modify(struct replmd_replicated_request *ar)
6215 struct ldb_context *ldb;
6216 struct ldb_request *change_req;
6217 enum ndr_err_code ndr_err;
6218 struct ldb_message *msg;
6219 struct replUpToDateVectorBlob ouv;
6220 const struct ldb_val *ouv_value;
6221 const struct drsuapi_DsReplicaCursor2CtrEx *ruv;
6222 struct replUpToDateVectorBlob nuv;
6223 struct ldb_val nuv_value;
6224 struct ldb_message_element *nuv_el = NULL;
6225 struct ldb_message_element *orf_el = NULL;
6226 struct repsFromToBlob nrf;
6227 struct ldb_val *nrf_value = NULL;
6228 struct ldb_message_element *nrf_el = NULL;
6232 time_t t = time(NULL);
6235 uint32_t instanceType;
6237 ldb = ldb_module_get_ctx(ar->module);
6238 ruv = ar->objs->uptodateness_vector;
6244 unix_to_nt_time(&now, t);
6246 if (ar->search_msg == NULL) {
6247 /* this happens for a REPL_OBJ call where we are
6248 creating the target object by replicating it. The
6249 subdomain join code does this for the partition DN
6251 DEBUG(4,(__location__ ": Skipping UDV and repsFrom update as no target DN\n"));
6252 return ldb_module_done(ar->req, NULL, NULL, LDB_SUCCESS);
6255 instanceType = ldb_msg_find_attr_as_uint(ar->search_msg, "instanceType", 0);
6256 if (! (instanceType & INSTANCE_TYPE_IS_NC_HEAD)) {
6257 DEBUG(4,(__location__ ": Skipping UDV and repsFrom update as not NC root: %s\n",
6258 ldb_dn_get_linearized(ar->search_msg->dn)));
6259 return ldb_module_done(ar->req, NULL, NULL, LDB_SUCCESS);
6263 * first create the new replUpToDateVector
6265 ouv_value = ldb_msg_find_ldb_val(ar->search_msg, "replUpToDateVector");
6267 ndr_err = ndr_pull_struct_blob(ouv_value, ar, &ouv,
6268 (ndr_pull_flags_fn_t)ndr_pull_replUpToDateVectorBlob);
6269 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
6270 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
6271 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
6274 if (ouv.version != 2) {
6275 return replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
6280 * the new uptodateness vector will at least
6281 * contain 1 entry, one for the source_dsa
6283 * plus optional values from our old vector and the one from the source_dsa
6285 nuv.ctr.ctr2.count = ouv.ctr.ctr2.count;
6286 if (ruv) nuv.ctr.ctr2.count += ruv->count;
6287 nuv.ctr.ctr2.cursors = talloc_array(ar,
6288 struct drsuapi_DsReplicaCursor2,
6289 nuv.ctr.ctr2.count);
6290 if (!nuv.ctr.ctr2.cursors) return replmd_replicated_request_werror(ar, WERR_NOT_ENOUGH_MEMORY);
6292 /* first copy the old vector */
6293 for (i=0; i < ouv.ctr.ctr2.count; i++) {
6294 nuv.ctr.ctr2.cursors[ni] = ouv.ctr.ctr2.cursors[i];
6298 /* merge in the source_dsa vector is available */
6299 for (i=0; (ruv && i < ruv->count); i++) {
6302 if (GUID_equal(&ruv->cursors[i].source_dsa_invocation_id,
6303 &ar->our_invocation_id)) {
6307 for (j=0; j < ni; j++) {
6308 if (!GUID_equal(&ruv->cursors[i].source_dsa_invocation_id,
6309 &nuv.ctr.ctr2.cursors[j].source_dsa_invocation_id)) {
6315 if (ruv->cursors[i].highest_usn > nuv.ctr.ctr2.cursors[j].highest_usn) {
6316 nuv.ctr.ctr2.cursors[j] = ruv->cursors[i];
6321 if (found) continue;
6323 /* if it's not there yet, add it */
6324 nuv.ctr.ctr2.cursors[ni] = ruv->cursors[i];
6329 * finally correct the size of the cursors array
6331 nuv.ctr.ctr2.count = ni;
6336 TYPESAFE_QSORT(nuv.ctr.ctr2.cursors, nuv.ctr.ctr2.count, drsuapi_DsReplicaCursor2_compare);
6339 * create the change ldb_message
6341 msg = ldb_msg_new(ar);
6342 if (!msg) return replmd_replicated_request_werror(ar, WERR_NOT_ENOUGH_MEMORY);
6343 msg->dn = ar->search_msg->dn;
6345 ndr_err = ndr_push_struct_blob(&nuv_value, msg, &nuv,
6346 (ndr_push_flags_fn_t)ndr_push_replUpToDateVectorBlob);
6347 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
6348 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
6349 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
6351 ret = ldb_msg_add_value(msg, "replUpToDateVector", &nuv_value, &nuv_el);
6352 if (ret != LDB_SUCCESS) {
6353 return replmd_replicated_request_error(ar, ret);
6355 nuv_el->flags = LDB_FLAG_MOD_REPLACE;
6358 * now create the new repsFrom value from the given repsFromTo1 structure
6362 nrf.ctr.ctr1 = *ar->objs->source_dsa;
6363 nrf.ctr.ctr1.last_attempt = now;
6364 nrf.ctr.ctr1.last_success = now;
6365 nrf.ctr.ctr1.result_last_attempt = WERR_OK;
6368 * first see if we already have a repsFrom value for the current source dsa
6369 * if so we'll later replace this value
6371 orf_el = ldb_msg_find_element(ar->search_msg, "repsFrom");
6373 for (i=0; i < orf_el->num_values; i++) {
6374 struct repsFromToBlob *trf;
6376 trf = talloc(ar, struct repsFromToBlob);
6377 if (!trf) return replmd_replicated_request_werror(ar, WERR_NOT_ENOUGH_MEMORY);
6379 ndr_err = ndr_pull_struct_blob(&orf_el->values[i], trf, trf,
6380 (ndr_pull_flags_fn_t)ndr_pull_repsFromToBlob);
6381 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
6382 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
6383 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
6386 if (trf->version != 1) {
6387 return replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
6391 * we compare the source dsa objectGUID not the invocation_id
6392 * because we want only one repsFrom value per source dsa
6393 * and when the invocation_id of the source dsa has changed we don't need
6394 * the old repsFrom with the old invocation_id
6396 if (!GUID_equal(&trf->ctr.ctr1.source_dsa_obj_guid,
6397 &ar->objs->source_dsa->source_dsa_obj_guid)) {
6403 nrf_value = &orf_el->values[i];
6408 * copy over all old values to the new ldb_message
6410 ret = ldb_msg_add_empty(msg, "repsFrom", 0, &nrf_el);
6411 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
6416 * if we haven't found an old repsFrom value for the current source dsa
6417 * we'll add a new value
6420 struct ldb_val zero_value;
6421 ZERO_STRUCT(zero_value);
6422 ret = ldb_msg_add_value(msg, "repsFrom", &zero_value, &nrf_el);
6423 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
6425 nrf_value = &nrf_el->values[nrf_el->num_values - 1];
6428 /* we now fill the value which is already attached to ldb_message */
6429 ndr_err = ndr_push_struct_blob(nrf_value, msg,
6431 (ndr_push_flags_fn_t)ndr_push_repsFromToBlob);
6432 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
6433 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
6434 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
6438 * the ldb_message_element for the attribute, has all the old values and the new one
6439 * so we'll replace the whole attribute with all values
6441 nrf_el->flags = LDB_FLAG_MOD_REPLACE;
6443 if (CHECK_DEBUGLVL(4)) {
6444 char *s = ldb_ldif_message_string(ldb, ar, LDB_CHANGETYPE_MODIFY, msg);
6445 DEBUG(4, ("DRS replication uptodate modify message:\n%s\n", s));
6449 /* prepare the ldb_modify() request */
6450 ret = ldb_build_mod_req(&change_req,
6456 replmd_replicated_uptodate_modify_callback,
6458 LDB_REQ_SET_LOCATION(change_req);
6459 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
6461 return ldb_next_request(ar->module, change_req);
6464 static int replmd_replicated_uptodate_search_callback(struct ldb_request *req,
6465 struct ldb_reply *ares)
6467 struct replmd_replicated_request *ar = talloc_get_type(req->context,
6468 struct replmd_replicated_request);
6472 return ldb_module_done(ar->req, NULL, NULL,
6473 LDB_ERR_OPERATIONS_ERROR);
6475 if (ares->error != LDB_SUCCESS &&
6476 ares->error != LDB_ERR_NO_SUCH_OBJECT) {
6477 return ldb_module_done(ar->req, ares->controls,
6478 ares->response, ares->error);
6481 switch (ares->type) {
6482 case LDB_REPLY_ENTRY:
6483 ar->search_msg = talloc_steal(ar, ares->message);
6486 case LDB_REPLY_REFERRAL:
6487 /* we ignore referrals */
6490 case LDB_REPLY_DONE:
6491 ret = replmd_replicated_uptodate_modify(ar);
6492 if (ret != LDB_SUCCESS) {
6493 return ldb_module_done(ar->req, NULL, NULL, ret);
6502 static int replmd_replicated_uptodate_vector(struct replmd_replicated_request *ar)
6504 struct ldb_context *ldb = ldb_module_get_ctx(ar->module);
6505 struct replmd_private *replmd_private =
6506 talloc_get_type_abort(ldb_module_get_private(ar->module),
6507 struct replmd_private);
6509 static const char *attrs[] = {
6510 "replUpToDateVector",
6515 struct ldb_request *search_req;
6517 ar->search_msg = NULL;
6520 * Let the caller know that we did an originating updates
6522 ar->objs->originating_updates = replmd_private->originating_updates;
6524 ret = ldb_build_search_req(&search_req,
6527 ar->objs->partition_dn,
6533 replmd_replicated_uptodate_search_callback,
6535 LDB_REQ_SET_LOCATION(search_req);
6536 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
6538 return ldb_next_request(ar->module, search_req);
6543 static int replmd_extended_replicated_objects(struct ldb_module *module, struct ldb_request *req)
6545 struct ldb_context *ldb;
6546 struct dsdb_extended_replicated_objects *objs;
6547 struct replmd_replicated_request *ar;
6548 struct ldb_control **ctrls;
6551 bool incomplete_subset;
6552 struct replmd_private *replmd_private =
6553 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
6555 ldb = ldb_module_get_ctx(module);
6557 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_extended_replicated_objects\n");
6559 objs = talloc_get_type(req->op.extended.data, struct dsdb_extended_replicated_objects);
6561 ldb_debug(ldb, LDB_DEBUG_FATAL, "replmd_extended_replicated_objects: invalid extended data\n");
6562 return LDB_ERR_PROTOCOL_ERROR;
6565 if (objs->version != DSDB_EXTENDED_REPLICATED_OBJECTS_VERSION) {
6566 ldb_debug(ldb, LDB_DEBUG_FATAL, "replmd_extended_replicated_objects: extended data invalid version [%u != %u]\n",
6567 objs->version, DSDB_EXTENDED_REPLICATED_OBJECTS_VERSION);
6568 return LDB_ERR_PROTOCOL_ERROR;
6571 ar = replmd_ctx_init(module, req);
6573 return LDB_ERR_OPERATIONS_ERROR;
6575 /* Set the flags to have the replmd_op_callback run over the full set of objects */
6576 ar->apply_mode = true;
6578 ar->schema = dsdb_get_schema(ldb, ar);
6580 ldb_debug_set(ldb, LDB_DEBUG_FATAL, "replmd_ctx_init: no loaded schema found\n");
6582 DEBUG(0,(__location__ ": %s\n", ldb_errstring(ldb)));
6583 return LDB_ERR_CONSTRAINT_VIOLATION;
6586 ctrls = req->controls;
6588 if (req->controls) {
6589 req->controls = talloc_memdup(ar, req->controls,
6590 talloc_get_size(req->controls));
6591 if (!req->controls) return replmd_replicated_request_werror(ar, WERR_NOT_ENOUGH_MEMORY);
6594 ret = ldb_request_add_control(req, DSDB_CONTROL_REPLICATED_UPDATE_OID, false, NULL);
6595 if (ret != LDB_SUCCESS) {
6599 /* If this change contained linked attributes in the body
6600 * (rather than in the links section) we need to update
6601 * backlinks in linked_attributes */
6602 ret = ldb_request_add_control(req, DSDB_CONTROL_APPLY_LINKS, false, NULL);
6603 if (ret != LDB_SUCCESS) {
6607 ar->controls = req->controls;
6608 req->controls = ctrls;
6609 incomplete_subset = (ar->objs->dsdb_repl_flags & DSDB_REPL_FLAG_OBJECT_SUBSET);
6611 DEBUG(4,("linked_attributes_count=%u\n", objs->linked_attributes_count));
6613 /* save away the linked attributes for the end of the
6615 for (i=0; i<ar->objs->linked_attributes_count; i++) {
6616 struct la_entry *la_entry;
6618 if (replmd_private->la_ctx == NULL) {
6619 replmd_private->la_ctx = talloc_new(replmd_private);
6621 la_entry = talloc(replmd_private->la_ctx, struct la_entry);
6622 if (la_entry == NULL) {
6624 return LDB_ERR_OPERATIONS_ERROR;
6626 la_entry->la = talloc(la_entry, struct drsuapi_DsReplicaLinkedAttribute);
6627 if (la_entry->la == NULL) {
6628 talloc_free(la_entry);
6630 return LDB_ERR_OPERATIONS_ERROR;
6632 *la_entry->la = ar->objs->linked_attributes[i];
6635 * we may not be able to resolve link targets properly when
6636 * dealing with subsets of objects, e.g. the source is a
6637 * critical object and the target isn't
6639 la_entry->incomplete_replica = incomplete_subset;
6641 /* we need to steal the non-scalars so they stay
6642 around until the end of the transaction */
6643 talloc_steal(la_entry->la, la_entry->la->identifier);
6644 talloc_steal(la_entry->la, la_entry->la->value.blob);
6646 DLIST_ADD(replmd_private->la_list, la_entry);
6649 return replmd_replicated_apply_next(ar);
6653 * Returns True if the source and target DNs both have the same naming context,
6654 * i.e. they're both in the same partition.
6656 static bool replmd_objects_have_same_nc(struct ldb_context *ldb,
6657 TALLOC_CTX *mem_ctx,
6658 struct ldb_dn *source_dn,
6659 struct ldb_dn *target_dn)
6661 TALLOC_CTX *tmp_ctx;
6662 struct ldb_dn *source_nc;
6663 struct ldb_dn *target_nc;
6665 bool same_nc = true;
6667 tmp_ctx = talloc_new(mem_ctx);
6669 ret = dsdb_find_nc_root(ldb, tmp_ctx, source_dn, &source_nc);
6670 if (ret != LDB_SUCCESS) {
6671 DBG_ERR("Failed to find base DN for source %s\n",
6672 ldb_dn_get_linearized(source_dn));
6673 talloc_free(tmp_ctx);
6677 ret = dsdb_find_nc_root(ldb, tmp_ctx, target_dn, &target_nc);
6678 if (ret != LDB_SUCCESS) {
6679 DBG_ERR("Failed to find base DN for target %s\n",
6680 ldb_dn_get_linearized(target_dn));
6681 talloc_free(tmp_ctx);
6685 same_nc = (ldb_dn_compare(source_nc, target_nc) == 0);
6687 talloc_free(tmp_ctx);
6693 * Checks that the target object for a linked attribute exists.
6694 * If it exists, its GUID and deletion-state are returned
6696 static int replmd_check_target_exists(struct ldb_module *module,
6697 struct dsdb_dn *dsdb_dn,
6698 struct la_entry *la_entry,
6699 struct ldb_dn *source_dn,
6701 enum deletion_state *target_deletion_state)
6703 struct drsuapi_DsReplicaLinkedAttribute *la = la_entry->la;
6704 struct ldb_context *ldb = ldb_module_get_ctx(module);
6705 struct ldb_result *target_res;
6706 TALLOC_CTX *tmp_ctx = talloc_new(la_entry);
6707 const char *attrs[] = { "isDeleted", "isRecycled", NULL };
6710 bool active = (la->flags & DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE) ? true : false;
6712 *target_deletion_state = OBJECT_REMOVED;
6714 ntstatus = dsdb_get_extended_dn_guid(dsdb_dn->dn, guid, "GUID");
6716 if (!NT_STATUS_IS_OK(ntstatus) && !active) {
6719 * This strange behaviour (allowing a NULL/missing
6720 * GUID) originally comes from:
6722 * commit e3054ce0fe0f8f62d2f5b2a77893e7a1479128bd
6723 * Author: Andrew Tridgell <tridge@samba.org>
6724 * Date: Mon Dec 21 21:21:55 2009 +1100
6726 * s4-drs: cope better with NULL GUIDS from DRS
6728 * It is valid to get a NULL GUID over DRS for a deleted forward link. We
6729 * need to match by DN if possible when seeing if we should update an
6732 * Pair-Programmed-With: Andrew Bartlett <abartlet@samba.org>
6734 ret = dsdb_module_search_dn(module, tmp_ctx, &target_res,
6736 DSDB_FLAG_NEXT_MODULE |
6737 DSDB_SEARCH_SHOW_RECYCLED |
6738 DSDB_SEARCH_SEARCH_ALL_PARTITIONS |
6739 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT,
6741 } else if (!NT_STATUS_IS_OK(ntstatus)) {
6742 ldb_asprintf_errstring(ldb, "Failed to find GUID in linked attribute 0x%x blob for %s from %s",
6744 ldb_dn_get_linearized(dsdb_dn->dn),
6745 ldb_dn_get_linearized(source_dn));
6746 talloc_free(tmp_ctx);
6747 return LDB_ERR_OPERATIONS_ERROR;
6749 ret = dsdb_module_search(module, tmp_ctx, &target_res,
6750 NULL, LDB_SCOPE_SUBTREE,
6752 DSDB_FLAG_NEXT_MODULE |
6753 DSDB_SEARCH_SHOW_RECYCLED |
6754 DSDB_SEARCH_SEARCH_ALL_PARTITIONS |
6755 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT,
6758 GUID_string(tmp_ctx, guid));
6761 if (ret != LDB_SUCCESS) {
6762 ldb_asprintf_errstring(ldb, "Failed to re-resolve GUID %s: %s\n",
6763 GUID_string(tmp_ctx, guid),
6764 ldb_errstring(ldb));
6765 talloc_free(tmp_ctx);
6769 if (target_res->count == 0) {
6773 * When we implement Trusted Domains we need to consider
6774 * whether they get treated as an incomplete replica here or not
6776 if (la_entry->incomplete_replica) {
6779 * If we're only replicating a subset of objects (e.g.
6780 * critical-only, single-object), then an unknown target
6781 * is probably not a critical problem. We don't increase
6782 * the highwater-mark so subsequent replications should
6783 * resolve any missing links
6785 DEBUG(2,(__location__
6786 ": Failed to find target %s linked from %s\n",
6787 ldb_dn_get_linearized(dsdb_dn->dn),
6788 ldb_dn_get_linearized(source_dn)));
6790 } else if (replmd_objects_have_same_nc(ldb, tmp_ctx, source_dn,
6792 ldb_asprintf_errstring(ldb, "Unknown target %s GUID %s linked from %s\n",
6793 ldb_dn_get_linearized(dsdb_dn->dn),
6794 GUID_string(tmp_ctx, guid),
6795 ldb_dn_get_linearized(source_dn));
6796 ret = LDB_ERR_NO_SUCH_OBJECT;
6801 * We don't handle cross-partition links well here (we
6802 * could potentially lose them), but don't fail the
6805 DEBUG(2,("Failed to resolve cross-partition link between %s and %s\n",
6806 ldb_dn_get_linearized(source_dn),
6807 ldb_dn_get_linearized(dsdb_dn->dn)));
6809 } else if (target_res->count != 1) {
6810 ldb_asprintf_errstring(ldb, "More than one object found matching objectGUID %s\n",
6811 GUID_string(tmp_ctx, guid));
6812 ret = LDB_ERR_OPERATIONS_ERROR;
6814 struct ldb_message *target_msg = target_res->msgs[0];
6816 dsdb_dn->dn = talloc_steal(dsdb_dn, target_msg->dn);
6818 /* Get the object's state (i.e. Not Deleted, Tombstone, etc) */
6819 replmd_deletion_state(module, target_msg,
6820 target_deletion_state, NULL);
6823 talloc_free(tmp_ctx);
6828 * Extracts the key details about the source/target object for a
6829 * linked-attribute entry.
6830 * This returns the following details:
6831 * @param ret_attr the schema details for the linked attribute
6832 * @param source_msg the search result for the source object
6833 * @param target_dsdb_dn the unpacked DN info for the target object
6835 static int replmd_extract_la_entry_details(struct ldb_module *module,
6836 struct la_entry *la_entry,
6837 TALLOC_CTX *mem_ctx,
6838 const struct dsdb_attribute **ret_attr,
6839 struct ldb_message **source_msg,
6840 struct dsdb_dn **target_dsdb_dn)
6842 struct drsuapi_DsReplicaLinkedAttribute *la = la_entry->la;
6843 struct ldb_context *ldb = ldb_module_get_ctx(module);
6844 const struct dsdb_schema *schema = dsdb_get_schema(ldb, mem_ctx);
6846 const struct dsdb_attribute *attr;
6848 struct ldb_result *res;
6849 const char *attrs[4];
6852 linked_attributes[0]:
6853 &objs->linked_attributes[i]: struct drsuapi_DsReplicaLinkedAttribute
6855 identifier: struct drsuapi_DsReplicaObjectIdentifier
6856 __ndr_size : 0x0000003a (58)
6857 __ndr_size_sid : 0x00000000 (0)
6858 guid : 8e95b6a9-13dd-4158-89db-3220a5be5cc7
6860 __ndr_size_dn : 0x00000000 (0)
6862 attid : DRSUAPI_ATTID_member (0x1F)
6863 value: struct drsuapi_DsAttributeValue
6864 __ndr_size : 0x0000007e (126)
6866 blob : DATA_BLOB length=126
6867 flags : 0x00000001 (1)
6868 1: DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE
6869 originating_add_time : Wed Sep 2 22:20:01 2009 EST
6870 meta_data: struct drsuapi_DsReplicaMetaData
6871 version : 0x00000015 (21)
6872 originating_change_time : Wed Sep 2 23:39:07 2009 EST
6873 originating_invocation_id: 794640f3-18cf-40ee-a211-a93992b67a64
6874 originating_usn : 0x000000000001e19c (123292)
6876 (for cases where the link is to a normal DN)
6877 &target: struct drsuapi_DsReplicaObjectIdentifier3
6878 __ndr_size : 0x0000007e (126)
6879 __ndr_size_sid : 0x0000001c (28)
6880 guid : 7639e594-db75-4086-b0d4-67890ae46031
6881 sid : S-1-5-21-2848215498-2472035911-1947525656-19924
6882 __ndr_size_dn : 0x00000022 (34)
6883 dn : 'CN=UOne,OU=TestOU,DC=vsofs8,DC=com'
6886 /* find the attribute being modified */
6887 attr = dsdb_attribute_by_attributeID_id(schema, la->attid);
6889 struct GUID_txt_buf guid_str;
6890 ldb_asprintf_errstring(ldb, "Unable to find attributeID 0x%x for link on <GUID=%s>",
6892 GUID_buf_string(&la->identifier->guid,
6894 return LDB_ERR_OPERATIONS_ERROR;
6897 attrs[0] = attr->lDAPDisplayName;
6898 attrs[1] = "isDeleted";
6899 attrs[2] = "isRecycled";
6903 * get the existing message from the db for the object with
6904 * this GUID, returning attribute being modified. We will then
6905 * use this msg as the basis for a modify call
6907 ret = dsdb_module_search(module, mem_ctx, &res, NULL, LDB_SCOPE_SUBTREE, attrs,
6908 DSDB_FLAG_NEXT_MODULE |
6909 DSDB_SEARCH_SEARCH_ALL_PARTITIONS |
6910 DSDB_SEARCH_SHOW_RECYCLED |
6911 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT |
6912 DSDB_SEARCH_REVEAL_INTERNALS,
6914 "objectGUID=%s", GUID_string(mem_ctx, &la->identifier->guid));
6915 if (ret != LDB_SUCCESS) {
6918 if (res->count != 1) {
6919 ldb_asprintf_errstring(ldb, "DRS linked attribute for GUID %s - DN not found",
6920 GUID_string(mem_ctx, &la->identifier->guid));
6921 return LDB_ERR_NO_SUCH_OBJECT;
6924 *source_msg = res->msgs[0];
6926 /* the value blob for the attribute holds the target object DN */
6927 status = dsdb_dn_la_from_blob(ldb, attr, schema, mem_ctx, la->value.blob, target_dsdb_dn);
6928 if (!W_ERROR_IS_OK(status)) {
6929 ldb_asprintf_errstring(ldb, "Failed to parsed linked attribute blob for %s on %s - %s\n",
6930 attr->lDAPDisplayName,
6931 ldb_dn_get_linearized(res->msgs[0]->dn),
6932 win_errstr(status));
6933 return LDB_ERR_OPERATIONS_ERROR;
6942 * Verifies that the source and target objects are known for each linked
6943 * attribute in the current transaction.
6945 static int replmd_verify_linked_attributes(struct replmd_replicated_request *ar)
6947 int ret = LDB_SUCCESS;
6948 struct la_entry *la;
6949 struct ldb_module *module = ar->module;
6950 TALLOC_CTX *tmp_ctx = talloc_new(ar);
6951 struct replmd_private *replmd_private =
6952 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
6954 for (la = DLIST_TAIL(replmd_private->la_list); la; la = DLIST_PREV(la)) {
6955 struct ldb_message *src_msg;
6956 const struct dsdb_attribute *attr;
6957 struct dsdb_dn *tgt_dsdb_dn;
6958 enum deletion_state del_state = OBJECT_NOT_DELETED;
6959 struct GUID guid = GUID_zero();
6961 ret = replmd_extract_la_entry_details(module, la, tmp_ctx, &attr,
6962 &src_msg, &tgt_dsdb_dn);
6964 if (ret != LDB_SUCCESS) {
6968 ret = replmd_check_target_exists(module, tgt_dsdb_dn, la,
6969 src_msg->dn, &guid, &del_state);
6972 * When we fail to find the target object, the error code we pass
6973 * back here is really important. It flags back to the callers to
6974 * retry this request with DRSUAPI_DRS_GET_TGT
6976 if (ret == LDB_ERR_NO_SUCH_OBJECT) {
6977 ret = replmd_replicated_request_werror(ar, WERR_DS_DRA_RECYCLED_TARGET);
6980 if (ret != LDB_SUCCESS) {
6985 talloc_free(tmp_ctx);
6990 process one linked attribute structure
6992 static int replmd_process_linked_attribute(struct ldb_module *module,
6993 struct replmd_private *replmd_private,
6994 struct la_entry *la_entry,
6995 struct ldb_request *parent)
6997 struct drsuapi_DsReplicaLinkedAttribute *la = la_entry->la;
6998 struct ldb_context *ldb = ldb_module_get_ctx(module);
6999 struct ldb_message *msg;
7000 TALLOC_CTX *tmp_ctx = talloc_new(la_entry);
7001 const struct dsdb_schema *schema = dsdb_get_schema(ldb, tmp_ctx);
7003 const struct dsdb_attribute *attr;
7004 struct dsdb_dn *dsdb_dn;
7005 uint64_t seq_num = 0;
7006 struct ldb_message_element *old_el;
7007 time_t t = time(NULL);
7008 struct parsed_dn *pdn_list, *pdn, *next;
7009 struct GUID guid = GUID_zero();
7010 bool active = (la->flags & DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE)?true:false;
7012 enum deletion_state deletion_state = OBJECT_NOT_DELETED;
7013 enum deletion_state target_deletion_state = OBJECT_NOT_DELETED;
7016 * get the attribute being modified, the search result for the source object,
7017 * and the target object's DN details
7019 ret = replmd_extract_la_entry_details(module, la_entry, tmp_ctx, &attr,
7022 if (ret != LDB_SUCCESS) {
7023 talloc_free(tmp_ctx);
7028 * Check for deleted objects per MS-DRSR 4.1.10.6.13
7029 * ProcessLinkValue, because link updates are not applied to
7030 * recycled and tombstone objects. We don't have to delete
7031 * any existing link, that should have happened when the
7032 * object deletion was replicated or initiated.
7034 replmd_deletion_state(module, msg, &deletion_state, NULL);
7036 if (deletion_state >= OBJECT_RECYCLED) {
7037 talloc_free(tmp_ctx);
7041 old_el = ldb_msg_find_element(msg, attr->lDAPDisplayName);
7042 if (old_el == NULL) {
7043 ret = ldb_msg_add_empty(msg, attr->lDAPDisplayName, LDB_FLAG_MOD_REPLACE, &old_el);
7044 if (ret != LDB_SUCCESS) {
7045 ldb_module_oom(module);
7046 talloc_free(tmp_ctx);
7047 return LDB_ERR_OPERATIONS_ERROR;
7050 old_el->flags = LDB_FLAG_MOD_REPLACE;
7053 /* parse the existing links */
7054 ret = get_parsed_dns_trusted(module, replmd_private, tmp_ctx, old_el, &pdn_list,
7055 attr->syntax->ldap_oid, parent);
7057 if (ret != LDB_SUCCESS) {
7058 talloc_free(tmp_ctx);
7062 ret = replmd_check_target_exists(module, dsdb_dn, la_entry, msg->dn,
7063 &guid, &target_deletion_state);
7065 if (ret != LDB_SUCCESS) {
7066 talloc_free(tmp_ctx);
7071 * Check for deleted objects per MS-DRSR 4.1.10.6.13
7072 * ProcessLinkValue, because link updates are not applied to
7073 * recycled and tombstone objects. We don't have to delete
7074 * any existing link, that should have happened when the
7075 * object deletion was replicated or initiated.
7077 if (target_deletion_state >= OBJECT_RECYCLED) {
7078 talloc_free(tmp_ctx);
7082 /* see if this link already exists */
7083 ret = parsed_dn_find(ldb, pdn_list, old_el->num_values,
7086 dsdb_dn->extra_part, 0,
7088 attr->syntax->ldap_oid,
7090 if (ret != LDB_SUCCESS) {
7091 talloc_free(tmp_ctx);
7097 /* see if this update is newer than what we have already */
7098 struct GUID invocation_id = GUID_zero();
7099 uint32_t version = 0;
7100 uint32_t originating_usn = 0;
7101 NTTIME change_time = 0;
7102 uint32_t rmd_flags = dsdb_dn_rmd_flags(pdn->dsdb_dn->dn);
7104 dsdb_get_extended_dn_guid(pdn->dsdb_dn->dn, &invocation_id, "RMD_INVOCID");
7105 dsdb_get_extended_dn_uint32(pdn->dsdb_dn->dn, &version, "RMD_VERSION");
7106 dsdb_get_extended_dn_uint32(pdn->dsdb_dn->dn, &originating_usn, "RMD_ORIGINATING_USN");
7107 dsdb_get_extended_dn_nttime(pdn->dsdb_dn->dn, &change_time, "RMD_CHANGETIME");
7109 if (!replmd_update_is_newer(&invocation_id,
7110 &la->meta_data.originating_invocation_id,
7112 la->meta_data.version,
7114 la->meta_data.originating_change_time)) {
7115 DEBUG(3,("Discarding older DRS linked attribute update to %s on %s from %s\n",
7116 old_el->name, ldb_dn_get_linearized(msg->dn),
7117 GUID_string(tmp_ctx, &la->meta_data.originating_invocation_id)));
7118 talloc_free(tmp_ctx);
7122 /* get a seq_num for this change */
7123 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &seq_num);
7124 if (ret != LDB_SUCCESS) {
7125 talloc_free(tmp_ctx);
7129 if (!(rmd_flags & DSDB_RMD_FLAG_DELETED)) {
7130 /* remove the existing backlink */
7131 ret = replmd_add_backlink(module, replmd_private,
7136 if (ret != LDB_SUCCESS) {
7137 talloc_free(tmp_ctx);
7142 ret = replmd_update_la_val(tmp_ctx, pdn->v, dsdb_dn, pdn->dsdb_dn,
7143 &la->meta_data.originating_invocation_id,
7144 la->meta_data.originating_usn, seq_num,
7145 la->meta_data.originating_change_time,
7146 la->meta_data.version,
7148 if (ret != LDB_SUCCESS) {
7149 talloc_free(tmp_ctx);
7154 /* add the new backlink */
7155 ret = replmd_add_backlink(module, replmd_private,
7160 if (ret != LDB_SUCCESS) {
7161 talloc_free(tmp_ctx);
7167 /* get a seq_num for this change */
7168 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &seq_num);
7169 if (ret != LDB_SUCCESS) {
7170 talloc_free(tmp_ctx);
7174 * We know where the new one needs to be, from the *next
7175 * pointer into pdn_list.
7178 offset = old_el->num_values;
7180 if (next->dsdb_dn == NULL) {
7181 ret = really_parse_trusted_dn(tmp_ctx, ldb, next,
7182 attr->syntax->ldap_oid);
7183 if (ret != LDB_SUCCESS) {
7187 offset = next - pdn_list;
7188 if (offset > old_el->num_values) {
7189 talloc_free(tmp_ctx);
7190 return LDB_ERR_OPERATIONS_ERROR;
7194 old_el->values = talloc_realloc(msg->elements, old_el->values,
7195 struct ldb_val, old_el->num_values+1);
7196 if (!old_el->values) {
7197 ldb_module_oom(module);
7198 return LDB_ERR_OPERATIONS_ERROR;
7201 if (offset != old_el->num_values) {
7202 memmove(&old_el->values[offset + 1], &old_el->values[offset],
7203 (old_el->num_values - offset) * sizeof(old_el->values[0]));
7206 old_el->num_values++;
7208 ret = replmd_build_la_val(tmp_ctx, &old_el->values[offset], dsdb_dn,
7209 &la->meta_data.originating_invocation_id,
7210 la->meta_data.originating_usn, seq_num,
7211 la->meta_data.originating_change_time,
7212 la->meta_data.version,
7214 if (ret != LDB_SUCCESS) {
7215 talloc_free(tmp_ctx);
7220 ret = replmd_add_backlink(module, replmd_private,
7225 if (ret != LDB_SUCCESS) {
7226 talloc_free(tmp_ctx);
7232 /* we only change whenChanged and uSNChanged if the seq_num
7234 ret = add_time_element(msg, "whenChanged", t);
7235 if (ret != LDB_SUCCESS) {
7236 talloc_free(tmp_ctx);
7241 ret = add_uint64_element(ldb, msg, "uSNChanged", seq_num);
7242 if (ret != LDB_SUCCESS) {
7243 talloc_free(tmp_ctx);
7248 old_el = ldb_msg_find_element(msg, attr->lDAPDisplayName);
7249 if (old_el == NULL) {
7250 talloc_free(tmp_ctx);
7251 return ldb_operr(ldb);
7254 ret = dsdb_check_single_valued_link(attr, old_el);
7255 if (ret != LDB_SUCCESS) {
7256 talloc_free(tmp_ctx);
7260 old_el->flags |= LDB_FLAG_INTERNAL_DISABLE_SINGLE_VALUE_CHECK;
7262 ret = linked_attr_modify(module, msg, parent);
7263 if (ret != LDB_SUCCESS) {
7264 ldb_debug(ldb, LDB_DEBUG_WARNING, "Failed to apply linked attribute change '%s'\n%s\n",
7266 ldb_ldif_message_string(ldb, tmp_ctx, LDB_CHANGETYPE_MODIFY, msg));
7267 talloc_free(tmp_ctx);
7271 talloc_free(tmp_ctx);
7276 static int replmd_extended(struct ldb_module *module, struct ldb_request *req)
7278 if (strcmp(req->op.extended.oid, DSDB_EXTENDED_REPLICATED_OBJECTS_OID) == 0) {
7279 return replmd_extended_replicated_objects(module, req);
7282 return ldb_next_request(module, req);
7287 we hook into the transaction operations to allow us to
7288 perform the linked attribute updates at the end of the whole
7289 transaction. This allows a forward linked attribute to be created
7290 before the object is created. During a vampire, w2k8 sends us linked
7291 attributes before the objects they are part of.
7293 static int replmd_start_transaction(struct ldb_module *module)
7295 /* create our private structure for this transaction */
7296 struct replmd_private *replmd_private = talloc_get_type(ldb_module_get_private(module),
7297 struct replmd_private);
7298 replmd_txn_cleanup(replmd_private);
7300 /* free any leftover mod_usn records from cancelled
7302 while (replmd_private->ncs) {
7303 struct nc_entry *e = replmd_private->ncs;
7304 DLIST_REMOVE(replmd_private->ncs, e);
7308 replmd_private->originating_updates = false;
7310 return ldb_next_start_trans(module);
7314 on prepare commit we loop over our queued la_context structures and
7317 static int replmd_prepare_commit(struct ldb_module *module)
7319 struct replmd_private *replmd_private =
7320 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
7321 struct la_entry *la, *prev;
7325 * Walk the list of linked attributes from DRS replication.
7327 * We walk backwards, to do the first entry first, as we
7328 * added the entries with DLIST_ADD() which puts them at the
7331 for (la = DLIST_TAIL(replmd_private->la_list); la; la=prev) {
7332 prev = DLIST_PREV(la);
7333 DLIST_REMOVE(replmd_private->la_list, la);
7334 ret = replmd_process_linked_attribute(module, replmd_private,
7336 if (ret != LDB_SUCCESS) {
7337 replmd_txn_cleanup(replmd_private);
7342 replmd_txn_cleanup(replmd_private);
7344 /* possibly change @REPLCHANGED */
7345 ret = replmd_notify_store(module, NULL);
7346 if (ret != LDB_SUCCESS) {
7350 return ldb_next_prepare_commit(module);
7353 static int replmd_del_transaction(struct ldb_module *module)
7355 struct replmd_private *replmd_private =
7356 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
7357 replmd_txn_cleanup(replmd_private);
7359 return ldb_next_del_trans(module);
7363 static const struct ldb_module_ops ldb_repl_meta_data_module_ops = {
7364 .name = "repl_meta_data",
7365 .init_context = replmd_init,
7367 .modify = replmd_modify,
7368 .rename = replmd_rename,
7369 .del = replmd_delete,
7370 .extended = replmd_extended,
7371 .start_transaction = replmd_start_transaction,
7372 .prepare_commit = replmd_prepare_commit,
7373 .del_transaction = replmd_del_transaction,
7376 int ldb_repl_meta_data_module_init(const char *version)
7378 LDB_MODULE_CHECK_VERSION(version);
7379 return ldb_register_module(&ldb_repl_meta_data_module_ops);