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;
79 struct replmd_replicated_request {
80 struct ldb_module *module;
81 struct ldb_request *req;
83 const struct dsdb_schema *schema;
84 struct GUID our_invocation_id;
86 /* the controls we pass down */
87 struct ldb_control **controls;
90 * Backlinks for the replmd_add() case (we want to create
91 * backlinks after creating the user, but before the end of
94 struct la_backlink *la_backlinks;
96 /* details for the mode where we apply a bunch of inbound replication meessages */
98 uint32_t index_current;
99 struct dsdb_extended_replicated_objects *objs;
101 struct ldb_message *search_msg;
102 struct GUID local_parent_guid;
110 static int replmd_replicated_apply_merge(struct replmd_replicated_request *ar);
111 static int replmd_delete_internals(struct ldb_module *module, struct ldb_request *req, bool re_delete);
112 static int replmd_check_upgrade_links(struct ldb_context *ldb,
113 struct parsed_dn *dns, uint32_t count,
114 struct ldb_message_element *el,
115 const char *ldap_oid);
117 enum urgent_situation {
118 REPL_URGENT_ON_CREATE = 1,
119 REPL_URGENT_ON_UPDATE = 2,
120 REPL_URGENT_ON_DELETE = 4
123 enum deletion_state {
124 OBJECT_NOT_DELETED=1,
131 static void replmd_deletion_state(struct ldb_module *module,
132 const struct ldb_message *msg,
133 enum deletion_state *current_state,
134 enum deletion_state *next_state)
137 bool enabled = false;
140 *current_state = OBJECT_REMOVED;
141 if (next_state != NULL) {
142 *next_state = OBJECT_REMOVED;
147 ret = dsdb_recyclebin_enabled(module, &enabled);
148 if (ret != LDB_SUCCESS) {
152 if (ldb_msg_check_string_attribute(msg, "isDeleted", "TRUE")) {
154 *current_state = OBJECT_TOMBSTONE;
155 if (next_state != NULL) {
156 *next_state = OBJECT_REMOVED;
161 if (ldb_msg_check_string_attribute(msg, "isRecycled", "TRUE")) {
162 *current_state = OBJECT_RECYCLED;
163 if (next_state != NULL) {
164 *next_state = OBJECT_REMOVED;
169 *current_state = OBJECT_DELETED;
170 if (next_state != NULL) {
171 *next_state = OBJECT_RECYCLED;
176 *current_state = OBJECT_NOT_DELETED;
177 if (next_state == NULL) {
182 *next_state = OBJECT_DELETED;
184 *next_state = OBJECT_TOMBSTONE;
188 static const struct {
189 const char *update_name;
190 enum urgent_situation repl_situation;
191 } urgent_objects[] = {
192 {"nTDSDSA", (REPL_URGENT_ON_CREATE | REPL_URGENT_ON_DELETE)},
193 {"crossRef", (REPL_URGENT_ON_CREATE | REPL_URGENT_ON_DELETE)},
194 {"attributeSchema", (REPL_URGENT_ON_CREATE | REPL_URGENT_ON_UPDATE)},
195 {"classSchema", (REPL_URGENT_ON_CREATE | REPL_URGENT_ON_UPDATE)},
196 {"secret", (REPL_URGENT_ON_CREATE | REPL_URGENT_ON_UPDATE)},
197 {"rIDManager", (REPL_URGENT_ON_CREATE | REPL_URGENT_ON_UPDATE)},
201 /* Attributes looked for when updating or deleting, to check for a urgent replication needed */
202 static const char *urgent_attrs[] = {
205 "userAccountControl",
210 static bool replmd_check_urgent_objectclass(const struct ldb_message_element *objectclass_el,
211 enum urgent_situation situation)
214 for (i=0; urgent_objects[i].update_name; i++) {
216 if ((situation & urgent_objects[i].repl_situation) == 0) {
220 for (j=0; j<objectclass_el->num_values; j++) {
221 const struct ldb_val *v = &objectclass_el->values[j];
222 if (ldb_attr_cmp((const char *)v->data, urgent_objects[i].update_name) == 0) {
230 static bool replmd_check_urgent_attribute(const struct ldb_message_element *el)
232 if (ldb_attr_in_list(urgent_attrs, el->name)) {
238 static int replmd_replicated_apply_isDeleted(struct replmd_replicated_request *ar);
241 initialise the module
242 allocate the private structure and build the list
243 of partition DNs for use by replmd_notify()
245 static int replmd_init(struct ldb_module *module)
247 struct replmd_private *replmd_private;
248 struct ldb_context *ldb = ldb_module_get_ctx(module);
249 static const char *samba_dsdb_attrs[] = { SAMBA_COMPATIBLE_FEATURES_ATTR, NULL };
250 struct ldb_dn *samba_dsdb_dn;
251 struct ldb_result *res;
253 TALLOC_CTX *frame = talloc_stackframe();
254 replmd_private = talloc_zero(module, struct replmd_private);
255 if (replmd_private == NULL) {
258 return LDB_ERR_OPERATIONS_ERROR;
260 ldb_module_set_private(module, replmd_private);
262 replmd_private->schema_dn = ldb_get_schema_basedn(ldb);
264 samba_dsdb_dn = ldb_dn_new(frame, ldb, "@SAMBA_DSDB");
265 if (!samba_dsdb_dn) {
270 ret = dsdb_module_search_dn(module, frame, &res, samba_dsdb_dn,
271 samba_dsdb_attrs, DSDB_FLAG_NEXT_MODULE, NULL);
272 if (ret == LDB_SUCCESS) {
273 replmd_private->sorted_links
274 = ldb_msg_check_string_attribute(res->msgs[0],
275 SAMBA_COMPATIBLE_FEATURES_ATTR,
276 SAMBA_SORTED_LINKS_FEATURE);
280 return ldb_next_init(module);
284 cleanup our per-transaction contexts
286 static void replmd_txn_cleanup(struct replmd_private *replmd_private)
288 talloc_free(replmd_private->la_ctx);
289 replmd_private->la_list = NULL;
290 replmd_private->la_ctx = NULL;
296 struct la_backlink *next, *prev;
297 const char *attr_name;
298 struct ldb_dn *forward_dn;
299 struct GUID target_guid;
304 a ldb_modify request operating on modules below the
307 static int linked_attr_modify(struct ldb_module *module,
308 const struct ldb_message *message,
309 struct ldb_request *parent)
311 struct ldb_request *mod_req;
313 struct ldb_context *ldb = ldb_module_get_ctx(module);
314 TALLOC_CTX *tmp_ctx = talloc_new(module);
315 struct ldb_result *res;
317 res = talloc_zero(tmp_ctx, struct ldb_result);
319 talloc_free(tmp_ctx);
320 return ldb_oom(ldb_module_get_ctx(module));
323 ret = ldb_build_mod_req(&mod_req, ldb, tmp_ctx,
327 ldb_modify_default_callback,
329 LDB_REQ_SET_LOCATION(mod_req);
330 if (ret != LDB_SUCCESS) {
331 talloc_free(tmp_ctx);
335 ret = ldb_request_add_control(mod_req, DSDB_CONTROL_REPLICATED_UPDATE_OID,
337 if (ret != LDB_SUCCESS) {
341 /* Run the new request */
342 ret = ldb_next_request(module, mod_req);
344 if (ret == LDB_SUCCESS) {
345 ret = ldb_wait(mod_req->handle, LDB_WAIT_ALL);
348 talloc_free(tmp_ctx);
353 process a backlinks we accumulated during a transaction, adding and
354 deleting the backlinks from the target objects
356 static int replmd_process_backlink(struct ldb_module *module, struct la_backlink *bl, struct ldb_request *parent)
358 struct ldb_dn *target_dn, *source_dn;
360 struct ldb_context *ldb = ldb_module_get_ctx(module);
361 struct ldb_message *msg;
362 TALLOC_CTX *frame = talloc_stackframe();
368 - construct ldb_message
369 - either an add or a delete
371 ret = dsdb_module_dn_by_guid(module, frame, &bl->target_guid, &target_dn, parent);
372 if (ret != LDB_SUCCESS) {
373 struct GUID_txt_buf guid_str;
374 DEBUG(2,(__location__ ": WARNING: Failed to find target DN for linked attribute with GUID %s\n",
375 GUID_buf_string(&bl->target_guid, &guid_str)));
380 msg = ldb_msg_new(frame);
382 ldb_module_oom(module);
384 return LDB_ERR_OPERATIONS_ERROR;
387 source_dn = ldb_dn_copy(frame, bl->forward_dn);
389 ldb_module_oom(module);
391 return LDB_ERR_OPERATIONS_ERROR;
393 /* Filter down to the attributes we want in the backlink */
394 const char *accept[] = { "GUID", "SID", NULL };
395 ldb_dn_extended_filter(source_dn, accept);
398 /* construct a ldb_message for adding/deleting the backlink */
400 dn_string = ldb_dn_get_extended_linearized(frame, bl->forward_dn, 1);
402 ldb_module_oom(module);
404 return LDB_ERR_OPERATIONS_ERROR;
406 ret = ldb_msg_add_steal_string(msg, bl->attr_name, dn_string);
407 if (ret != LDB_SUCCESS) {
411 msg->elements[0].flags = bl->active?LDB_FLAG_MOD_ADD:LDB_FLAG_MOD_DELETE;
413 /* a backlink should never be single valued. Unfortunately the
414 exchange schema has a attribute
415 msExchBridgeheadedLocalConnectorsDNBL which is single
416 valued and a backlink. We need to cope with that by
417 ignoring the single value flag */
418 msg->elements[0].flags |= LDB_FLAG_INTERNAL_DISABLE_SINGLE_VALUE_CHECK;
420 ret = dsdb_module_modify(module, msg, DSDB_FLAG_NEXT_MODULE, parent);
421 if (ret == LDB_ERR_NO_SUCH_ATTRIBUTE && !bl->active) {
422 /* we allow LDB_ERR_NO_SUCH_ATTRIBUTE as success to
423 cope with possible corruption where the backlink has
424 already been removed */
425 DEBUG(3,("WARNING: backlink from %s already removed from %s - %s\n",
426 ldb_dn_get_linearized(target_dn),
427 ldb_dn_get_linearized(source_dn),
428 ldb_errstring(ldb)));
430 } else if (ret != LDB_SUCCESS) {
431 ldb_asprintf_errstring(ldb, "Failed to %s backlink from %s to %s - %s",
432 bl->active?"add":"remove",
433 ldb_dn_get_linearized(source_dn),
434 ldb_dn_get_linearized(target_dn),
444 add a backlink to the list of backlinks to add/delete in the prepare
447 forward_dn is stolen onto the defereed context
449 static int replmd_defer_add_backlink(struct ldb_module *module,
450 struct replmd_private *replmd_private,
451 const struct dsdb_schema *schema,
452 struct replmd_replicated_request *ac,
453 struct ldb_dn *forward_dn,
454 struct GUID *target_guid, bool active,
455 const struct dsdb_attribute *schema_attr,
456 struct ldb_request *parent)
458 const struct dsdb_attribute *target_attr;
459 struct la_backlink *bl;
461 bl = talloc(ac, struct la_backlink);
463 ldb_module_oom(module);
464 return LDB_ERR_OPERATIONS_ERROR;
467 target_attr = dsdb_attribute_by_linkID(schema, schema_attr->linkID ^ 1);
470 * windows 2003 has a broken schema where the
471 * definition of msDS-IsDomainFor is missing (which is
472 * supposed to be the backlink of the
473 * msDS-HasDomainNCs attribute
478 bl->attr_name = target_attr->lDAPDisplayName;
479 bl->forward_dn = talloc_steal(bl, forward_dn);
480 bl->target_guid = *target_guid;
483 DLIST_ADD(ac->la_backlinks, bl);
489 add a backlink to the list of backlinks to add/delete in the prepare
492 static int replmd_add_backlink(struct ldb_module *module,
493 struct replmd_private *replmd_private,
494 const struct dsdb_schema *schema,
495 struct ldb_dn *forward_dn,
496 struct GUID *target_guid, bool active,
497 const struct dsdb_attribute *schema_attr,
498 struct ldb_request *parent)
500 const struct dsdb_attribute *target_attr;
501 struct la_backlink bl;
504 target_attr = dsdb_attribute_by_linkID(schema, schema_attr->linkID ^ 1);
507 * windows 2003 has a broken schema where the
508 * definition of msDS-IsDomainFor is missing (which is
509 * supposed to be the backlink of the
510 * msDS-HasDomainNCs attribute
515 bl.attr_name = target_attr->lDAPDisplayName;
516 bl.forward_dn = forward_dn;
517 bl.target_guid = *target_guid;
520 ret = replmd_process_backlink(module, &bl, parent);
526 * Callback for most write operations in this module:
528 * notify the repl task that a object has changed. The notifies are
529 * gathered up in the replmd_private structure then written to the
530 * @REPLCHANGED object in each partition during the prepare_commit
532 static int replmd_op_callback(struct ldb_request *req, struct ldb_reply *ares)
535 struct replmd_replicated_request *ac =
536 talloc_get_type_abort(req->context, struct replmd_replicated_request);
537 struct replmd_private *replmd_private =
538 talloc_get_type_abort(ldb_module_get_private(ac->module), struct replmd_private);
539 struct nc_entry *modified_partition;
540 struct ldb_control *partition_ctrl;
541 const struct dsdb_control_current_partition *partition;
543 struct ldb_control **controls;
545 partition_ctrl = ldb_reply_get_control(ares, DSDB_CONTROL_CURRENT_PARTITION_OID);
547 controls = ares->controls;
548 if (ldb_request_get_control(ac->req,
549 DSDB_CONTROL_CURRENT_PARTITION_OID) == NULL) {
551 * Remove the current partition control from what we pass up
552 * the chain if it hasn't been requested manually.
554 controls = ldb_controls_except_specified(ares->controls, ares,
558 if (ares->error != LDB_SUCCESS) {
559 DEBUG(5,("%s failure. Error is: %s\n", __FUNCTION__, ldb_strerror(ares->error)));
560 return ldb_module_done(ac->req, controls,
561 ares->response, ares->error);
564 if (ares->type != LDB_REPLY_DONE) {
565 ldb_set_errstring(ldb_module_get_ctx(ac->module), "Invalid reply type for notify\n!");
566 return ldb_module_done(ac->req, NULL,
567 NULL, LDB_ERR_OPERATIONS_ERROR);
570 if (ac->apply_mode == false) {
571 struct la_backlink *bl;
573 * process our backlink list after an replmd_add(),
574 * creating and deleting backlinks as necessary (this
575 * code is sync). The other cases are handled inline
578 for (bl=ac->la_backlinks; bl; bl=bl->next) {
579 ret = replmd_process_backlink(ac->module, bl, ac->req);
580 if (ret != LDB_SUCCESS) {
581 return ldb_module_done(ac->req, NULL,
587 if (!partition_ctrl) {
588 ldb_set_errstring(ldb_module_get_ctx(ac->module),"No partition control on reply");
589 return ldb_module_done(ac->req, NULL,
590 NULL, LDB_ERR_OPERATIONS_ERROR);
593 partition = talloc_get_type_abort(partition_ctrl->data,
594 struct dsdb_control_current_partition);
596 if (ac->seq_num > 0) {
597 for (modified_partition = replmd_private->ncs; modified_partition;
598 modified_partition = modified_partition->next) {
599 if (ldb_dn_compare(modified_partition->dn, partition->dn) == 0) {
604 if (modified_partition == NULL) {
605 modified_partition = talloc_zero(replmd_private, struct nc_entry);
606 if (!modified_partition) {
607 ldb_oom(ldb_module_get_ctx(ac->module));
608 return ldb_module_done(ac->req, NULL,
609 NULL, LDB_ERR_OPERATIONS_ERROR);
611 modified_partition->dn = ldb_dn_copy(modified_partition, partition->dn);
612 if (!modified_partition->dn) {
613 ldb_oom(ldb_module_get_ctx(ac->module));
614 return ldb_module_done(ac->req, NULL,
615 NULL, LDB_ERR_OPERATIONS_ERROR);
617 DLIST_ADD(replmd_private->ncs, modified_partition);
620 if (ac->seq_num > modified_partition->mod_usn) {
621 modified_partition->mod_usn = ac->seq_num;
623 modified_partition->mod_usn_urgent = ac->seq_num;
626 if (!ac->apply_mode) {
627 replmd_private->originating_updates = true;
631 if (ac->apply_mode) {
632 ret = replmd_replicated_apply_isDeleted(ac);
633 if (ret != LDB_SUCCESS) {
634 return ldb_module_done(ac->req, NULL, NULL, ret);
638 /* free the partition control container here, for the
639 * common path. Other cases will have it cleaned up
640 * eventually with the ares */
641 talloc_free(partition_ctrl);
642 return ldb_module_done(ac->req, controls,
643 ares->response, LDB_SUCCESS);
649 * update a @REPLCHANGED record in each partition if there have been
650 * any writes of replicated data in the partition
652 static int replmd_notify_store(struct ldb_module *module, struct ldb_request *parent)
654 struct replmd_private *replmd_private =
655 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
657 while (replmd_private->ncs) {
659 struct nc_entry *modified_partition = replmd_private->ncs;
661 ret = dsdb_module_save_partition_usn(module, modified_partition->dn,
662 modified_partition->mod_usn,
663 modified_partition->mod_usn_urgent, parent);
664 if (ret != LDB_SUCCESS) {
665 DEBUG(0,(__location__ ": Failed to save partition uSN for %s\n",
666 ldb_dn_get_linearized(modified_partition->dn)));
670 if (ldb_dn_compare(modified_partition->dn,
671 replmd_private->schema_dn) == 0) {
672 struct ldb_result *ext_res;
673 ret = dsdb_module_extended(module,
674 replmd_private->schema_dn,
676 DSDB_EXTENDED_SCHEMA_UPDATE_NOW_OID,
678 DSDB_FLAG_NEXT_MODULE,
680 if (ret != LDB_SUCCESS) {
683 talloc_free(ext_res);
686 DLIST_REMOVE(replmd_private->ncs, modified_partition);
687 talloc_free(modified_partition);
695 created a replmd_replicated_request context
697 static struct replmd_replicated_request *replmd_ctx_init(struct ldb_module *module,
698 struct ldb_request *req)
700 struct ldb_context *ldb;
701 struct replmd_replicated_request *ac;
702 const struct GUID *our_invocation_id;
704 ldb = ldb_module_get_ctx(module);
706 ac = talloc_zero(req, struct replmd_replicated_request);
715 ac->schema = dsdb_get_schema(ldb, ac);
717 ldb_debug_set(ldb, LDB_DEBUG_FATAL,
718 "replmd_modify: no dsdb_schema loaded");
719 DEBUG(0,(__location__ ": %s\n", ldb_errstring(ldb)));
724 /* get our invocationId */
725 our_invocation_id = samdb_ntds_invocation_id(ldb);
726 if (!our_invocation_id) {
727 ldb_debug_set(ldb, LDB_DEBUG_FATAL,
728 "replmd_add: unable to find invocationId\n");
732 ac->our_invocation_id = *our_invocation_id;
738 add a time element to a record
740 static int add_time_element(struct ldb_message *msg, const char *attr, time_t t)
742 struct ldb_message_element *el;
746 if (ldb_msg_find_element(msg, attr) != NULL) {
750 s = ldb_timestring(msg, t);
752 return LDB_ERR_OPERATIONS_ERROR;
755 ret = ldb_msg_add_string(msg, attr, s);
756 if (ret != LDB_SUCCESS) {
760 el = ldb_msg_find_element(msg, attr);
761 /* always set as replace. This works because on add ops, the flag
763 el->flags = LDB_FLAG_MOD_REPLACE;
769 add a uint64_t element to a record
771 static int add_uint64_element(struct ldb_context *ldb, struct ldb_message *msg,
772 const char *attr, uint64_t v)
774 struct ldb_message_element *el;
777 if (ldb_msg_find_element(msg, attr) != NULL) {
781 ret = samdb_msg_add_uint64(ldb, msg, msg, attr, v);
782 if (ret != LDB_SUCCESS) {
786 el = ldb_msg_find_element(msg, attr);
787 /* always set as replace. This works because on add ops, the flag
789 el->flags = LDB_FLAG_MOD_REPLACE;
794 static int replmd_replPropertyMetaData1_attid_sort(const struct replPropertyMetaData1 *m1,
795 const struct replPropertyMetaData1 *m2,
796 const uint32_t *rdn_attid)
799 * This assignment seems inoccous, but it is critical for the
800 * system, as we need to do the comparisons as a unsigned
801 * quantity, not signed (enums are signed integers)
803 uint32_t attid_1 = m1->attid;
804 uint32_t attid_2 = m2->attid;
806 if (attid_1 == attid_2) {
811 * See above regarding this being an unsigned comparison.
812 * Otherwise when the high bit is set on non-standard
813 * attributes, they would end up first, before objectClass
816 return attid_1 > attid_2 ? 1 : -1;
819 static int replmd_replPropertyMetaDataCtr1_verify(struct ldb_context *ldb,
820 struct replPropertyMetaDataCtr1 *ctr1,
823 if (ctr1->count == 0) {
824 ldb_debug_set(ldb, LDB_DEBUG_FATAL,
825 "No elements found in replPropertyMetaData for %s!\n",
826 ldb_dn_get_linearized(dn));
827 return LDB_ERR_CONSTRAINT_VIOLATION;
830 /* the objectClass attribute is value 0x00000000, so must be first */
831 if (ctr1->array[0].attid != DRSUAPI_ATTID_objectClass) {
832 ldb_debug_set(ldb, LDB_DEBUG_FATAL,
833 "No objectClass found in replPropertyMetaData for %s!\n",
834 ldb_dn_get_linearized(dn));
835 return LDB_ERR_OBJECT_CLASS_VIOLATION;
841 static int replmd_replPropertyMetaDataCtr1_sort_and_verify(struct ldb_context *ldb,
842 struct replPropertyMetaDataCtr1 *ctr1,
845 /* Note this is O(n^2) for the almost-sorted case, which this is */
846 LDB_TYPESAFE_QSORT(ctr1->array, ctr1->count, NULL,
847 replmd_replPropertyMetaData1_attid_sort);
848 return replmd_replPropertyMetaDataCtr1_verify(ldb, ctr1, dn);
851 static int replmd_ldb_message_element_attid_sort(const struct ldb_message_element *e1,
852 const struct ldb_message_element *e2,
853 const struct dsdb_schema *schema)
855 const struct dsdb_attribute *a1;
856 const struct dsdb_attribute *a2;
859 * TODO: make this faster by caching the dsdb_attribute pointer
860 * on the ldb_messag_element
863 a1 = dsdb_attribute_by_lDAPDisplayName(schema, e1->name);
864 a2 = dsdb_attribute_by_lDAPDisplayName(schema, e2->name);
867 * TODO: remove this check, we should rely on e1 and e2 having valid attribute names
871 return strcasecmp(e1->name, e2->name);
873 if (a1->attributeID_id == a2->attributeID_id) {
876 return a1->attributeID_id > a2->attributeID_id ? 1 : -1;
879 static void replmd_ldb_message_sort(struct ldb_message *msg,
880 const struct dsdb_schema *schema)
882 LDB_TYPESAFE_QSORT(msg->elements, msg->num_elements, schema, replmd_ldb_message_element_attid_sort);
885 static int replmd_build_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct dsdb_dn *dsdb_dn,
886 const struct GUID *invocation_id, uint64_t seq_num,
887 uint64_t local_usn, NTTIME nttime, uint32_t version, bool deleted);
889 static int get_parsed_dns(struct ldb_module *module, TALLOC_CTX *mem_ctx,
890 struct ldb_message_element *el, struct parsed_dn **pdn,
891 const char *ldap_oid, struct ldb_request *parent);
894 fix up linked attributes in replmd_add.
895 This involves setting up the right meta-data in extended DN
896 components, and creating backlinks to the object
898 static int replmd_add_fix_la(struct ldb_module *module, TALLOC_CTX *mem_ctx,
899 struct replmd_private *replmd_private,
900 struct ldb_message_element *el,
901 struct replmd_replicated_request *ac,
903 struct ldb_dn *forward_dn,
904 const struct dsdb_attribute *sa,
905 struct ldb_request *parent)
908 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
909 struct ldb_context *ldb = ldb_module_get_ctx(module);
910 struct parsed_dn *pdn;
911 /* We will take a reference to the schema in replmd_add_backlink */
912 const struct dsdb_schema *schema = dsdb_get_schema(ldb, NULL);
913 struct ldb_val *new_values = NULL;
915 int ret = get_parsed_dns(module, tmp_ctx, el, &pdn,
916 sa->syntax->ldap_oid, parent);
917 if (ret != LDB_SUCCESS) {
918 talloc_free(tmp_ctx);
922 new_values = talloc_array(tmp_ctx, struct ldb_val, el->num_values);
923 if (new_values == NULL) {
924 ldb_module_oom(module);
925 talloc_free(tmp_ctx);
926 return LDB_ERR_OPERATIONS_ERROR;
929 for (i = 0; i < el->num_values; i++) {
930 struct parsed_dn *p = &pdn[i];
931 ret = replmd_build_la_val(el->values, p->v, p->dsdb_dn,
932 &ac->our_invocation_id,
933 ac->seq_num, ac->seq_num, now, 0, false);
934 if (ret != LDB_SUCCESS) {
935 talloc_free(tmp_ctx);
939 ret = replmd_defer_add_backlink(module, replmd_private,
941 forward_dn, &p->guid, true, sa,
943 if (ret != LDB_SUCCESS) {
944 talloc_free(tmp_ctx);
948 new_values[i] = *p->v;
950 el->values = talloc_steal(mem_ctx, new_values);
952 talloc_free(tmp_ctx);
956 static int replmd_add_make_extended_dn(struct ldb_request *req,
957 const DATA_BLOB *guid_blob,
958 struct ldb_dn **_extended_dn)
961 const DATA_BLOB *sid_blob;
962 /* Calculate an extended DN for any linked attributes */
963 struct ldb_dn *extended_dn = ldb_dn_copy(req, req->op.add.message->dn);
965 return LDB_ERR_OPERATIONS_ERROR;
967 ret = ldb_dn_set_extended_component(extended_dn, "GUID", guid_blob);
968 if (ret != LDB_SUCCESS) {
972 sid_blob = ldb_msg_find_ldb_val(req->op.add.message, "objectSID");
973 if (sid_blob != NULL) {
974 ret = ldb_dn_set_extended_component(extended_dn, "SID", sid_blob);
975 if (ret != LDB_SUCCESS) {
979 *_extended_dn = extended_dn;
984 intercept add requests
986 static int replmd_add(struct ldb_module *module, struct ldb_request *req)
988 struct ldb_context *ldb;
989 struct ldb_control *control;
990 struct replmd_replicated_request *ac;
991 enum ndr_err_code ndr_err;
992 struct ldb_request *down_req;
993 struct ldb_message *msg;
994 const DATA_BLOB *guid_blob;
995 DATA_BLOB guid_blob_stack;
997 uint8_t guid_data[16];
998 struct replPropertyMetaDataBlob nmd;
999 struct ldb_val nmd_value;
1000 struct ldb_dn *extended_dn = NULL;
1003 * The use of a time_t here seems odd, but as the NTTIME
1004 * elements are actually declared as NTTIME_1sec in the IDL,
1005 * getting a higher resolution timestamp is not required.
1007 time_t t = time(NULL);
1012 unsigned int functional_level;
1014 bool allow_add_guid = false;
1015 bool remove_current_guid = false;
1016 bool is_urgent = false;
1017 bool is_schema_nc = false;
1018 struct ldb_message_element *objectclass_el;
1019 struct replmd_private *replmd_private =
1020 talloc_get_type_abort(ldb_module_get_private(module), struct replmd_private);
1022 /* check if there's a show relax control (used by provision to say 'I know what I'm doing') */
1023 control = ldb_request_get_control(req, LDB_CONTROL_RELAX_OID);
1025 allow_add_guid = true;
1028 /* do not manipulate our control entries */
1029 if (ldb_dn_is_special(req->op.add.message->dn)) {
1030 return ldb_next_request(module, req);
1033 ldb = ldb_module_get_ctx(module);
1035 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_add\n");
1037 guid_blob = ldb_msg_find_ldb_val(req->op.add.message, "objectGUID");
1038 if (guid_blob != NULL) {
1039 if (!allow_add_guid) {
1040 ldb_set_errstring(ldb,
1041 "replmd_add: it's not allowed to add an object with objectGUID!");
1042 return LDB_ERR_UNWILLING_TO_PERFORM;
1044 NTSTATUS status = GUID_from_data_blob(guid_blob,&guid);
1045 if (!NT_STATUS_IS_OK(status)) {
1046 ldb_set_errstring(ldb,
1047 "replmd_add: Unable to parse the 'objectGUID' as a GUID!");
1048 return LDB_ERR_UNWILLING_TO_PERFORM;
1050 /* we remove this attribute as it can be a string and
1051 * will not be treated correctly and then we will re-add
1052 * it later on in the good format */
1053 remove_current_guid = true;
1057 guid = GUID_random();
1059 guid_blob_stack = data_blob_const(guid_data, sizeof(guid_data));
1061 /* This can't fail */
1062 ndr_push_struct_into_fixed_blob(&guid_blob_stack, &guid,
1063 (ndr_push_flags_fn_t)ndr_push_GUID);
1064 guid_blob = &guid_blob_stack;
1067 ac = replmd_ctx_init(module, req);
1069 return ldb_module_oom(module);
1072 functional_level = dsdb_functional_level(ldb);
1074 /* Get a sequence number from the backend */
1075 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &ac->seq_num);
1076 if (ret != LDB_SUCCESS) {
1081 /* we have to copy the message as the caller might have it as a const */
1082 msg = ldb_msg_copy_shallow(ac, req->op.add.message);
1086 return LDB_ERR_OPERATIONS_ERROR;
1089 /* generated times */
1090 unix_to_nt_time(&now, t);
1091 time_str = ldb_timestring(msg, t);
1095 return LDB_ERR_OPERATIONS_ERROR;
1097 if (remove_current_guid) {
1098 ldb_msg_remove_attr(msg,"objectGUID");
1102 * remove autogenerated attributes
1104 ldb_msg_remove_attr(msg, "whenCreated");
1105 ldb_msg_remove_attr(msg, "whenChanged");
1106 ldb_msg_remove_attr(msg, "uSNCreated");
1107 ldb_msg_remove_attr(msg, "uSNChanged");
1108 ldb_msg_remove_attr(msg, "replPropertyMetaData");
1111 * readd replicated attributes
1113 ret = ldb_msg_add_string(msg, "whenCreated", time_str);
1114 if (ret != LDB_SUCCESS) {
1120 /* build the replication meta_data */
1123 nmd.ctr.ctr1.count = msg->num_elements;
1124 nmd.ctr.ctr1.array = talloc_array(msg,
1125 struct replPropertyMetaData1,
1126 nmd.ctr.ctr1.count);
1127 if (!nmd.ctr.ctr1.array) {
1130 return LDB_ERR_OPERATIONS_ERROR;
1133 is_schema_nc = ldb_dn_compare_base(replmd_private->schema_dn, msg->dn) == 0;
1135 for (i=0; i < msg->num_elements;) {
1136 struct ldb_message_element *e = &msg->elements[i];
1137 struct replPropertyMetaData1 *m = &nmd.ctr.ctr1.array[ni];
1138 const struct dsdb_attribute *sa;
1140 if (e->name[0] == '@') {
1145 sa = dsdb_attribute_by_lDAPDisplayName(ac->schema, e->name);
1147 ldb_debug_set(ldb, LDB_DEBUG_ERROR,
1148 "replmd_add: attribute '%s' not defined in schema\n",
1151 return LDB_ERR_NO_SUCH_ATTRIBUTE;
1154 if ((sa->systemFlags & DS_FLAG_ATTR_NOT_REPLICATED) || (sa->systemFlags & DS_FLAG_ATTR_IS_CONSTRUCTED)) {
1155 /* if the attribute is not replicated (0x00000001)
1156 * or constructed (0x00000004) it has no metadata
1162 if (sa->linkID != 0 && functional_level > DS_DOMAIN_FUNCTION_2000) {
1163 if (extended_dn == NULL) {
1164 ret = replmd_add_make_extended_dn(req,
1167 if (ret != LDB_SUCCESS) {
1174 * Prepare the context for the backlinks and
1175 * create metadata for the forward links. The
1176 * backlinks are created in
1177 * replmd_op_callback() after the successful
1178 * ADD of the object.
1180 ret = replmd_add_fix_la(module, msg->elements,
1185 if (ret != LDB_SUCCESS) {
1189 /* linked attributes are not stored in
1190 replPropertyMetaData in FL above w2k */
1195 m->attid = dsdb_attribute_get_attid(sa, is_schema_nc);
1197 if (m->attid == DRSUAPI_ATTID_isDeleted) {
1198 const struct ldb_val *rdn_val = ldb_dn_get_rdn_val(msg->dn);
1201 if (rdn_val == NULL) {
1204 return LDB_ERR_OPERATIONS_ERROR;
1207 rdn = (const char*)rdn_val->data;
1208 if (strcmp(rdn, "Deleted Objects") == 0) {
1210 * Set the originating_change_time to 29/12/9999 at 23:59:59
1211 * as specified in MS-ADTS 7.1.1.4.2 Deleted Objects Container
1213 m->originating_change_time = DELETED_OBJECT_CONTAINER_CHANGE_TIME;
1215 m->originating_change_time = now;
1218 m->originating_change_time = now;
1220 m->originating_invocation_id = ac->our_invocation_id;
1221 m->originating_usn = ac->seq_num;
1222 m->local_usn = ac->seq_num;
1225 if (!(e->flags & DSDB_FLAG_INTERNAL_FORCE_META_DATA)) {
1230 e->flags &= ~DSDB_FLAG_INTERNAL_FORCE_META_DATA;
1232 if (e->num_values != 0) {
1237 ldb_msg_remove_element(msg, e);
1240 /* fix meta data count */
1241 nmd.ctr.ctr1.count = ni;
1244 * sort meta data array
1246 ret = replmd_replPropertyMetaDataCtr1_sort_and_verify(ldb, &nmd.ctr.ctr1, msg->dn);
1247 if (ret != LDB_SUCCESS) {
1248 ldb_asprintf_errstring(ldb, "%s: error during direct ADD: %s", __func__, ldb_errstring(ldb));
1253 /* generated NDR encoded values */
1254 ndr_err = ndr_push_struct_blob(&nmd_value, msg,
1256 (ndr_push_flags_fn_t)ndr_push_replPropertyMetaDataBlob);
1257 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1260 return LDB_ERR_OPERATIONS_ERROR;
1264 * add the autogenerated values
1266 ret = dsdb_msg_add_guid(msg, &guid, "objectGUID");
1267 if (ret != LDB_SUCCESS) {
1272 ret = ldb_msg_add_string(msg, "whenChanged", time_str);
1273 if (ret != LDB_SUCCESS) {
1278 ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNCreated", ac->seq_num);
1279 if (ret != LDB_SUCCESS) {
1284 ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNChanged", ac->seq_num);
1285 if (ret != LDB_SUCCESS) {
1290 ret = ldb_msg_add_value(msg, "replPropertyMetaData", &nmd_value, NULL);
1291 if (ret != LDB_SUCCESS) {
1298 * sort the attributes by attid before storing the object
1300 replmd_ldb_message_sort(msg, ac->schema);
1303 * Assert that we do have an objectClass
1305 objectclass_el = ldb_msg_find_element(msg, "objectClass");
1306 if (objectclass_el == NULL) {
1307 ldb_asprintf_errstring(ldb, __location__
1308 ": objectClass missing on %s\n",
1309 ldb_dn_get_linearized(msg->dn));
1311 return LDB_ERR_OBJECT_CLASS_VIOLATION;
1313 is_urgent = replmd_check_urgent_objectclass(objectclass_el,
1314 REPL_URGENT_ON_CREATE);
1316 ac->is_urgent = is_urgent;
1317 ret = ldb_build_add_req(&down_req, ldb, ac,
1320 ac, replmd_op_callback,
1323 LDB_REQ_SET_LOCATION(down_req);
1324 if (ret != LDB_SUCCESS) {
1329 /* current partition control is needed by "replmd_op_callback" */
1330 if (ldb_request_get_control(req, DSDB_CONTROL_CURRENT_PARTITION_OID) == NULL) {
1331 ret = ldb_request_add_control(down_req,
1332 DSDB_CONTROL_CURRENT_PARTITION_OID,
1334 if (ret != LDB_SUCCESS) {
1340 if (functional_level == DS_DOMAIN_FUNCTION_2000) {
1341 ret = ldb_request_add_control(down_req, DSDB_CONTROL_APPLY_LINKS, false, NULL);
1342 if (ret != LDB_SUCCESS) {
1348 /* mark the control done */
1350 control->critical = 0;
1352 /* go on with the call chain */
1353 return ldb_next_request(module, down_req);
1358 * update the replPropertyMetaData for one element
1360 static int replmd_update_rpmd_element(struct ldb_context *ldb,
1361 struct ldb_message *msg,
1362 struct ldb_message_element *el,
1363 struct ldb_message_element *old_el,
1364 struct replPropertyMetaDataBlob *omd,
1365 const struct dsdb_schema *schema,
1367 const struct GUID *our_invocation_id,
1370 struct ldb_request *req)
1373 const struct dsdb_attribute *a;
1374 struct replPropertyMetaData1 *md1;
1375 bool may_skip = false;
1378 a = dsdb_attribute_by_lDAPDisplayName(schema, el->name);
1380 if (ldb_request_get_control(req, LDB_CONTROL_RELAX_OID)) {
1381 /* allow this to make it possible for dbcheck
1382 to remove bad attributes */
1386 DEBUG(0,(__location__ ": Unable to find attribute %s in schema\n",
1388 return LDB_ERR_OPERATIONS_ERROR;
1391 attid = dsdb_attribute_get_attid(a, is_schema_nc);
1393 if ((a->systemFlags & DS_FLAG_ATTR_NOT_REPLICATED) || (a->systemFlags & DS_FLAG_ATTR_IS_CONSTRUCTED)) {
1398 * if the attribute's value haven't changed, and this isn't
1399 * just a delete of everything then return LDB_SUCCESS Unless
1400 * we have the provision control or if the attribute is
1401 * interSiteTopologyGenerator as this page explain:
1402 * http://support.microsoft.com/kb/224815 this attribute is
1403 * periodicaly written by the DC responsible for the intersite
1404 * generation in a given site
1406 * Unchanged could be deleting or replacing an already-gone
1407 * thing with an unconstrained delete/empty replace or a
1408 * replace with the same value, but not an add with the same
1409 * value because that could be about adding a duplicate (which
1410 * is for someone else to error out on).
1412 if (old_el != NULL && ldb_msg_element_equal_ordered(el, old_el)) {
1413 if (LDB_FLAG_MOD_TYPE(el->flags) == LDB_FLAG_MOD_REPLACE) {
1416 } else if (old_el == NULL && el->num_values == 0) {
1417 if (LDB_FLAG_MOD_TYPE(el->flags) == LDB_FLAG_MOD_REPLACE) {
1419 } else if (LDB_FLAG_MOD_TYPE(el->flags) == LDB_FLAG_MOD_DELETE) {
1422 } else if (a->linkID != 0 && LDB_FLAG_MOD_TYPE(el->flags) == LDB_FLAG_MOD_DELETE &&
1423 ldb_request_get_control(req, DSDB_CONTROL_REPLMD_VANISH_LINKS) != NULL) {
1425 * We intentionally skip the version bump when attempting to
1428 * The control is set by dbcheck and expunge-tombstones which
1429 * both attempt to be non-replicating. Otherwise, making an
1430 * alteration to the replication state would trigger a
1431 * broadcast of all expunged objects.
1436 if (el->flags & DSDB_FLAG_INTERNAL_FORCE_META_DATA) {
1438 el->flags &= ~DSDB_FLAG_INTERNAL_FORCE_META_DATA;
1442 if (strcmp(el->name, "interSiteTopologyGenerator") != 0 &&
1443 !ldb_request_get_control(req, LDB_CONTROL_PROVISION_OID)) {
1445 * allow this to make it possible for dbcheck
1446 * to rebuild broken metadata
1452 for (i=0; i<omd->ctr.ctr1.count; i++) {
1454 * First check if we find it under the msDS-IntID,
1455 * then check if we find it under the OID and
1458 * This allows the administrator to simply re-write
1459 * the attributes and so restore replication, which is
1460 * likely what they will try to do.
1462 if (attid == omd->ctr.ctr1.array[i].attid) {
1466 if (a->attributeID_id == omd->ctr.ctr1.array[i].attid) {
1471 if (a->linkID != 0 && dsdb_functional_level(ldb) > DS_DOMAIN_FUNCTION_2000) {
1472 /* linked attributes are not stored in
1473 replPropertyMetaData in FL above w2k, but we do
1474 raise the seqnum for the object */
1475 if (*seq_num == 0 &&
1476 ldb_sequence_number(ldb, LDB_SEQ_NEXT, seq_num) != LDB_SUCCESS) {
1477 return LDB_ERR_OPERATIONS_ERROR;
1482 if (i == omd->ctr.ctr1.count) {
1483 /* we need to add a new one */
1484 omd->ctr.ctr1.array = talloc_realloc(msg, omd->ctr.ctr1.array,
1485 struct replPropertyMetaData1, omd->ctr.ctr1.count+1);
1486 if (omd->ctr.ctr1.array == NULL) {
1488 return LDB_ERR_OPERATIONS_ERROR;
1490 omd->ctr.ctr1.count++;
1491 ZERO_STRUCT(omd->ctr.ctr1.array[i]);
1494 /* Get a new sequence number from the backend. We only do this
1495 * if we have a change that requires a new
1496 * replPropertyMetaData element
1498 if (*seq_num == 0) {
1499 int ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, seq_num);
1500 if (ret != LDB_SUCCESS) {
1501 return LDB_ERR_OPERATIONS_ERROR;
1505 md1 = &omd->ctr.ctr1.array[i];
1509 if (md1->attid == DRSUAPI_ATTID_isDeleted) {
1510 const struct ldb_val *rdn_val = ldb_dn_get_rdn_val(msg->dn);
1513 if (rdn_val == NULL) {
1515 return LDB_ERR_OPERATIONS_ERROR;
1518 rdn = (const char*)rdn_val->data;
1519 if (strcmp(rdn, "Deleted Objects") == 0) {
1521 * Set the originating_change_time to 29/12/9999 at 23:59:59
1522 * as specified in MS-ADTS 7.1.1.4.2 Deleted Objects Container
1524 md1->originating_change_time = DELETED_OBJECT_CONTAINER_CHANGE_TIME;
1526 md1->originating_change_time = now;
1529 md1->originating_change_time = now;
1531 md1->originating_invocation_id = *our_invocation_id;
1532 md1->originating_usn = *seq_num;
1533 md1->local_usn = *seq_num;
1535 if (ldb_request_get_control(req, DSDB_CONTROL_FORCE_RODC_LOCAL_CHANGE) != NULL) {
1536 /* Force version to 0 to be overriden later via replication */
1537 bool am_rodc = false;
1538 int ret = samdb_rodc(ldb, &am_rodc);
1539 if (ret == LDB_SUCCESS && am_rodc) {
1548 * Bump the replPropertyMetaData version on an attribute, and if it
1549 * has changed (or forced by leaving rdn_old NULL), update the value
1552 * This is important, as calling a modify operation may not change the
1553 * version number if the values appear unchanged, but a rename between
1554 * parents bumps this value.
1557 static int replmd_update_rpmd_rdn_attr(struct ldb_context *ldb,
1558 struct ldb_message *msg,
1559 const struct ldb_val *rdn_new,
1560 const struct ldb_val *rdn_old,
1561 struct replPropertyMetaDataBlob *omd,
1562 struct replmd_replicated_request *ar,
1566 const char *rdn_name = ldb_dn_get_rdn_name(msg->dn);
1567 const struct dsdb_attribute *rdn_attr =
1568 dsdb_attribute_by_lDAPDisplayName(ar->schema, rdn_name);
1569 const char *attr_name = rdn_attr != NULL ?
1570 rdn_attr->lDAPDisplayName :
1572 struct ldb_message_element new_el = {
1573 .flags = LDB_FLAG_MOD_REPLACE,
1576 .values = discard_const_p(struct ldb_val, rdn_new)
1578 struct ldb_message_element old_el = {
1579 .flags = LDB_FLAG_MOD_REPLACE,
1581 .num_values = rdn_old ? 1 : 0,
1582 .values = discard_const_p(struct ldb_val, rdn_old)
1585 if (ldb_msg_element_equal_ordered(&new_el, &old_el) == false) {
1586 int ret = ldb_msg_add(msg, &new_el, LDB_FLAG_MOD_REPLACE);
1587 if (ret != LDB_SUCCESS) {
1588 return ldb_oom(ldb);
1592 return replmd_update_rpmd_element(ldb, msg, &new_el, NULL,
1593 omd, ar->schema, &ar->seq_num,
1594 &ar->our_invocation_id,
1595 now, is_schema_nc, ar->req);
1599 static uint64_t find_max_local_usn(struct replPropertyMetaDataBlob omd)
1601 uint32_t count = omd.ctr.ctr1.count;
1604 for (i=0; i < count; i++) {
1605 struct replPropertyMetaData1 m = omd.ctr.ctr1.array[i];
1606 if (max < m.local_usn) {
1614 * update the replPropertyMetaData object each time we modify an
1615 * object. This is needed for DRS replication, as the merge on the
1616 * client is based on this object
1618 static int replmd_update_rpmd(struct ldb_module *module,
1619 const struct dsdb_schema *schema,
1620 struct ldb_request *req,
1621 const char * const *rename_attrs,
1622 struct ldb_message *msg, uint64_t *seq_num,
1623 time_t t, bool is_schema_nc,
1624 bool *is_urgent, bool *rodc)
1626 const struct ldb_val *omd_value;
1627 enum ndr_err_code ndr_err;
1628 struct replPropertyMetaDataBlob omd;
1631 const struct GUID *our_invocation_id;
1633 const char * const *attrs = NULL;
1634 const char * const attrs2[] = { "uSNChanged", "objectClass", "instanceType", NULL };
1635 struct ldb_result *res;
1636 struct ldb_context *ldb;
1637 struct ldb_message_element *objectclass_el;
1638 enum urgent_situation situation;
1639 bool rmd_is_provided;
1640 bool rmd_is_just_resorted = false;
1641 const char *not_rename_attrs[4 + msg->num_elements];
1644 attrs = rename_attrs;
1646 for (i = 0; i < msg->num_elements; i++) {
1647 not_rename_attrs[i] = msg->elements[i].name;
1649 not_rename_attrs[i] = "replPropertyMetaData";
1650 not_rename_attrs[i+1] = "objectClass";
1651 not_rename_attrs[i+2] = "instanceType";
1652 not_rename_attrs[i+3] = NULL;
1653 attrs = not_rename_attrs;
1656 ldb = ldb_module_get_ctx(module);
1658 our_invocation_id = samdb_ntds_invocation_id(ldb);
1659 if (!our_invocation_id) {
1660 /* this happens during an initial vampire while
1661 updating the schema */
1662 DEBUG(5,("No invocationID - skipping replPropertyMetaData update\n"));
1666 unix_to_nt_time(&now, t);
1668 if (ldb_request_get_control(req, DSDB_CONTROL_CHANGEREPLMETADATA_OID)) {
1669 rmd_is_provided = true;
1670 if (ldb_request_get_control(req, DSDB_CONTROL_CHANGEREPLMETADATA_RESORT_OID)) {
1671 rmd_is_just_resorted = true;
1674 rmd_is_provided = false;
1677 /* if isDeleted is present and is TRUE, then we consider we are deleting,
1678 * otherwise we consider we are updating */
1679 if (ldb_msg_check_string_attribute(msg, "isDeleted", "TRUE")) {
1680 situation = REPL_URGENT_ON_DELETE;
1681 } else if (rename_attrs) {
1682 situation = REPL_URGENT_ON_CREATE | REPL_URGENT_ON_DELETE;
1684 situation = REPL_URGENT_ON_UPDATE;
1687 if (rmd_is_provided) {
1688 /* In this case the change_replmetadata control was supplied */
1689 /* We check that it's the only attribute that is provided
1690 * (it's a rare case so it's better to keep the code simplier)
1691 * We also check that the highest local_usn is bigger or the same as
1694 if( msg->num_elements != 1 ||
1695 strncmp(msg->elements[0].name,
1696 "replPropertyMetaData", 20) ) {
1697 DEBUG(0,(__location__ ": changereplmetada control called without "\
1698 "a specified replPropertyMetaData attribute or with others\n"));
1699 return LDB_ERR_OPERATIONS_ERROR;
1701 if (situation != REPL_URGENT_ON_UPDATE) {
1702 DEBUG(0,(__location__ ": changereplmetada control can't be called when deleting an object\n"));
1703 return LDB_ERR_OPERATIONS_ERROR;
1705 omd_value = ldb_msg_find_ldb_val(msg, "replPropertyMetaData");
1707 DEBUG(0,(__location__ ": replPropertyMetaData was not specified for Object %s\n",
1708 ldb_dn_get_linearized(msg->dn)));
1709 return LDB_ERR_OPERATIONS_ERROR;
1711 ndr_err = ndr_pull_struct_blob(omd_value, msg, &omd,
1712 (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
1713 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1714 DEBUG(0,(__location__ ": Failed to parse replPropertyMetaData for %s\n",
1715 ldb_dn_get_linearized(msg->dn)));
1716 return LDB_ERR_OPERATIONS_ERROR;
1719 ret = dsdb_module_search_dn(module, msg, &res, msg->dn, attrs2,
1720 DSDB_FLAG_NEXT_MODULE |
1721 DSDB_SEARCH_SHOW_RECYCLED |
1722 DSDB_SEARCH_SHOW_EXTENDED_DN |
1723 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT |
1724 DSDB_SEARCH_REVEAL_INTERNALS, req);
1726 if (ret != LDB_SUCCESS) {
1730 if (rmd_is_just_resorted == false) {
1731 *seq_num = find_max_local_usn(omd);
1733 db_seq = ldb_msg_find_attr_as_uint64(res->msgs[0], "uSNChanged", 0);
1736 * The test here now allows for a new
1737 * replPropertyMetaData with no change, if was
1738 * just dbcheck re-sorting the values.
1740 if (*seq_num <= db_seq) {
1741 DEBUG(0,(__location__ ": changereplmetada control provided but max(local_usn)" \
1742 " is less than uSNChanged (max = %lld uSNChanged = %lld)\n",
1743 (long long)*seq_num, (long long)db_seq));
1744 return LDB_ERR_OPERATIONS_ERROR;
1749 /* search for the existing replPropertyMetaDataBlob. We need
1750 * to use REVEAL and ask for DNs in storage format to support
1751 * the check for values being the same in
1752 * replmd_update_rpmd_element()
1754 ret = dsdb_module_search_dn(module, msg, &res, msg->dn, attrs,
1755 DSDB_FLAG_NEXT_MODULE |
1756 DSDB_SEARCH_SHOW_RECYCLED |
1757 DSDB_SEARCH_SHOW_EXTENDED_DN |
1758 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT |
1759 DSDB_SEARCH_REVEAL_INTERNALS, req);
1760 if (ret != LDB_SUCCESS) {
1764 omd_value = ldb_msg_find_ldb_val(res->msgs[0], "replPropertyMetaData");
1766 DEBUG(0,(__location__ ": Object %s does not have a replPropertyMetaData attribute\n",
1767 ldb_dn_get_linearized(msg->dn)));
1768 return LDB_ERR_OPERATIONS_ERROR;
1771 ndr_err = ndr_pull_struct_blob(omd_value, msg, &omd,
1772 (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
1773 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1774 DEBUG(0,(__location__ ": Failed to parse replPropertyMetaData for %s\n",
1775 ldb_dn_get_linearized(msg->dn)));
1776 return LDB_ERR_OPERATIONS_ERROR;
1779 if (omd.version != 1) {
1780 DEBUG(0,(__location__ ": bad version %u in replPropertyMetaData for %s\n",
1781 omd.version, ldb_dn_get_linearized(msg->dn)));
1782 return LDB_ERR_OPERATIONS_ERROR;
1785 for (i=0; i<msg->num_elements;) {
1786 struct ldb_message_element *el = &msg->elements[i];
1787 struct ldb_message_element *old_el;
1789 old_el = ldb_msg_find_element(res->msgs[0], el->name);
1790 ret = replmd_update_rpmd_element(ldb, msg, el, old_el,
1791 &omd, schema, seq_num,
1795 if (ret != LDB_SUCCESS) {
1799 if (!*is_urgent && (situation == REPL_URGENT_ON_UPDATE)) {
1800 *is_urgent = replmd_check_urgent_attribute(el);
1803 if (!(el->flags & DSDB_FLAG_INTERNAL_FORCE_META_DATA)) {
1808 el->flags &= ~DSDB_FLAG_INTERNAL_FORCE_META_DATA;
1810 if (el->num_values != 0) {
1815 ldb_msg_remove_element(msg, el);
1820 * Assert that we have an objectClass attribute - this is major
1821 * corruption if we don't have this!
1823 objectclass_el = ldb_msg_find_element(res->msgs[0], "objectClass");
1824 if (objectclass_el != NULL) {
1826 * Now check if this objectClass means we need to do urgent replication
1828 if (!*is_urgent && replmd_check_urgent_objectclass(objectclass_el,
1832 } else if (!ldb_request_get_control(req, DSDB_CONTROL_DBCHECK)) {
1833 ldb_asprintf_errstring(ldb, __location__
1834 ": objectClass missing on %s\n",
1835 ldb_dn_get_linearized(msg->dn));
1836 return LDB_ERR_OBJECT_CLASS_VIOLATION;
1840 * replmd_update_rpmd_element has done an update if the
1843 if (*seq_num != 0 || rmd_is_just_resorted == true) {
1844 struct ldb_val *md_value;
1845 struct ldb_message_element *el;
1847 /*if we are RODC and this is a DRSR update then its ok*/
1848 if (!ldb_request_get_control(req, DSDB_CONTROL_REPLICATED_UPDATE_OID)
1849 && !ldb_request_get_control(req, DSDB_CONTROL_DBCHECK_MODIFY_RO_REPLICA)
1850 && !ldb_request_get_control(req, DSDB_CONTROL_FORCE_RODC_LOCAL_CHANGE)) {
1851 unsigned instanceType;
1853 ret = samdb_rodc(ldb, rodc);
1854 if (ret != LDB_SUCCESS) {
1855 DEBUG(4, (__location__ ": unable to tell if we are an RODC\n"));
1857 ldb_set_errstring(ldb, "RODC modify is forbidden!");
1858 return LDB_ERR_REFERRAL;
1861 instanceType = ldb_msg_find_attr_as_uint(res->msgs[0], "instanceType", INSTANCE_TYPE_WRITE);
1862 if (!(instanceType & INSTANCE_TYPE_WRITE)) {
1863 return ldb_error(ldb, LDB_ERR_UNWILLING_TO_PERFORM,
1864 "cannot change replicated attribute on partial replica");
1868 md_value = talloc(msg, struct ldb_val);
1869 if (md_value == NULL) {
1871 return LDB_ERR_OPERATIONS_ERROR;
1874 ret = replmd_replPropertyMetaDataCtr1_sort_and_verify(ldb, &omd.ctr.ctr1, msg->dn);
1875 if (ret != LDB_SUCCESS) {
1876 ldb_asprintf_errstring(ldb, "%s: %s", __func__, ldb_errstring(ldb));
1880 ndr_err = ndr_push_struct_blob(md_value, msg, &omd,
1881 (ndr_push_flags_fn_t)ndr_push_replPropertyMetaDataBlob);
1882 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1883 DEBUG(0,(__location__ ": Failed to marshall replPropertyMetaData for %s\n",
1884 ldb_dn_get_linearized(msg->dn)));
1885 return LDB_ERR_OPERATIONS_ERROR;
1888 ret = ldb_msg_add_empty(msg, "replPropertyMetaData", LDB_FLAG_MOD_REPLACE, &el);
1889 if (ret != LDB_SUCCESS) {
1890 DEBUG(0,(__location__ ": Failed to add updated replPropertyMetaData %s\n",
1891 ldb_dn_get_linearized(msg->dn)));
1896 el->values = md_value;
1902 static int parsed_dn_compare(struct parsed_dn *pdn1, struct parsed_dn *pdn2)
1904 int ret = ndr_guid_compare(&pdn1->guid, &pdn2->guid);
1906 return data_blob_cmp(&pdn1->dsdb_dn->extra_part,
1907 &pdn2->dsdb_dn->extra_part);
1913 get a series of message element values as an array of DNs and GUIDs
1914 the result is sorted by GUID
1916 static int get_parsed_dns(struct ldb_module *module, TALLOC_CTX *mem_ctx,
1917 struct ldb_message_element *el, struct parsed_dn **pdn,
1918 const char *ldap_oid, struct ldb_request *parent)
1921 bool values_are_sorted = true;
1922 struct ldb_context *ldb = ldb_module_get_ctx(module);
1929 (*pdn) = talloc_array(mem_ctx, struct parsed_dn, el->num_values);
1931 ldb_module_oom(module);
1932 return LDB_ERR_OPERATIONS_ERROR;
1935 for (i=0; i<el->num_values; i++) {
1936 struct ldb_val *v = &el->values[i];
1939 struct parsed_dn *p;
1943 p->dsdb_dn = dsdb_dn_parse(*pdn, ldb, v, ldap_oid);
1944 if (p->dsdb_dn == NULL) {
1945 return LDB_ERR_INVALID_DN_SYNTAX;
1948 dn = p->dsdb_dn->dn;
1950 status = dsdb_get_extended_dn_guid(dn, &p->guid, "GUID");
1951 if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND) ||
1952 unlikely(GUID_all_zero(&p->guid))) {
1953 /* we got a DN without a GUID - go find the GUID */
1954 int ret = dsdb_module_guid_by_dn(module, dn, &p->guid, parent);
1955 if (ret != LDB_SUCCESS) {
1956 ldb_asprintf_errstring(ldb, "Unable to find GUID for DN %s\n",
1957 ldb_dn_get_linearized(dn));
1958 if (ret == LDB_ERR_NO_SUCH_OBJECT &&
1959 LDB_FLAG_MOD_TYPE(el->flags) == LDB_FLAG_MOD_DELETE &&
1960 ldb_attr_cmp(el->name, "member") == 0) {
1961 return LDB_ERR_UNWILLING_TO_PERFORM;
1965 ret = dsdb_set_extended_dn_guid(dn, &p->guid, "GUID");
1966 if (ret != LDB_SUCCESS) {
1969 } else if (!NT_STATUS_IS_OK(status)) {
1970 return LDB_ERR_OPERATIONS_ERROR;
1972 if (i > 0 && values_are_sorted) {
1973 int cmp = parsed_dn_compare(p, &(*pdn)[i - 1]);
1975 values_are_sorted = false;
1978 /* keep a pointer to the original ldb_val */
1981 if (! values_are_sorted) {
1982 TYPESAFE_QSORT(*pdn, el->num_values, parsed_dn_compare);
1988 * Get a series of trusted message element values. The result is sorted by
1989 * GUID, even though the GUIDs might not be known. That works because we trust
1990 * the database to give us the elements like that if the
1991 * replmd_private->sorted_links flag is set.
1993 * We also ensure that the links are in the Functional Level 2003
1994 * linked attributes format.
1996 static int get_parsed_dns_trusted(struct ldb_module *module,
1997 struct replmd_private *replmd_private,
1998 TALLOC_CTX *mem_ctx,
1999 struct ldb_message_element *el,
2000 struct parsed_dn **pdn,
2001 const char *ldap_oid,
2002 struct ldb_request *parent)
2011 if (!replmd_private->sorted_links) {
2012 /* We need to sort the list. This is the slow old path we want
2015 ret = get_parsed_dns(module, mem_ctx, el, pdn, ldap_oid,
2017 if (ret != LDB_SUCCESS) {
2021 /* Here we get a list of 'struct parsed_dns' without the parsing */
2022 *pdn = talloc_zero_array(mem_ctx, struct parsed_dn,
2025 ldb_module_oom(module);
2026 return LDB_ERR_OPERATIONS_ERROR;
2029 for (i = 0; i < el->num_values; i++) {
2030 (*pdn)[i].v = &el->values[i];
2035 * This upgrades links to FL2003 style, and sorts the result
2036 * if that was needed.
2038 * TODO: Add a database feature that asserts we have no FL2000
2039 * style links to avoid this check or add a feature that
2040 * uses a similar check to find sorted/unsorted links
2041 * for an on-the-fly upgrade.
2044 ret = replmd_check_upgrade_links(ldb_module_get_ctx(module),
2045 *pdn, el->num_values,
2048 if (ret != LDB_SUCCESS) {
2056 build a new extended DN, including all meta data fields
2058 RMD_FLAGS = DSDB_RMD_FLAG_* bits
2059 RMD_ADDTIME = originating_add_time
2060 RMD_INVOCID = originating_invocation_id
2061 RMD_CHANGETIME = originating_change_time
2062 RMD_ORIGINATING_USN = originating_usn
2063 RMD_LOCAL_USN = local_usn
2064 RMD_VERSION = version
2066 static int replmd_build_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct dsdb_dn *dsdb_dn,
2067 const struct GUID *invocation_id, uint64_t seq_num,
2068 uint64_t local_usn, NTTIME nttime, uint32_t version, bool deleted)
2070 struct ldb_dn *dn = dsdb_dn->dn;
2071 const char *tstring, *usn_string, *flags_string;
2072 struct ldb_val tval;
2074 struct ldb_val usnv, local_usnv;
2075 struct ldb_val vers, flagsv;
2078 const char *dnstring;
2080 uint32_t rmd_flags = deleted?DSDB_RMD_FLAG_DELETED:0;
2082 tstring = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)nttime);
2084 return LDB_ERR_OPERATIONS_ERROR;
2086 tval = data_blob_string_const(tstring);
2088 usn_string = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)seq_num);
2090 return LDB_ERR_OPERATIONS_ERROR;
2092 usnv = data_blob_string_const(usn_string);
2094 usn_string = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)local_usn);
2096 return LDB_ERR_OPERATIONS_ERROR;
2098 local_usnv = data_blob_string_const(usn_string);
2100 vstring = talloc_asprintf(mem_ctx, "%lu", (unsigned long)version);
2102 return LDB_ERR_OPERATIONS_ERROR;
2104 vers = data_blob_string_const(vstring);
2106 status = GUID_to_ndr_blob(invocation_id, dn, &iid);
2107 if (!NT_STATUS_IS_OK(status)) {
2108 return LDB_ERR_OPERATIONS_ERROR;
2111 flags_string = talloc_asprintf(mem_ctx, "%u", rmd_flags);
2112 if (!flags_string) {
2113 return LDB_ERR_OPERATIONS_ERROR;
2115 flagsv = data_blob_string_const(flags_string);
2117 ret = ldb_dn_set_extended_component(dn, "RMD_FLAGS", &flagsv);
2118 if (ret != LDB_SUCCESS) return ret;
2119 ret = ldb_dn_set_extended_component(dn, "RMD_ADDTIME", &tval);
2120 if (ret != LDB_SUCCESS) return ret;
2121 ret = ldb_dn_set_extended_component(dn, "RMD_INVOCID", &iid);
2122 if (ret != LDB_SUCCESS) return ret;
2123 ret = ldb_dn_set_extended_component(dn, "RMD_CHANGETIME", &tval);
2124 if (ret != LDB_SUCCESS) return ret;
2125 ret = ldb_dn_set_extended_component(dn, "RMD_LOCAL_USN", &local_usnv);
2126 if (ret != LDB_SUCCESS) return ret;
2127 ret = ldb_dn_set_extended_component(dn, "RMD_ORIGINATING_USN", &usnv);
2128 if (ret != LDB_SUCCESS) return ret;
2129 ret = ldb_dn_set_extended_component(dn, "RMD_VERSION", &vers);
2130 if (ret != LDB_SUCCESS) return ret;
2132 dnstring = dsdb_dn_get_extended_linearized(mem_ctx, dsdb_dn, 1);
2133 if (dnstring == NULL) {
2134 return LDB_ERR_OPERATIONS_ERROR;
2136 *v = data_blob_string_const(dnstring);
2141 static int replmd_update_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct dsdb_dn *dsdb_dn,
2142 struct dsdb_dn *old_dsdb_dn, const struct GUID *invocation_id,
2143 uint64_t seq_num, uint64_t local_usn, NTTIME nttime,
2144 uint32_t version, bool deleted);
2147 check if any links need upgrading from w2k format
2149 static int replmd_check_upgrade_links(struct ldb_context *ldb,
2150 struct parsed_dn *dns, uint32_t count,
2151 struct ldb_message_element *el,
2152 const char *ldap_oid)
2155 const struct GUID *invocation_id = NULL;
2156 for (i=0; i<count; i++) {
2160 if (dns[i].dsdb_dn == NULL) {
2161 ret = really_parse_trusted_dn(dns, ldb, &dns[i],
2163 if (ret != LDB_SUCCESS) {
2164 return LDB_ERR_INVALID_DN_SYNTAX;
2168 status = dsdb_get_extended_dn_uint32(dns[i].dsdb_dn->dn,
2169 &version, "RMD_VERSION");
2170 if (!NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
2172 * We optimistically assume they are all the same; if
2173 * the first one is fixed, they are all fixed.
2175 * If the first one was *not* fixed and we find a
2176 * later one that is, that is an occasion to shout
2182 DEBUG(0, ("Mixed w2k and fixed format "
2183 "linked attributes\n"));
2187 if (invocation_id == NULL) {
2188 invocation_id = samdb_ntds_invocation_id(ldb);
2189 if (invocation_id == NULL) {
2190 return LDB_ERR_OPERATIONS_ERROR;
2195 /* it's an old one that needs upgrading */
2196 ret = replmd_update_la_val(el->values, dns[i].v,
2197 dns[i].dsdb_dn, dns[i].dsdb_dn,
2198 invocation_id, 1, 1, 0, 0, false);
2199 if (ret != LDB_SUCCESS) {
2205 * This sort() is critical for the operation of
2206 * get_parsed_dns_trusted() because callers of this function
2207 * expect a sorted list, and FL2000 style links are not
2208 * sorted. In particular, as well as the upgrade case,
2209 * get_parsed_dns_trusted() is called from
2210 * replmd_delete_remove_link() even in FL2000 mode
2212 * We do not normally pay the cost of the qsort() due to the
2213 * early return in the RMD_VERSION found case.
2215 TYPESAFE_QSORT(dns, count, parsed_dn_compare);
2220 update an extended DN, including all meta data fields
2222 see replmd_build_la_val for value names
2224 static int replmd_update_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct dsdb_dn *dsdb_dn,
2225 struct dsdb_dn *old_dsdb_dn, const struct GUID *invocation_id,
2226 uint64_t usn, uint64_t local_usn, NTTIME nttime,
2227 uint32_t version, bool deleted)
2229 struct ldb_dn *dn = dsdb_dn->dn;
2230 const char *tstring, *usn_string, *flags_string;
2231 struct ldb_val tval;
2233 struct ldb_val usnv, local_usnv;
2234 struct ldb_val vers, flagsv;
2235 const struct ldb_val *old_addtime;
2236 uint32_t old_version;
2239 const char *dnstring;
2241 uint32_t rmd_flags = deleted?DSDB_RMD_FLAG_DELETED:0;
2243 tstring = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)nttime);
2245 return LDB_ERR_OPERATIONS_ERROR;
2247 tval = data_blob_string_const(tstring);
2249 usn_string = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)usn);
2251 return LDB_ERR_OPERATIONS_ERROR;
2253 usnv = data_blob_string_const(usn_string);
2255 usn_string = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)local_usn);
2257 return LDB_ERR_OPERATIONS_ERROR;
2259 local_usnv = data_blob_string_const(usn_string);
2261 status = GUID_to_ndr_blob(invocation_id, dn, &iid);
2262 if (!NT_STATUS_IS_OK(status)) {
2263 return LDB_ERR_OPERATIONS_ERROR;
2266 flags_string = talloc_asprintf(mem_ctx, "%u", rmd_flags);
2267 if (!flags_string) {
2268 return LDB_ERR_OPERATIONS_ERROR;
2270 flagsv = data_blob_string_const(flags_string);
2272 ret = ldb_dn_set_extended_component(dn, "RMD_FLAGS", &flagsv);
2273 if (ret != LDB_SUCCESS) return ret;
2275 /* get the ADDTIME from the original */
2276 old_addtime = ldb_dn_get_extended_component(old_dsdb_dn->dn, "RMD_ADDTIME");
2277 if (old_addtime == NULL) {
2278 old_addtime = &tval;
2280 if (dsdb_dn != old_dsdb_dn ||
2281 ldb_dn_get_extended_component(dn, "RMD_ADDTIME") == NULL) {
2282 ret = ldb_dn_set_extended_component(dn, "RMD_ADDTIME", old_addtime);
2283 if (ret != LDB_SUCCESS) return ret;
2286 /* use our invocation id */
2287 ret = ldb_dn_set_extended_component(dn, "RMD_INVOCID", &iid);
2288 if (ret != LDB_SUCCESS) return ret;
2290 /* changetime is the current time */
2291 ret = ldb_dn_set_extended_component(dn, "RMD_CHANGETIME", &tval);
2292 if (ret != LDB_SUCCESS) return ret;
2294 /* update the USN */
2295 ret = ldb_dn_set_extended_component(dn, "RMD_ORIGINATING_USN", &usnv);
2296 if (ret != LDB_SUCCESS) return ret;
2298 ret = ldb_dn_set_extended_component(dn, "RMD_LOCAL_USN", &local_usnv);
2299 if (ret != LDB_SUCCESS) return ret;
2301 /* increase the version by 1 */
2302 status = dsdb_get_extended_dn_uint32(old_dsdb_dn->dn, &old_version, "RMD_VERSION");
2303 if (NT_STATUS_IS_OK(status) && old_version >= version) {
2304 version = old_version+1;
2306 vstring = talloc_asprintf(dn, "%lu", (unsigned long)version);
2307 vers = data_blob_string_const(vstring);
2308 ret = ldb_dn_set_extended_component(dn, "RMD_VERSION", &vers);
2309 if (ret != LDB_SUCCESS) return ret;
2311 dnstring = dsdb_dn_get_extended_linearized(mem_ctx, dsdb_dn, 1);
2312 if (dnstring == NULL) {
2313 return LDB_ERR_OPERATIONS_ERROR;
2315 *v = data_blob_string_const(dnstring);
2321 handle adding a linked attribute
2323 static int replmd_modify_la_add(struct ldb_module *module,
2324 struct replmd_private *replmd_private,
2325 const struct dsdb_schema *schema,
2326 struct ldb_message *msg,
2327 struct ldb_message_element *el,
2328 struct ldb_message_element *old_el,
2329 const struct dsdb_attribute *schema_attr,
2332 struct ldb_dn *msg_dn,
2333 struct ldb_request *parent)
2336 struct parsed_dn *dns, *old_dns;
2337 TALLOC_CTX *tmp_ctx = talloc_new(msg);
2339 struct ldb_val *new_values = NULL;
2340 unsigned old_num_values = old_el ? old_el->num_values : 0;
2341 unsigned num_values = 0;
2342 unsigned max_num_values;
2343 const struct GUID *invocation_id;
2344 struct ldb_context *ldb = ldb_module_get_ctx(module);
2346 unix_to_nt_time(&now, t);
2348 invocation_id = samdb_ntds_invocation_id(ldb);
2349 if (!invocation_id) {
2350 talloc_free(tmp_ctx);
2351 return LDB_ERR_OPERATIONS_ERROR;
2354 /* get the DNs to be added, fully parsed.
2356 * We need full parsing because they came off the wire and we don't
2357 * trust them, besides which we need their details to know where to put
2360 ret = get_parsed_dns(module, tmp_ctx, el, &dns,
2361 schema_attr->syntax->ldap_oid, parent);
2362 if (ret != LDB_SUCCESS) {
2363 talloc_free(tmp_ctx);
2367 /* get the existing DNs, lazily parsed */
2368 ret = get_parsed_dns_trusted(module, replmd_private,
2369 tmp_ctx, old_el, &old_dns,
2370 schema_attr->syntax->ldap_oid, parent);
2372 if (ret != LDB_SUCCESS) {
2373 talloc_free(tmp_ctx);
2377 max_num_values = old_num_values + el->num_values;
2378 if (max_num_values < old_num_values) {
2379 DEBUG(0, ("we seem to have overflow in replmd_modify_la_add. "
2380 "old values: %u, new values: %u, sum: %u",
2381 old_num_values, el->num_values, max_num_values));
2382 talloc_free(tmp_ctx);
2383 return LDB_ERR_OPERATIONS_ERROR;
2386 new_values = talloc_zero_array(tmp_ctx, struct ldb_val, max_num_values);
2388 if (new_values == NULL) {
2389 ldb_module_oom(module);
2390 talloc_free(tmp_ctx);
2391 return LDB_ERR_OPERATIONS_ERROR;
2395 * For each new value, find where it would go in the list. If there is
2396 * a matching GUID there, we update the existing value; otherwise we
2400 for (i = 0; i < el->num_values; i++) {
2401 struct parsed_dn *exact;
2402 struct parsed_dn *next;
2404 int err = parsed_dn_find(ldb, old_dns, old_num_values,
2407 dns[i].dsdb_dn->extra_part, 0,
2409 schema_attr->syntax->ldap_oid,
2411 if (err != LDB_SUCCESS) {
2412 talloc_free(tmp_ctx);
2416 if (exact != NULL) {
2418 * We are trying to add one that exists, which is only
2419 * allowed if it was previously deleted.
2421 * When we do undelete a link we change it in place.
2422 * It will be copied across into the right spot in due
2426 rmd_flags = dsdb_dn_rmd_flags(exact->dsdb_dn->dn);
2428 if (!(rmd_flags & DSDB_RMD_FLAG_DELETED)) {
2429 struct GUID_txt_buf guid_str;
2430 ldb_asprintf_errstring(ldb,
2431 "Attribute %s already "
2432 "exists for target GUID %s",
2434 GUID_buf_string(&exact->guid,
2436 talloc_free(tmp_ctx);
2437 /* error codes for 'member' need to be
2439 if (ldb_attr_cmp(el->name, "member") == 0) {
2440 return LDB_ERR_ENTRY_ALREADY_EXISTS;
2442 return LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS;
2446 ret = replmd_update_la_val(new_values, exact->v,
2449 invocation_id, seq_num,
2450 seq_num, now, 0, false);
2451 if (ret != LDB_SUCCESS) {
2452 talloc_free(tmp_ctx);
2456 ret = replmd_add_backlink(module, replmd_private,
2463 if (ret != LDB_SUCCESS) {
2464 talloc_free(tmp_ctx);
2470 * Here we don't have an exact match.
2472 * If next is NULL, this one goes beyond the end of the
2473 * existing list, so we need to add all of those ones first.
2475 * If next is not NULL, we need to add all the ones before
2479 offset = old_num_values;
2481 /* next should have been parsed, but let's make sure */
2482 if (next->dsdb_dn == NULL) {
2483 ret = really_parse_trusted_dn(tmp_ctx, ldb, next,
2484 schema_attr->syntax->ldap_oid);
2485 if (ret != LDB_SUCCESS) {
2489 offset = MIN(next - old_dns, old_num_values);
2492 /* put all the old ones before next on the list */
2493 for (; j < offset; j++) {
2494 new_values[num_values] = *old_dns[j].v;
2498 ret = replmd_add_backlink(module, replmd_private,
2503 /* Make the new linked attribute ldb_val. */
2504 ret = replmd_build_la_val(new_values, &new_values[num_values],
2505 dns[i].dsdb_dn, invocation_id,
2508 if (ret != LDB_SUCCESS) {
2509 talloc_free(tmp_ctx);
2513 if (ret != LDB_SUCCESS) {
2514 talloc_free(tmp_ctx);
2518 /* copy the rest of the old ones (if any) */
2519 for (; j < old_num_values; j++) {
2520 new_values[num_values] = *old_dns[j].v;
2524 talloc_steal(msg->elements, new_values);
2525 if (old_el != NULL) {
2526 talloc_steal(msg->elements, old_el->values);
2528 el->values = new_values;
2529 el->num_values = num_values;
2531 talloc_free(tmp_ctx);
2533 /* we now tell the backend to replace all existing values
2534 with the one we have constructed */
2535 el->flags = LDB_FLAG_MOD_REPLACE;
2542 handle deleting all active linked attributes
2544 static int replmd_modify_la_delete(struct ldb_module *module,
2545 struct replmd_private *replmd_private,
2546 const struct dsdb_schema *schema,
2547 struct ldb_message *msg,
2548 struct ldb_message_element *el,
2549 struct ldb_message_element *old_el,
2550 const struct dsdb_attribute *schema_attr,
2553 struct ldb_dn *msg_dn,
2554 struct ldb_request *parent)
2557 struct parsed_dn *dns, *old_dns;
2558 TALLOC_CTX *tmp_ctx = NULL;
2560 struct ldb_context *ldb = ldb_module_get_ctx(module);
2561 struct ldb_control *vanish_links_ctrl = NULL;
2562 bool vanish_links = false;
2563 unsigned int num_to_delete = el->num_values;
2565 const struct GUID *invocation_id;
2568 unix_to_nt_time(&now, t);
2570 invocation_id = samdb_ntds_invocation_id(ldb);
2571 if (!invocation_id) {
2572 return LDB_ERR_OPERATIONS_ERROR;
2575 if (old_el == NULL || old_el->num_values == 0) {
2576 /* there is nothing to delete... */
2577 if (num_to_delete == 0) {
2578 /* and we're deleting nothing, so that's OK */
2581 return LDB_ERR_NO_SUCH_ATTRIBUTE;
2584 tmp_ctx = talloc_new(msg);
2585 if (tmp_ctx == NULL) {
2586 return LDB_ERR_OPERATIONS_ERROR;
2589 ret = get_parsed_dns(module, tmp_ctx, el, &dns,
2590 schema_attr->syntax->ldap_oid, parent);
2591 if (ret != LDB_SUCCESS) {
2592 talloc_free(tmp_ctx);
2596 ret = get_parsed_dns_trusted(module, replmd_private,
2597 tmp_ctx, old_el, &old_dns,
2598 schema_attr->syntax->ldap_oid, parent);
2600 if (ret != LDB_SUCCESS) {
2601 talloc_free(tmp_ctx);
2606 vanish_links_ctrl = ldb_request_get_control(parent, DSDB_CONTROL_REPLMD_VANISH_LINKS);
2607 if (vanish_links_ctrl) {
2608 vanish_links = true;
2609 vanish_links_ctrl->critical = false;
2613 /* we empty out el->values here to avoid damage if we return early. */
2618 * If vanish links is set, we are actually removing members of
2619 * old_el->values; otherwise we are just marking them deleted.
2621 * There is a special case when no values are given: we remove them
2622 * all. When we have the vanish_links control we just have to remove
2623 * the backlinks and change our element to replace the existing values
2624 * with the empty list.
2627 if (num_to_delete == 0) {
2628 for (i = 0; i < old_el->num_values; i++) {
2629 struct parsed_dn *p = &old_dns[i];
2630 if (p->dsdb_dn == NULL) {
2631 ret = really_parse_trusted_dn(tmp_ctx, ldb, p,
2632 schema_attr->syntax->ldap_oid);
2633 if (ret != LDB_SUCCESS) {
2637 ret = replmd_add_backlink(module, replmd_private,
2638 schema, msg_dn, &p->guid,
2641 if (ret != LDB_SUCCESS) {
2642 talloc_free(tmp_ctx);
2649 rmd_flags = dsdb_dn_rmd_flags(p->dsdb_dn->dn);
2650 if (rmd_flags & DSDB_RMD_FLAG_DELETED) {
2654 ret = replmd_update_la_val(old_el->values, p->v,
2655 p->dsdb_dn, p->dsdb_dn,
2656 invocation_id, seq_num,
2657 seq_num, now, 0, true);
2658 if (ret != LDB_SUCCESS) {
2659 talloc_free(tmp_ctx);
2665 el->flags = LDB_FLAG_MOD_REPLACE;
2666 talloc_free(tmp_ctx);
2672 for (i = 0; i < num_to_delete; i++) {
2673 struct parsed_dn *p = &dns[i];
2674 struct parsed_dn *exact = NULL;
2675 struct parsed_dn *next = NULL;
2676 ret = parsed_dn_find(ldb, old_dns, old_el->num_values,
2679 p->dsdb_dn->extra_part, 0,
2681 schema_attr->syntax->ldap_oid,
2683 if (ret != LDB_SUCCESS) {
2684 talloc_free(tmp_ctx);
2687 if (exact == NULL) {
2688 struct GUID_txt_buf buf;
2689 ldb_asprintf_errstring(ldb, "Attribute %s doesn't "
2690 "exist for target GUID %s",
2692 GUID_buf_string(&p->guid, &buf));
2693 if (ldb_attr_cmp(el->name, "member") == 0) {
2694 talloc_free(tmp_ctx);
2695 return LDB_ERR_UNWILLING_TO_PERFORM;
2697 talloc_free(tmp_ctx);
2698 return LDB_ERR_NO_SUCH_ATTRIBUTE;
2703 if (CHECK_DEBUGLVL(5)) {
2704 rmd_flags = dsdb_dn_rmd_flags(exact->dsdb_dn->dn);
2705 if ((rmd_flags & DSDB_RMD_FLAG_DELETED)) {
2706 struct GUID_txt_buf buf;
2707 const char *guid_str = \
2708 GUID_buf_string(&p->guid, &buf);
2709 DEBUG(5, ("Deleting deleted linked "
2710 "attribute %s to %s, because "
2711 "vanish_links control is set\n",
2712 el->name, guid_str));
2716 /* remove the backlink */
2717 ret = replmd_add_backlink(module,
2724 if (ret != LDB_SUCCESS) {
2725 talloc_free(tmp_ctx);
2729 /* We flag the deletion and tidy it up later. */
2734 rmd_flags = dsdb_dn_rmd_flags(exact->dsdb_dn->dn);
2736 if (rmd_flags & DSDB_RMD_FLAG_DELETED) {
2737 struct GUID_txt_buf buf;
2738 const char *guid_str = GUID_buf_string(&p->guid, &buf);
2739 ldb_asprintf_errstring(ldb, "Attribute %s already "
2740 "deleted for target GUID %s",
2741 el->name, guid_str);
2742 if (ldb_attr_cmp(el->name, "member") == 0) {
2743 talloc_free(tmp_ctx);
2744 return LDB_ERR_UNWILLING_TO_PERFORM;
2746 talloc_free(tmp_ctx);
2747 return LDB_ERR_NO_SUCH_ATTRIBUTE;
2751 ret = replmd_update_la_val(old_el->values, exact->v,
2752 exact->dsdb_dn, exact->dsdb_dn,
2753 invocation_id, seq_num, seq_num,
2755 if (ret != LDB_SUCCESS) {
2756 talloc_free(tmp_ctx);
2759 ret = replmd_add_backlink(module, replmd_private,
2764 if (ret != LDB_SUCCESS) {
2765 talloc_free(tmp_ctx);
2772 for (i = 0; i < old_el->num_values; i++) {
2773 if (old_dns[i].v != NULL) {
2774 old_el->values[j] = *old_dns[i].v;
2778 old_el->num_values = j;
2781 el->values = talloc_steal(msg->elements, old_el->values);
2782 el->num_values = old_el->num_values;
2784 talloc_free(tmp_ctx);
2786 /* we now tell the backend to replace all existing values
2787 with the one we have constructed */
2788 el->flags = LDB_FLAG_MOD_REPLACE;
2794 handle replacing a linked attribute
2796 static int replmd_modify_la_replace(struct ldb_module *module,
2797 struct replmd_private *replmd_private,
2798 const struct dsdb_schema *schema,
2799 struct ldb_message *msg,
2800 struct ldb_message_element *el,
2801 struct ldb_message_element *old_el,
2802 const struct dsdb_attribute *schema_attr,
2805 struct ldb_dn *msg_dn,
2806 struct ldb_request *parent)
2808 unsigned int i, old_i, new_i;
2809 struct parsed_dn *dns, *old_dns;
2810 TALLOC_CTX *tmp_ctx = talloc_new(msg);
2812 const struct GUID *invocation_id;
2813 struct ldb_context *ldb = ldb_module_get_ctx(module);
2814 struct ldb_val *new_values = NULL;
2815 const char *ldap_oid = schema_attr->syntax->ldap_oid;
2816 unsigned int old_num_values;
2817 unsigned int repl_num_values;
2818 unsigned int max_num_values;
2821 unix_to_nt_time(&now, t);
2823 invocation_id = samdb_ntds_invocation_id(ldb);
2824 if (!invocation_id) {
2825 return LDB_ERR_OPERATIONS_ERROR;
2829 * The replace operation is unlike the replace and delete cases in that
2830 * we need to look at every existing link to see whether it is being
2831 * retained or deleted. In other words, we can't avoid parsing the GUIDs.
2833 * As we are trying to combine two sorted lists, the algorithm we use
2834 * is akin to the merge phase of a merge sort. We interleave the two
2835 * lists, doing different things depending on which side the current
2838 * There are three main cases, with some sub-cases.
2840 * - a DN is in the old list but not the new one. It needs to be
2841 * marked as deleted (but left in the list).
2842 * - maybe it is already deleted, and we have less to do.
2844 * - a DN is in both lists. The old data gets replaced by the new,
2845 * and the list doesn't grow. The old link may have been marked as
2846 * deleted, in which case we undelete it.
2848 * - a DN is in the new list only. We add it in the right place.
2851 old_num_values = old_el ? old_el->num_values : 0;
2852 repl_num_values = el->num_values;
2853 max_num_values = old_num_values + repl_num_values;
2855 if (max_num_values == 0) {
2856 /* There is nothing to do! */
2860 ret = get_parsed_dns(module, tmp_ctx, el, &dns, ldap_oid, parent);
2861 if (ret != LDB_SUCCESS) {
2862 talloc_free(tmp_ctx);
2866 ret = get_parsed_dns(module, tmp_ctx, old_el, &old_dns,
2868 if (ret != LDB_SUCCESS) {
2869 talloc_free(tmp_ctx);
2873 ret = replmd_check_upgrade_links(ldb, old_dns, old_num_values,
2875 if (ret != LDB_SUCCESS) {
2876 talloc_free(tmp_ctx);
2880 new_values = talloc_array(tmp_ctx, struct ldb_val, max_num_values);
2881 if (new_values == NULL) {
2882 ldb_module_oom(module);
2883 talloc_free(tmp_ctx);
2884 return LDB_ERR_OPERATIONS_ERROR;
2889 for (i = 0; i < max_num_values; i++) {
2891 struct parsed_dn *old_p, *new_p;
2892 if (old_i < old_num_values && new_i < repl_num_values) {
2893 old_p = &old_dns[old_i];
2894 new_p = &dns[new_i];
2895 cmp = parsed_dn_compare(old_p, new_p);
2896 } else if (old_i < old_num_values) {
2897 /* the new list is empty, read the old list */
2898 old_p = &old_dns[old_i];
2901 } else if (new_i < repl_num_values) {
2902 /* the old list is empty, read new list */
2904 new_p = &dns[new_i];
2912 * An old ones that come before the next replacement
2913 * (if any). We mark it as deleted and add it to the
2916 uint32_t rmd_flags = dsdb_dn_rmd_flags(old_p->dsdb_dn->dn);
2917 if ((rmd_flags & DSDB_RMD_FLAG_DELETED) == 0) {
2918 ret = replmd_update_la_val(new_values, old_p->v,
2924 if (ret != LDB_SUCCESS) {
2925 talloc_free(tmp_ctx);
2929 ret = replmd_add_backlink(module, replmd_private,
2932 &old_p->guid, false,
2935 if (ret != LDB_SUCCESS) {
2936 talloc_free(tmp_ctx);
2940 new_values[i] = *old_p->v;
2942 } else if (cmp == 0) {
2944 * We are overwriting one. If it was previously
2945 * deleted, we need to add a backlink.
2947 * Note that if any RMD_FLAGs in an extended new DN
2952 ret = replmd_update_la_val(new_values, old_p->v,
2958 if (ret != LDB_SUCCESS) {
2959 talloc_free(tmp_ctx);
2963 rmd_flags = dsdb_dn_rmd_flags(old_p->dsdb_dn->dn);
2964 if ((rmd_flags & DSDB_RMD_FLAG_DELETED) != 0) {
2965 ret = replmd_add_backlink(module, replmd_private,
2971 if (ret != LDB_SUCCESS) {
2972 talloc_free(tmp_ctx);
2977 new_values[i] = *old_p->v;
2982 * Replacements that don't match an existing one. We
2983 * just add them to the final list.
2985 ret = replmd_build_la_val(new_values,
2991 if (ret != LDB_SUCCESS) {
2992 talloc_free(tmp_ctx);
2995 ret = replmd_add_backlink(module, replmd_private,
3001 if (ret != LDB_SUCCESS) {
3002 talloc_free(tmp_ctx);
3005 new_values[i] = *new_p->v;
3009 if (old_el != NULL) {
3010 talloc_steal(msg->elements, old_el->values);
3012 el->values = talloc_steal(msg->elements, new_values);
3014 talloc_free(tmp_ctx);
3016 el->flags = LDB_FLAG_MOD_REPLACE;
3023 handle linked attributes in modify requests
3025 static int replmd_modify_handle_linked_attribs(struct ldb_module *module,
3026 struct replmd_private *replmd_private,
3027 struct ldb_message *msg,
3028 uint64_t seq_num, time_t t,
3029 struct ldb_request *parent)
3031 struct ldb_result *res;
3034 struct ldb_context *ldb = ldb_module_get_ctx(module);
3035 struct ldb_message *old_msg;
3037 const struct dsdb_schema *schema;
3039 if (dsdb_functional_level(ldb) == DS_DOMAIN_FUNCTION_2000) {
3041 * Nothing special is required for modifying or vanishing links
3042 * in fl2000 since they are just strings in a multi-valued
3045 struct ldb_control *ctrl = ldb_request_get_control(parent,
3046 DSDB_CONTROL_REPLMD_VANISH_LINKS);
3048 ctrl->critical = false;
3056 * We should restrict this to the intersection of the list of
3057 * linked attributes in the schema and the list of attributes
3060 * This will help performance a little, as otherwise we have
3061 * to allocate the entire object value-by-value.
3063 ret = dsdb_module_search_dn(module, msg, &res, msg->dn, NULL,
3064 DSDB_FLAG_NEXT_MODULE |
3065 DSDB_SEARCH_SHOW_RECYCLED |
3066 DSDB_SEARCH_REVEAL_INTERNALS |
3067 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT,
3069 if (ret != LDB_SUCCESS) {
3072 schema = dsdb_get_schema(ldb, res);
3074 return LDB_ERR_OPERATIONS_ERROR;
3077 old_msg = res->msgs[0];
3079 for (i=0; i<msg->num_elements; i++) {
3080 struct ldb_message_element *el = &msg->elements[i];
3081 struct ldb_message_element *old_el, *new_el;
3082 const struct dsdb_attribute *schema_attr
3083 = dsdb_attribute_by_lDAPDisplayName(schema, el->name);
3085 ldb_asprintf_errstring(ldb,
3086 "%s: attribute %s is not a valid attribute in schema",
3087 __FUNCTION__, el->name);
3088 return LDB_ERR_OBJECT_CLASS_VIOLATION;
3090 if (schema_attr->linkID == 0) {
3093 if ((schema_attr->linkID & 1) == 1) {
3094 if (parent && ldb_request_get_control(parent, DSDB_CONTROL_DBCHECK)) {
3097 /* Odd is for the target. Illegal to modify */
3098 ldb_asprintf_errstring(ldb,
3099 "attribute %s must not be modified directly, it is a linked attribute", el->name);
3100 return LDB_ERR_UNWILLING_TO_PERFORM;
3102 old_el = ldb_msg_find_element(old_msg, el->name);
3103 switch (el->flags & LDB_FLAG_MOD_MASK) {
3104 case LDB_FLAG_MOD_REPLACE:
3105 ret = replmd_modify_la_replace(module, replmd_private,
3106 schema, msg, el, old_el,
3107 schema_attr, seq_num, t,
3111 case LDB_FLAG_MOD_DELETE:
3112 ret = replmd_modify_la_delete(module, replmd_private,
3113 schema, msg, el, old_el,
3114 schema_attr, seq_num, t,
3118 case LDB_FLAG_MOD_ADD:
3119 ret = replmd_modify_la_add(module, replmd_private,
3120 schema, msg, el, old_el,
3121 schema_attr, seq_num, t,
3126 ldb_asprintf_errstring(ldb,
3127 "invalid flags 0x%x for %s linked attribute",
3128 el->flags, el->name);
3129 return LDB_ERR_UNWILLING_TO_PERFORM;
3131 if (dsdb_check_single_valued_link(schema_attr, el) != LDB_SUCCESS) {
3132 ldb_asprintf_errstring(ldb,
3133 "Attribute %s is single valued but more than one value has been supplied",
3135 return LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS;
3137 el->flags |= LDB_FLAG_INTERNAL_DISABLE_SINGLE_VALUE_CHECK;
3142 if (ret != LDB_SUCCESS) {
3146 ldb_msg_remove_attr(old_msg, el->name);
3148 ldb_msg_add_empty(old_msg, el->name, 0, &new_el);
3149 new_el->num_values = el->num_values;
3150 new_el->values = talloc_steal(msg->elements, el->values);
3152 /* TODO: this relises a bit too heavily on the exact
3153 behaviour of ldb_msg_find_element and
3154 ldb_msg_remove_element */
3155 old_el = ldb_msg_find_element(msg, el->name);
3157 ldb_msg_remove_element(msg, old_el);
3167 static int send_rodc_referral(struct ldb_request *req,
3168 struct ldb_context *ldb,
3171 char *referral = NULL;
3172 struct loadparm_context *lp_ctx = NULL;
3173 struct ldb_dn *fsmo_role_dn = NULL;
3174 struct ldb_dn *role_owner_dn = NULL;
3175 const char *domain = NULL;
3178 lp_ctx = talloc_get_type(ldb_get_opaque(ldb, "loadparm"),
3179 struct loadparm_context);
3181 werr = dsdb_get_fsmo_role_info(req, ldb, DREPL_PDC_MASTER,
3182 &fsmo_role_dn, &role_owner_dn);
3184 if (W_ERROR_IS_OK(werr)) {
3185 struct ldb_dn *server_dn = ldb_dn_copy(req, role_owner_dn);
3186 if (server_dn != NULL) {
3187 ldb_dn_remove_child_components(server_dn, 1);
3188 domain = samdb_dn_to_dnshostname(ldb, req,
3193 if (domain == NULL) {
3194 domain = lpcfg_dnsdomain(lp_ctx);
3197 referral = talloc_asprintf(req, "ldap://%s/%s",
3199 ldb_dn_get_linearized(dn));
3200 if (referral == NULL) {
3202 return LDB_ERR_OPERATIONS_ERROR;
3205 return ldb_module_send_referral(req, referral);
3209 static int replmd_modify(struct ldb_module *module, struct ldb_request *req)
3211 struct ldb_context *ldb;
3212 struct replmd_replicated_request *ac;
3213 struct ldb_request *down_req;
3214 struct ldb_message *msg;
3215 time_t t = time(NULL);
3217 bool is_urgent = false, rodc = false;
3218 bool is_schema_nc = false;
3219 unsigned int functional_level;
3220 const struct ldb_message_element *guid_el = NULL;
3221 struct ldb_control *sd_propagation_control;
3222 struct replmd_private *replmd_private =
3223 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
3225 /* do not manipulate our control entries */
3226 if (ldb_dn_is_special(req->op.mod.message->dn)) {
3227 return ldb_next_request(module, req);
3230 sd_propagation_control = ldb_request_get_control(req,
3231 DSDB_CONTROL_SEC_DESC_PROPAGATION_OID);
3232 if (sd_propagation_control != NULL) {
3233 if (req->op.mod.message->num_elements != 1) {
3234 return ldb_module_operr(module);
3236 ret = strcmp(req->op.mod.message->elements[0].name,
3237 "nTSecurityDescriptor");
3239 return ldb_module_operr(module);
3242 return ldb_next_request(module, req);
3245 ldb = ldb_module_get_ctx(module);
3247 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_modify\n");
3249 guid_el = ldb_msg_find_element(req->op.mod.message, "objectGUID");
3250 if (guid_el != NULL) {
3251 ldb_set_errstring(ldb,
3252 "replmd_modify: it's not allowed to change the objectGUID!");
3253 return LDB_ERR_CONSTRAINT_VIOLATION;
3256 ac = replmd_ctx_init(module, req);
3258 return ldb_module_oom(module);
3261 functional_level = dsdb_functional_level(ldb);
3263 /* we have to copy the message as the caller might have it as a const */
3264 msg = ldb_msg_copy_shallow(ac, req->op.mod.message);
3268 return LDB_ERR_OPERATIONS_ERROR;
3271 ldb_msg_remove_attr(msg, "whenChanged");
3272 ldb_msg_remove_attr(msg, "uSNChanged");
3274 is_schema_nc = ldb_dn_compare_base(replmd_private->schema_dn, msg->dn) == 0;
3276 ret = replmd_update_rpmd(module, ac->schema, req, NULL,
3277 msg, &ac->seq_num, t, is_schema_nc,
3279 if (rodc && (ret == LDB_ERR_REFERRAL)) {
3280 ret = send_rodc_referral(req, ldb, msg->dn);
3286 if (ret != LDB_SUCCESS) {
3291 ret = replmd_modify_handle_linked_attribs(module, replmd_private,
3292 msg, ac->seq_num, t, req);
3293 if (ret != LDB_SUCCESS) {
3299 * - replace the old object with the newly constructed one
3302 ac->is_urgent = is_urgent;
3304 ret = ldb_build_mod_req(&down_req, ldb, ac,
3307 ac, replmd_op_callback,
3309 LDB_REQ_SET_LOCATION(down_req);
3310 if (ret != LDB_SUCCESS) {
3315 /* current partition control is needed by "replmd_op_callback" */
3316 if (ldb_request_get_control(req, DSDB_CONTROL_CURRENT_PARTITION_OID) == NULL) {
3317 ret = ldb_request_add_control(down_req,
3318 DSDB_CONTROL_CURRENT_PARTITION_OID,
3320 if (ret != LDB_SUCCESS) {
3326 /* If we are in functional level 2000, then
3327 * replmd_modify_handle_linked_attribs will have done
3329 if (functional_level == DS_DOMAIN_FUNCTION_2000) {
3330 ret = ldb_request_add_control(down_req, DSDB_CONTROL_APPLY_LINKS, false, NULL);
3331 if (ret != LDB_SUCCESS) {
3337 talloc_steal(down_req, msg);
3339 /* we only change whenChanged and uSNChanged if the seq_num
3341 if (ac->seq_num != 0) {
3342 ret = add_time_element(msg, "whenChanged", t);
3343 if (ret != LDB_SUCCESS) {
3349 ret = add_uint64_element(ldb, msg, "uSNChanged", ac->seq_num);
3350 if (ret != LDB_SUCCESS) {
3357 /* go on with the call chain */
3358 return ldb_next_request(module, down_req);
3361 static int replmd_rename_callback(struct ldb_request *req, struct ldb_reply *ares);
3364 handle a rename request
3366 On a rename we need to do an extra ldb_modify which sets the
3367 whenChanged and uSNChanged attributes. We do this in a callback after the success.
3369 static int replmd_rename(struct ldb_module *module, struct ldb_request *req)
3371 struct ldb_context *ldb;
3372 struct replmd_replicated_request *ac;
3374 struct ldb_request *down_req;
3376 /* do not manipulate our control entries */
3377 if (ldb_dn_is_special(req->op.mod.message->dn)) {
3378 return ldb_next_request(module, req);
3381 ldb = ldb_module_get_ctx(module);
3383 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_rename\n");
3385 ac = replmd_ctx_init(module, req);
3387 return ldb_module_oom(module);
3390 ret = ldb_build_rename_req(&down_req, ldb, ac,
3391 ac->req->op.rename.olddn,
3392 ac->req->op.rename.newdn,
3394 ac, replmd_rename_callback,
3396 LDB_REQ_SET_LOCATION(down_req);
3397 if (ret != LDB_SUCCESS) {
3402 /* go on with the call chain */
3403 return ldb_next_request(module, down_req);
3406 /* After the rename is compleated, update the whenchanged etc */
3407 static int replmd_rename_callback(struct ldb_request *req, struct ldb_reply *ares)
3409 struct ldb_context *ldb;
3410 struct ldb_request *down_req;
3411 struct ldb_message *msg;
3412 const struct dsdb_attribute *rdn_attr;
3413 const char *rdn_name;
3414 const struct ldb_val *rdn_val;
3415 const char *attrs[5] = { NULL, };
3416 time_t t = time(NULL);
3418 bool is_urgent = false, rodc = false;
3420 struct replmd_replicated_request *ac =
3421 talloc_get_type(req->context, struct replmd_replicated_request);
3422 struct replmd_private *replmd_private =
3423 talloc_get_type(ldb_module_get_private(ac->module),
3424 struct replmd_private);
3426 ldb = ldb_module_get_ctx(ac->module);
3428 if (ares->error != LDB_SUCCESS) {
3429 return ldb_module_done(ac->req, ares->controls,
3430 ares->response, ares->error);
3433 if (ares->type != LDB_REPLY_DONE) {
3434 ldb_set_errstring(ldb,
3435 "invalid ldb_reply_type in callback");
3437 return ldb_module_done(ac->req, NULL, NULL,
3438 LDB_ERR_OPERATIONS_ERROR);
3442 * - replace the old object with the newly constructed one
3445 msg = ldb_msg_new(ac);
3448 return LDB_ERR_OPERATIONS_ERROR;
3451 msg->dn = ac->req->op.rename.newdn;
3453 is_schema_nc = ldb_dn_compare_base(replmd_private->schema_dn, msg->dn) == 0;
3455 rdn_name = ldb_dn_get_rdn_name(msg->dn);
3456 if (rdn_name == NULL) {
3458 return ldb_module_done(ac->req, NULL, NULL,
3462 /* normalize the rdn attribute name */
3463 rdn_attr = dsdb_attribute_by_lDAPDisplayName(ac->schema, rdn_name);
3464 if (rdn_attr == NULL) {
3466 return ldb_module_done(ac->req, NULL, NULL,
3469 rdn_name = rdn_attr->lDAPDisplayName;
3471 rdn_val = ldb_dn_get_rdn_val(msg->dn);
3472 if (rdn_val == NULL) {
3474 return ldb_module_done(ac->req, NULL, NULL,
3478 if (ldb_msg_add_empty(msg, rdn_name, LDB_FLAG_MOD_REPLACE, NULL) != 0) {
3480 return ldb_module_done(ac->req, NULL, NULL,
3483 if (ldb_msg_add_value(msg, rdn_name, rdn_val, NULL) != 0) {
3485 return ldb_module_done(ac->req, NULL, NULL,
3488 if (ldb_msg_add_empty(msg, "name", LDB_FLAG_MOD_REPLACE, NULL) != 0) {
3490 return ldb_module_done(ac->req, NULL, NULL,
3493 if (ldb_msg_add_value(msg, "name", rdn_val, NULL) != 0) {
3495 return ldb_module_done(ac->req, NULL, NULL,
3500 * here we let replmd_update_rpmd() only search for
3501 * the existing "replPropertyMetaData" and rdn_name attributes.
3503 * We do not want the existing "name" attribute as
3504 * the "name" attribute needs to get the version
3505 * updated on rename even if the rdn value hasn't changed.
3507 * This is the diff of the meta data, for a moved user
3508 * on a w2k8r2 server:
3511 * -dn: CN=sdf df,CN=Users,DC=bla,DC=base
3512 * +dn: CN=sdf df,OU=TestOU,DC=bla,DC=base
3513 * replPropertyMetaData: NDR: struct replPropertyMetaDataBlob
3514 * version : 0x00000001 (1)
3515 * reserved : 0x00000000 (0)
3516 * @@ -66,11 +66,11 @@ replPropertyMetaData: NDR: struct re
3517 * local_usn : 0x00000000000037a5 (14245)
3518 * array: struct replPropertyMetaData1
3519 * attid : DRSUAPI_ATTID_name (0x90001)
3520 * - version : 0x00000001 (1)
3521 * - originating_change_time : Wed Feb 9 17:20:49 2011 CET
3522 * + version : 0x00000002 (2)
3523 * + originating_change_time : Wed Apr 6 15:21:01 2011 CEST
3524 * originating_invocation_id: 0d36ca05-5507-4e62-aca3-354bab0d39e1
3525 * - originating_usn : 0x00000000000037a5 (14245)
3526 * - local_usn : 0x00000000000037a5 (14245)
3527 * + originating_usn : 0x0000000000003834 (14388)
3528 * + local_usn : 0x0000000000003834 (14388)
3529 * array: struct replPropertyMetaData1
3530 * attid : DRSUAPI_ATTID_userAccountControl (0x90008)
3531 * version : 0x00000004 (4)
3533 attrs[0] = "replPropertyMetaData";
3534 attrs[1] = "objectClass";
3535 attrs[2] = "instanceType";
3536 attrs[3] = rdn_name;
3539 ret = replmd_update_rpmd(ac->module, ac->schema, req, attrs,
3540 msg, &ac->seq_num, t,
3541 is_schema_nc, &is_urgent, &rodc);
3542 if (rodc && (ret == LDB_ERR_REFERRAL)) {
3543 ret = send_rodc_referral(req, ldb, ac->req->op.rename.olddn);
3545 return ldb_module_done(req, NULL, NULL, ret);
3548 if (ret != LDB_SUCCESS) {
3550 return ldb_module_done(ac->req, NULL, NULL, ret);
3553 if (ac->seq_num == 0) {
3555 return ldb_module_done(ac->req, NULL, NULL,
3557 "internal error seq_num == 0"));
3559 ac->is_urgent = is_urgent;
3561 ret = ldb_build_mod_req(&down_req, ldb, ac,
3564 ac, replmd_op_callback,
3566 LDB_REQ_SET_LOCATION(down_req);
3567 if (ret != LDB_SUCCESS) {
3572 /* current partition control is needed by "replmd_op_callback" */
3573 if (ldb_request_get_control(req, DSDB_CONTROL_CURRENT_PARTITION_OID) == NULL) {
3574 ret = ldb_request_add_control(down_req,
3575 DSDB_CONTROL_CURRENT_PARTITION_OID,
3577 if (ret != LDB_SUCCESS) {
3583 talloc_steal(down_req, msg);
3585 ret = add_time_element(msg, "whenChanged", t);
3586 if (ret != LDB_SUCCESS) {
3592 ret = add_uint64_element(ldb, msg, "uSNChanged", ac->seq_num);
3593 if (ret != LDB_SUCCESS) {
3599 /* go on with the call chain - do the modify after the rename */
3600 return ldb_next_request(ac->module, down_req);
3604 * remove links from objects that point at this object when an object
3605 * is deleted. We remove it from the NEXT module per MS-DRSR 5.160
3606 * RemoveObj which states that link removal due to the object being
3607 * deleted is NOT an originating update - they just go away!
3610 static int replmd_delete_remove_link(struct ldb_module *module,
3611 const struct dsdb_schema *schema,
3612 struct replmd_private *replmd_private,
3615 struct ldb_message_element *el,
3616 const struct dsdb_attribute *sa,
3617 struct ldb_request *parent)
3620 TALLOC_CTX *tmp_ctx = talloc_new(module);
3621 struct ldb_context *ldb = ldb_module_get_ctx(module);
3623 for (i=0; i<el->num_values; i++) {
3624 struct dsdb_dn *dsdb_dn;
3626 struct ldb_message *msg;
3627 const struct dsdb_attribute *target_attr;
3628 struct ldb_message_element *el2;
3630 struct ldb_val dn_val;
3631 uint32_t dsdb_flags = 0;
3632 const char *attrs[] = { NULL, NULL };
3633 struct ldb_result *link_res;
3634 struct ldb_message *link_msg;
3635 struct ldb_message_element *link_el;
3636 struct parsed_dn *link_dns;
3637 struct parsed_dn *p = NULL, *unused = NULL;
3639 if (dsdb_dn_is_deleted_val(&el->values[i])) {
3643 dsdb_dn = dsdb_dn_parse(tmp_ctx, ldb, &el->values[i], sa->syntax->ldap_oid);
3645 talloc_free(tmp_ctx);
3646 return LDB_ERR_OPERATIONS_ERROR;
3649 /* remove the link */
3650 msg = ldb_msg_new(tmp_ctx);
3652 ldb_module_oom(module);
3653 talloc_free(tmp_ctx);
3654 return LDB_ERR_OPERATIONS_ERROR;
3658 msg->dn = dsdb_dn->dn;
3660 target_attr = dsdb_attribute_by_linkID(schema, sa->linkID ^ 1);
3661 if (target_attr == NULL) {
3664 attrs[0] = target_attr->lDAPDisplayName;
3666 ret = ldb_msg_add_empty(msg, target_attr->lDAPDisplayName,
3667 LDB_FLAG_MOD_DELETE, &el2);
3668 if (ret != LDB_SUCCESS) {
3669 ldb_module_oom(module);
3670 talloc_free(tmp_ctx);
3671 return LDB_ERR_OPERATIONS_ERROR;
3674 ret = dsdb_module_search_dn(module, tmp_ctx, &link_res,
3676 DSDB_FLAG_NEXT_MODULE |
3677 DSDB_SEARCH_SHOW_EXTENDED_DN,
3680 if (ret != LDB_SUCCESS) {
3681 talloc_free(tmp_ctx);
3685 link_msg = link_res->msgs[0];
3686 link_el = ldb_msg_find_element(link_msg,
3687 target_attr->lDAPDisplayName);
3688 if (link_el == NULL) {
3689 talloc_free(tmp_ctx);
3690 return LDB_ERR_NO_SUCH_ATTRIBUTE;
3694 * This call 'upgrades' the links in link_dns, but we
3695 * do not commit the result back into the database, so
3696 * this is safe to call in FL2000 or on databases that
3697 * have been run at that level in the past.
3699 ret = get_parsed_dns_trusted(module, replmd_private, tmp_ctx,
3701 target_attr->syntax->ldap_oid, parent);
3702 if (ret != LDB_SUCCESS) {
3703 talloc_free(tmp_ctx);
3707 ret = parsed_dn_find(ldb, link_dns, link_el->num_values,
3711 target_attr->syntax->ldap_oid, false);
3712 if (ret != LDB_SUCCESS) {
3713 talloc_free(tmp_ctx);
3718 ldb_asprintf_errstring(ldb_module_get_ctx(module),
3719 "Failed to find forward link on %s "
3720 "as %s to remove backlink %s on %s",
3721 ldb_dn_get_linearized(msg->dn),
3722 target_attr->lDAPDisplayName,
3723 sa->lDAPDisplayName,
3724 ldb_dn_get_linearized(dn));
3725 talloc_free(tmp_ctx);
3726 return LDB_ERR_NO_SUCH_ATTRIBUTE;
3730 /* This needs to get the Binary DN, by first searching */
3731 dn_str = dsdb_dn_get_linearized(tmp_ctx,
3734 dn_val = data_blob_string_const(dn_str);
3735 el2->values = &dn_val;
3736 el2->num_values = 1;
3739 * Ensure that we tell the modification to vanish any linked
3740 * attributes (not simply mark them as isDeleted = TRUE)
3742 dsdb_flags |= DSDB_REPLMD_VANISH_LINKS;
3744 ret = dsdb_module_modify(module, msg, dsdb_flags|DSDB_FLAG_OWN_MODULE, parent);
3745 if (ret != LDB_SUCCESS) {
3746 talloc_free(tmp_ctx);
3750 talloc_free(tmp_ctx);
3756 handle update of replication meta data for deletion of objects
3758 This also handles the mapping of delete to a rename operation
3759 to allow deletes to be replicated.
3761 It also handles the incoming deleted objects, to ensure they are
3762 fully deleted here. In that case re_delete is true, and we do not
3763 use this as a signal to change the deleted state, just reinforce it.
3766 static int replmd_delete_internals(struct ldb_module *module, struct ldb_request *req, bool re_delete)
3768 int ret = LDB_ERR_OTHER;
3769 bool retb, disallow_move_on_delete;
3770 struct ldb_dn *old_dn, *new_dn;
3771 const char *rdn_name;
3772 const struct ldb_val *rdn_value, *new_rdn_value;
3774 struct ldb_context *ldb = ldb_module_get_ctx(module);
3775 const struct dsdb_schema *schema;
3776 struct ldb_message *msg, *old_msg;
3777 struct ldb_message_element *el;
3778 TALLOC_CTX *tmp_ctx;
3779 struct ldb_result *res, *parent_res;
3780 static const char * const preserved_attrs[] = {
3781 /* yes, this really is a hard coded list. See MS-ADTS
3782 section 3.1.1.5.5.1.1 */
3785 "dNReferenceUpdate",
3796 "msDS-LastKnownRDN",
3802 "distinguishedName",
3806 "proxiedObjectName",
3808 "nTSecurityDescriptor",
3809 "replPropertyMetaData",
3811 "securityIdentifier",
3819 "userAccountControl",
3826 static const char * const all_attrs[] = {
3827 DSDB_SECRET_ATTRIBUTES,
3831 unsigned int i, el_count = 0;
3832 uint32_t dsdb_flags = 0;
3833 struct replmd_private *replmd_private;
3834 enum deletion_state deletion_state, next_deletion_state;
3836 if (ldb_dn_is_special(req->op.del.dn)) {
3837 return ldb_next_request(module, req);
3841 * We have to allow dbcheck to remove an object that
3842 * is beyond repair, and to do so totally. This could
3843 * mean we we can get a partial object from the other
3844 * DC, causing havoc, so dbcheck suggests
3845 * re-replication first. dbcheck sets both DBCHECK
3846 * and RELAX in this situation.
3848 if (ldb_request_get_control(req, LDB_CONTROL_RELAX_OID)
3849 && ldb_request_get_control(req, DSDB_CONTROL_DBCHECK)) {
3850 /* really, really remove it */
3851 return ldb_next_request(module, req);
3854 tmp_ctx = talloc_new(ldb);
3857 return LDB_ERR_OPERATIONS_ERROR;
3860 schema = dsdb_get_schema(ldb, tmp_ctx);
3862 talloc_free(tmp_ctx);
3863 return LDB_ERR_OPERATIONS_ERROR;
3866 old_dn = ldb_dn_copy(tmp_ctx, req->op.del.dn);
3868 /* we need the complete msg off disk, so we can work out which
3869 attributes need to be removed */
3870 ret = dsdb_module_search_dn(module, tmp_ctx, &res, old_dn, all_attrs,
3871 DSDB_FLAG_NEXT_MODULE |
3872 DSDB_SEARCH_SHOW_RECYCLED |
3873 DSDB_SEARCH_REVEAL_INTERNALS |
3874 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT, req);
3875 if (ret != LDB_SUCCESS) {
3876 ldb_asprintf_errstring(ldb_module_get_ctx(module),
3877 "repmd_delete: Failed to %s %s, because we failed to find it: %s",
3878 re_delete ? "re-delete" : "delete",
3879 ldb_dn_get_linearized(old_dn),
3880 ldb_errstring(ldb_module_get_ctx(module)));
3881 talloc_free(tmp_ctx);
3884 old_msg = res->msgs[0];
3886 replmd_deletion_state(module, old_msg,
3888 &next_deletion_state);
3890 /* This supports us noticing an incoming isDeleted and acting on it */
3892 SMB_ASSERT(deletion_state > OBJECT_NOT_DELETED);
3893 next_deletion_state = deletion_state;
3896 if (next_deletion_state == OBJECT_REMOVED) {
3898 * We have to prevent objects being deleted, even if
3899 * the administrator really wants them gone, as
3900 * without the tombstone, we can get a partial object
3901 * from the other DC, causing havoc.
3903 * The only other valid case is when the 180 day
3904 * timeout has expired, when relax is specified.
3906 if (ldb_request_get_control(req, LDB_CONTROL_RELAX_OID)) {
3907 /* it is already deleted - really remove it this time */
3908 talloc_free(tmp_ctx);
3909 return ldb_next_request(module, req);
3912 ldb_asprintf_errstring(ldb, "Refusing to delete tombstone object %s. "
3913 "This check is to prevent corruption of the replicated state.",
3914 ldb_dn_get_linearized(old_msg->dn));
3915 return LDB_ERR_UNWILLING_TO_PERFORM;
3918 rdn_name = ldb_dn_get_rdn_name(old_dn);
3919 rdn_value = ldb_dn_get_rdn_val(old_dn);
3920 if ((rdn_name == NULL) || (rdn_value == NULL)) {
3921 talloc_free(tmp_ctx);
3922 return ldb_operr(ldb);
3925 msg = ldb_msg_new(tmp_ctx);
3927 ldb_module_oom(module);
3928 talloc_free(tmp_ctx);
3929 return LDB_ERR_OPERATIONS_ERROR;
3934 /* consider the SYSTEM_FLAG_DISALLOW_MOVE_ON_DELETE flag */
3935 disallow_move_on_delete =
3936 (ldb_msg_find_attr_as_int(old_msg, "systemFlags", 0)
3937 & SYSTEM_FLAG_DISALLOW_MOVE_ON_DELETE);
3939 /* work out where we will be renaming this object to */
3940 if (!disallow_move_on_delete) {
3941 struct ldb_dn *deleted_objects_dn;
3942 ret = dsdb_get_deleted_objects_dn(ldb, tmp_ctx, old_dn,
3943 &deleted_objects_dn);
3946 * We should not move objects if we can't find the
3947 * deleted objects DN. Not moving (or otherwise
3948 * harming) the Deleted Objects DN itself is handled
3951 if (re_delete && (ret != LDB_SUCCESS)) {
3952 new_dn = ldb_dn_get_parent(tmp_ctx, old_dn);
3953 if (new_dn == NULL) {
3954 ldb_module_oom(module);
3955 talloc_free(tmp_ctx);
3956 return LDB_ERR_OPERATIONS_ERROR;
3958 } else if (ret != LDB_SUCCESS) {
3959 /* this is probably an attempted delete on a partition
3960 * that doesn't allow delete operations, such as the
3961 * schema partition */
3962 ldb_asprintf_errstring(ldb, "No Deleted Objects container for DN %s",
3963 ldb_dn_get_linearized(old_dn));
3964 talloc_free(tmp_ctx);
3965 return LDB_ERR_UNWILLING_TO_PERFORM;
3967 new_dn = deleted_objects_dn;
3970 new_dn = ldb_dn_get_parent(tmp_ctx, old_dn);
3971 if (new_dn == NULL) {
3972 ldb_module_oom(module);
3973 talloc_free(tmp_ctx);
3974 return LDB_ERR_OPERATIONS_ERROR;
3978 /* get the objects GUID from the search we just did */
3979 guid = samdb_result_guid(old_msg, "objectGUID");
3981 if (deletion_state == OBJECT_NOT_DELETED) {
3982 /* Add a formatted child */
3983 retb = ldb_dn_add_child_fmt(new_dn, "%s=%s\\0ADEL:%s",
3985 ldb_dn_escape_value(tmp_ctx, *rdn_value),
3986 GUID_string(tmp_ctx, &guid));
3988 ldb_asprintf_errstring(ldb, __location__
3989 ": Unable to add a formatted child to dn: %s",
3990 ldb_dn_get_linearized(new_dn));
3991 talloc_free(tmp_ctx);
3992 return LDB_ERR_OPERATIONS_ERROR;
3995 ret = ldb_msg_add_string(msg, "isDeleted", "TRUE");
3996 if (ret != LDB_SUCCESS) {
3997 ldb_asprintf_errstring(ldb, __location__
3998 ": Failed to add isDeleted string to the msg");
3999 talloc_free(tmp_ctx);
4002 msg->elements[el_count++].flags = LDB_FLAG_MOD_REPLACE;
4005 * No matter what has happened with other renames etc, try again to
4006 * get this to be under the deleted DN. See MS-DRSR 5.160 RemoveObj
4009 struct ldb_dn *rdn = ldb_dn_copy(tmp_ctx, old_dn);
4010 retb = ldb_dn_remove_base_components(rdn, ldb_dn_get_comp_num(rdn) - 1);
4012 ldb_asprintf_errstring(ldb, __location__
4013 ": Unable to add a prepare rdn of %s",
4014 ldb_dn_get_linearized(rdn));
4015 talloc_free(tmp_ctx);
4016 return LDB_ERR_OPERATIONS_ERROR;
4018 SMB_ASSERT(ldb_dn_get_comp_num(rdn) == 1);
4020 retb = ldb_dn_add_child(new_dn, rdn);
4022 ldb_asprintf_errstring(ldb, __location__
4023 ": Unable to add rdn %s to base dn: %s",
4024 ldb_dn_get_linearized(rdn),
4025 ldb_dn_get_linearized(new_dn));
4026 talloc_free(tmp_ctx);
4027 return LDB_ERR_OPERATIONS_ERROR;
4032 now we need to modify the object in the following ways:
4034 - add isDeleted=TRUE
4035 - update rDN and name, with new rDN
4036 - remove linked attributes
4037 - remove objectCategory and sAMAccountType
4038 - remove attribs not on the preserved list
4039 - preserved if in above list, or is rDN
4040 - remove all linked attribs from this object
4041 - remove all links from other objects to this object
4042 - add lastKnownParent
4043 - update replPropertyMetaData?
4045 see MS-ADTS "Tombstone Requirements" section 3.1.1.5.5.1.1
4048 if (deletion_state == OBJECT_NOT_DELETED) {
4049 struct ldb_dn *parent_dn = ldb_dn_get_parent(tmp_ctx, old_dn);
4050 char *parent_dn_str = NULL;
4052 /* we need the storage form of the parent GUID */
4053 ret = dsdb_module_search_dn(module, tmp_ctx, &parent_res,
4055 DSDB_FLAG_NEXT_MODULE |
4056 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT |
4057 DSDB_SEARCH_REVEAL_INTERNALS|
4058 DSDB_SEARCH_SHOW_RECYCLED, req);
4059 if (ret != LDB_SUCCESS) {
4060 ldb_asprintf_errstring(ldb_module_get_ctx(module),
4061 "repmd_delete: Failed to %s %s, "
4062 "because we failed to find it's parent (%s): %s",
4063 re_delete ? "re-delete" : "delete",
4064 ldb_dn_get_linearized(old_dn),
4065 ldb_dn_get_linearized(parent_dn),
4066 ldb_errstring(ldb_module_get_ctx(module)));
4067 talloc_free(tmp_ctx);
4072 * Now we can use the DB version,
4073 * it will have the extended DN info in it
4075 parent_dn = parent_res->msgs[0]->dn;
4076 parent_dn_str = ldb_dn_get_extended_linearized(tmp_ctx,
4079 if (parent_dn_str == NULL) {
4080 talloc_free(tmp_ctx);
4081 return ldb_module_oom(module);
4084 ret = ldb_msg_add_steal_string(msg, "lastKnownParent",
4086 if (ret != LDB_SUCCESS) {
4087 ldb_asprintf_errstring(ldb, __location__
4088 ": Failed to add lastKnownParent "
4089 "string when deleting %s",
4090 ldb_dn_get_linearized(old_dn));
4091 talloc_free(tmp_ctx);
4094 msg->elements[el_count++].flags = LDB_FLAG_MOD_REPLACE;
4096 if (next_deletion_state == OBJECT_DELETED) {
4097 ret = ldb_msg_add_value(msg, "msDS-LastKnownRDN", rdn_value, NULL);
4098 if (ret != LDB_SUCCESS) {
4099 ldb_asprintf_errstring(ldb, __location__
4100 ": Failed to add msDS-LastKnownRDN "
4101 "string when deleting %s",
4102 ldb_dn_get_linearized(old_dn));
4103 talloc_free(tmp_ctx);
4106 msg->elements[el_count++].flags = LDB_FLAG_MOD_ADD;
4110 switch (next_deletion_state) {
4112 case OBJECT_RECYCLED:
4113 case OBJECT_TOMBSTONE:
4116 * MS-ADTS 3.1.1.5.5.1.1 Tombstone Requirements
4117 * describes what must be removed from a tombstone
4120 * MS-ADTS 3.1.1.5.5.1.3 Recycled-Object Requirements
4121 * describes what must be removed from a recycled
4127 * we also mark it as recycled, meaning this object can't be
4128 * recovered (we are stripping its attributes).
4129 * This is done only if we have this schema object of course ...
4130 * This behavior is identical to the one of Windows 2008R2 which
4131 * always set the isRecycled attribute, even if the recycle-bin is
4132 * not activated and what ever the forest level is.
4134 if (dsdb_attribute_by_lDAPDisplayName(schema, "isRecycled") != NULL) {
4135 ret = ldb_msg_add_string(msg, "isRecycled", "TRUE");
4136 if (ret != LDB_SUCCESS) {
4137 DEBUG(0,(__location__ ": Failed to add isRecycled string to the msg\n"));
4138 ldb_module_oom(module);
4139 talloc_free(tmp_ctx);
4142 msg->elements[el_count++].flags = LDB_FLAG_MOD_REPLACE;
4145 replmd_private = talloc_get_type(ldb_module_get_private(module),
4146 struct replmd_private);
4147 /* work out which of the old attributes we will be removing */
4148 for (i=0; i<old_msg->num_elements; i++) {
4149 const struct dsdb_attribute *sa;
4150 el = &old_msg->elements[i];
4151 sa = dsdb_attribute_by_lDAPDisplayName(schema, el->name);
4153 talloc_free(tmp_ctx);
4154 return LDB_ERR_OPERATIONS_ERROR;
4156 if (ldb_attr_cmp(el->name, rdn_name) == 0) {
4157 /* don't remove the rDN */
4160 if (sa->linkID & 1) {
4162 we have a backlink in this object
4163 that needs to be removed. We're not
4164 allowed to remove it directly
4165 however, so we instead setup a
4166 modify to delete the corresponding
4169 ret = replmd_delete_remove_link(module, schema,
4173 if (ret != LDB_SUCCESS) {
4174 const char *old_dn_str
4175 = ldb_dn_get_linearized(old_dn);
4176 ldb_asprintf_errstring(ldb,
4178 ": Failed to remove backlink of "
4179 "%s when deleting %s: %s",
4182 ldb_errstring(ldb));
4183 talloc_free(tmp_ctx);
4184 return LDB_ERR_OPERATIONS_ERROR;
4186 /* now we continue, which means we
4187 won't remove this backlink
4191 } else if (sa->linkID == 0) {
4192 if (ldb_attr_in_list(preserved_attrs, el->name)) {
4195 if (sa->searchFlags & SEARCH_FLAG_PRESERVEONDELETE) {
4200 * Ensure that we tell the modification to vanish any linked
4201 * attributes (not simply mark them as isDeleted = TRUE)
4203 dsdb_flags |= DSDB_REPLMD_VANISH_LINKS;
4205 ret = ldb_msg_add_empty(msg, el->name, LDB_FLAG_MOD_DELETE, &el);
4206 if (ret != LDB_SUCCESS) {
4207 talloc_free(tmp_ctx);
4208 ldb_module_oom(module);
4215 case OBJECT_DELETED:
4217 * MS-ADTS 3.1.1.5.5.1.2 Deleted-Object Requirements
4218 * describes what must be removed from a deleted
4222 ret = ldb_msg_add_empty(msg, "objectCategory", LDB_FLAG_MOD_REPLACE, NULL);
4223 if (ret != LDB_SUCCESS) {
4224 talloc_free(tmp_ctx);
4225 ldb_module_oom(module);
4229 ret = ldb_msg_add_empty(msg, "sAMAccountType", LDB_FLAG_MOD_REPLACE, NULL);
4230 if (ret != LDB_SUCCESS) {
4231 talloc_free(tmp_ctx);
4232 ldb_module_oom(module);
4242 if (deletion_state == OBJECT_NOT_DELETED) {
4243 const struct dsdb_attribute *sa;
4245 /* work out what the new rdn value is, for updating the
4246 rDN and name fields */
4247 new_rdn_value = ldb_dn_get_rdn_val(new_dn);
4248 if (new_rdn_value == NULL) {
4249 talloc_free(tmp_ctx);
4250 return ldb_operr(ldb);
4253 sa = dsdb_attribute_by_lDAPDisplayName(schema, rdn_name);
4255 talloc_free(tmp_ctx);
4256 return LDB_ERR_OPERATIONS_ERROR;
4259 ret = ldb_msg_add_value(msg, sa->lDAPDisplayName, new_rdn_value,
4261 if (ret != LDB_SUCCESS) {
4262 talloc_free(tmp_ctx);
4265 el->flags = LDB_FLAG_MOD_REPLACE;
4267 el = ldb_msg_find_element(old_msg, "name");
4269 ret = ldb_msg_add_value(msg, "name", new_rdn_value, &el);
4270 if (ret != LDB_SUCCESS) {
4271 talloc_free(tmp_ctx);
4274 el->flags = LDB_FLAG_MOD_REPLACE;
4279 * TODO: Per MS-DRSR 5.160 RemoveObj we should remove links directly, not as an originating update!
4284 * No matter what has happned with other renames, try again to
4285 * get this to be under the deleted DN.
4287 if (strcmp(ldb_dn_get_linearized(old_dn), ldb_dn_get_linearized(new_dn)) != 0) {
4288 /* now rename onto the new DN */
4289 ret = dsdb_module_rename(module, old_dn, new_dn, DSDB_FLAG_NEXT_MODULE, req);
4290 if (ret != LDB_SUCCESS){
4291 DEBUG(0,(__location__ ": Failed to rename object from '%s' to '%s' - %s\n",
4292 ldb_dn_get_linearized(old_dn),
4293 ldb_dn_get_linearized(new_dn),
4294 ldb_errstring(ldb)));
4295 talloc_free(tmp_ctx);
4301 ret = dsdb_module_modify(module, msg, dsdb_flags|DSDB_FLAG_OWN_MODULE, req);
4302 if (ret != LDB_SUCCESS) {
4303 ldb_asprintf_errstring(ldb, "replmd_delete: Failed to modify object %s in delete - %s",
4304 ldb_dn_get_linearized(old_dn), ldb_errstring(ldb));
4305 talloc_free(tmp_ctx);
4309 talloc_free(tmp_ctx);
4311 return ldb_module_done(req, NULL, NULL, LDB_SUCCESS);
4314 static int replmd_delete(struct ldb_module *module, struct ldb_request *req)
4316 return replmd_delete_internals(module, req, false);
4320 static int replmd_replicated_request_error(struct replmd_replicated_request *ar, int ret)
4325 static int replmd_replicated_request_werror(struct replmd_replicated_request *ar, WERROR status)
4327 int ret = LDB_ERR_OTHER;
4328 /* TODO: do some error mapping */
4330 /* Let the caller know the full WERROR */
4331 ar->objs->error = status;
4337 static struct replPropertyMetaData1 *
4338 replmd_replPropertyMetaData1_find_attid(struct replPropertyMetaDataBlob *md_blob,
4339 enum drsuapi_DsAttributeId attid)
4342 struct replPropertyMetaDataCtr1 *rpmd_ctr = &md_blob->ctr.ctr1;
4344 for (i = 0; i < rpmd_ctr->count; i++) {
4345 if (rpmd_ctr->array[i].attid == attid) {
4346 return &rpmd_ctr->array[i];
4354 return true if an update is newer than an existing entry
4355 see section 5.11 of MS-ADTS
4357 static bool replmd_update_is_newer(const struct GUID *current_invocation_id,
4358 const struct GUID *update_invocation_id,
4359 uint32_t current_version,
4360 uint32_t update_version,
4361 NTTIME current_change_time,
4362 NTTIME update_change_time)
4364 if (update_version != current_version) {
4365 return update_version > current_version;
4367 if (update_change_time != current_change_time) {
4368 return update_change_time > current_change_time;
4370 return GUID_compare(update_invocation_id, current_invocation_id) > 0;
4373 static bool replmd_replPropertyMetaData1_is_newer(struct replPropertyMetaData1 *cur_m,
4374 struct replPropertyMetaData1 *new_m)
4376 return replmd_update_is_newer(&cur_m->originating_invocation_id,
4377 &new_m->originating_invocation_id,
4380 cur_m->originating_change_time,
4381 new_m->originating_change_time);
4384 static bool replmd_replPropertyMetaData1_new_should_be_taken(uint32_t dsdb_repl_flags,
4385 struct replPropertyMetaData1 *cur_m,
4386 struct replPropertyMetaData1 *new_m)
4391 * If the new replPropertyMetaData entry for this attribute is
4392 * not provided (this happens in the case where we look for
4393 * ATTID_name, but the name was not changed), then the local
4394 * state is clearly still current, as the remote
4395 * server didn't send it due to being older the high watermark
4398 if (new_m == NULL) {
4402 if (dsdb_repl_flags & DSDB_REPL_FLAG_PRIORITISE_INCOMING) {
4404 * if we compare equal then do an
4405 * update. This is used when a client
4406 * asks for a FULL_SYNC, and can be
4407 * used to recover a corrupt
4410 * This call is a bit tricky, what we
4411 * are doing it turning the 'is_newer'
4412 * call into a 'not is older' by
4413 * swapping cur_m and new_m, and negating the
4416 cmp = !replmd_replPropertyMetaData1_is_newer(new_m,
4419 cmp = replmd_replPropertyMetaData1_is_newer(cur_m,
4429 static struct ldb_dn *replmd_conflict_dn(TALLOC_CTX *mem_ctx, struct ldb_dn *dn, struct GUID *guid)
4431 const struct ldb_val *rdn_val;
4432 const char *rdn_name;
4433 struct ldb_dn *new_dn;
4435 rdn_val = ldb_dn_get_rdn_val(dn);
4436 rdn_name = ldb_dn_get_rdn_name(dn);
4437 if (!rdn_val || !rdn_name) {
4441 new_dn = ldb_dn_copy(mem_ctx, dn);
4446 if (!ldb_dn_remove_child_components(new_dn, 1)) {
4450 if (!ldb_dn_add_child_fmt(new_dn, "%s=%s\\0ACNF:%s",
4452 ldb_dn_escape_value(new_dn, *rdn_val),
4453 GUID_string(new_dn, guid))) {
4462 perform a modify operation which sets the rDN and name attributes to
4463 their current values. This has the effect of changing these
4464 attributes to have been last updated by the current DC. This is
4465 needed to ensure that renames performed as part of conflict
4466 resolution are propogated to other DCs
4468 static int replmd_name_modify(struct replmd_replicated_request *ar,
4469 struct ldb_request *req, struct ldb_dn *dn)
4471 struct ldb_message *msg;
4472 const char *rdn_name;
4473 const struct ldb_val *rdn_val;
4474 const struct dsdb_attribute *rdn_attr;
4477 msg = ldb_msg_new(req);
4483 rdn_name = ldb_dn_get_rdn_name(dn);
4484 if (rdn_name == NULL) {
4488 /* normalize the rdn attribute name */
4489 rdn_attr = dsdb_attribute_by_lDAPDisplayName(ar->schema, rdn_name);
4490 if (rdn_attr == NULL) {
4493 rdn_name = rdn_attr->lDAPDisplayName;
4495 rdn_val = ldb_dn_get_rdn_val(dn);
4496 if (rdn_val == NULL) {
4500 if (ldb_msg_add_empty(msg, rdn_name, LDB_FLAG_MOD_REPLACE, NULL) != 0) {
4503 if (ldb_msg_add_value(msg, rdn_name, rdn_val, NULL) != 0) {
4506 if (ldb_msg_add_empty(msg, "name", LDB_FLAG_MOD_REPLACE, NULL) != 0) {
4509 if (ldb_msg_add_value(msg, "name", rdn_val, NULL) != 0) {
4513 ret = dsdb_module_modify(ar->module, msg, DSDB_FLAG_OWN_MODULE, req);
4514 if (ret != LDB_SUCCESS) {
4515 DEBUG(0,(__location__ ": Failed to modify rDN/name of conflict DN '%s' - %s",
4516 ldb_dn_get_linearized(dn),
4517 ldb_errstring(ldb_module_get_ctx(ar->module))));
4527 DEBUG(0,(__location__ ": Failed to setup modify rDN/name of conflict DN '%s'",
4528 ldb_dn_get_linearized(dn)));
4529 return LDB_ERR_OPERATIONS_ERROR;
4534 callback for conflict DN handling where we have renamed the incoming
4535 record. After renaming it, we need to ensure the change of name and
4536 rDN for the incoming record is seen as an originating update by this DC.
4538 This also handles updating lastKnownParent for entries sent to lostAndFound
4540 static int replmd_op_name_modify_callback(struct ldb_request *req, struct ldb_reply *ares)
4542 struct replmd_replicated_request *ar =
4543 talloc_get_type_abort(req->context, struct replmd_replicated_request);
4544 struct ldb_dn *conflict_dn = NULL;
4547 if (ares->error != LDB_SUCCESS) {
4548 /* call the normal callback for everything except success */
4549 return replmd_op_callback(req, ares);
4552 switch (req->operation) {
4554 conflict_dn = req->op.add.message->dn;
4557 conflict_dn = req->op.mod.message->dn;
4560 smb_panic("replmd_op_name_modify_callback called in unknown circumstances");
4563 /* perform a modify of the rDN and name of the record */
4564 ret = replmd_name_modify(ar, req, conflict_dn);
4565 if (ret != LDB_SUCCESS) {
4567 return replmd_op_callback(req, ares);
4570 if (ar->objs->objects[ar->index_current].last_known_parent) {
4571 struct ldb_message *msg = ldb_msg_new(req);
4573 ldb_module_oom(ar->module);
4574 return LDB_ERR_OPERATIONS_ERROR;
4577 msg->dn = req->op.add.message->dn;
4579 ret = ldb_msg_add_steal_string(msg, "lastKnownParent",
4580 ldb_dn_get_extended_linearized(msg, ar->objs->objects[ar->index_current].last_known_parent, 1));
4581 if (ret != LDB_SUCCESS) {
4582 DEBUG(0,(__location__ ": Failed to add lastKnownParent string to the msg\n"));
4583 ldb_module_oom(ar->module);
4586 msg->elements[0].flags = LDB_FLAG_MOD_REPLACE;
4588 ret = dsdb_module_modify(ar->module, msg, DSDB_FLAG_OWN_MODULE, req);
4589 if (ret != LDB_SUCCESS) {
4590 DEBUG(0,(__location__ ": Failed to modify lastKnownParent of lostAndFound DN '%s' - %s",
4591 ldb_dn_get_linearized(msg->dn),
4592 ldb_errstring(ldb_module_get_ctx(ar->module))));
4598 return replmd_op_callback(req, ares);
4602 callback for replmd_replicated_apply_add()
4603 This copes with the creation of conflict records in the case where
4604 the DN exists, but with a different objectGUID
4606 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))
4608 struct ldb_dn *conflict_dn;
4609 struct replmd_replicated_request *ar =
4610 talloc_get_type_abort(req->context, struct replmd_replicated_request);
4611 struct ldb_result *res;
4612 const char *attrs[] = { "replPropertyMetaData", "objectGUID", NULL };
4614 const struct ldb_val *omd_value;
4615 struct replPropertyMetaDataBlob omd, *rmd;
4616 enum ndr_err_code ndr_err;
4617 bool rename_incoming_record, rodc;
4618 struct replPropertyMetaData1 *rmd_name, *omd_name;
4619 struct ldb_message *msg;
4620 struct ldb_request *down_req = NULL;
4622 /* call the normal callback for success */
4623 if (ares->error == LDB_SUCCESS) {
4624 return callback(req, ares);
4628 * we have a conflict, and need to decide if we will keep the
4629 * new record or the old record
4632 msg = ar->objs->objects[ar->index_current].msg;
4633 conflict_dn = msg->dn;
4635 /* For failures other than conflicts, fail the whole operation here */
4636 if (ares->error != LDB_ERR_ENTRY_ALREADY_EXISTS) {
4637 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module), "Failed to locally apply remote add of %s: %s",
4638 ldb_dn_get_linearized(conflict_dn),
4639 ldb_errstring(ldb_module_get_ctx(ar->module)));
4641 return ldb_module_done(ar->req, NULL, NULL,
4642 LDB_ERR_OPERATIONS_ERROR);
4645 ret = samdb_rodc(ldb_module_get_ctx(ar->module), &rodc);
4646 if (ret != LDB_SUCCESS) {
4647 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)));
4648 return ldb_module_done(ar->req, NULL, NULL,
4649 LDB_ERR_OPERATIONS_ERROR);
4655 * We are on an RODC, or were a GC for this
4656 * partition, so we have to fail this until
4657 * someone who owns the partition sorts it
4660 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
4661 "Conflict adding object '%s' from incoming replication as we are read only for the partition. \n"
4662 " - We must fail the operation until a master for this partition resolves the conflict",
4663 ldb_dn_get_linearized(conflict_dn));
4668 * first we need the replPropertyMetaData attribute from the
4669 * local, conflicting record
4671 ret = dsdb_module_search_dn(ar->module, req, &res, conflict_dn,
4673 DSDB_FLAG_NEXT_MODULE |
4674 DSDB_SEARCH_SHOW_DELETED |
4675 DSDB_SEARCH_SHOW_RECYCLED, req);
4676 if (ret != LDB_SUCCESS) {
4677 DEBUG(0,(__location__ ": Unable to find object for conflicting record '%s'\n",
4678 ldb_dn_get_linearized(conflict_dn)));
4682 omd_value = ldb_msg_find_ldb_val(res->msgs[0], "replPropertyMetaData");
4683 if (omd_value == NULL) {
4684 DEBUG(0,(__location__ ": Unable to find replPropertyMetaData for conflicting record '%s'\n",
4685 ldb_dn_get_linearized(conflict_dn)));
4689 ndr_err = ndr_pull_struct_blob(omd_value, res->msgs[0], &omd,
4690 (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
4691 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
4692 DEBUG(0,(__location__ ": Failed to parse old replPropertyMetaData for %s\n",
4693 ldb_dn_get_linearized(conflict_dn)));
4697 rmd = ar->objs->objects[ar->index_current].meta_data;
4700 * we decide which is newer based on the RPMD on the name
4701 * attribute. See [MS-DRSR] ResolveNameConflict.
4703 * We expect omd_name to be present, as this is from a local
4704 * search, but while rmd_name should have been given to us by
4705 * the remote server, if it is missing we just prefer the
4707 * replmd_replPropertyMetaData1_new_should_be_taken()
4709 rmd_name = replmd_replPropertyMetaData1_find_attid(rmd, DRSUAPI_ATTID_name);
4710 omd_name = replmd_replPropertyMetaData1_find_attid(&omd, DRSUAPI_ATTID_name);
4712 DEBUG(0,(__location__ ": Failed to find name attribute in local LDB replPropertyMetaData for %s\n",
4713 ldb_dn_get_linearized(conflict_dn)));
4718 * Should we preserve the current record, and so rename the
4719 * incoming record to be a conflict?
4721 rename_incoming_record
4722 = !replmd_replPropertyMetaData1_new_should_be_taken(ar->objs->dsdb_repl_flags & DSDB_REPL_FLAG_PRIORITISE_INCOMING,
4723 omd_name, rmd_name);
4725 if (rename_incoming_record) {
4727 struct ldb_dn *new_dn;
4729 guid = samdb_result_guid(msg, "objectGUID");
4730 if (GUID_all_zero(&guid)) {
4731 DEBUG(0,(__location__ ": Failed to find objectGUID for conflicting incoming record %s\n",
4732 ldb_dn_get_linearized(conflict_dn)));
4735 new_dn = replmd_conflict_dn(req, conflict_dn, &guid);
4736 if (new_dn == NULL) {
4737 DEBUG(0,(__location__ ": Failed to form conflict DN for %s\n",
4738 ldb_dn_get_linearized(conflict_dn)));
4742 DEBUG(2,(__location__ ": Resolving conflict record via incoming rename '%s' -> '%s'\n",
4743 ldb_dn_get_linearized(conflict_dn), ldb_dn_get_linearized(new_dn)));
4745 /* re-submit the request, but with the new DN */
4746 callback = replmd_op_name_modify_callback;
4749 /* we are renaming the existing record */
4751 struct ldb_dn *new_dn;
4753 guid = samdb_result_guid(res->msgs[0], "objectGUID");
4754 if (GUID_all_zero(&guid)) {
4755 DEBUG(0,(__location__ ": Failed to find objectGUID for existing conflict record %s\n",
4756 ldb_dn_get_linearized(conflict_dn)));
4760 new_dn = replmd_conflict_dn(req, conflict_dn, &guid);
4761 if (new_dn == NULL) {
4762 DEBUG(0,(__location__ ": Failed to form conflict DN for %s\n",
4763 ldb_dn_get_linearized(conflict_dn)));
4767 DEBUG(2,(__location__ ": Resolving conflict record via existing-record rename '%s' -> '%s'\n",
4768 ldb_dn_get_linearized(conflict_dn), ldb_dn_get_linearized(new_dn)));
4770 ret = dsdb_module_rename(ar->module, conflict_dn, new_dn,
4771 DSDB_FLAG_OWN_MODULE, req);
4772 if (ret != LDB_SUCCESS) {
4773 DEBUG(0,(__location__ ": Failed to rename conflict dn '%s' to '%s' - %s\n",
4774 ldb_dn_get_linearized(conflict_dn),
4775 ldb_dn_get_linearized(new_dn),
4776 ldb_errstring(ldb_module_get_ctx(ar->module))));
4781 * now we need to ensure that the rename is seen as an
4782 * originating update. We do that with a modify.
4784 ret = replmd_name_modify(ar, req, new_dn);
4785 if (ret != LDB_SUCCESS) {
4789 DEBUG(2,(__location__ ": With conflicting record renamed, re-apply replicated creation of '%s'\n",
4790 ldb_dn_get_linearized(req->op.add.message->dn)));
4793 ret = ldb_build_add_req(&down_req,
4794 ldb_module_get_ctx(ar->module),
4801 if (ret != LDB_SUCCESS) {
4804 LDB_REQ_SET_LOCATION(down_req);
4806 /* current partition control needed by "repmd_op_callback" */
4807 ret = ldb_request_add_control(down_req,
4808 DSDB_CONTROL_CURRENT_PARTITION_OID,
4810 if (ret != LDB_SUCCESS) {
4811 return replmd_replicated_request_error(ar, ret);
4814 if (ar->objs->dsdb_repl_flags & DSDB_REPL_FLAG_PARTIAL_REPLICA) {
4815 /* this tells the partition module to make it a
4816 partial replica if creating an NC */
4817 ret = ldb_request_add_control(down_req,
4818 DSDB_CONTROL_PARTIAL_REPLICA,
4820 if (ret != LDB_SUCCESS) {
4821 return replmd_replicated_request_error(ar, ret);
4826 * Finally we re-run the add, otherwise the new record won't
4827 * exist, as we are here because of that exact failure!
4829 return ldb_next_request(ar->module, down_req);
4832 /* on failure make the caller get the error. This means
4833 * replication will stop with an error, but there is not much
4836 return ldb_module_done(ar->req, NULL, NULL,
4841 callback for replmd_replicated_apply_add()
4842 This copes with the creation of conflict records in the case where
4843 the DN exists, but with a different objectGUID
4845 static int replmd_op_add_callback(struct ldb_request *req, struct ldb_reply *ares)
4847 struct replmd_replicated_request *ar =
4848 talloc_get_type_abort(req->context, struct replmd_replicated_request);
4850 if (ar->objs->objects[ar->index_current].last_known_parent) {
4851 /* This is like a conflict DN, where we put the object in LostAndFound
4852 see MS-DRSR 4.1.10.6.10 FindBestParentObject */
4853 return replmd_op_possible_conflict_callback(req, ares, replmd_op_name_modify_callback);
4856 return replmd_op_possible_conflict_callback(req, ares, replmd_op_callback);
4860 this is called when a new object comes in over DRS
4862 static int replmd_replicated_apply_add(struct replmd_replicated_request *ar)
4864 struct ldb_context *ldb;
4865 struct ldb_request *change_req;
4866 enum ndr_err_code ndr_err;
4867 struct ldb_message *msg;
4868 struct replPropertyMetaDataBlob *md;
4869 struct ldb_val md_value;
4872 bool remote_isDeleted = false;
4875 time_t t = time(NULL);
4876 const struct ldb_val *rdn_val;
4877 struct replmd_private *replmd_private =
4878 talloc_get_type(ldb_module_get_private(ar->module),
4879 struct replmd_private);
4880 unix_to_nt_time(&now, t);
4882 ldb = ldb_module_get_ctx(ar->module);
4883 msg = ar->objs->objects[ar->index_current].msg;
4884 md = ar->objs->objects[ar->index_current].meta_data;
4885 is_schema_nc = ldb_dn_compare_base(replmd_private->schema_dn, msg->dn) == 0;
4887 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &ar->seq_num);
4888 if (ret != LDB_SUCCESS) {
4889 return replmd_replicated_request_error(ar, ret);
4892 ret = dsdb_msg_add_guid(msg,
4893 &ar->objs->objects[ar->index_current].object_guid,
4895 if (ret != LDB_SUCCESS) {
4896 return replmd_replicated_request_error(ar, ret);
4899 ret = ldb_msg_add_string(msg, "whenChanged", ar->objs->objects[ar->index_current].when_changed);
4900 if (ret != LDB_SUCCESS) {
4901 return replmd_replicated_request_error(ar, ret);
4904 ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNCreated", ar->seq_num);
4905 if (ret != LDB_SUCCESS) {
4906 return replmd_replicated_request_error(ar, ret);
4909 ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNChanged", ar->seq_num);
4910 if (ret != LDB_SUCCESS) {
4911 return replmd_replicated_request_error(ar, ret);
4914 /* remove any message elements that have zero values */
4915 for (i=0; i<msg->num_elements; i++) {
4916 struct ldb_message_element *el = &msg->elements[i];
4918 if (el->num_values == 0) {
4919 if (ldb_attr_cmp(msg->elements[i].name, "objectClass") == 0) {
4920 ldb_asprintf_errstring(ldb, __location__
4921 ": empty objectClass sent on %s, aborting replication\n",
4922 ldb_dn_get_linearized(msg->dn));
4923 return replmd_replicated_request_error(ar, LDB_ERR_OBJECT_CLASS_VIOLATION);
4926 DEBUG(4,(__location__ ": Removing attribute %s with num_values==0\n",
4928 memmove(el, el+1, sizeof(*el)*(msg->num_elements - (i+1)));
4929 msg->num_elements--;
4936 struct GUID_txt_buf guid_txt;
4938 char *s = ldb_ldif_message_string(ldb, ar, LDB_CHANGETYPE_ADD, msg);
4939 DEBUG(4, ("DRS replication add message of %s:\n%s\n",
4940 GUID_buf_string(&ar->objs->objects[ar->index_current].object_guid, &guid_txt),
4945 remote_isDeleted = ldb_msg_find_attr_as_bool(msg,
4946 "isDeleted", false);
4949 * the meta data array is already sorted by the caller, except
4950 * for the RDN, which needs to be added.
4954 rdn_val = ldb_dn_get_rdn_val(msg->dn);
4955 ret = replmd_update_rpmd_rdn_attr(ldb, msg, rdn_val, NULL,
4956 md, ar, now, is_schema_nc);
4957 if (ret != LDB_SUCCESS) {
4958 ldb_asprintf_errstring(ldb, "%s: error during DRS repl ADD: %s", __func__, ldb_errstring(ldb));
4959 return replmd_replicated_request_error(ar, ret);
4962 ret = replmd_replPropertyMetaDataCtr1_sort_and_verify(ldb, &md->ctr.ctr1, msg->dn);
4963 if (ret != LDB_SUCCESS) {
4964 ldb_asprintf_errstring(ldb, "%s: error during DRS repl ADD: %s", __func__, ldb_errstring(ldb));
4965 return replmd_replicated_request_error(ar, ret);
4968 for (i=0; i < md->ctr.ctr1.count; i++) {
4969 md->ctr.ctr1.array[i].local_usn = ar->seq_num;
4971 ndr_err = ndr_push_struct_blob(&md_value, msg, md,
4972 (ndr_push_flags_fn_t)ndr_push_replPropertyMetaDataBlob);
4973 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
4974 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
4975 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
4977 ret = ldb_msg_add_value(msg, "replPropertyMetaData", &md_value, NULL);
4978 if (ret != LDB_SUCCESS) {
4979 return replmd_replicated_request_error(ar, ret);
4982 replmd_ldb_message_sort(msg, ar->schema);
4984 if (!remote_isDeleted) {
4985 ret = dsdb_module_schedule_sd_propagation(ar->module,
4986 ar->objs->partition_dn,
4988 if (ret != LDB_SUCCESS) {
4989 return replmd_replicated_request_error(ar, ret);
4993 ar->isDeleted = remote_isDeleted;
4995 ret = ldb_build_add_req(&change_req,
5001 replmd_op_add_callback,
5003 LDB_REQ_SET_LOCATION(change_req);
5004 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
5006 /* current partition control needed by "repmd_op_callback" */
5007 ret = ldb_request_add_control(change_req,
5008 DSDB_CONTROL_CURRENT_PARTITION_OID,
5010 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
5012 if (ar->objs->dsdb_repl_flags & DSDB_REPL_FLAG_PARTIAL_REPLICA) {
5013 /* this tells the partition module to make it a
5014 partial replica if creating an NC */
5015 ret = ldb_request_add_control(change_req,
5016 DSDB_CONTROL_PARTIAL_REPLICA,
5018 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
5021 return ldb_next_request(ar->module, change_req);
5024 static int replmd_replicated_apply_search_for_parent_callback(struct ldb_request *req,
5025 struct ldb_reply *ares)
5027 struct replmd_replicated_request *ar = talloc_get_type(req->context,
5028 struct replmd_replicated_request);
5032 return ldb_module_done(ar->req, NULL, NULL,
5033 LDB_ERR_OPERATIONS_ERROR);
5037 * The error NO_SUCH_OBJECT is not expected, unless the search
5038 * base is the partition DN, and that case doesn't happen here
5039 * because then we wouldn't get a parent_guid_value in any
5042 if (ares->error != LDB_SUCCESS) {
5043 return ldb_module_done(ar->req, ares->controls,
5044 ares->response, ares->error);
5047 switch (ares->type) {
5048 case LDB_REPLY_ENTRY:
5050 struct ldb_message *parent_msg = ares->message;
5051 struct ldb_message *msg = ar->objs->objects[ar->index_current].msg;
5052 struct ldb_dn *parent_dn;
5055 if (!ldb_msg_check_string_attribute(msg, "isDeleted", "TRUE")
5056 && ldb_msg_check_string_attribute(parent_msg, "isDeleted", "TRUE")) {
5057 /* Per MS-DRSR 4.1.10.6.10
5058 * FindBestParentObject we need to move this
5059 * new object under a deleted object to
5061 struct ldb_dn *nc_root;
5063 ret = dsdb_find_nc_root(ldb_module_get_ctx(ar->module), msg, msg->dn, &nc_root);
5064 if (ret == LDB_ERR_NO_SUCH_OBJECT) {
5065 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
5066 "No suitable NC root found for %s. "
5067 "We need to move this object because parent object %s "
5068 "is deleted, but this object is not.",
5069 ldb_dn_get_linearized(msg->dn),
5070 ldb_dn_get_linearized(parent_msg->dn));
5071 return ldb_module_done(ar->req, NULL, NULL, LDB_ERR_OPERATIONS_ERROR);
5072 } else if (ret != LDB_SUCCESS) {
5073 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
5074 "Unable to find NC root for %s: %s. "
5075 "We need to move this object because parent object %s "
5076 "is deleted, but this object is not.",
5077 ldb_dn_get_linearized(msg->dn),
5078 ldb_errstring(ldb_module_get_ctx(ar->module)),
5079 ldb_dn_get_linearized(parent_msg->dn));
5080 return ldb_module_done(ar->req, NULL, NULL, LDB_ERR_OPERATIONS_ERROR);
5083 ret = dsdb_wellknown_dn(ldb_module_get_ctx(ar->module), msg,
5085 DS_GUID_LOSTANDFOUND_CONTAINER,
5087 if (ret != LDB_SUCCESS) {
5088 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
5089 "Unable to find LostAndFound Container for %s "
5090 "in partition %s: %s. "
5091 "We need to move this object because parent object %s "
5092 "is deleted, but this object is not.",
5093 ldb_dn_get_linearized(msg->dn), ldb_dn_get_linearized(nc_root),
5094 ldb_errstring(ldb_module_get_ctx(ar->module)),
5095 ldb_dn_get_linearized(parent_msg->dn));
5096 return ldb_module_done(ar->req, NULL, NULL, LDB_ERR_OPERATIONS_ERROR);
5098 ar->objs->objects[ar->index_current].last_known_parent
5099 = talloc_steal(ar->objs->objects[ar->index_current].msg, parent_msg->dn);
5103 = talloc_steal(ar->objs->objects[ar->index_current].msg, parent_msg->dn);
5106 ar->objs->objects[ar->index_current].local_parent_dn = parent_dn;
5108 comp_num = ldb_dn_get_comp_num(msg->dn);
5110 if (!ldb_dn_remove_base_components(msg->dn, comp_num - 1)) {
5112 return ldb_module_done(ar->req, NULL, NULL, ldb_module_operr(ar->module));
5115 if (!ldb_dn_add_base(msg->dn, parent_dn)) {
5117 return ldb_module_done(ar->req, NULL, NULL, ldb_module_operr(ar->module));
5121 case LDB_REPLY_REFERRAL:
5122 /* we ignore referrals */
5125 case LDB_REPLY_DONE:
5127 if (ar->objs->objects[ar->index_current].local_parent_dn == NULL) {
5128 struct GUID_txt_buf str_buf;
5129 if (ar->search_msg != NULL) {
5130 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
5131 "No parent with GUID %s found for object locally known as %s",
5132 GUID_buf_string(ar->objs->objects[ar->index_current].parent_guid, &str_buf),
5133 ldb_dn_get_linearized(ar->search_msg->dn));
5135 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
5136 "No parent with GUID %s found for object remotely known as %s",
5137 GUID_buf_string(ar->objs->objects[ar->index_current].parent_guid, &str_buf),
5138 ldb_dn_get_linearized(ar->objs->objects[ar->index_current].msg->dn));
5142 * This error code is really important, as it
5143 * is the flag back to the callers to retry
5144 * this with DRSUAPI_DRS_GET_ANC, and so get
5145 * the parent objects before the child
5148 return ldb_module_done(ar->req, NULL, NULL,
5149 replmd_replicated_request_werror(ar, WERR_DS_DRA_MISSING_PARENT));
5152 if (ar->search_msg != NULL) {
5153 ret = replmd_replicated_apply_merge(ar);
5155 ret = replmd_replicated_apply_add(ar);
5157 if (ret != LDB_SUCCESS) {
5158 return ldb_module_done(ar->req, NULL, NULL, ret);
5167 * Look for the parent object, so we put the new object in the right
5168 * place This is akin to NameObject in MS-DRSR - this routine and the
5169 * callbacks find the right parent name, and correct name for this
5173 static int replmd_replicated_apply_search_for_parent(struct replmd_replicated_request *ar)
5175 struct ldb_context *ldb;
5179 struct ldb_request *search_req;
5180 static const char *attrs[] = {"isDeleted", NULL};
5181 struct GUID_txt_buf guid_str_buf;
5183 ldb = ldb_module_get_ctx(ar->module);
5185 if (ar->objs->objects[ar->index_current].parent_guid == NULL) {
5186 if (ar->search_msg != NULL) {
5187 return replmd_replicated_apply_merge(ar);
5189 return replmd_replicated_apply_add(ar);
5193 tmp_str = GUID_buf_string(ar->objs->objects[ar->index_current].parent_guid,
5196 filter = talloc_asprintf(ar, "(objectGUID=%s)", tmp_str);
5197 if (!filter) return replmd_replicated_request_werror(ar, WERR_NOT_ENOUGH_MEMORY);
5199 ret = ldb_build_search_req(&search_req,
5202 ar->objs->partition_dn,
5208 replmd_replicated_apply_search_for_parent_callback,
5210 LDB_REQ_SET_LOCATION(search_req);
5212 ret = dsdb_request_add_controls(search_req,
5213 DSDB_SEARCH_SHOW_RECYCLED|
5214 DSDB_SEARCH_SHOW_DELETED|
5215 DSDB_SEARCH_SHOW_EXTENDED_DN);
5216 if (ret != LDB_SUCCESS) {
5220 return ldb_next_request(ar->module, search_req);
5224 handle renames that come in over DRS replication
5226 static int replmd_replicated_handle_rename(struct replmd_replicated_request *ar,
5227 struct ldb_message *msg,
5228 struct ldb_request *parent,
5232 TALLOC_CTX *tmp_ctx = talloc_new(msg);
5233 struct ldb_result *res;
5234 struct ldb_dn *conflict_dn;
5235 const char *attrs[] = { "replPropertyMetaData", "objectGUID", NULL };
5236 const struct ldb_val *omd_value;
5237 struct replPropertyMetaDataBlob omd, *rmd;
5238 enum ndr_err_code ndr_err;
5239 bool rename_incoming_record, rodc;
5240 struct replPropertyMetaData1 *rmd_name, *omd_name;
5241 struct ldb_dn *new_dn;
5244 DEBUG(4,("replmd_replicated_request rename %s => %s\n",
5245 ldb_dn_get_linearized(ar->search_msg->dn),
5246 ldb_dn_get_linearized(msg->dn)));
5249 ret = dsdb_module_rename(ar->module, ar->search_msg->dn, msg->dn,
5250 DSDB_FLAG_NEXT_MODULE, ar->req);
5251 if (ret == LDB_SUCCESS) {
5252 talloc_free(tmp_ctx);
5257 if (ret != LDB_ERR_ENTRY_ALREADY_EXISTS) {
5258 talloc_free(tmp_ctx);
5259 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module), "Failed to locally apply remote rename from %s to %s: %s",
5260 ldb_dn_get_linearized(ar->search_msg->dn),
5261 ldb_dn_get_linearized(msg->dn),
5262 ldb_errstring(ldb_module_get_ctx(ar->module)));
5266 ret = samdb_rodc(ldb_module_get_ctx(ar->module), &rodc);
5267 if (ret != LDB_SUCCESS) {
5268 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
5269 "Failed to determine if we are an RODC when attempting to form conflict DN: %s",
5270 ldb_errstring(ldb_module_get_ctx(ar->module)));
5271 return LDB_ERR_OPERATIONS_ERROR;
5274 * we have a conflict, and need to decide if we will keep the
5275 * new record or the old record
5278 conflict_dn = msg->dn;
5282 * We are on an RODC, or were a GC for this
5283 * partition, so we have to fail this until
5284 * someone who owns the partition sorts it
5287 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
5288 "Conflict adding object '%s' from incoming replication but we are read only for the partition. \n"
5289 " - We must fail the operation until a master for this partition resolves the conflict",
5290 ldb_dn_get_linearized(conflict_dn));
5295 * first we need the replPropertyMetaData attribute from the
5298 ret = dsdb_module_search_dn(ar->module, tmp_ctx, &res, conflict_dn,
5300 DSDB_FLAG_NEXT_MODULE |
5301 DSDB_SEARCH_SHOW_DELETED |
5302 DSDB_SEARCH_SHOW_RECYCLED, ar->req);
5303 if (ret != LDB_SUCCESS) {
5304 DEBUG(0,(__location__ ": Unable to find object for conflicting record '%s'\n",
5305 ldb_dn_get_linearized(conflict_dn)));
5309 omd_value = ldb_msg_find_ldb_val(res->msgs[0], "replPropertyMetaData");
5310 if (omd_value == NULL) {
5311 DEBUG(0,(__location__ ": Unable to find replPropertyMetaData for conflicting record '%s'\n",
5312 ldb_dn_get_linearized(conflict_dn)));
5316 ndr_err = ndr_pull_struct_blob(omd_value, res->msgs[0], &omd,
5317 (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
5318 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
5319 DEBUG(0,(__location__ ": Failed to parse old replPropertyMetaData for %s\n",
5320 ldb_dn_get_linearized(conflict_dn)));
5324 rmd = ar->objs->objects[ar->index_current].meta_data;
5327 * we decide which is newer based on the RPMD on the name
5328 * attribute. See [MS-DRSR] ResolveNameConflict.
5330 * We expect omd_name to be present, as this is from a local
5331 * search, but while rmd_name should have been given to us by
5332 * the remote server, if it is missing we just prefer the
5334 * replmd_replPropertyMetaData1_new_should_be_taken()
5336 rmd_name = replmd_replPropertyMetaData1_find_attid(rmd, DRSUAPI_ATTID_name);
5337 omd_name = replmd_replPropertyMetaData1_find_attid(&omd, DRSUAPI_ATTID_name);
5339 DEBUG(0,(__location__ ": Failed to find name attribute in local LDB replPropertyMetaData for %s\n",
5340 ldb_dn_get_linearized(conflict_dn)));
5345 * Should we preserve the current record, and so rename the
5346 * incoming record to be a conflict?
5348 rename_incoming_record =
5349 !replmd_replPropertyMetaData1_new_should_be_taken(
5350 ar->objs->dsdb_repl_flags & DSDB_REPL_FLAG_PRIORITISE_INCOMING,
5351 omd_name, rmd_name);
5353 if (rename_incoming_record) {
5355 new_dn = replmd_conflict_dn(msg, msg->dn,
5356 &ar->objs->objects[ar->index_current].object_guid);
5357 if (new_dn == NULL) {
5358 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
5359 "Failed to form conflict DN for %s\n",
5360 ldb_dn_get_linearized(msg->dn));
5362 return replmd_replicated_request_werror(ar, WERR_NOT_ENOUGH_MEMORY);
5365 ret = dsdb_module_rename(ar->module, ar->search_msg->dn, new_dn,
5366 DSDB_FLAG_NEXT_MODULE, ar->req);
5367 if (ret != LDB_SUCCESS) {
5368 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
5369 "Failed to rename incoming conflicting dn '%s' (was '%s') to '%s' - %s\n",
5370 ldb_dn_get_linearized(conflict_dn),
5371 ldb_dn_get_linearized(ar->search_msg->dn),
5372 ldb_dn_get_linearized(new_dn),
5373 ldb_errstring(ldb_module_get_ctx(ar->module)));
5374 return replmd_replicated_request_werror(ar, WERR_DS_DRA_DB_ERROR);
5382 /* we are renaming the existing record */
5384 guid = samdb_result_guid(res->msgs[0], "objectGUID");
5385 if (GUID_all_zero(&guid)) {
5386 DEBUG(0,(__location__ ": Failed to find objectGUID for existing conflict record %s\n",
5387 ldb_dn_get_linearized(conflict_dn)));
5391 new_dn = replmd_conflict_dn(tmp_ctx, conflict_dn, &guid);
5392 if (new_dn == NULL) {
5393 DEBUG(0,(__location__ ": Failed to form conflict DN for %s\n",
5394 ldb_dn_get_linearized(conflict_dn)));
5398 DEBUG(2,(__location__ ": Resolving conflict record via existing-record rename '%s' -> '%s'\n",
5399 ldb_dn_get_linearized(conflict_dn), ldb_dn_get_linearized(new_dn)));
5401 ret = dsdb_module_rename(ar->module, conflict_dn, new_dn,
5402 DSDB_FLAG_OWN_MODULE, ar->req);
5403 if (ret != LDB_SUCCESS) {
5404 DEBUG(0,(__location__ ": Failed to rename conflict dn '%s' to '%s' - %s\n",
5405 ldb_dn_get_linearized(conflict_dn),
5406 ldb_dn_get_linearized(new_dn),
5407 ldb_errstring(ldb_module_get_ctx(ar->module))));
5412 * now we need to ensure that the rename is seen as an
5413 * originating update. We do that with a modify.
5415 ret = replmd_name_modify(ar, ar->req, new_dn);
5416 if (ret != LDB_SUCCESS) {
5420 DEBUG(2,(__location__ ": With conflicting record renamed, re-apply replicated rename '%s' -> '%s'\n",
5421 ldb_dn_get_linearized(ar->search_msg->dn),
5422 ldb_dn_get_linearized(msg->dn)));
5425 ret = dsdb_module_rename(ar->module, ar->search_msg->dn, msg->dn,
5426 DSDB_FLAG_NEXT_MODULE, ar->req);
5427 if (ret != LDB_SUCCESS) {
5428 DEBUG(0,(__location__ ": After conflict resolution, failed to rename dn '%s' to '%s' - %s\n",
5429 ldb_dn_get_linearized(ar->search_msg->dn),
5430 ldb_dn_get_linearized(msg->dn),
5431 ldb_errstring(ldb_module_get_ctx(ar->module))));
5437 * On failure make the caller get the error
5438 * This means replication will stop with an error,
5439 * but there is not much else we can do. In the
5440 * LDB_ERR_ENTRY_ALREADY_EXISTS case this is exactly what is
5444 talloc_free(tmp_ctx);
5449 static int replmd_replicated_apply_merge(struct replmd_replicated_request *ar)
5451 struct ldb_context *ldb;
5452 struct ldb_request *change_req;
5453 enum ndr_err_code ndr_err;
5454 struct ldb_message *msg;
5455 struct replPropertyMetaDataBlob *rmd;
5456 struct replPropertyMetaDataBlob omd;
5457 const struct ldb_val *omd_value;
5458 struct replPropertyMetaDataBlob nmd;
5459 struct ldb_val nmd_value;
5460 struct GUID remote_parent_guid;
5463 unsigned int removed_attrs = 0;
5465 int (*callback)(struct ldb_request *req, struct ldb_reply *ares) = replmd_op_callback;
5466 bool isDeleted = false;
5467 bool local_isDeleted = false;
5468 bool remote_isDeleted = false;
5469 bool take_remote_isDeleted = false;
5470 bool sd_updated = false;
5471 bool renamed = false;
5472 bool is_schema_nc = false;
5474 const struct ldb_val *old_rdn, *new_rdn;
5475 struct replmd_private *replmd_private =
5476 talloc_get_type(ldb_module_get_private(ar->module),
5477 struct replmd_private);
5479 time_t t = time(NULL);
5480 unix_to_nt_time(&now, t);
5482 ldb = ldb_module_get_ctx(ar->module);
5483 msg = ar->objs->objects[ar->index_current].msg;
5485 is_schema_nc = ldb_dn_compare_base(replmd_private->schema_dn, msg->dn) == 0;
5487 rmd = ar->objs->objects[ar->index_current].meta_data;
5491 /* find existing meta data */
5492 omd_value = ldb_msg_find_ldb_val(ar->search_msg, "replPropertyMetaData");
5494 ndr_err = ndr_pull_struct_blob(omd_value, ar, &omd,
5495 (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
5496 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
5497 nt_status = ndr_map_error2ntstatus(ndr_err);
5498 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
5501 if (omd.version != 1) {
5502 return replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
5507 struct GUID_txt_buf guid_txt;
5509 char *s = ldb_ldif_message_string(ldb, ar, LDB_CHANGETYPE_MODIFY, msg);
5510 DEBUG(5, ("Initial DRS replication modify message of %s is:\n%s\n"
5513 GUID_buf_string(&ar->objs->objects[ar->index_current].object_guid, &guid_txt),
5515 ndr_print_struct_string(s,
5516 (ndr_print_fn_t)ndr_print_replPropertyMetaDataBlob,
5517 "existing replPropertyMetaData",
5519 ndr_print_struct_string(s,
5520 (ndr_print_fn_t)ndr_print_replPropertyMetaDataBlob,
5521 "incoming replPropertyMetaData",
5526 local_isDeleted = ldb_msg_find_attr_as_bool(ar->search_msg,
5527 "isDeleted", false);
5528 remote_isDeleted = ldb_msg_find_attr_as_bool(msg,
5529 "isDeleted", false);
5532 * Fill in the remote_parent_guid with the GUID or an all-zero
5535 if (ar->objs->objects[ar->index_current].parent_guid != NULL) {
5536 remote_parent_guid = *ar->objs->objects[ar->index_current].parent_guid;
5538 remote_parent_guid = GUID_zero();
5542 * To ensure we follow a complex rename chain around, we have
5543 * to confirm that the DN is the same (mostly to confirm the
5544 * RDN) and the parentGUID is the same.
5546 * This ensures we keep things under the correct parent, which
5547 * replmd_replicated_handle_rename() will do.
5550 if (strcmp(ldb_dn_get_linearized(msg->dn), ldb_dn_get_linearized(ar->search_msg->dn)) == 0
5551 && GUID_equal(&remote_parent_guid, &ar->local_parent_guid)) {
5555 * handle renames, even just by case that come in over
5556 * DRS. Changes in the parent DN don't hit us here,
5557 * because the search for a parent will clean up those
5560 * We also have already filtered out the case where
5561 * the peer has an older name to what we have (see
5562 * replmd_replicated_apply_search_callback())
5564 ret = replmd_replicated_handle_rename(ar, msg, ar->req, &renamed);
5567 if (ret != LDB_SUCCESS) {
5568 ldb_debug(ldb, LDB_DEBUG_FATAL,
5569 "replmd_replicated_request rename %s => %s failed - %s\n",
5570 ldb_dn_get_linearized(ar->search_msg->dn),
5571 ldb_dn_get_linearized(msg->dn),
5572 ldb_errstring(ldb));
5573 return replmd_replicated_request_werror(ar, WERR_DS_DRA_DB_ERROR);
5576 if (renamed == true) {
5578 * Set the callback to one that will fix up the name
5579 * metadata on the new conflict DN
5581 callback = replmd_op_name_modify_callback;
5586 nmd.ctr.ctr1.count = omd.ctr.ctr1.count + rmd->ctr.ctr1.count;
5587 nmd.ctr.ctr1.array = talloc_array(ar,
5588 struct replPropertyMetaData1,
5589 nmd.ctr.ctr1.count);
5590 if (!nmd.ctr.ctr1.array) return replmd_replicated_request_werror(ar, WERR_NOT_ENOUGH_MEMORY);
5592 /* first copy the old meta data */
5593 for (i=0; i < omd.ctr.ctr1.count; i++) {
5594 nmd.ctr.ctr1.array[ni] = omd.ctr.ctr1.array[i];
5599 /* now merge in the new meta data */
5600 for (i=0; i < rmd->ctr.ctr1.count; i++) {
5603 for (j=0; j < ni; j++) {
5606 if (rmd->ctr.ctr1.array[i].attid != nmd.ctr.ctr1.array[j].attid) {
5610 cmp = replmd_replPropertyMetaData1_new_should_be_taken(
5611 ar->objs->dsdb_repl_flags,
5612 &nmd.ctr.ctr1.array[j],
5613 &rmd->ctr.ctr1.array[i]);
5615 /* replace the entry */
5616 nmd.ctr.ctr1.array[j] = rmd->ctr.ctr1.array[i];
5617 if (ar->seq_num == 0) {
5618 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &ar->seq_num);
5619 if (ret != LDB_SUCCESS) {
5620 return replmd_replicated_request_error(ar, ret);
5623 nmd.ctr.ctr1.array[j].local_usn = ar->seq_num;
5624 switch (nmd.ctr.ctr1.array[j].attid) {
5625 case DRSUAPI_ATTID_ntSecurityDescriptor:
5628 case DRSUAPI_ATTID_isDeleted:
5629 take_remote_isDeleted = true;
5638 if (rmd->ctr.ctr1.array[i].attid != DRSUAPI_ATTID_instanceType) {
5639 DEBUG(3,("Discarding older DRS attribute update to %s on %s from %s\n",
5640 msg->elements[i-removed_attrs].name,
5641 ldb_dn_get_linearized(msg->dn),
5642 GUID_string(ar, &rmd->ctr.ctr1.array[i].originating_invocation_id)));
5645 /* we don't want to apply this change so remove the attribute */
5646 ldb_msg_remove_element(msg, &msg->elements[i-removed_attrs]);
5653 if (found) continue;
5655 nmd.ctr.ctr1.array[ni] = rmd->ctr.ctr1.array[i];
5656 if (ar->seq_num == 0) {
5657 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &ar->seq_num);
5658 if (ret != LDB_SUCCESS) {
5659 return replmd_replicated_request_error(ar, ret);
5662 nmd.ctr.ctr1.array[ni].local_usn = ar->seq_num;
5663 switch (nmd.ctr.ctr1.array[ni].attid) {
5664 case DRSUAPI_ATTID_ntSecurityDescriptor:
5667 case DRSUAPI_ATTID_isDeleted:
5668 take_remote_isDeleted = true;
5677 * finally correct the size of the meta_data array
5679 nmd.ctr.ctr1.count = ni;
5681 new_rdn = ldb_dn_get_rdn_val(msg->dn);
5682 old_rdn = ldb_dn_get_rdn_val(ar->search_msg->dn);
5685 ret = replmd_update_rpmd_rdn_attr(ldb, msg, new_rdn, old_rdn,
5686 &nmd, ar, now, is_schema_nc);
5687 if (ret != LDB_SUCCESS) {
5688 ldb_asprintf_errstring(ldb, "%s: error during DRS repl merge: %s", __func__, ldb_errstring(ldb));
5689 return replmd_replicated_request_error(ar, ret);
5693 * sort the new meta data array
5695 ret = replmd_replPropertyMetaDataCtr1_sort_and_verify(ldb, &nmd.ctr.ctr1, msg->dn);
5696 if (ret != LDB_SUCCESS) {
5697 ldb_asprintf_errstring(ldb, "%s: error during DRS repl merge: %s", __func__, ldb_errstring(ldb));
5702 * Work out if this object is deleted, so we can prune any extra attributes. See MS-DRSR 4.1.10.6.9
5705 * This also controls SD propagation below
5707 if (take_remote_isDeleted) {
5708 isDeleted = remote_isDeleted;
5710 isDeleted = local_isDeleted;
5713 ar->isDeleted = isDeleted;
5716 * check if some replicated attributes left, otherwise skip the ldb_modify() call
5718 if (msg->num_elements == 0) {
5719 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_replicated_apply_merge[%u]: skip replace\n",
5722 return replmd_replicated_apply_isDeleted(ar);
5725 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_replicated_apply_merge[%u]: replace %u attributes\n",
5726 ar->index_current, msg->num_elements);
5732 if (sd_updated && !isDeleted) {
5733 ret = dsdb_module_schedule_sd_propagation(ar->module,
5734 ar->objs->partition_dn,
5736 if (ret != LDB_SUCCESS) {
5737 return ldb_operr(ldb);
5741 /* create the meta data value */
5742 ndr_err = ndr_push_struct_blob(&nmd_value, msg, &nmd,
5743 (ndr_push_flags_fn_t)ndr_push_replPropertyMetaDataBlob);
5744 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
5745 nt_status = ndr_map_error2ntstatus(ndr_err);
5746 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
5750 * when we know that we'll modify the record, add the whenChanged, uSNChanged
5751 * and replPopertyMetaData attributes
5753 ret = ldb_msg_add_string(msg, "whenChanged", ar->objs->objects[ar->index_current].when_changed);
5754 if (ret != LDB_SUCCESS) {
5755 return replmd_replicated_request_error(ar, ret);
5757 ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNChanged", ar->seq_num);
5758 if (ret != LDB_SUCCESS) {
5759 return replmd_replicated_request_error(ar, ret);
5761 ret = ldb_msg_add_value(msg, "replPropertyMetaData", &nmd_value, NULL);
5762 if (ret != LDB_SUCCESS) {
5763 return replmd_replicated_request_error(ar, ret);
5766 replmd_ldb_message_sort(msg, ar->schema);
5768 /* we want to replace the old values */
5769 for (i=0; i < msg->num_elements; i++) {
5770 msg->elements[i].flags = LDB_FLAG_MOD_REPLACE;
5771 if (ldb_attr_cmp(msg->elements[i].name, "objectClass") == 0) {
5772 if (msg->elements[i].num_values == 0) {
5773 ldb_asprintf_errstring(ldb, __location__
5774 ": objectClass removed on %s, aborting replication\n",
5775 ldb_dn_get_linearized(msg->dn));
5776 return replmd_replicated_request_error(ar, LDB_ERR_OBJECT_CLASS_VIOLATION);
5782 struct GUID_txt_buf guid_txt;
5784 char *s = ldb_ldif_message_string(ldb, ar, LDB_CHANGETYPE_MODIFY, msg);
5785 DEBUG(4, ("Final DRS replication modify message of %s:\n%s\n",
5786 GUID_buf_string(&ar->objs->objects[ar->index_current].object_guid, &guid_txt),
5791 ret = ldb_build_mod_req(&change_req,
5799 LDB_REQ_SET_LOCATION(change_req);
5800 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
5802 /* current partition control needed by "repmd_op_callback" */
5803 ret = ldb_request_add_control(change_req,
5804 DSDB_CONTROL_CURRENT_PARTITION_OID,
5806 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
5808 return ldb_next_request(ar->module, change_req);
5811 static int replmd_replicated_apply_search_callback(struct ldb_request *req,
5812 struct ldb_reply *ares)
5814 struct replmd_replicated_request *ar = talloc_get_type(req->context,
5815 struct replmd_replicated_request);
5819 return ldb_module_done(ar->req, NULL, NULL,
5820 LDB_ERR_OPERATIONS_ERROR);
5822 if (ares->error != LDB_SUCCESS &&
5823 ares->error != LDB_ERR_NO_SUCH_OBJECT) {
5824 return ldb_module_done(ar->req, ares->controls,
5825 ares->response, ares->error);
5828 switch (ares->type) {
5829 case LDB_REPLY_ENTRY:
5830 ar->search_msg = talloc_steal(ar, ares->message);
5833 case LDB_REPLY_REFERRAL:
5834 /* we ignore referrals */
5837 case LDB_REPLY_DONE:
5839 struct replPropertyMetaData1 *md_remote;
5840 struct replPropertyMetaData1 *md_local;
5842 struct replPropertyMetaDataBlob omd;
5843 const struct ldb_val *omd_value;
5844 struct replPropertyMetaDataBlob *rmd;
5845 struct ldb_message *msg;
5847 ar->objs->objects[ar->index_current].local_parent_dn = NULL;
5848 ar->objs->objects[ar->index_current].last_known_parent = NULL;
5851 * This is the ADD case, find the appropriate parent,
5852 * as this object doesn't exist locally:
5854 if (ar->search_msg == NULL) {
5855 ret = replmd_replicated_apply_search_for_parent(ar);
5856 if (ret != LDB_SUCCESS) {
5857 return ldb_module_done(ar->req, NULL, NULL, ret);
5864 * Otherwise, in the MERGE case, work out if we are
5865 * attempting a rename, and if so find the parent the
5866 * newly renamed object wants to belong under (which
5867 * may not be the parent in it's attached string DN
5869 rmd = ar->objs->objects[ar->index_current].meta_data;
5873 /* find existing meta data */
5874 omd_value = ldb_msg_find_ldb_val(ar->search_msg, "replPropertyMetaData");
5876 enum ndr_err_code ndr_err;
5877 ndr_err = ndr_pull_struct_blob(omd_value, ar, &omd,
5878 (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
5879 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
5880 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
5881 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
5884 if (omd.version != 1) {
5885 return replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
5889 ar->local_parent_guid = samdb_result_guid(ar->search_msg, "parentGUID");
5891 instanceType = ldb_msg_find_attr_as_int(ar->search_msg, "instanceType", 0);
5892 if (((instanceType & INSTANCE_TYPE_IS_NC_HEAD) == 0)
5893 && GUID_all_zero(&ar->local_parent_guid)) {
5894 DEBUG(0, ("Refusing to replicate new version of %s "
5895 "as local object has an all-zero parentGUID attribute, "
5896 "despite not being an NC root\n",
5897 ldb_dn_get_linearized(ar->search_msg->dn)));
5898 return replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
5902 * now we need to check for double renames. We could have a
5903 * local rename pending which our replication partner hasn't
5904 * received yet. We choose which one wins by looking at the
5905 * attribute stamps on the two objects, the newer one wins.
5907 * This also simply applies the correct algorithms for
5908 * determining if a change was made to name at all, or
5909 * if the object has just been renamed under the same
5912 md_remote = replmd_replPropertyMetaData1_find_attid(rmd, DRSUAPI_ATTID_name);
5913 md_local = replmd_replPropertyMetaData1_find_attid(&omd, DRSUAPI_ATTID_name);
5915 DEBUG(0,(__location__ ": Failed to find name attribute in local LDB replPropertyMetaData for %s\n",
5916 ldb_dn_get_linearized(ar->search_msg->dn)));
5917 return replmd_replicated_request_werror(ar, WERR_DS_DRA_DB_ERROR);
5921 * if there is no name attribute given then we have to assume the
5922 * object we've received has the older name
5924 if (replmd_replPropertyMetaData1_new_should_be_taken(
5925 ar->objs->dsdb_repl_flags & DSDB_REPL_FLAG_PRIORITISE_INCOMING,
5926 md_local, md_remote)) {
5927 struct GUID_txt_buf p_guid_local;
5928 struct GUID_txt_buf p_guid_remote;
5929 msg = ar->objs->objects[ar->index_current].msg;
5931 /* Merge on the existing object, with rename */
5933 DEBUG(4,(__location__ ": Looking for new parent for object %s currently under %s "
5934 "as incoming object changing to %s under %s\n",
5935 ldb_dn_get_linearized(ar->search_msg->dn),
5936 GUID_buf_string(&ar->local_parent_guid, &p_guid_local),
5937 ldb_dn_get_linearized(msg->dn),
5938 GUID_buf_string(ar->objs->objects[ar->index_current].parent_guid,
5940 ret = replmd_replicated_apply_search_for_parent(ar);
5942 struct GUID_txt_buf p_guid_local;
5943 struct GUID_txt_buf p_guid_remote;
5944 msg = ar->objs->objects[ar->index_current].msg;
5947 * Merge on the existing object, force no
5948 * rename (code below just to explain why in
5952 if (strcmp(ldb_dn_get_linearized(ar->search_msg->dn),
5953 ldb_dn_get_linearized(msg->dn)) == 0) {
5954 if (ar->objs->objects[ar->index_current].parent_guid != NULL &&
5955 GUID_equal(&ar->local_parent_guid,
5956 ar->objs->objects[ar->index_current].parent_guid)
5958 DEBUG(4,(__location__ ": Keeping object %s at under %s "
5959 "despite incoming object changing parent to %s\n",
5960 ldb_dn_get_linearized(ar->search_msg->dn),
5961 GUID_buf_string(&ar->local_parent_guid, &p_guid_local),
5962 GUID_buf_string(ar->objs->objects[ar->index_current].parent_guid,
5966 DEBUG(4,(__location__ ": Keeping object %s at under %s "
5967 " and rejecting older rename to %s under %s\n",
5968 ldb_dn_get_linearized(ar->search_msg->dn),
5969 GUID_buf_string(&ar->local_parent_guid, &p_guid_local),
5970 ldb_dn_get_linearized(msg->dn),
5971 GUID_buf_string(ar->objs->objects[ar->index_current].parent_guid,
5975 * This assignment ensures that the strcmp()
5976 * and GUID_equal() calls in
5977 * replmd_replicated_apply_merge() avoids the
5980 ar->objs->objects[ar->index_current].parent_guid =
5981 &ar->local_parent_guid;
5983 msg->dn = ar->search_msg->dn;
5984 ret = replmd_replicated_apply_merge(ar);
5986 if (ret != LDB_SUCCESS) {
5987 return ldb_module_done(ar->req, NULL, NULL, ret);
5996 static int replmd_replicated_uptodate_vector(struct replmd_replicated_request *ar);
5998 static int replmd_replicated_apply_next(struct replmd_replicated_request *ar)
6000 struct ldb_context *ldb;
6004 struct ldb_request *search_req;
6005 static const char *attrs[] = { "repsFrom", "replUpToDateVector",
6006 "parentGUID", "instanceType",
6007 "replPropertyMetaData", "nTSecurityDescriptor",
6008 "isDeleted", NULL };
6009 struct GUID_txt_buf guid_str_buf;
6011 if (ar->index_current >= ar->objs->num_objects) {
6012 /* done with it, go to next stage */
6013 return replmd_replicated_uptodate_vector(ar);
6016 ldb = ldb_module_get_ctx(ar->module);
6017 ar->search_msg = NULL;
6018 ar->isDeleted = false;
6020 tmp_str = GUID_buf_string(&ar->objs->objects[ar->index_current].object_guid,
6023 filter = talloc_asprintf(ar, "(objectGUID=%s)", tmp_str);
6024 if (!filter) return replmd_replicated_request_werror(ar, WERR_NOT_ENOUGH_MEMORY);
6026 ret = ldb_build_search_req(&search_req,
6029 ar->objs->partition_dn,
6035 replmd_replicated_apply_search_callback,
6037 LDB_REQ_SET_LOCATION(search_req);
6039 ret = dsdb_request_add_controls(search_req, DSDB_SEARCH_SHOW_RECYCLED);
6041 if (ret != LDB_SUCCESS) {
6045 return ldb_next_request(ar->module, search_req);
6049 * This is essentially a wrapper for replmd_replicated_apply_next()
6051 * This is needed to ensure that both codepaths call this handler.
6053 static int replmd_replicated_apply_isDeleted(struct replmd_replicated_request *ar)
6055 struct ldb_dn *deleted_objects_dn;
6056 struct ldb_message *msg = ar->objs->objects[ar->index_current].msg;
6057 int ret = dsdb_get_deleted_objects_dn(ldb_module_get_ctx(ar->module), msg, msg->dn,
6058 &deleted_objects_dn);
6059 if (ar->isDeleted && (ret != LDB_SUCCESS || ldb_dn_compare(msg->dn, deleted_objects_dn) != 0)) {
6061 * Do a delete here again, so that if there is
6062 * anything local that conflicts with this
6063 * object being deleted, it is removed. This
6064 * includes links. See MS-DRSR 4.1.10.6.9
6067 * If the object is already deleted, and there
6068 * is no more work required, it doesn't do
6072 /* This has been updated to point to the DN we eventually did the modify on */
6074 struct ldb_request *del_req;
6075 struct ldb_result *res;
6077 TALLOC_CTX *tmp_ctx = talloc_new(ar);
6079 ret = ldb_oom(ldb_module_get_ctx(ar->module));
6083 res = talloc_zero(tmp_ctx, struct ldb_result);
6085 ret = ldb_oom(ldb_module_get_ctx(ar->module));
6086 talloc_free(tmp_ctx);
6090 /* Build a delete request, which hopefully will artually turn into nothing */
6091 ret = ldb_build_del_req(&del_req, ldb_module_get_ctx(ar->module), tmp_ctx,
6095 ldb_modify_default_callback,
6097 LDB_REQ_SET_LOCATION(del_req);
6098 if (ret != LDB_SUCCESS) {
6099 talloc_free(tmp_ctx);
6104 * This is the guts of the call, call back
6105 * into our delete code, but setting the
6106 * re_delete flag so we delete anything that
6107 * shouldn't be there on a deleted or recycled
6110 ret = replmd_delete_internals(ar->module, del_req, true);
6111 if (ret == LDB_SUCCESS) {
6112 ret = ldb_wait(del_req->handle, LDB_WAIT_ALL);
6115 talloc_free(tmp_ctx);
6116 if (ret != LDB_SUCCESS) {
6121 ar->index_current++;
6122 return replmd_replicated_apply_next(ar);
6125 static int replmd_replicated_uptodate_modify_callback(struct ldb_request *req,
6126 struct ldb_reply *ares)
6128 struct ldb_context *ldb;
6129 struct replmd_replicated_request *ar = talloc_get_type(req->context,
6130 struct replmd_replicated_request);
6131 ldb = ldb_module_get_ctx(ar->module);
6134 return ldb_module_done(ar->req, NULL, NULL,
6135 LDB_ERR_OPERATIONS_ERROR);
6137 if (ares->error != LDB_SUCCESS) {
6138 return ldb_module_done(ar->req, ares->controls,
6139 ares->response, ares->error);
6142 if (ares->type != LDB_REPLY_DONE) {
6143 ldb_asprintf_errstring(ldb, "Invalid LDB reply type %d", ares->type);
6144 return ldb_module_done(ar->req, NULL, NULL,
6145 LDB_ERR_OPERATIONS_ERROR);
6150 return ldb_module_done(ar->req, NULL, NULL, LDB_SUCCESS);
6153 static int replmd_replicated_uptodate_modify(struct replmd_replicated_request *ar)
6155 struct ldb_context *ldb;
6156 struct ldb_request *change_req;
6157 enum ndr_err_code ndr_err;
6158 struct ldb_message *msg;
6159 struct replUpToDateVectorBlob ouv;
6160 const struct ldb_val *ouv_value;
6161 const struct drsuapi_DsReplicaCursor2CtrEx *ruv;
6162 struct replUpToDateVectorBlob nuv;
6163 struct ldb_val nuv_value;
6164 struct ldb_message_element *nuv_el = NULL;
6165 struct ldb_message_element *orf_el = NULL;
6166 struct repsFromToBlob nrf;
6167 struct ldb_val *nrf_value = NULL;
6168 struct ldb_message_element *nrf_el = NULL;
6172 time_t t = time(NULL);
6175 uint32_t instanceType;
6177 ldb = ldb_module_get_ctx(ar->module);
6178 ruv = ar->objs->uptodateness_vector;
6184 unix_to_nt_time(&now, t);
6186 if (ar->search_msg == NULL) {
6187 /* this happens for a REPL_OBJ call where we are
6188 creating the target object by replicating it. The
6189 subdomain join code does this for the partition DN
6191 DEBUG(4,(__location__ ": Skipping UDV and repsFrom update as no target DN\n"));
6192 return ldb_module_done(ar->req, NULL, NULL, LDB_SUCCESS);
6195 instanceType = ldb_msg_find_attr_as_uint(ar->search_msg, "instanceType", 0);
6196 if (! (instanceType & INSTANCE_TYPE_IS_NC_HEAD)) {
6197 DEBUG(4,(__location__ ": Skipping UDV and repsFrom update as not NC root: %s\n",
6198 ldb_dn_get_linearized(ar->search_msg->dn)));
6199 return ldb_module_done(ar->req, NULL, NULL, LDB_SUCCESS);
6203 * first create the new replUpToDateVector
6205 ouv_value = ldb_msg_find_ldb_val(ar->search_msg, "replUpToDateVector");
6207 ndr_err = ndr_pull_struct_blob(ouv_value, ar, &ouv,
6208 (ndr_pull_flags_fn_t)ndr_pull_replUpToDateVectorBlob);
6209 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
6210 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
6211 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
6214 if (ouv.version != 2) {
6215 return replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
6220 * the new uptodateness vector will at least
6221 * contain 1 entry, one for the source_dsa
6223 * plus optional values from our old vector and the one from the source_dsa
6225 nuv.ctr.ctr2.count = ouv.ctr.ctr2.count;
6226 if (ruv) nuv.ctr.ctr2.count += ruv->count;
6227 nuv.ctr.ctr2.cursors = talloc_array(ar,
6228 struct drsuapi_DsReplicaCursor2,
6229 nuv.ctr.ctr2.count);
6230 if (!nuv.ctr.ctr2.cursors) return replmd_replicated_request_werror(ar, WERR_NOT_ENOUGH_MEMORY);
6232 /* first copy the old vector */
6233 for (i=0; i < ouv.ctr.ctr2.count; i++) {
6234 nuv.ctr.ctr2.cursors[ni] = ouv.ctr.ctr2.cursors[i];
6238 /* merge in the source_dsa vector is available */
6239 for (i=0; (ruv && i < ruv->count); i++) {
6242 if (GUID_equal(&ruv->cursors[i].source_dsa_invocation_id,
6243 &ar->our_invocation_id)) {
6247 for (j=0; j < ni; j++) {
6248 if (!GUID_equal(&ruv->cursors[i].source_dsa_invocation_id,
6249 &nuv.ctr.ctr2.cursors[j].source_dsa_invocation_id)) {
6255 if (ruv->cursors[i].highest_usn > nuv.ctr.ctr2.cursors[j].highest_usn) {
6256 nuv.ctr.ctr2.cursors[j] = ruv->cursors[i];
6261 if (found) continue;
6263 /* if it's not there yet, add it */
6264 nuv.ctr.ctr2.cursors[ni] = ruv->cursors[i];
6269 * finally correct the size of the cursors array
6271 nuv.ctr.ctr2.count = ni;
6276 TYPESAFE_QSORT(nuv.ctr.ctr2.cursors, nuv.ctr.ctr2.count, drsuapi_DsReplicaCursor2_compare);
6279 * create the change ldb_message
6281 msg = ldb_msg_new(ar);
6282 if (!msg) return replmd_replicated_request_werror(ar, WERR_NOT_ENOUGH_MEMORY);
6283 msg->dn = ar->search_msg->dn;
6285 ndr_err = ndr_push_struct_blob(&nuv_value, msg, &nuv,
6286 (ndr_push_flags_fn_t)ndr_push_replUpToDateVectorBlob);
6287 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
6288 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
6289 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
6291 ret = ldb_msg_add_value(msg, "replUpToDateVector", &nuv_value, &nuv_el);
6292 if (ret != LDB_SUCCESS) {
6293 return replmd_replicated_request_error(ar, ret);
6295 nuv_el->flags = LDB_FLAG_MOD_REPLACE;
6298 * now create the new repsFrom value from the given repsFromTo1 structure
6302 nrf.ctr.ctr1 = *ar->objs->source_dsa;
6303 nrf.ctr.ctr1.last_attempt = now;
6304 nrf.ctr.ctr1.last_success = now;
6305 nrf.ctr.ctr1.result_last_attempt = WERR_OK;
6308 * first see if we already have a repsFrom value for the current source dsa
6309 * if so we'll later replace this value
6311 orf_el = ldb_msg_find_element(ar->search_msg, "repsFrom");
6313 for (i=0; i < orf_el->num_values; i++) {
6314 struct repsFromToBlob *trf;
6316 trf = talloc(ar, struct repsFromToBlob);
6317 if (!trf) return replmd_replicated_request_werror(ar, WERR_NOT_ENOUGH_MEMORY);
6319 ndr_err = ndr_pull_struct_blob(&orf_el->values[i], trf, trf,
6320 (ndr_pull_flags_fn_t)ndr_pull_repsFromToBlob);
6321 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
6322 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
6323 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
6326 if (trf->version != 1) {
6327 return replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
6331 * we compare the source dsa objectGUID not the invocation_id
6332 * because we want only one repsFrom value per source dsa
6333 * and when the invocation_id of the source dsa has changed we don't need
6334 * the old repsFrom with the old invocation_id
6336 if (!GUID_equal(&trf->ctr.ctr1.source_dsa_obj_guid,
6337 &ar->objs->source_dsa->source_dsa_obj_guid)) {
6343 nrf_value = &orf_el->values[i];
6348 * copy over all old values to the new ldb_message
6350 ret = ldb_msg_add_empty(msg, "repsFrom", 0, &nrf_el);
6351 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
6356 * if we haven't found an old repsFrom value for the current source dsa
6357 * we'll add a new value
6360 struct ldb_val zero_value;
6361 ZERO_STRUCT(zero_value);
6362 ret = ldb_msg_add_value(msg, "repsFrom", &zero_value, &nrf_el);
6363 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
6365 nrf_value = &nrf_el->values[nrf_el->num_values - 1];
6368 /* we now fill the value which is already attached to ldb_message */
6369 ndr_err = ndr_push_struct_blob(nrf_value, msg,
6371 (ndr_push_flags_fn_t)ndr_push_repsFromToBlob);
6372 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
6373 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
6374 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
6378 * the ldb_message_element for the attribute, has all the old values and the new one
6379 * so we'll replace the whole attribute with all values
6381 nrf_el->flags = LDB_FLAG_MOD_REPLACE;
6383 if (CHECK_DEBUGLVL(4)) {
6384 char *s = ldb_ldif_message_string(ldb, ar, LDB_CHANGETYPE_MODIFY, msg);
6385 DEBUG(4, ("DRS replication uptodate modify message:\n%s\n", s));
6389 /* prepare the ldb_modify() request */
6390 ret = ldb_build_mod_req(&change_req,
6396 replmd_replicated_uptodate_modify_callback,
6398 LDB_REQ_SET_LOCATION(change_req);
6399 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
6401 return ldb_next_request(ar->module, change_req);
6404 static int replmd_replicated_uptodate_search_callback(struct ldb_request *req,
6405 struct ldb_reply *ares)
6407 struct replmd_replicated_request *ar = talloc_get_type(req->context,
6408 struct replmd_replicated_request);
6412 return ldb_module_done(ar->req, NULL, NULL,
6413 LDB_ERR_OPERATIONS_ERROR);
6415 if (ares->error != LDB_SUCCESS &&
6416 ares->error != LDB_ERR_NO_SUCH_OBJECT) {
6417 return ldb_module_done(ar->req, ares->controls,
6418 ares->response, ares->error);
6421 switch (ares->type) {
6422 case LDB_REPLY_ENTRY:
6423 ar->search_msg = talloc_steal(ar, ares->message);
6426 case LDB_REPLY_REFERRAL:
6427 /* we ignore referrals */
6430 case LDB_REPLY_DONE:
6431 ret = replmd_replicated_uptodate_modify(ar);
6432 if (ret != LDB_SUCCESS) {
6433 return ldb_module_done(ar->req, NULL, NULL, ret);
6442 static int replmd_replicated_uptodate_vector(struct replmd_replicated_request *ar)
6444 struct ldb_context *ldb = ldb_module_get_ctx(ar->module);
6445 struct replmd_private *replmd_private =
6446 talloc_get_type_abort(ldb_module_get_private(ar->module),
6447 struct replmd_private);
6449 static const char *attrs[] = {
6450 "replUpToDateVector",
6455 struct ldb_request *search_req;
6457 ar->search_msg = NULL;
6460 * Let the caller know that we did an originating updates
6462 ar->objs->originating_updates = replmd_private->originating_updates;
6464 ret = ldb_build_search_req(&search_req,
6467 ar->objs->partition_dn,
6473 replmd_replicated_uptodate_search_callback,
6475 LDB_REQ_SET_LOCATION(search_req);
6476 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
6478 return ldb_next_request(ar->module, search_req);
6483 static int replmd_extended_replicated_objects(struct ldb_module *module, struct ldb_request *req)
6485 struct ldb_context *ldb;
6486 struct dsdb_extended_replicated_objects *objs;
6487 struct replmd_replicated_request *ar;
6488 struct ldb_control **ctrls;
6491 struct replmd_private *replmd_private =
6492 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
6494 ldb = ldb_module_get_ctx(module);
6496 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_extended_replicated_objects\n");
6498 objs = talloc_get_type(req->op.extended.data, struct dsdb_extended_replicated_objects);
6500 ldb_debug(ldb, LDB_DEBUG_FATAL, "replmd_extended_replicated_objects: invalid extended data\n");
6501 return LDB_ERR_PROTOCOL_ERROR;
6504 if (objs->version != DSDB_EXTENDED_REPLICATED_OBJECTS_VERSION) {
6505 ldb_debug(ldb, LDB_DEBUG_FATAL, "replmd_extended_replicated_objects: extended data invalid version [%u != %u]\n",
6506 objs->version, DSDB_EXTENDED_REPLICATED_OBJECTS_VERSION);
6507 return LDB_ERR_PROTOCOL_ERROR;
6510 ar = replmd_ctx_init(module, req);
6512 return LDB_ERR_OPERATIONS_ERROR;
6514 /* Set the flags to have the replmd_op_callback run over the full set of objects */
6515 ar->apply_mode = true;
6517 ar->schema = dsdb_get_schema(ldb, ar);
6519 ldb_debug_set(ldb, LDB_DEBUG_FATAL, "replmd_ctx_init: no loaded schema found\n");
6521 DEBUG(0,(__location__ ": %s\n", ldb_errstring(ldb)));
6522 return LDB_ERR_CONSTRAINT_VIOLATION;
6525 ctrls = req->controls;
6527 if (req->controls) {
6528 req->controls = talloc_memdup(ar, req->controls,
6529 talloc_get_size(req->controls));
6530 if (!req->controls) return replmd_replicated_request_werror(ar, WERR_NOT_ENOUGH_MEMORY);
6533 ret = ldb_request_add_control(req, DSDB_CONTROL_REPLICATED_UPDATE_OID, false, NULL);
6534 if (ret != LDB_SUCCESS) {
6538 /* If this change contained linked attributes in the body
6539 * (rather than in the links section) we need to update
6540 * backlinks in linked_attributes */
6541 ret = ldb_request_add_control(req, DSDB_CONTROL_APPLY_LINKS, false, NULL);
6542 if (ret != LDB_SUCCESS) {
6546 ar->controls = req->controls;
6547 req->controls = ctrls;
6549 DEBUG(4,("linked_attributes_count=%u\n", objs->linked_attributes_count));
6551 /* save away the linked attributes for the end of the
6553 for (i=0; i<ar->objs->linked_attributes_count; i++) {
6554 struct la_entry *la_entry;
6556 if (replmd_private->la_ctx == NULL) {
6557 replmd_private->la_ctx = talloc_new(replmd_private);
6559 la_entry = talloc(replmd_private->la_ctx, struct la_entry);
6560 if (la_entry == NULL) {
6562 return LDB_ERR_OPERATIONS_ERROR;
6564 la_entry->la = talloc(la_entry, struct drsuapi_DsReplicaLinkedAttribute);
6565 if (la_entry->la == NULL) {
6566 talloc_free(la_entry);
6568 return LDB_ERR_OPERATIONS_ERROR;
6570 *la_entry->la = ar->objs->linked_attributes[i];
6572 /* we need to steal the non-scalars so they stay
6573 around until the end of the transaction */
6574 talloc_steal(la_entry->la, la_entry->la->identifier);
6575 talloc_steal(la_entry->la, la_entry->la->value.blob);
6577 DLIST_ADD(replmd_private->la_list, la_entry);
6580 return replmd_replicated_apply_next(ar);
6584 process one linked attribute structure
6586 static int replmd_process_linked_attribute(struct ldb_module *module,
6587 struct replmd_private *replmd_private,
6588 struct la_entry *la_entry,
6589 struct ldb_request *parent)
6591 struct drsuapi_DsReplicaLinkedAttribute *la = la_entry->la;
6592 struct ldb_context *ldb = ldb_module_get_ctx(module);
6593 struct ldb_message *msg;
6594 struct ldb_message *target_msg = NULL;
6595 TALLOC_CTX *tmp_ctx = talloc_new(la_entry);
6596 const struct dsdb_schema *schema = dsdb_get_schema(ldb, tmp_ctx);
6598 const struct dsdb_attribute *attr;
6599 struct dsdb_dn *dsdb_dn;
6600 uint64_t seq_num = 0;
6601 struct ldb_message_element *old_el;
6603 time_t t = time(NULL);
6604 struct ldb_result *res;
6605 struct ldb_result *target_res;
6606 const char *attrs[4];
6607 const char *attrs2[] = { "isDeleted", "isRecycled", NULL };
6608 struct parsed_dn *pdn_list, *pdn, *next;
6609 struct GUID guid = GUID_zero();
6611 bool active = (la->flags & DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE)?true:false;
6613 enum deletion_state deletion_state = OBJECT_NOT_DELETED;
6614 enum deletion_state target_deletion_state = OBJECT_NOT_DELETED;
6617 linked_attributes[0]:
6618 &objs->linked_attributes[i]: struct drsuapi_DsReplicaLinkedAttribute
6620 identifier: struct drsuapi_DsReplicaObjectIdentifier
6621 __ndr_size : 0x0000003a (58)
6622 __ndr_size_sid : 0x00000000 (0)
6623 guid : 8e95b6a9-13dd-4158-89db-3220a5be5cc7
6625 __ndr_size_dn : 0x00000000 (0)
6627 attid : DRSUAPI_ATTID_member (0x1F)
6628 value: struct drsuapi_DsAttributeValue
6629 __ndr_size : 0x0000007e (126)
6631 blob : DATA_BLOB length=126
6632 flags : 0x00000001 (1)
6633 1: DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE
6634 originating_add_time : Wed Sep 2 22:20:01 2009 EST
6635 meta_data: struct drsuapi_DsReplicaMetaData
6636 version : 0x00000015 (21)
6637 originating_change_time : Wed Sep 2 23:39:07 2009 EST
6638 originating_invocation_id: 794640f3-18cf-40ee-a211-a93992b67a64
6639 originating_usn : 0x000000000001e19c (123292)
6641 (for cases where the link is to a normal DN)
6642 &target: struct drsuapi_DsReplicaObjectIdentifier3
6643 __ndr_size : 0x0000007e (126)
6644 __ndr_size_sid : 0x0000001c (28)
6645 guid : 7639e594-db75-4086-b0d4-67890ae46031
6646 sid : S-1-5-21-2848215498-2472035911-1947525656-19924
6647 __ndr_size_dn : 0x00000022 (34)
6648 dn : 'CN=UOne,OU=TestOU,DC=vsofs8,DC=com'
6651 /* find the attribute being modified */
6652 attr = dsdb_attribute_by_attributeID_id(schema, la->attid);
6654 struct GUID_txt_buf guid_str;
6655 ldb_asprintf_errstring(ldb, "Unable to find attributeID 0x%x for link on <GUID=%s>",
6657 GUID_buf_string(&la->identifier->guid,
6659 talloc_free(tmp_ctx);
6660 return LDB_ERR_OPERATIONS_ERROR;
6663 attrs[0] = attr->lDAPDisplayName;
6664 attrs[1] = "isDeleted";
6665 attrs[2] = "isRecycled";
6668 /* get the existing message from the db for the object with
6669 this GUID, returning attribute being modified. We will then
6670 use this msg as the basis for a modify call */
6671 ret = dsdb_module_search(module, tmp_ctx, &res, NULL, LDB_SCOPE_SUBTREE, attrs,
6672 DSDB_FLAG_NEXT_MODULE |
6673 DSDB_SEARCH_SEARCH_ALL_PARTITIONS |
6674 DSDB_SEARCH_SHOW_RECYCLED |
6675 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT |
6676 DSDB_SEARCH_REVEAL_INTERNALS,
6678 "objectGUID=%s", GUID_string(tmp_ctx, &la->identifier->guid));
6679 if (ret != LDB_SUCCESS) {
6680 talloc_free(tmp_ctx);
6683 if (res->count != 1) {
6684 ldb_asprintf_errstring(ldb, "DRS linked attribute for GUID %s - DN not found",
6685 GUID_string(tmp_ctx, &la->identifier->guid));
6686 talloc_free(tmp_ctx);
6687 return LDB_ERR_NO_SUCH_OBJECT;
6692 * Check for deleted objects per MS-DRSR 4.1.10.6.13
6693 * ProcessLinkValue, because link updates are not applied to
6694 * recycled and tombstone objects. We don't have to delete
6695 * any existing link, that should have happened when the
6696 * object deletion was replicated or initiated.
6699 replmd_deletion_state(module, msg, &deletion_state, NULL);
6701 if (deletion_state >= OBJECT_RECYCLED) {
6702 talloc_free(tmp_ctx);
6706 old_el = ldb_msg_find_element(msg, attr->lDAPDisplayName);
6707 if (old_el == NULL) {
6708 ret = ldb_msg_add_empty(msg, attr->lDAPDisplayName, LDB_FLAG_MOD_REPLACE, &old_el);
6709 if (ret != LDB_SUCCESS) {
6710 ldb_module_oom(module);
6711 talloc_free(tmp_ctx);
6712 return LDB_ERR_OPERATIONS_ERROR;
6715 old_el->flags = LDB_FLAG_MOD_REPLACE;
6718 /* parse the existing links */
6719 ret = get_parsed_dns_trusted(module, replmd_private, tmp_ctx, old_el, &pdn_list,
6720 attr->syntax->ldap_oid, parent);
6722 if (ret != LDB_SUCCESS) {
6723 talloc_free(tmp_ctx);
6727 status = dsdb_dn_la_from_blob(ldb, attr, schema, tmp_ctx, la->value.blob, &dsdb_dn);
6728 if (!W_ERROR_IS_OK(status)) {
6729 ldb_asprintf_errstring(ldb, "Failed to parsed linked attribute blob for %s on %s - %s\n",
6730 old_el->name, ldb_dn_get_linearized(msg->dn), win_errstr(status));
6731 talloc_free(tmp_ctx);
6732 return LDB_ERR_OPERATIONS_ERROR;
6735 ntstatus = dsdb_get_extended_dn_guid(dsdb_dn->dn, &guid, "GUID");
6736 if (!NT_STATUS_IS_OK(ntstatus) && !active) {
6738 * This strange behaviour (allowing a NULL/missing
6739 * GUID) originally comes from:
6741 * commit e3054ce0fe0f8f62d2f5b2a77893e7a1479128bd
6742 * Author: Andrew Tridgell <tridge@samba.org>
6743 * Date: Mon Dec 21 21:21:55 2009 +1100
6745 * s4-drs: cope better with NULL GUIDS from DRS
6747 * It is valid to get a NULL GUID over DRS for a deleted forward link. We
6748 * need to match by DN if possible when seeing if we should update an
6751 * Pair-Programmed-With: Andrew Bartlett <abartlet@samba.org>
6754 ret = dsdb_module_search_dn(module, tmp_ctx, &target_res,
6755 dsdb_dn->dn, attrs2,
6756 DSDB_FLAG_NEXT_MODULE |
6757 DSDB_SEARCH_SHOW_RECYCLED |
6758 DSDB_SEARCH_SEARCH_ALL_PARTITIONS |
6759 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT,
6761 } else if (!NT_STATUS_IS_OK(ntstatus)) {
6762 ldb_asprintf_errstring(ldb, "Failed to find GUID in linked attribute blob for %s on %s from %s",
6764 ldb_dn_get_linearized(dsdb_dn->dn),
6765 ldb_dn_get_linearized(msg->dn));
6766 talloc_free(tmp_ctx);
6767 return LDB_ERR_OPERATIONS_ERROR;
6769 ret = dsdb_module_search(module, tmp_ctx, &target_res,
6770 NULL, LDB_SCOPE_SUBTREE,
6772 DSDB_FLAG_NEXT_MODULE |
6773 DSDB_SEARCH_SHOW_RECYCLED |
6774 DSDB_SEARCH_SEARCH_ALL_PARTITIONS |
6775 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT,
6778 GUID_string(tmp_ctx, &guid));
6781 if (ret != LDB_SUCCESS) {
6782 ldb_asprintf_errstring(ldb_module_get_ctx(module), "Failed to re-resolve GUID %s: %s\n",
6783 GUID_string(tmp_ctx, &guid),
6784 ldb_errstring(ldb_module_get_ctx(module)));
6785 talloc_free(tmp_ctx);
6789 if (target_res->count == 0) {
6790 DEBUG(2,(__location__ ": WARNING: Failed to re-resolve GUID %s - using %s\n",
6791 GUID_string(tmp_ctx, &guid),
6792 ldb_dn_get_linearized(dsdb_dn->dn)));
6793 } else if (target_res->count != 1) {
6794 ldb_asprintf_errstring(ldb_module_get_ctx(module), "More than one object found matching objectGUID %s\n",
6795 GUID_string(tmp_ctx, &guid));
6796 talloc_free(tmp_ctx);
6797 return LDB_ERR_OPERATIONS_ERROR;
6799 target_msg = target_res->msgs[0];
6800 dsdb_dn->dn = talloc_steal(dsdb_dn, target_msg->dn);
6804 * Check for deleted objects per MS-DRSR 4.1.10.6.13
6805 * ProcessLinkValue, because link updates are not applied to
6806 * recycled and tombstone objects. We don't have to delete
6807 * any existing link, that should have happened when the
6808 * object deletion was replicated or initiated.
6810 replmd_deletion_state(module, target_msg,
6811 &target_deletion_state, NULL);
6813 if (target_deletion_state >= OBJECT_RECYCLED) {
6814 talloc_free(tmp_ctx);
6818 /* see if this link already exists */
6819 ret = parsed_dn_find(ldb, pdn_list, old_el->num_values,
6822 dsdb_dn->extra_part, 0,
6824 attr->syntax->ldap_oid,
6826 if (ret != LDB_SUCCESS) {
6827 talloc_free(tmp_ctx);
6833 /* see if this update is newer than what we have already */
6834 struct GUID invocation_id = GUID_zero();
6835 uint32_t version = 0;
6836 uint32_t originating_usn = 0;
6837 NTTIME change_time = 0;
6838 uint32_t rmd_flags = dsdb_dn_rmd_flags(pdn->dsdb_dn->dn);
6840 dsdb_get_extended_dn_guid(pdn->dsdb_dn->dn, &invocation_id, "RMD_INVOCID");
6841 dsdb_get_extended_dn_uint32(pdn->dsdb_dn->dn, &version, "RMD_VERSION");
6842 dsdb_get_extended_dn_uint32(pdn->dsdb_dn->dn, &originating_usn, "RMD_ORIGINATING_USN");
6843 dsdb_get_extended_dn_nttime(pdn->dsdb_dn->dn, &change_time, "RMD_CHANGETIME");
6845 if (!replmd_update_is_newer(&invocation_id,
6846 &la->meta_data.originating_invocation_id,
6848 la->meta_data.version,
6850 la->meta_data.originating_change_time)) {
6851 DEBUG(3,("Discarding older DRS linked attribute update to %s on %s from %s\n",
6852 old_el->name, ldb_dn_get_linearized(msg->dn),
6853 GUID_string(tmp_ctx, &la->meta_data.originating_invocation_id)));
6854 talloc_free(tmp_ctx);
6858 /* get a seq_num for this change */
6859 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &seq_num);
6860 if (ret != LDB_SUCCESS) {
6861 talloc_free(tmp_ctx);
6865 if (!(rmd_flags & DSDB_RMD_FLAG_DELETED)) {
6866 /* remove the existing backlink */
6867 ret = replmd_add_backlink(module, replmd_private,
6872 if (ret != LDB_SUCCESS) {
6873 talloc_free(tmp_ctx);
6878 ret = replmd_update_la_val(tmp_ctx, pdn->v, dsdb_dn, pdn->dsdb_dn,
6879 &la->meta_data.originating_invocation_id,
6880 la->meta_data.originating_usn, seq_num,
6881 la->meta_data.originating_change_time,
6882 la->meta_data.version,
6884 if (ret != LDB_SUCCESS) {
6885 talloc_free(tmp_ctx);
6890 /* add the new backlink */
6891 ret = replmd_add_backlink(module, replmd_private,
6896 if (ret != LDB_SUCCESS) {
6897 talloc_free(tmp_ctx);
6903 /* get a seq_num for this change */
6904 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &seq_num);
6905 if (ret != LDB_SUCCESS) {
6906 talloc_free(tmp_ctx);
6910 * We know where the new one needs to be, from the *next
6911 * pointer into pdn_list.
6914 offset = old_el->num_values;
6916 if (next->dsdb_dn == NULL) {
6917 ret = really_parse_trusted_dn(tmp_ctx, ldb, next,
6918 attr->syntax->ldap_oid);
6919 if (ret != LDB_SUCCESS) {
6923 offset = next - pdn_list;
6924 if (offset > old_el->num_values) {
6925 talloc_free(tmp_ctx);
6926 return LDB_ERR_OPERATIONS_ERROR;
6930 old_el->values = talloc_realloc(msg->elements, old_el->values,
6931 struct ldb_val, old_el->num_values+1);
6932 if (!old_el->values) {
6933 ldb_module_oom(module);
6934 return LDB_ERR_OPERATIONS_ERROR;
6937 if (offset != old_el->num_values) {
6938 memmove(&old_el->values[offset + 1], &old_el->values[offset],
6939 (old_el->num_values - offset) * sizeof(old_el->values[0]));
6942 old_el->num_values++;
6944 ret = replmd_build_la_val(tmp_ctx, &old_el->values[offset], dsdb_dn,
6945 &la->meta_data.originating_invocation_id,
6946 la->meta_data.originating_usn, seq_num,
6947 la->meta_data.originating_change_time,
6948 la->meta_data.version,
6950 if (ret != LDB_SUCCESS) {
6951 talloc_free(tmp_ctx);
6956 ret = replmd_add_backlink(module, replmd_private,
6961 if (ret != LDB_SUCCESS) {
6962 talloc_free(tmp_ctx);
6968 /* we only change whenChanged and uSNChanged if the seq_num
6970 ret = add_time_element(msg, "whenChanged", t);
6971 if (ret != LDB_SUCCESS) {
6972 talloc_free(tmp_ctx);
6977 ret = add_uint64_element(ldb, msg, "uSNChanged", seq_num);
6978 if (ret != LDB_SUCCESS) {
6979 talloc_free(tmp_ctx);
6984 old_el = ldb_msg_find_element(msg, attr->lDAPDisplayName);
6985 if (old_el == NULL) {
6986 talloc_free(tmp_ctx);
6987 return ldb_operr(ldb);
6990 ret = dsdb_check_single_valued_link(attr, old_el);
6991 if (ret != LDB_SUCCESS) {
6992 talloc_free(tmp_ctx);
6996 old_el->flags |= LDB_FLAG_INTERNAL_DISABLE_SINGLE_VALUE_CHECK;
6998 ret = linked_attr_modify(module, msg, parent);
6999 if (ret != LDB_SUCCESS) {
7000 ldb_debug(ldb, LDB_DEBUG_WARNING, "Failed to apply linked attribute change '%s'\n%s\n",
7002 ldb_ldif_message_string(ldb, tmp_ctx, LDB_CHANGETYPE_MODIFY, msg));
7003 talloc_free(tmp_ctx);
7007 talloc_free(tmp_ctx);
7012 static int replmd_extended(struct ldb_module *module, struct ldb_request *req)
7014 if (strcmp(req->op.extended.oid, DSDB_EXTENDED_REPLICATED_OBJECTS_OID) == 0) {
7015 return replmd_extended_replicated_objects(module, req);
7018 return ldb_next_request(module, req);
7023 we hook into the transaction operations to allow us to
7024 perform the linked attribute updates at the end of the whole
7025 transaction. This allows a forward linked attribute to be created
7026 before the object is created. During a vampire, w2k8 sends us linked
7027 attributes before the objects they are part of.
7029 static int replmd_start_transaction(struct ldb_module *module)
7031 /* create our private structure for this transaction */
7032 struct replmd_private *replmd_private = talloc_get_type(ldb_module_get_private(module),
7033 struct replmd_private);
7034 replmd_txn_cleanup(replmd_private);
7036 /* free any leftover mod_usn records from cancelled
7038 while (replmd_private->ncs) {
7039 struct nc_entry *e = replmd_private->ncs;
7040 DLIST_REMOVE(replmd_private->ncs, e);
7044 replmd_private->originating_updates = false;
7046 return ldb_next_start_trans(module);
7050 on prepare commit we loop over our queued la_context structures and
7053 static int replmd_prepare_commit(struct ldb_module *module)
7055 struct replmd_private *replmd_private =
7056 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
7057 struct la_entry *la, *prev;
7061 * Walk the list of linked attributes from DRS replication.
7063 * We walk backwards, to do the first entry first, as we
7064 * added the entries with DLIST_ADD() which puts them at the
7067 for (la = DLIST_TAIL(replmd_private->la_list); la; la=prev) {
7068 prev = DLIST_PREV(la);
7069 DLIST_REMOVE(replmd_private->la_list, la);
7070 ret = replmd_process_linked_attribute(module, replmd_private,
7072 if (ret != LDB_SUCCESS) {
7073 replmd_txn_cleanup(replmd_private);
7078 replmd_txn_cleanup(replmd_private);
7080 /* possibly change @REPLCHANGED */
7081 ret = replmd_notify_store(module, NULL);
7082 if (ret != LDB_SUCCESS) {
7086 return ldb_next_prepare_commit(module);
7089 static int replmd_del_transaction(struct ldb_module *module)
7091 struct replmd_private *replmd_private =
7092 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
7093 replmd_txn_cleanup(replmd_private);
7095 return ldb_next_del_trans(module);
7099 static const struct ldb_module_ops ldb_repl_meta_data_module_ops = {
7100 .name = "repl_meta_data",
7101 .init_context = replmd_init,
7103 .modify = replmd_modify,
7104 .rename = replmd_rename,
7105 .del = replmd_delete,
7106 .extended = replmd_extended,
7107 .start_transaction = replmd_start_transaction,
7108 .prepare_commit = replmd_prepare_commit,
7109 .del_transaction = replmd_del_transaction,
7112 int ldb_repl_meta_data_module_init(const char *version)
7114 LDB_MODULE_CHECK_VERSION(version);
7115 return ldb_register_module(&ldb_repl_meta_data_module_ops);