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 bool is_forced_rodc,
1371 struct ldb_request *req)
1374 const struct dsdb_attribute *a;
1375 struct replPropertyMetaData1 *md1;
1376 bool may_skip = false;
1379 a = dsdb_attribute_by_lDAPDisplayName(schema, el->name);
1381 if (ldb_request_get_control(req, LDB_CONTROL_RELAX_OID)) {
1382 /* allow this to make it possible for dbcheck
1383 to remove bad attributes */
1387 DEBUG(0,(__location__ ": Unable to find attribute %s in schema\n",
1389 return LDB_ERR_OPERATIONS_ERROR;
1392 attid = dsdb_attribute_get_attid(a, is_schema_nc);
1394 if ((a->systemFlags & DS_FLAG_ATTR_NOT_REPLICATED) || (a->systemFlags & DS_FLAG_ATTR_IS_CONSTRUCTED)) {
1399 * if the attribute's value haven't changed, and this isn't
1400 * just a delete of everything then return LDB_SUCCESS Unless
1401 * we have the provision control or if the attribute is
1402 * interSiteTopologyGenerator as this page explain:
1403 * http://support.microsoft.com/kb/224815 this attribute is
1404 * periodicaly written by the DC responsible for the intersite
1405 * generation in a given site
1407 * Unchanged could be deleting or replacing an already-gone
1408 * thing with an unconstrained delete/empty replace or a
1409 * replace with the same value, but not an add with the same
1410 * value because that could be about adding a duplicate (which
1411 * is for someone else to error out on).
1413 if (old_el != NULL && ldb_msg_element_equal_ordered(el, old_el)) {
1414 if (LDB_FLAG_MOD_TYPE(el->flags) == LDB_FLAG_MOD_REPLACE) {
1417 } else if (old_el == NULL && el->num_values == 0) {
1418 if (LDB_FLAG_MOD_TYPE(el->flags) == LDB_FLAG_MOD_REPLACE) {
1420 } else if (LDB_FLAG_MOD_TYPE(el->flags) == LDB_FLAG_MOD_DELETE) {
1423 } else if (a->linkID != 0 && LDB_FLAG_MOD_TYPE(el->flags) == LDB_FLAG_MOD_DELETE &&
1424 ldb_request_get_control(req, DSDB_CONTROL_REPLMD_VANISH_LINKS) != NULL) {
1426 * We intentionally skip the version bump when attempting to
1429 * The control is set by dbcheck and expunge-tombstones which
1430 * both attempt to be non-replicating. Otherwise, making an
1431 * alteration to the replication state would trigger a
1432 * broadcast of all expunged objects.
1437 if (el->flags & DSDB_FLAG_INTERNAL_FORCE_META_DATA) {
1439 el->flags &= ~DSDB_FLAG_INTERNAL_FORCE_META_DATA;
1443 if (strcmp(el->name, "interSiteTopologyGenerator") != 0 &&
1444 !ldb_request_get_control(req, LDB_CONTROL_PROVISION_OID)) {
1446 * allow this to make it possible for dbcheck
1447 * to rebuild broken metadata
1453 for (i=0; i<omd->ctr.ctr1.count; i++) {
1455 * First check if we find it under the msDS-IntID,
1456 * then check if we find it under the OID and
1459 * This allows the administrator to simply re-write
1460 * the attributes and so restore replication, which is
1461 * likely what they will try to do.
1463 if (attid == omd->ctr.ctr1.array[i].attid) {
1467 if (a->attributeID_id == omd->ctr.ctr1.array[i].attid) {
1472 if (a->linkID != 0 && dsdb_functional_level(ldb) > DS_DOMAIN_FUNCTION_2000) {
1473 /* linked attributes are not stored in
1474 replPropertyMetaData in FL above w2k, but we do
1475 raise the seqnum for the object */
1476 if (*seq_num == 0 &&
1477 ldb_sequence_number(ldb, LDB_SEQ_NEXT, seq_num) != LDB_SUCCESS) {
1478 return LDB_ERR_OPERATIONS_ERROR;
1483 if (i == omd->ctr.ctr1.count) {
1484 /* we need to add a new one */
1485 omd->ctr.ctr1.array = talloc_realloc(msg, omd->ctr.ctr1.array,
1486 struct replPropertyMetaData1, omd->ctr.ctr1.count+1);
1487 if (omd->ctr.ctr1.array == NULL) {
1489 return LDB_ERR_OPERATIONS_ERROR;
1491 omd->ctr.ctr1.count++;
1492 ZERO_STRUCT(omd->ctr.ctr1.array[i]);
1495 /* Get a new sequence number from the backend. We only do this
1496 * if we have a change that requires a new
1497 * replPropertyMetaData element
1499 if (*seq_num == 0) {
1500 int ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, seq_num);
1501 if (ret != LDB_SUCCESS) {
1502 return LDB_ERR_OPERATIONS_ERROR;
1506 md1 = &omd->ctr.ctr1.array[i];
1510 if (md1->attid == DRSUAPI_ATTID_isDeleted) {
1511 const struct ldb_val *rdn_val = ldb_dn_get_rdn_val(msg->dn);
1514 if (rdn_val == NULL) {
1516 return LDB_ERR_OPERATIONS_ERROR;
1519 rdn = (const char*)rdn_val->data;
1520 if (strcmp(rdn, "Deleted Objects") == 0) {
1522 * Set the originating_change_time to 29/12/9999 at 23:59:59
1523 * as specified in MS-ADTS 7.1.1.4.2 Deleted Objects Container
1525 md1->originating_change_time = DELETED_OBJECT_CONTAINER_CHANGE_TIME;
1527 md1->originating_change_time = now;
1530 md1->originating_change_time = now;
1532 md1->originating_invocation_id = *our_invocation_id;
1533 md1->originating_usn = *seq_num;
1534 md1->local_usn = *seq_num;
1536 if (is_forced_rodc) {
1537 /* Force version to 0 to be overriden later via replication */
1545 * Bump the replPropertyMetaData version on an attribute, and if it
1546 * has changed (or forced by leaving rdn_old NULL), update the value
1549 * This is important, as calling a modify operation may not change the
1550 * version number if the values appear unchanged, but a rename between
1551 * parents bumps this value.
1554 static int replmd_update_rpmd_rdn_attr(struct ldb_context *ldb,
1555 struct ldb_message *msg,
1556 const struct ldb_val *rdn_new,
1557 const struct ldb_val *rdn_old,
1558 struct replPropertyMetaDataBlob *omd,
1559 struct replmd_replicated_request *ar,
1562 bool is_forced_rodc)
1564 const char *rdn_name = ldb_dn_get_rdn_name(msg->dn);
1565 const struct dsdb_attribute *rdn_attr =
1566 dsdb_attribute_by_lDAPDisplayName(ar->schema, rdn_name);
1567 const char *attr_name = rdn_attr != NULL ?
1568 rdn_attr->lDAPDisplayName :
1570 struct ldb_message_element new_el = {
1571 .flags = LDB_FLAG_MOD_REPLACE,
1574 .values = discard_const_p(struct ldb_val, rdn_new)
1576 struct ldb_message_element old_el = {
1577 .flags = LDB_FLAG_MOD_REPLACE,
1579 .num_values = rdn_old ? 1 : 0,
1580 .values = discard_const_p(struct ldb_val, rdn_old)
1583 if (ldb_msg_element_equal_ordered(&new_el, &old_el) == false) {
1584 int ret = ldb_msg_add(msg, &new_el, LDB_FLAG_MOD_REPLACE);
1585 if (ret != LDB_SUCCESS) {
1586 return ldb_oom(ldb);
1590 return replmd_update_rpmd_element(ldb, msg, &new_el, NULL,
1591 omd, ar->schema, &ar->seq_num,
1592 &ar->our_invocation_id,
1593 now, is_schema_nc, is_forced_rodc,
1598 static uint64_t find_max_local_usn(struct replPropertyMetaDataBlob omd)
1600 uint32_t count = omd.ctr.ctr1.count;
1603 for (i=0; i < count; i++) {
1604 struct replPropertyMetaData1 m = omd.ctr.ctr1.array[i];
1605 if (max < m.local_usn) {
1613 * update the replPropertyMetaData object each time we modify an
1614 * object. This is needed for DRS replication, as the merge on the
1615 * client is based on this object
1617 static int replmd_update_rpmd(struct ldb_module *module,
1618 const struct dsdb_schema *schema,
1619 struct ldb_request *req,
1620 const char * const *rename_attrs,
1621 struct ldb_message *msg, uint64_t *seq_num,
1622 time_t t, bool is_schema_nc,
1623 bool *is_urgent, bool *rodc)
1625 const struct ldb_val *omd_value;
1626 enum ndr_err_code ndr_err;
1627 struct replPropertyMetaDataBlob omd;
1630 const struct GUID *our_invocation_id;
1632 const char * const *attrs = NULL;
1633 const char * const attrs2[] = { "uSNChanged", "objectClass", "instanceType", NULL };
1634 struct ldb_result *res;
1635 struct ldb_context *ldb;
1636 struct ldb_message_element *objectclass_el;
1637 enum urgent_situation situation;
1638 bool rmd_is_provided;
1639 bool rmd_is_just_resorted = false;
1640 const char *not_rename_attrs[4 + msg->num_elements];
1641 bool is_forced_rodc = false;
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 ret = samdb_rodc(ldb, rodc);
1659 if (ret != LDB_SUCCESS) {
1660 DEBUG(4, (__location__ ": unable to tell if we are an RODC\n"));
1665 ldb_request_get_control(req, DSDB_CONTROL_FORCE_RODC_LOCAL_CHANGE)) {
1666 is_forced_rodc = true;
1669 our_invocation_id = samdb_ntds_invocation_id(ldb);
1670 if (!our_invocation_id) {
1671 /* this happens during an initial vampire while
1672 updating the schema */
1673 DEBUG(5,("No invocationID - skipping replPropertyMetaData update\n"));
1677 unix_to_nt_time(&now, t);
1679 if (ldb_request_get_control(req, DSDB_CONTROL_CHANGEREPLMETADATA_OID)) {
1680 rmd_is_provided = true;
1681 if (ldb_request_get_control(req, DSDB_CONTROL_CHANGEREPLMETADATA_RESORT_OID)) {
1682 rmd_is_just_resorted = true;
1685 rmd_is_provided = false;
1688 /* if isDeleted is present and is TRUE, then we consider we are deleting,
1689 * otherwise we consider we are updating */
1690 if (ldb_msg_check_string_attribute(msg, "isDeleted", "TRUE")) {
1691 situation = REPL_URGENT_ON_DELETE;
1692 } else if (rename_attrs) {
1693 situation = REPL_URGENT_ON_CREATE | REPL_URGENT_ON_DELETE;
1695 situation = REPL_URGENT_ON_UPDATE;
1698 if (rmd_is_provided) {
1699 /* In this case the change_replmetadata control was supplied */
1700 /* We check that it's the only attribute that is provided
1701 * (it's a rare case so it's better to keep the code simplier)
1702 * We also check that the highest local_usn is bigger or the same as
1705 if( msg->num_elements != 1 ||
1706 strncmp(msg->elements[0].name,
1707 "replPropertyMetaData", 20) ) {
1708 DEBUG(0,(__location__ ": changereplmetada control called without "\
1709 "a specified replPropertyMetaData attribute or with others\n"));
1710 return LDB_ERR_OPERATIONS_ERROR;
1712 if (situation != REPL_URGENT_ON_UPDATE) {
1713 DEBUG(0,(__location__ ": changereplmetada control can't be called when deleting an object\n"));
1714 return LDB_ERR_OPERATIONS_ERROR;
1716 omd_value = ldb_msg_find_ldb_val(msg, "replPropertyMetaData");
1718 DEBUG(0,(__location__ ": replPropertyMetaData was not specified for Object %s\n",
1719 ldb_dn_get_linearized(msg->dn)));
1720 return LDB_ERR_OPERATIONS_ERROR;
1722 ndr_err = ndr_pull_struct_blob(omd_value, msg, &omd,
1723 (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
1724 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1725 DEBUG(0,(__location__ ": Failed to parse replPropertyMetaData for %s\n",
1726 ldb_dn_get_linearized(msg->dn)));
1727 return LDB_ERR_OPERATIONS_ERROR;
1730 ret = dsdb_module_search_dn(module, msg, &res, msg->dn, attrs2,
1731 DSDB_FLAG_NEXT_MODULE |
1732 DSDB_SEARCH_SHOW_RECYCLED |
1733 DSDB_SEARCH_SHOW_EXTENDED_DN |
1734 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT |
1735 DSDB_SEARCH_REVEAL_INTERNALS, req);
1737 if (ret != LDB_SUCCESS) {
1741 if (rmd_is_just_resorted == false) {
1742 *seq_num = find_max_local_usn(omd);
1744 db_seq = ldb_msg_find_attr_as_uint64(res->msgs[0], "uSNChanged", 0);
1747 * The test here now allows for a new
1748 * replPropertyMetaData with no change, if was
1749 * just dbcheck re-sorting the values.
1751 if (*seq_num <= db_seq) {
1752 DEBUG(0,(__location__ ": changereplmetada control provided but max(local_usn)" \
1753 " is less than uSNChanged (max = %lld uSNChanged = %lld)\n",
1754 (long long)*seq_num, (long long)db_seq));
1755 return LDB_ERR_OPERATIONS_ERROR;
1760 /* search for the existing replPropertyMetaDataBlob. We need
1761 * to use REVEAL and ask for DNs in storage format to support
1762 * the check for values being the same in
1763 * replmd_update_rpmd_element()
1765 ret = dsdb_module_search_dn(module, msg, &res, msg->dn, attrs,
1766 DSDB_FLAG_NEXT_MODULE |
1767 DSDB_SEARCH_SHOW_RECYCLED |
1768 DSDB_SEARCH_SHOW_EXTENDED_DN |
1769 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT |
1770 DSDB_SEARCH_REVEAL_INTERNALS, req);
1771 if (ret != LDB_SUCCESS) {
1775 omd_value = ldb_msg_find_ldb_val(res->msgs[0], "replPropertyMetaData");
1777 DEBUG(0,(__location__ ": Object %s does not have a replPropertyMetaData attribute\n",
1778 ldb_dn_get_linearized(msg->dn)));
1779 return LDB_ERR_OPERATIONS_ERROR;
1782 ndr_err = ndr_pull_struct_blob(omd_value, msg, &omd,
1783 (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
1784 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1785 DEBUG(0,(__location__ ": Failed to parse replPropertyMetaData for %s\n",
1786 ldb_dn_get_linearized(msg->dn)));
1787 return LDB_ERR_OPERATIONS_ERROR;
1790 if (omd.version != 1) {
1791 DEBUG(0,(__location__ ": bad version %u in replPropertyMetaData for %s\n",
1792 omd.version, ldb_dn_get_linearized(msg->dn)));
1793 return LDB_ERR_OPERATIONS_ERROR;
1796 for (i=0; i<msg->num_elements;) {
1797 struct ldb_message_element *el = &msg->elements[i];
1798 struct ldb_message_element *old_el;
1800 old_el = ldb_msg_find_element(res->msgs[0], el->name);
1801 ret = replmd_update_rpmd_element(ldb, msg, el, old_el,
1802 &omd, schema, seq_num,
1807 if (ret != LDB_SUCCESS) {
1811 if (!*is_urgent && (situation == REPL_URGENT_ON_UPDATE)) {
1812 *is_urgent = replmd_check_urgent_attribute(el);
1815 if (!(el->flags & DSDB_FLAG_INTERNAL_FORCE_META_DATA)) {
1820 el->flags &= ~DSDB_FLAG_INTERNAL_FORCE_META_DATA;
1822 if (el->num_values != 0) {
1827 ldb_msg_remove_element(msg, el);
1832 * Assert that we have an objectClass attribute - this is major
1833 * corruption if we don't have this!
1835 objectclass_el = ldb_msg_find_element(res->msgs[0], "objectClass");
1836 if (objectclass_el != NULL) {
1838 * Now check if this objectClass means we need to do urgent replication
1840 if (!*is_urgent && replmd_check_urgent_objectclass(objectclass_el,
1844 } else if (!ldb_request_get_control(req, DSDB_CONTROL_DBCHECK)) {
1845 ldb_asprintf_errstring(ldb, __location__
1846 ": objectClass missing on %s\n",
1847 ldb_dn_get_linearized(msg->dn));
1848 return LDB_ERR_OBJECT_CLASS_VIOLATION;
1852 * replmd_update_rpmd_element has done an update if the
1855 if (*seq_num != 0 || rmd_is_just_resorted == true) {
1856 struct ldb_val *md_value;
1857 struct ldb_message_element *el;
1859 /*if we are RODC and this is a DRSR update then its ok*/
1860 if (!ldb_request_get_control(req, DSDB_CONTROL_REPLICATED_UPDATE_OID)
1861 && !ldb_request_get_control(req, DSDB_CONTROL_DBCHECK_MODIFY_RO_REPLICA)
1862 && !is_forced_rodc) {
1863 unsigned instanceType;
1866 ldb_set_errstring(ldb, "RODC modify is forbidden!");
1867 return LDB_ERR_REFERRAL;
1870 instanceType = ldb_msg_find_attr_as_uint(res->msgs[0], "instanceType", INSTANCE_TYPE_WRITE);
1871 if (!(instanceType & INSTANCE_TYPE_WRITE)) {
1872 return ldb_error(ldb, LDB_ERR_UNWILLING_TO_PERFORM,
1873 "cannot change replicated attribute on partial replica");
1877 md_value = talloc(msg, struct ldb_val);
1878 if (md_value == NULL) {
1880 return LDB_ERR_OPERATIONS_ERROR;
1883 ret = replmd_replPropertyMetaDataCtr1_sort_and_verify(ldb, &omd.ctr.ctr1, msg->dn);
1884 if (ret != LDB_SUCCESS) {
1885 ldb_asprintf_errstring(ldb, "%s: %s", __func__, ldb_errstring(ldb));
1889 ndr_err = ndr_push_struct_blob(md_value, msg, &omd,
1890 (ndr_push_flags_fn_t)ndr_push_replPropertyMetaDataBlob);
1891 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1892 DEBUG(0,(__location__ ": Failed to marshall replPropertyMetaData for %s\n",
1893 ldb_dn_get_linearized(msg->dn)));
1894 return LDB_ERR_OPERATIONS_ERROR;
1897 ret = ldb_msg_add_empty(msg, "replPropertyMetaData", LDB_FLAG_MOD_REPLACE, &el);
1898 if (ret != LDB_SUCCESS) {
1899 DEBUG(0,(__location__ ": Failed to add updated replPropertyMetaData %s\n",
1900 ldb_dn_get_linearized(msg->dn)));
1905 el->values = md_value;
1911 static int parsed_dn_compare(struct parsed_dn *pdn1, struct parsed_dn *pdn2)
1913 int ret = ndr_guid_compare(&pdn1->guid, &pdn2->guid);
1915 return data_blob_cmp(&pdn1->dsdb_dn->extra_part,
1916 &pdn2->dsdb_dn->extra_part);
1922 get a series of message element values as an array of DNs and GUIDs
1923 the result is sorted by GUID
1925 static int get_parsed_dns(struct ldb_module *module, TALLOC_CTX *mem_ctx,
1926 struct ldb_message_element *el, struct parsed_dn **pdn,
1927 const char *ldap_oid, struct ldb_request *parent)
1930 bool values_are_sorted = true;
1931 struct ldb_context *ldb = ldb_module_get_ctx(module);
1938 (*pdn) = talloc_array(mem_ctx, struct parsed_dn, el->num_values);
1940 ldb_module_oom(module);
1941 return LDB_ERR_OPERATIONS_ERROR;
1944 for (i=0; i<el->num_values; i++) {
1945 struct ldb_val *v = &el->values[i];
1948 struct parsed_dn *p;
1952 p->dsdb_dn = dsdb_dn_parse(*pdn, ldb, v, ldap_oid);
1953 if (p->dsdb_dn == NULL) {
1954 return LDB_ERR_INVALID_DN_SYNTAX;
1957 dn = p->dsdb_dn->dn;
1959 status = dsdb_get_extended_dn_guid(dn, &p->guid, "GUID");
1960 if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND) ||
1961 unlikely(GUID_all_zero(&p->guid))) {
1962 /* we got a DN without a GUID - go find the GUID */
1963 int ret = dsdb_module_guid_by_dn(module, dn, &p->guid, parent);
1964 if (ret != LDB_SUCCESS) {
1965 ldb_asprintf_errstring(ldb, "Unable to find GUID for DN %s\n",
1966 ldb_dn_get_linearized(dn));
1967 if (ret == LDB_ERR_NO_SUCH_OBJECT &&
1968 LDB_FLAG_MOD_TYPE(el->flags) == LDB_FLAG_MOD_DELETE &&
1969 ldb_attr_cmp(el->name, "member") == 0) {
1970 return LDB_ERR_UNWILLING_TO_PERFORM;
1974 ret = dsdb_set_extended_dn_guid(dn, &p->guid, "GUID");
1975 if (ret != LDB_SUCCESS) {
1978 } else if (!NT_STATUS_IS_OK(status)) {
1979 return LDB_ERR_OPERATIONS_ERROR;
1981 if (i > 0 && values_are_sorted) {
1982 int cmp = parsed_dn_compare(p, &(*pdn)[i - 1]);
1984 values_are_sorted = false;
1987 /* keep a pointer to the original ldb_val */
1990 if (! values_are_sorted) {
1991 TYPESAFE_QSORT(*pdn, el->num_values, parsed_dn_compare);
1997 * Get a series of trusted message element values. The result is sorted by
1998 * GUID, even though the GUIDs might not be known. That works because we trust
1999 * the database to give us the elements like that if the
2000 * replmd_private->sorted_links flag is set.
2002 * We also ensure that the links are in the Functional Level 2003
2003 * linked attributes format.
2005 static int get_parsed_dns_trusted(struct ldb_module *module,
2006 struct replmd_private *replmd_private,
2007 TALLOC_CTX *mem_ctx,
2008 struct ldb_message_element *el,
2009 struct parsed_dn **pdn,
2010 const char *ldap_oid,
2011 struct ldb_request *parent)
2020 if (!replmd_private->sorted_links) {
2021 /* We need to sort the list. This is the slow old path we want
2024 ret = get_parsed_dns(module, mem_ctx, el, pdn, ldap_oid,
2026 if (ret != LDB_SUCCESS) {
2030 /* Here we get a list of 'struct parsed_dns' without the parsing */
2031 *pdn = talloc_zero_array(mem_ctx, struct parsed_dn,
2034 ldb_module_oom(module);
2035 return LDB_ERR_OPERATIONS_ERROR;
2038 for (i = 0; i < el->num_values; i++) {
2039 (*pdn)[i].v = &el->values[i];
2044 * This upgrades links to FL2003 style, and sorts the result
2045 * if that was needed.
2047 * TODO: Add a database feature that asserts we have no FL2000
2048 * style links to avoid this check or add a feature that
2049 * uses a similar check to find sorted/unsorted links
2050 * for an on-the-fly upgrade.
2053 ret = replmd_check_upgrade_links(ldb_module_get_ctx(module),
2054 *pdn, el->num_values,
2057 if (ret != LDB_SUCCESS) {
2065 build a new extended DN, including all meta data fields
2067 RMD_FLAGS = DSDB_RMD_FLAG_* bits
2068 RMD_ADDTIME = originating_add_time
2069 RMD_INVOCID = originating_invocation_id
2070 RMD_CHANGETIME = originating_change_time
2071 RMD_ORIGINATING_USN = originating_usn
2072 RMD_LOCAL_USN = local_usn
2073 RMD_VERSION = version
2075 static int replmd_build_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct dsdb_dn *dsdb_dn,
2076 const struct GUID *invocation_id, uint64_t seq_num,
2077 uint64_t local_usn, NTTIME nttime, uint32_t version, bool deleted)
2079 struct ldb_dn *dn = dsdb_dn->dn;
2080 const char *tstring, *usn_string, *flags_string;
2081 struct ldb_val tval;
2083 struct ldb_val usnv, local_usnv;
2084 struct ldb_val vers, flagsv;
2087 const char *dnstring;
2089 uint32_t rmd_flags = deleted?DSDB_RMD_FLAG_DELETED:0;
2091 tstring = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)nttime);
2093 return LDB_ERR_OPERATIONS_ERROR;
2095 tval = data_blob_string_const(tstring);
2097 usn_string = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)seq_num);
2099 return LDB_ERR_OPERATIONS_ERROR;
2101 usnv = data_blob_string_const(usn_string);
2103 usn_string = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)local_usn);
2105 return LDB_ERR_OPERATIONS_ERROR;
2107 local_usnv = data_blob_string_const(usn_string);
2109 vstring = talloc_asprintf(mem_ctx, "%lu", (unsigned long)version);
2111 return LDB_ERR_OPERATIONS_ERROR;
2113 vers = data_blob_string_const(vstring);
2115 status = GUID_to_ndr_blob(invocation_id, dn, &iid);
2116 if (!NT_STATUS_IS_OK(status)) {
2117 return LDB_ERR_OPERATIONS_ERROR;
2120 flags_string = talloc_asprintf(mem_ctx, "%u", rmd_flags);
2121 if (!flags_string) {
2122 return LDB_ERR_OPERATIONS_ERROR;
2124 flagsv = data_blob_string_const(flags_string);
2126 ret = ldb_dn_set_extended_component(dn, "RMD_FLAGS", &flagsv);
2127 if (ret != LDB_SUCCESS) return ret;
2128 ret = ldb_dn_set_extended_component(dn, "RMD_ADDTIME", &tval);
2129 if (ret != LDB_SUCCESS) return ret;
2130 ret = ldb_dn_set_extended_component(dn, "RMD_INVOCID", &iid);
2131 if (ret != LDB_SUCCESS) return ret;
2132 ret = ldb_dn_set_extended_component(dn, "RMD_CHANGETIME", &tval);
2133 if (ret != LDB_SUCCESS) return ret;
2134 ret = ldb_dn_set_extended_component(dn, "RMD_LOCAL_USN", &local_usnv);
2135 if (ret != LDB_SUCCESS) return ret;
2136 ret = ldb_dn_set_extended_component(dn, "RMD_ORIGINATING_USN", &usnv);
2137 if (ret != LDB_SUCCESS) return ret;
2138 ret = ldb_dn_set_extended_component(dn, "RMD_VERSION", &vers);
2139 if (ret != LDB_SUCCESS) return ret;
2141 dnstring = dsdb_dn_get_extended_linearized(mem_ctx, dsdb_dn, 1);
2142 if (dnstring == NULL) {
2143 return LDB_ERR_OPERATIONS_ERROR;
2145 *v = data_blob_string_const(dnstring);
2150 static int replmd_update_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct dsdb_dn *dsdb_dn,
2151 struct dsdb_dn *old_dsdb_dn, const struct GUID *invocation_id,
2152 uint64_t seq_num, uint64_t local_usn, NTTIME nttime,
2153 uint32_t version, bool deleted);
2156 check if any links need upgrading from w2k format
2158 static int replmd_check_upgrade_links(struct ldb_context *ldb,
2159 struct parsed_dn *dns, uint32_t count,
2160 struct ldb_message_element *el,
2161 const char *ldap_oid)
2164 const struct GUID *invocation_id = NULL;
2165 for (i=0; i<count; i++) {
2169 if (dns[i].dsdb_dn == NULL) {
2170 ret = really_parse_trusted_dn(dns, ldb, &dns[i],
2172 if (ret != LDB_SUCCESS) {
2173 return LDB_ERR_INVALID_DN_SYNTAX;
2177 status = dsdb_get_extended_dn_uint32(dns[i].dsdb_dn->dn,
2178 &version, "RMD_VERSION");
2179 if (!NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
2181 * We optimistically assume they are all the same; if
2182 * the first one is fixed, they are all fixed.
2184 * If the first one was *not* fixed and we find a
2185 * later one that is, that is an occasion to shout
2191 DEBUG(0, ("Mixed w2k and fixed format "
2192 "linked attributes\n"));
2196 if (invocation_id == NULL) {
2197 invocation_id = samdb_ntds_invocation_id(ldb);
2198 if (invocation_id == NULL) {
2199 return LDB_ERR_OPERATIONS_ERROR;
2204 /* it's an old one that needs upgrading */
2205 ret = replmd_update_la_val(el->values, dns[i].v,
2206 dns[i].dsdb_dn, dns[i].dsdb_dn,
2207 invocation_id, 1, 1, 0, 0, false);
2208 if (ret != LDB_SUCCESS) {
2214 * This sort() is critical for the operation of
2215 * get_parsed_dns_trusted() because callers of this function
2216 * expect a sorted list, and FL2000 style links are not
2217 * sorted. In particular, as well as the upgrade case,
2218 * get_parsed_dns_trusted() is called from
2219 * replmd_delete_remove_link() even in FL2000 mode
2221 * We do not normally pay the cost of the qsort() due to the
2222 * early return in the RMD_VERSION found case.
2224 TYPESAFE_QSORT(dns, count, parsed_dn_compare);
2229 update an extended DN, including all meta data fields
2231 see replmd_build_la_val for value names
2233 static int replmd_update_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct dsdb_dn *dsdb_dn,
2234 struct dsdb_dn *old_dsdb_dn, const struct GUID *invocation_id,
2235 uint64_t usn, uint64_t local_usn, NTTIME nttime,
2236 uint32_t version, bool deleted)
2238 struct ldb_dn *dn = dsdb_dn->dn;
2239 const char *tstring, *usn_string, *flags_string;
2240 struct ldb_val tval;
2242 struct ldb_val usnv, local_usnv;
2243 struct ldb_val vers, flagsv;
2244 const struct ldb_val *old_addtime;
2245 uint32_t old_version;
2248 const char *dnstring;
2250 uint32_t rmd_flags = deleted?DSDB_RMD_FLAG_DELETED:0;
2252 tstring = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)nttime);
2254 return LDB_ERR_OPERATIONS_ERROR;
2256 tval = data_blob_string_const(tstring);
2258 usn_string = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)usn);
2260 return LDB_ERR_OPERATIONS_ERROR;
2262 usnv = data_blob_string_const(usn_string);
2264 usn_string = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)local_usn);
2266 return LDB_ERR_OPERATIONS_ERROR;
2268 local_usnv = data_blob_string_const(usn_string);
2270 status = GUID_to_ndr_blob(invocation_id, dn, &iid);
2271 if (!NT_STATUS_IS_OK(status)) {
2272 return LDB_ERR_OPERATIONS_ERROR;
2275 flags_string = talloc_asprintf(mem_ctx, "%u", rmd_flags);
2276 if (!flags_string) {
2277 return LDB_ERR_OPERATIONS_ERROR;
2279 flagsv = data_blob_string_const(flags_string);
2281 ret = ldb_dn_set_extended_component(dn, "RMD_FLAGS", &flagsv);
2282 if (ret != LDB_SUCCESS) return ret;
2284 /* get the ADDTIME from the original */
2285 old_addtime = ldb_dn_get_extended_component(old_dsdb_dn->dn, "RMD_ADDTIME");
2286 if (old_addtime == NULL) {
2287 old_addtime = &tval;
2289 if (dsdb_dn != old_dsdb_dn ||
2290 ldb_dn_get_extended_component(dn, "RMD_ADDTIME") == NULL) {
2291 ret = ldb_dn_set_extended_component(dn, "RMD_ADDTIME", old_addtime);
2292 if (ret != LDB_SUCCESS) return ret;
2295 /* use our invocation id */
2296 ret = ldb_dn_set_extended_component(dn, "RMD_INVOCID", &iid);
2297 if (ret != LDB_SUCCESS) return ret;
2299 /* changetime is the current time */
2300 ret = ldb_dn_set_extended_component(dn, "RMD_CHANGETIME", &tval);
2301 if (ret != LDB_SUCCESS) return ret;
2303 /* update the USN */
2304 ret = ldb_dn_set_extended_component(dn, "RMD_ORIGINATING_USN", &usnv);
2305 if (ret != LDB_SUCCESS) return ret;
2307 ret = ldb_dn_set_extended_component(dn, "RMD_LOCAL_USN", &local_usnv);
2308 if (ret != LDB_SUCCESS) return ret;
2310 /* increase the version by 1 */
2311 status = dsdb_get_extended_dn_uint32(old_dsdb_dn->dn, &old_version, "RMD_VERSION");
2312 if (NT_STATUS_IS_OK(status) && old_version >= version) {
2313 version = old_version+1;
2315 vstring = talloc_asprintf(dn, "%lu", (unsigned long)version);
2316 vers = data_blob_string_const(vstring);
2317 ret = ldb_dn_set_extended_component(dn, "RMD_VERSION", &vers);
2318 if (ret != LDB_SUCCESS) return ret;
2320 dnstring = dsdb_dn_get_extended_linearized(mem_ctx, dsdb_dn, 1);
2321 if (dnstring == NULL) {
2322 return LDB_ERR_OPERATIONS_ERROR;
2324 *v = data_blob_string_const(dnstring);
2330 handle adding a linked attribute
2332 static int replmd_modify_la_add(struct ldb_module *module,
2333 struct replmd_private *replmd_private,
2334 const struct dsdb_schema *schema,
2335 struct ldb_message *msg,
2336 struct ldb_message_element *el,
2337 struct ldb_message_element *old_el,
2338 const struct dsdb_attribute *schema_attr,
2341 struct ldb_dn *msg_dn,
2342 struct ldb_request *parent)
2345 struct parsed_dn *dns, *old_dns;
2346 TALLOC_CTX *tmp_ctx = talloc_new(msg);
2348 struct ldb_val *new_values = NULL;
2349 unsigned old_num_values = old_el ? old_el->num_values : 0;
2350 unsigned num_values = 0;
2351 unsigned max_num_values;
2352 const struct GUID *invocation_id;
2353 struct ldb_context *ldb = ldb_module_get_ctx(module);
2355 unix_to_nt_time(&now, t);
2357 invocation_id = samdb_ntds_invocation_id(ldb);
2358 if (!invocation_id) {
2359 talloc_free(tmp_ctx);
2360 return LDB_ERR_OPERATIONS_ERROR;
2363 /* get the DNs to be added, fully parsed.
2365 * We need full parsing because they came off the wire and we don't
2366 * trust them, besides which we need their details to know where to put
2369 ret = get_parsed_dns(module, tmp_ctx, el, &dns,
2370 schema_attr->syntax->ldap_oid, parent);
2371 if (ret != LDB_SUCCESS) {
2372 talloc_free(tmp_ctx);
2376 /* get the existing DNs, lazily parsed */
2377 ret = get_parsed_dns_trusted(module, replmd_private,
2378 tmp_ctx, old_el, &old_dns,
2379 schema_attr->syntax->ldap_oid, parent);
2381 if (ret != LDB_SUCCESS) {
2382 talloc_free(tmp_ctx);
2386 max_num_values = old_num_values + el->num_values;
2387 if (max_num_values < old_num_values) {
2388 DEBUG(0, ("we seem to have overflow in replmd_modify_la_add. "
2389 "old values: %u, new values: %u, sum: %u",
2390 old_num_values, el->num_values, max_num_values));
2391 talloc_free(tmp_ctx);
2392 return LDB_ERR_OPERATIONS_ERROR;
2395 new_values = talloc_zero_array(tmp_ctx, struct ldb_val, max_num_values);
2397 if (new_values == NULL) {
2398 ldb_module_oom(module);
2399 talloc_free(tmp_ctx);
2400 return LDB_ERR_OPERATIONS_ERROR;
2404 * For each new value, find where it would go in the list. If there is
2405 * a matching GUID there, we update the existing value; otherwise we
2409 for (i = 0; i < el->num_values; i++) {
2410 struct parsed_dn *exact;
2411 struct parsed_dn *next;
2413 int err = parsed_dn_find(ldb, old_dns, old_num_values,
2416 dns[i].dsdb_dn->extra_part, 0,
2418 schema_attr->syntax->ldap_oid,
2420 if (err != LDB_SUCCESS) {
2421 talloc_free(tmp_ctx);
2425 if (exact != NULL) {
2427 * We are trying to add one that exists, which is only
2428 * allowed if it was previously deleted.
2430 * When we do undelete a link we change it in place.
2431 * It will be copied across into the right spot in due
2435 rmd_flags = dsdb_dn_rmd_flags(exact->dsdb_dn->dn);
2437 if (!(rmd_flags & DSDB_RMD_FLAG_DELETED)) {
2438 struct GUID_txt_buf guid_str;
2439 ldb_asprintf_errstring(ldb,
2440 "Attribute %s already "
2441 "exists for target GUID %s",
2443 GUID_buf_string(&exact->guid,
2445 talloc_free(tmp_ctx);
2446 /* error codes for 'member' need to be
2448 if (ldb_attr_cmp(el->name, "member") == 0) {
2449 return LDB_ERR_ENTRY_ALREADY_EXISTS;
2451 return LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS;
2455 ret = replmd_update_la_val(new_values, exact->v,
2458 invocation_id, seq_num,
2459 seq_num, now, 0, false);
2460 if (ret != LDB_SUCCESS) {
2461 talloc_free(tmp_ctx);
2465 ret = replmd_add_backlink(module, replmd_private,
2472 if (ret != LDB_SUCCESS) {
2473 talloc_free(tmp_ctx);
2479 * Here we don't have an exact match.
2481 * If next is NULL, this one goes beyond the end of the
2482 * existing list, so we need to add all of those ones first.
2484 * If next is not NULL, we need to add all the ones before
2488 offset = old_num_values;
2490 /* next should have been parsed, but let's make sure */
2491 if (next->dsdb_dn == NULL) {
2492 ret = really_parse_trusted_dn(tmp_ctx, ldb, next,
2493 schema_attr->syntax->ldap_oid);
2494 if (ret != LDB_SUCCESS) {
2498 offset = MIN(next - old_dns, old_num_values);
2501 /* put all the old ones before next on the list */
2502 for (; j < offset; j++) {
2503 new_values[num_values] = *old_dns[j].v;
2507 ret = replmd_add_backlink(module, replmd_private,
2512 /* Make the new linked attribute ldb_val. */
2513 ret = replmd_build_la_val(new_values, &new_values[num_values],
2514 dns[i].dsdb_dn, invocation_id,
2517 if (ret != LDB_SUCCESS) {
2518 talloc_free(tmp_ctx);
2522 if (ret != LDB_SUCCESS) {
2523 talloc_free(tmp_ctx);
2527 /* copy the rest of the old ones (if any) */
2528 for (; j < old_num_values; j++) {
2529 new_values[num_values] = *old_dns[j].v;
2533 talloc_steal(msg->elements, new_values);
2534 if (old_el != NULL) {
2535 talloc_steal(msg->elements, old_el->values);
2537 el->values = new_values;
2538 el->num_values = num_values;
2540 talloc_free(tmp_ctx);
2542 /* we now tell the backend to replace all existing values
2543 with the one we have constructed */
2544 el->flags = LDB_FLAG_MOD_REPLACE;
2551 handle deleting all active linked attributes
2553 static int replmd_modify_la_delete(struct ldb_module *module,
2554 struct replmd_private *replmd_private,
2555 const struct dsdb_schema *schema,
2556 struct ldb_message *msg,
2557 struct ldb_message_element *el,
2558 struct ldb_message_element *old_el,
2559 const struct dsdb_attribute *schema_attr,
2562 struct ldb_dn *msg_dn,
2563 struct ldb_request *parent)
2566 struct parsed_dn *dns, *old_dns;
2567 TALLOC_CTX *tmp_ctx = NULL;
2569 struct ldb_context *ldb = ldb_module_get_ctx(module);
2570 struct ldb_control *vanish_links_ctrl = NULL;
2571 bool vanish_links = false;
2572 unsigned int num_to_delete = el->num_values;
2574 const struct GUID *invocation_id;
2577 unix_to_nt_time(&now, t);
2579 invocation_id = samdb_ntds_invocation_id(ldb);
2580 if (!invocation_id) {
2581 return LDB_ERR_OPERATIONS_ERROR;
2584 if (old_el == NULL || old_el->num_values == 0) {
2585 /* there is nothing to delete... */
2586 if (num_to_delete == 0) {
2587 /* and we're deleting nothing, so that's OK */
2590 return LDB_ERR_NO_SUCH_ATTRIBUTE;
2593 tmp_ctx = talloc_new(msg);
2594 if (tmp_ctx == NULL) {
2595 return LDB_ERR_OPERATIONS_ERROR;
2598 ret = get_parsed_dns(module, tmp_ctx, el, &dns,
2599 schema_attr->syntax->ldap_oid, parent);
2600 if (ret != LDB_SUCCESS) {
2601 talloc_free(tmp_ctx);
2605 ret = get_parsed_dns_trusted(module, replmd_private,
2606 tmp_ctx, old_el, &old_dns,
2607 schema_attr->syntax->ldap_oid, parent);
2609 if (ret != LDB_SUCCESS) {
2610 talloc_free(tmp_ctx);
2615 vanish_links_ctrl = ldb_request_get_control(parent, DSDB_CONTROL_REPLMD_VANISH_LINKS);
2616 if (vanish_links_ctrl) {
2617 vanish_links = true;
2618 vanish_links_ctrl->critical = false;
2622 /* we empty out el->values here to avoid damage if we return early. */
2627 * If vanish links is set, we are actually removing members of
2628 * old_el->values; otherwise we are just marking them deleted.
2630 * There is a special case when no values are given: we remove them
2631 * all. When we have the vanish_links control we just have to remove
2632 * the backlinks and change our element to replace the existing values
2633 * with the empty list.
2636 if (num_to_delete == 0) {
2637 for (i = 0; i < old_el->num_values; i++) {
2638 struct parsed_dn *p = &old_dns[i];
2639 if (p->dsdb_dn == NULL) {
2640 ret = really_parse_trusted_dn(tmp_ctx, ldb, p,
2641 schema_attr->syntax->ldap_oid);
2642 if (ret != LDB_SUCCESS) {
2646 ret = replmd_add_backlink(module, replmd_private,
2647 schema, msg_dn, &p->guid,
2650 if (ret != LDB_SUCCESS) {
2651 talloc_free(tmp_ctx);
2658 rmd_flags = dsdb_dn_rmd_flags(p->dsdb_dn->dn);
2659 if (rmd_flags & DSDB_RMD_FLAG_DELETED) {
2663 ret = replmd_update_la_val(old_el->values, p->v,
2664 p->dsdb_dn, p->dsdb_dn,
2665 invocation_id, seq_num,
2666 seq_num, now, 0, true);
2667 if (ret != LDB_SUCCESS) {
2668 talloc_free(tmp_ctx);
2674 el->flags = LDB_FLAG_MOD_REPLACE;
2675 talloc_free(tmp_ctx);
2681 for (i = 0; i < num_to_delete; i++) {
2682 struct parsed_dn *p = &dns[i];
2683 struct parsed_dn *exact = NULL;
2684 struct parsed_dn *next = NULL;
2685 ret = parsed_dn_find(ldb, old_dns, old_el->num_values,
2688 p->dsdb_dn->extra_part, 0,
2690 schema_attr->syntax->ldap_oid,
2692 if (ret != LDB_SUCCESS) {
2693 talloc_free(tmp_ctx);
2696 if (exact == NULL) {
2697 struct GUID_txt_buf buf;
2698 ldb_asprintf_errstring(ldb, "Attribute %s doesn't "
2699 "exist for target GUID %s",
2701 GUID_buf_string(&p->guid, &buf));
2702 if (ldb_attr_cmp(el->name, "member") == 0) {
2703 talloc_free(tmp_ctx);
2704 return LDB_ERR_UNWILLING_TO_PERFORM;
2706 talloc_free(tmp_ctx);
2707 return LDB_ERR_NO_SUCH_ATTRIBUTE;
2712 if (CHECK_DEBUGLVL(5)) {
2713 rmd_flags = dsdb_dn_rmd_flags(exact->dsdb_dn->dn);
2714 if ((rmd_flags & DSDB_RMD_FLAG_DELETED)) {
2715 struct GUID_txt_buf buf;
2716 const char *guid_str = \
2717 GUID_buf_string(&p->guid, &buf);
2718 DEBUG(5, ("Deleting deleted linked "
2719 "attribute %s to %s, because "
2720 "vanish_links control is set\n",
2721 el->name, guid_str));
2725 /* remove the backlink */
2726 ret = replmd_add_backlink(module,
2733 if (ret != LDB_SUCCESS) {
2734 talloc_free(tmp_ctx);
2738 /* We flag the deletion and tidy it up later. */
2743 rmd_flags = dsdb_dn_rmd_flags(exact->dsdb_dn->dn);
2745 if (rmd_flags & DSDB_RMD_FLAG_DELETED) {
2746 struct GUID_txt_buf buf;
2747 const char *guid_str = GUID_buf_string(&p->guid, &buf);
2748 ldb_asprintf_errstring(ldb, "Attribute %s already "
2749 "deleted for target GUID %s",
2750 el->name, guid_str);
2751 if (ldb_attr_cmp(el->name, "member") == 0) {
2752 talloc_free(tmp_ctx);
2753 return LDB_ERR_UNWILLING_TO_PERFORM;
2755 talloc_free(tmp_ctx);
2756 return LDB_ERR_NO_SUCH_ATTRIBUTE;
2760 ret = replmd_update_la_val(old_el->values, exact->v,
2761 exact->dsdb_dn, exact->dsdb_dn,
2762 invocation_id, seq_num, seq_num,
2764 if (ret != LDB_SUCCESS) {
2765 talloc_free(tmp_ctx);
2768 ret = replmd_add_backlink(module, replmd_private,
2773 if (ret != LDB_SUCCESS) {
2774 talloc_free(tmp_ctx);
2781 for (i = 0; i < old_el->num_values; i++) {
2782 if (old_dns[i].v != NULL) {
2783 old_el->values[j] = *old_dns[i].v;
2787 old_el->num_values = j;
2790 el->values = talloc_steal(msg->elements, old_el->values);
2791 el->num_values = old_el->num_values;
2793 talloc_free(tmp_ctx);
2795 /* we now tell the backend to replace all existing values
2796 with the one we have constructed */
2797 el->flags = LDB_FLAG_MOD_REPLACE;
2803 handle replacing a linked attribute
2805 static int replmd_modify_la_replace(struct ldb_module *module,
2806 struct replmd_private *replmd_private,
2807 const struct dsdb_schema *schema,
2808 struct ldb_message *msg,
2809 struct ldb_message_element *el,
2810 struct ldb_message_element *old_el,
2811 const struct dsdb_attribute *schema_attr,
2814 struct ldb_dn *msg_dn,
2815 struct ldb_request *parent)
2817 unsigned int i, old_i, new_i;
2818 struct parsed_dn *dns, *old_dns;
2819 TALLOC_CTX *tmp_ctx = talloc_new(msg);
2821 const struct GUID *invocation_id;
2822 struct ldb_context *ldb = ldb_module_get_ctx(module);
2823 struct ldb_val *new_values = NULL;
2824 const char *ldap_oid = schema_attr->syntax->ldap_oid;
2825 unsigned int old_num_values;
2826 unsigned int repl_num_values;
2827 unsigned int max_num_values;
2830 unix_to_nt_time(&now, t);
2832 invocation_id = samdb_ntds_invocation_id(ldb);
2833 if (!invocation_id) {
2834 return LDB_ERR_OPERATIONS_ERROR;
2838 * The replace operation is unlike the replace and delete cases in that
2839 * we need to look at every existing link to see whether it is being
2840 * retained or deleted. In other words, we can't avoid parsing the GUIDs.
2842 * As we are trying to combine two sorted lists, the algorithm we use
2843 * is akin to the merge phase of a merge sort. We interleave the two
2844 * lists, doing different things depending on which side the current
2847 * There are three main cases, with some sub-cases.
2849 * - a DN is in the old list but not the new one. It needs to be
2850 * marked as deleted (but left in the list).
2851 * - maybe it is already deleted, and we have less to do.
2853 * - a DN is in both lists. The old data gets replaced by the new,
2854 * and the list doesn't grow. The old link may have been marked as
2855 * deleted, in which case we undelete it.
2857 * - a DN is in the new list only. We add it in the right place.
2860 old_num_values = old_el ? old_el->num_values : 0;
2861 repl_num_values = el->num_values;
2862 max_num_values = old_num_values + repl_num_values;
2864 if (max_num_values == 0) {
2865 /* There is nothing to do! */
2869 ret = get_parsed_dns(module, tmp_ctx, el, &dns, ldap_oid, parent);
2870 if (ret != LDB_SUCCESS) {
2871 talloc_free(tmp_ctx);
2875 ret = get_parsed_dns(module, tmp_ctx, old_el, &old_dns,
2877 if (ret != LDB_SUCCESS) {
2878 talloc_free(tmp_ctx);
2882 ret = replmd_check_upgrade_links(ldb, old_dns, old_num_values,
2884 if (ret != LDB_SUCCESS) {
2885 talloc_free(tmp_ctx);
2889 new_values = talloc_array(tmp_ctx, struct ldb_val, max_num_values);
2890 if (new_values == NULL) {
2891 ldb_module_oom(module);
2892 talloc_free(tmp_ctx);
2893 return LDB_ERR_OPERATIONS_ERROR;
2898 for (i = 0; i < max_num_values; i++) {
2900 struct parsed_dn *old_p, *new_p;
2901 if (old_i < old_num_values && new_i < repl_num_values) {
2902 old_p = &old_dns[old_i];
2903 new_p = &dns[new_i];
2904 cmp = parsed_dn_compare(old_p, new_p);
2905 } else if (old_i < old_num_values) {
2906 /* the new list is empty, read the old list */
2907 old_p = &old_dns[old_i];
2910 } else if (new_i < repl_num_values) {
2911 /* the old list is empty, read new list */
2913 new_p = &dns[new_i];
2921 * An old ones that come before the next replacement
2922 * (if any). We mark it as deleted and add it to the
2925 uint32_t rmd_flags = dsdb_dn_rmd_flags(old_p->dsdb_dn->dn);
2926 if ((rmd_flags & DSDB_RMD_FLAG_DELETED) == 0) {
2927 ret = replmd_update_la_val(new_values, old_p->v,
2933 if (ret != LDB_SUCCESS) {
2934 talloc_free(tmp_ctx);
2938 ret = replmd_add_backlink(module, replmd_private,
2941 &old_p->guid, false,
2944 if (ret != LDB_SUCCESS) {
2945 talloc_free(tmp_ctx);
2949 new_values[i] = *old_p->v;
2951 } else if (cmp == 0) {
2953 * We are overwriting one. If it was previously
2954 * deleted, we need to add a backlink.
2956 * Note that if any RMD_FLAGs in an extended new DN
2961 ret = replmd_update_la_val(new_values, old_p->v,
2967 if (ret != LDB_SUCCESS) {
2968 talloc_free(tmp_ctx);
2972 rmd_flags = dsdb_dn_rmd_flags(old_p->dsdb_dn->dn);
2973 if ((rmd_flags & DSDB_RMD_FLAG_DELETED) != 0) {
2974 ret = replmd_add_backlink(module, replmd_private,
2980 if (ret != LDB_SUCCESS) {
2981 talloc_free(tmp_ctx);
2986 new_values[i] = *old_p->v;
2991 * Replacements that don't match an existing one. We
2992 * just add them to the final list.
2994 ret = replmd_build_la_val(new_values,
3000 if (ret != LDB_SUCCESS) {
3001 talloc_free(tmp_ctx);
3004 ret = replmd_add_backlink(module, replmd_private,
3010 if (ret != LDB_SUCCESS) {
3011 talloc_free(tmp_ctx);
3014 new_values[i] = *new_p->v;
3018 if (old_el != NULL) {
3019 talloc_steal(msg->elements, old_el->values);
3021 el->values = talloc_steal(msg->elements, new_values);
3023 talloc_free(tmp_ctx);
3025 el->flags = LDB_FLAG_MOD_REPLACE;
3032 handle linked attributes in modify requests
3034 static int replmd_modify_handle_linked_attribs(struct ldb_module *module,
3035 struct replmd_private *replmd_private,
3036 struct ldb_message *msg,
3037 uint64_t seq_num, time_t t,
3038 struct ldb_request *parent)
3040 struct ldb_result *res;
3043 struct ldb_context *ldb = ldb_module_get_ctx(module);
3044 struct ldb_message *old_msg;
3046 const struct dsdb_schema *schema;
3048 if (dsdb_functional_level(ldb) == DS_DOMAIN_FUNCTION_2000) {
3050 * Nothing special is required for modifying or vanishing links
3051 * in fl2000 since they are just strings in a multi-valued
3054 struct ldb_control *ctrl = ldb_request_get_control(parent,
3055 DSDB_CONTROL_REPLMD_VANISH_LINKS);
3057 ctrl->critical = false;
3065 * We should restrict this to the intersection of the list of
3066 * linked attributes in the schema and the list of attributes
3069 * This will help performance a little, as otherwise we have
3070 * to allocate the entire object value-by-value.
3072 ret = dsdb_module_search_dn(module, msg, &res, msg->dn, NULL,
3073 DSDB_FLAG_NEXT_MODULE |
3074 DSDB_SEARCH_SHOW_RECYCLED |
3075 DSDB_SEARCH_REVEAL_INTERNALS |
3076 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT,
3078 if (ret != LDB_SUCCESS) {
3081 schema = dsdb_get_schema(ldb, res);
3083 return LDB_ERR_OPERATIONS_ERROR;
3086 old_msg = res->msgs[0];
3088 for (i=0; i<msg->num_elements; i++) {
3089 struct ldb_message_element *el = &msg->elements[i];
3090 struct ldb_message_element *old_el, *new_el;
3091 const struct dsdb_attribute *schema_attr
3092 = dsdb_attribute_by_lDAPDisplayName(schema, el->name);
3094 ldb_asprintf_errstring(ldb,
3095 "%s: attribute %s is not a valid attribute in schema",
3096 __FUNCTION__, el->name);
3097 return LDB_ERR_OBJECT_CLASS_VIOLATION;
3099 if (schema_attr->linkID == 0) {
3102 if ((schema_attr->linkID & 1) == 1) {
3103 if (parent && ldb_request_get_control(parent, DSDB_CONTROL_DBCHECK)) {
3106 /* Odd is for the target. Illegal to modify */
3107 ldb_asprintf_errstring(ldb,
3108 "attribute %s must not be modified directly, it is a linked attribute", el->name);
3109 return LDB_ERR_UNWILLING_TO_PERFORM;
3111 old_el = ldb_msg_find_element(old_msg, el->name);
3112 switch (el->flags & LDB_FLAG_MOD_MASK) {
3113 case LDB_FLAG_MOD_REPLACE:
3114 ret = replmd_modify_la_replace(module, replmd_private,
3115 schema, msg, el, old_el,
3116 schema_attr, seq_num, t,
3120 case LDB_FLAG_MOD_DELETE:
3121 ret = replmd_modify_la_delete(module, replmd_private,
3122 schema, msg, el, old_el,
3123 schema_attr, seq_num, t,
3127 case LDB_FLAG_MOD_ADD:
3128 ret = replmd_modify_la_add(module, replmd_private,
3129 schema, msg, el, old_el,
3130 schema_attr, seq_num, t,
3135 ldb_asprintf_errstring(ldb,
3136 "invalid flags 0x%x for %s linked attribute",
3137 el->flags, el->name);
3138 return LDB_ERR_UNWILLING_TO_PERFORM;
3140 if (dsdb_check_single_valued_link(schema_attr, el) != LDB_SUCCESS) {
3141 ldb_asprintf_errstring(ldb,
3142 "Attribute %s is single valued but more than one value has been supplied",
3144 return LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS;
3146 el->flags |= LDB_FLAG_INTERNAL_DISABLE_SINGLE_VALUE_CHECK;
3151 if (ret != LDB_SUCCESS) {
3155 ldb_msg_remove_attr(old_msg, el->name);
3157 ldb_msg_add_empty(old_msg, el->name, 0, &new_el);
3158 new_el->num_values = el->num_values;
3159 new_el->values = talloc_steal(msg->elements, el->values);
3161 /* TODO: this relises a bit too heavily on the exact
3162 behaviour of ldb_msg_find_element and
3163 ldb_msg_remove_element */
3164 old_el = ldb_msg_find_element(msg, el->name);
3166 ldb_msg_remove_element(msg, old_el);
3176 static int send_rodc_referral(struct ldb_request *req,
3177 struct ldb_context *ldb,
3180 char *referral = NULL;
3181 struct loadparm_context *lp_ctx = NULL;
3182 struct ldb_dn *fsmo_role_dn = NULL;
3183 struct ldb_dn *role_owner_dn = NULL;
3184 const char *domain = NULL;
3187 lp_ctx = talloc_get_type(ldb_get_opaque(ldb, "loadparm"),
3188 struct loadparm_context);
3190 werr = dsdb_get_fsmo_role_info(req, ldb, DREPL_PDC_MASTER,
3191 &fsmo_role_dn, &role_owner_dn);
3193 if (W_ERROR_IS_OK(werr)) {
3194 struct ldb_dn *server_dn = ldb_dn_copy(req, role_owner_dn);
3195 if (server_dn != NULL) {
3196 ldb_dn_remove_child_components(server_dn, 1);
3197 domain = samdb_dn_to_dnshostname(ldb, req,
3202 if (domain == NULL) {
3203 domain = lpcfg_dnsdomain(lp_ctx);
3206 referral = talloc_asprintf(req, "ldap://%s/%s",
3208 ldb_dn_get_linearized(dn));
3209 if (referral == NULL) {
3211 return LDB_ERR_OPERATIONS_ERROR;
3214 return ldb_module_send_referral(req, referral);
3218 static int replmd_modify(struct ldb_module *module, struct ldb_request *req)
3220 struct ldb_context *ldb;
3221 struct replmd_replicated_request *ac;
3222 struct ldb_request *down_req;
3223 struct ldb_message *msg;
3224 time_t t = time(NULL);
3226 bool is_urgent = false, rodc = false;
3227 bool is_schema_nc = false;
3228 unsigned int functional_level;
3229 const struct ldb_message_element *guid_el = NULL;
3230 struct ldb_control *sd_propagation_control;
3231 struct replmd_private *replmd_private =
3232 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
3234 /* do not manipulate our control entries */
3235 if (ldb_dn_is_special(req->op.mod.message->dn)) {
3236 return ldb_next_request(module, req);
3239 sd_propagation_control = ldb_request_get_control(req,
3240 DSDB_CONTROL_SEC_DESC_PROPAGATION_OID);
3241 if (sd_propagation_control != NULL) {
3242 if (req->op.mod.message->num_elements != 1) {
3243 return ldb_module_operr(module);
3245 ret = strcmp(req->op.mod.message->elements[0].name,
3246 "nTSecurityDescriptor");
3248 return ldb_module_operr(module);
3251 return ldb_next_request(module, req);
3254 ldb = ldb_module_get_ctx(module);
3256 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_modify\n");
3258 guid_el = ldb_msg_find_element(req->op.mod.message, "objectGUID");
3259 if (guid_el != NULL) {
3260 ldb_set_errstring(ldb,
3261 "replmd_modify: it's not allowed to change the objectGUID!");
3262 return LDB_ERR_CONSTRAINT_VIOLATION;
3265 ac = replmd_ctx_init(module, req);
3267 return ldb_module_oom(module);
3270 functional_level = dsdb_functional_level(ldb);
3272 /* we have to copy the message as the caller might have it as a const */
3273 msg = ldb_msg_copy_shallow(ac, req->op.mod.message);
3277 return LDB_ERR_OPERATIONS_ERROR;
3280 ldb_msg_remove_attr(msg, "whenChanged");
3281 ldb_msg_remove_attr(msg, "uSNChanged");
3283 is_schema_nc = ldb_dn_compare_base(replmd_private->schema_dn, msg->dn) == 0;
3285 ret = replmd_update_rpmd(module, ac->schema, req, NULL,
3286 msg, &ac->seq_num, t, is_schema_nc,
3288 if (rodc && (ret == LDB_ERR_REFERRAL)) {
3289 ret = send_rodc_referral(req, ldb, msg->dn);
3295 if (ret != LDB_SUCCESS) {
3300 ret = replmd_modify_handle_linked_attribs(module, replmd_private,
3301 msg, ac->seq_num, t, req);
3302 if (ret != LDB_SUCCESS) {
3308 * - replace the old object with the newly constructed one
3311 ac->is_urgent = is_urgent;
3313 ret = ldb_build_mod_req(&down_req, ldb, ac,
3316 ac, replmd_op_callback,
3318 LDB_REQ_SET_LOCATION(down_req);
3319 if (ret != LDB_SUCCESS) {
3324 /* current partition control is needed by "replmd_op_callback" */
3325 if (ldb_request_get_control(req, DSDB_CONTROL_CURRENT_PARTITION_OID) == NULL) {
3326 ret = ldb_request_add_control(down_req,
3327 DSDB_CONTROL_CURRENT_PARTITION_OID,
3329 if (ret != LDB_SUCCESS) {
3335 /* If we are in functional level 2000, then
3336 * replmd_modify_handle_linked_attribs will have done
3338 if (functional_level == DS_DOMAIN_FUNCTION_2000) {
3339 ret = ldb_request_add_control(down_req, DSDB_CONTROL_APPLY_LINKS, false, NULL);
3340 if (ret != LDB_SUCCESS) {
3346 talloc_steal(down_req, msg);
3348 /* we only change whenChanged and uSNChanged if the seq_num
3350 if (ac->seq_num != 0) {
3351 ret = add_time_element(msg, "whenChanged", t);
3352 if (ret != LDB_SUCCESS) {
3358 ret = add_uint64_element(ldb, msg, "uSNChanged", ac->seq_num);
3359 if (ret != LDB_SUCCESS) {
3366 /* go on with the call chain */
3367 return ldb_next_request(module, down_req);
3370 static int replmd_rename_callback(struct ldb_request *req, struct ldb_reply *ares);
3373 handle a rename request
3375 On a rename we need to do an extra ldb_modify which sets the
3376 whenChanged and uSNChanged attributes. We do this in a callback after the success.
3378 static int replmd_rename(struct ldb_module *module, struct ldb_request *req)
3380 struct ldb_context *ldb;
3381 struct replmd_replicated_request *ac;
3383 struct ldb_request *down_req;
3385 /* do not manipulate our control entries */
3386 if (ldb_dn_is_special(req->op.mod.message->dn)) {
3387 return ldb_next_request(module, req);
3390 ldb = ldb_module_get_ctx(module);
3392 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_rename\n");
3394 ac = replmd_ctx_init(module, req);
3396 return ldb_module_oom(module);
3399 ret = ldb_build_rename_req(&down_req, ldb, ac,
3400 ac->req->op.rename.olddn,
3401 ac->req->op.rename.newdn,
3403 ac, replmd_rename_callback,
3405 LDB_REQ_SET_LOCATION(down_req);
3406 if (ret != LDB_SUCCESS) {
3411 /* go on with the call chain */
3412 return ldb_next_request(module, down_req);
3415 /* After the rename is compleated, update the whenchanged etc */
3416 static int replmd_rename_callback(struct ldb_request *req, struct ldb_reply *ares)
3418 struct ldb_context *ldb;
3419 struct ldb_request *down_req;
3420 struct ldb_message *msg;
3421 const struct dsdb_attribute *rdn_attr;
3422 const char *rdn_name;
3423 const struct ldb_val *rdn_val;
3424 const char *attrs[5] = { NULL, };
3425 time_t t = time(NULL);
3427 bool is_urgent = false, rodc = false;
3429 struct replmd_replicated_request *ac =
3430 talloc_get_type(req->context, struct replmd_replicated_request);
3431 struct replmd_private *replmd_private =
3432 talloc_get_type(ldb_module_get_private(ac->module),
3433 struct replmd_private);
3435 ldb = ldb_module_get_ctx(ac->module);
3437 if (ares->error != LDB_SUCCESS) {
3438 return ldb_module_done(ac->req, ares->controls,
3439 ares->response, ares->error);
3442 if (ares->type != LDB_REPLY_DONE) {
3443 ldb_set_errstring(ldb,
3444 "invalid ldb_reply_type in callback");
3446 return ldb_module_done(ac->req, NULL, NULL,
3447 LDB_ERR_OPERATIONS_ERROR);
3451 * - replace the old object with the newly constructed one
3454 msg = ldb_msg_new(ac);
3457 return LDB_ERR_OPERATIONS_ERROR;
3460 msg->dn = ac->req->op.rename.newdn;
3462 is_schema_nc = ldb_dn_compare_base(replmd_private->schema_dn, msg->dn) == 0;
3464 rdn_name = ldb_dn_get_rdn_name(msg->dn);
3465 if (rdn_name == NULL) {
3467 return ldb_module_done(ac->req, NULL, NULL,
3471 /* normalize the rdn attribute name */
3472 rdn_attr = dsdb_attribute_by_lDAPDisplayName(ac->schema, rdn_name);
3473 if (rdn_attr == NULL) {
3475 return ldb_module_done(ac->req, NULL, NULL,
3478 rdn_name = rdn_attr->lDAPDisplayName;
3480 rdn_val = ldb_dn_get_rdn_val(msg->dn);
3481 if (rdn_val == NULL) {
3483 return ldb_module_done(ac->req, NULL, NULL,
3487 if (ldb_msg_add_empty(msg, rdn_name, LDB_FLAG_MOD_REPLACE, NULL) != 0) {
3489 return ldb_module_done(ac->req, NULL, NULL,
3492 if (ldb_msg_add_value(msg, rdn_name, rdn_val, NULL) != 0) {
3494 return ldb_module_done(ac->req, NULL, NULL,
3497 if (ldb_msg_add_empty(msg, "name", LDB_FLAG_MOD_REPLACE, NULL) != 0) {
3499 return ldb_module_done(ac->req, NULL, NULL,
3502 if (ldb_msg_add_value(msg, "name", rdn_val, NULL) != 0) {
3504 return ldb_module_done(ac->req, NULL, NULL,
3509 * here we let replmd_update_rpmd() only search for
3510 * the existing "replPropertyMetaData" and rdn_name attributes.
3512 * We do not want the existing "name" attribute as
3513 * the "name" attribute needs to get the version
3514 * updated on rename even if the rdn value hasn't changed.
3516 * This is the diff of the meta data, for a moved user
3517 * on a w2k8r2 server:
3520 * -dn: CN=sdf df,CN=Users,DC=bla,DC=base
3521 * +dn: CN=sdf df,OU=TestOU,DC=bla,DC=base
3522 * replPropertyMetaData: NDR: struct replPropertyMetaDataBlob
3523 * version : 0x00000001 (1)
3524 * reserved : 0x00000000 (0)
3525 * @@ -66,11 +66,11 @@ replPropertyMetaData: NDR: struct re
3526 * local_usn : 0x00000000000037a5 (14245)
3527 * array: struct replPropertyMetaData1
3528 * attid : DRSUAPI_ATTID_name (0x90001)
3529 * - version : 0x00000001 (1)
3530 * - originating_change_time : Wed Feb 9 17:20:49 2011 CET
3531 * + version : 0x00000002 (2)
3532 * + originating_change_time : Wed Apr 6 15:21:01 2011 CEST
3533 * originating_invocation_id: 0d36ca05-5507-4e62-aca3-354bab0d39e1
3534 * - originating_usn : 0x00000000000037a5 (14245)
3535 * - local_usn : 0x00000000000037a5 (14245)
3536 * + originating_usn : 0x0000000000003834 (14388)
3537 * + local_usn : 0x0000000000003834 (14388)
3538 * array: struct replPropertyMetaData1
3539 * attid : DRSUAPI_ATTID_userAccountControl (0x90008)
3540 * version : 0x00000004 (4)
3542 attrs[0] = "replPropertyMetaData";
3543 attrs[1] = "objectClass";
3544 attrs[2] = "instanceType";
3545 attrs[3] = rdn_name;
3548 ret = replmd_update_rpmd(ac->module, ac->schema, req, attrs,
3549 msg, &ac->seq_num, t,
3550 is_schema_nc, &is_urgent, &rodc);
3551 if (rodc && (ret == LDB_ERR_REFERRAL)) {
3552 ret = send_rodc_referral(req, ldb, ac->req->op.rename.olddn);
3554 return ldb_module_done(req, NULL, NULL, ret);
3557 if (ret != LDB_SUCCESS) {
3559 return ldb_module_done(ac->req, NULL, NULL, ret);
3562 if (ac->seq_num == 0) {
3564 return ldb_module_done(ac->req, NULL, NULL,
3566 "internal error seq_num == 0"));
3568 ac->is_urgent = is_urgent;
3570 ret = ldb_build_mod_req(&down_req, ldb, ac,
3573 ac, replmd_op_callback,
3575 LDB_REQ_SET_LOCATION(down_req);
3576 if (ret != LDB_SUCCESS) {
3581 /* current partition control is needed by "replmd_op_callback" */
3582 if (ldb_request_get_control(req, DSDB_CONTROL_CURRENT_PARTITION_OID) == NULL) {
3583 ret = ldb_request_add_control(down_req,
3584 DSDB_CONTROL_CURRENT_PARTITION_OID,
3586 if (ret != LDB_SUCCESS) {
3592 talloc_steal(down_req, msg);
3594 ret = add_time_element(msg, "whenChanged", t);
3595 if (ret != LDB_SUCCESS) {
3601 ret = add_uint64_element(ldb, msg, "uSNChanged", ac->seq_num);
3602 if (ret != LDB_SUCCESS) {
3608 /* go on with the call chain - do the modify after the rename */
3609 return ldb_next_request(ac->module, down_req);
3613 * remove links from objects that point at this object when an object
3614 * is deleted. We remove it from the NEXT module per MS-DRSR 5.160
3615 * RemoveObj which states that link removal due to the object being
3616 * deleted is NOT an originating update - they just go away!
3619 static int replmd_delete_remove_link(struct ldb_module *module,
3620 const struct dsdb_schema *schema,
3621 struct replmd_private *replmd_private,
3624 struct ldb_message_element *el,
3625 const struct dsdb_attribute *sa,
3626 struct ldb_request *parent)
3629 TALLOC_CTX *tmp_ctx = talloc_new(module);
3630 struct ldb_context *ldb = ldb_module_get_ctx(module);
3632 for (i=0; i<el->num_values; i++) {
3633 struct dsdb_dn *dsdb_dn;
3635 struct ldb_message *msg;
3636 const struct dsdb_attribute *target_attr;
3637 struct ldb_message_element *el2;
3639 struct ldb_val dn_val;
3640 uint32_t dsdb_flags = 0;
3641 const char *attrs[] = { NULL, NULL };
3642 struct ldb_result *link_res;
3643 struct ldb_message *link_msg;
3644 struct ldb_message_element *link_el;
3645 struct parsed_dn *link_dns;
3646 struct parsed_dn *p = NULL, *unused = NULL;
3648 if (dsdb_dn_is_deleted_val(&el->values[i])) {
3652 dsdb_dn = dsdb_dn_parse(tmp_ctx, ldb, &el->values[i], sa->syntax->ldap_oid);
3654 talloc_free(tmp_ctx);
3655 return LDB_ERR_OPERATIONS_ERROR;
3658 /* remove the link */
3659 msg = ldb_msg_new(tmp_ctx);
3661 ldb_module_oom(module);
3662 talloc_free(tmp_ctx);
3663 return LDB_ERR_OPERATIONS_ERROR;
3667 msg->dn = dsdb_dn->dn;
3669 target_attr = dsdb_attribute_by_linkID(schema, sa->linkID ^ 1);
3670 if (target_attr == NULL) {
3673 attrs[0] = target_attr->lDAPDisplayName;
3675 ret = ldb_msg_add_empty(msg, target_attr->lDAPDisplayName,
3676 LDB_FLAG_MOD_DELETE, &el2);
3677 if (ret != LDB_SUCCESS) {
3678 ldb_module_oom(module);
3679 talloc_free(tmp_ctx);
3680 return LDB_ERR_OPERATIONS_ERROR;
3683 ret = dsdb_module_search_dn(module, tmp_ctx, &link_res,
3685 DSDB_FLAG_NEXT_MODULE |
3686 DSDB_SEARCH_SHOW_EXTENDED_DN,
3689 if (ret != LDB_SUCCESS) {
3690 talloc_free(tmp_ctx);
3694 link_msg = link_res->msgs[0];
3695 link_el = ldb_msg_find_element(link_msg,
3696 target_attr->lDAPDisplayName);
3697 if (link_el == NULL) {
3698 talloc_free(tmp_ctx);
3699 return LDB_ERR_NO_SUCH_ATTRIBUTE;
3703 * This call 'upgrades' the links in link_dns, but we
3704 * do not commit the result back into the database, so
3705 * this is safe to call in FL2000 or on databases that
3706 * have been run at that level in the past.
3708 ret = get_parsed_dns_trusted(module, replmd_private, tmp_ctx,
3710 target_attr->syntax->ldap_oid, parent);
3711 if (ret != LDB_SUCCESS) {
3712 talloc_free(tmp_ctx);
3716 ret = parsed_dn_find(ldb, link_dns, link_el->num_values,
3720 target_attr->syntax->ldap_oid, false);
3721 if (ret != LDB_SUCCESS) {
3722 talloc_free(tmp_ctx);
3727 ldb_asprintf_errstring(ldb_module_get_ctx(module),
3728 "Failed to find forward link on %s "
3729 "as %s to remove backlink %s on %s",
3730 ldb_dn_get_linearized(msg->dn),
3731 target_attr->lDAPDisplayName,
3732 sa->lDAPDisplayName,
3733 ldb_dn_get_linearized(dn));
3734 talloc_free(tmp_ctx);
3735 return LDB_ERR_NO_SUCH_ATTRIBUTE;
3739 /* This needs to get the Binary DN, by first searching */
3740 dn_str = dsdb_dn_get_linearized(tmp_ctx,
3743 dn_val = data_blob_string_const(dn_str);
3744 el2->values = &dn_val;
3745 el2->num_values = 1;
3748 * Ensure that we tell the modification to vanish any linked
3749 * attributes (not simply mark them as isDeleted = TRUE)
3751 dsdb_flags |= DSDB_REPLMD_VANISH_LINKS;
3753 ret = dsdb_module_modify(module, msg, dsdb_flags|DSDB_FLAG_OWN_MODULE, parent);
3754 if (ret != LDB_SUCCESS) {
3755 talloc_free(tmp_ctx);
3759 talloc_free(tmp_ctx);
3765 handle update of replication meta data for deletion of objects
3767 This also handles the mapping of delete to a rename operation
3768 to allow deletes to be replicated.
3770 It also handles the incoming deleted objects, to ensure they are
3771 fully deleted here. In that case re_delete is true, and we do not
3772 use this as a signal to change the deleted state, just reinforce it.
3775 static int replmd_delete_internals(struct ldb_module *module, struct ldb_request *req, bool re_delete)
3777 int ret = LDB_ERR_OTHER;
3778 bool retb, disallow_move_on_delete;
3779 struct ldb_dn *old_dn, *new_dn;
3780 const char *rdn_name;
3781 const struct ldb_val *rdn_value, *new_rdn_value;
3783 struct ldb_context *ldb = ldb_module_get_ctx(module);
3784 const struct dsdb_schema *schema;
3785 struct ldb_message *msg, *old_msg;
3786 struct ldb_message_element *el;
3787 TALLOC_CTX *tmp_ctx;
3788 struct ldb_result *res, *parent_res;
3789 static const char * const preserved_attrs[] = {
3790 /* yes, this really is a hard coded list. See MS-ADTS
3791 section 3.1.1.5.5.1.1 */
3794 "dNReferenceUpdate",
3805 "msDS-LastKnownRDN",
3811 "distinguishedName",
3815 "proxiedObjectName",
3817 "nTSecurityDescriptor",
3818 "replPropertyMetaData",
3820 "securityIdentifier",
3828 "userAccountControl",
3835 static const char * const all_attrs[] = {
3836 DSDB_SECRET_ATTRIBUTES,
3840 unsigned int i, el_count = 0;
3841 uint32_t dsdb_flags = 0;
3842 struct replmd_private *replmd_private;
3843 enum deletion_state deletion_state, next_deletion_state;
3845 if (ldb_dn_is_special(req->op.del.dn)) {
3846 return ldb_next_request(module, req);
3850 * We have to allow dbcheck to remove an object that
3851 * is beyond repair, and to do so totally. This could
3852 * mean we we can get a partial object from the other
3853 * DC, causing havoc, so dbcheck suggests
3854 * re-replication first. dbcheck sets both DBCHECK
3855 * and RELAX in this situation.
3857 if (ldb_request_get_control(req, LDB_CONTROL_RELAX_OID)
3858 && ldb_request_get_control(req, DSDB_CONTROL_DBCHECK)) {
3859 /* really, really remove it */
3860 return ldb_next_request(module, req);
3863 tmp_ctx = talloc_new(ldb);
3866 return LDB_ERR_OPERATIONS_ERROR;
3869 schema = dsdb_get_schema(ldb, tmp_ctx);
3871 talloc_free(tmp_ctx);
3872 return LDB_ERR_OPERATIONS_ERROR;
3875 old_dn = ldb_dn_copy(tmp_ctx, req->op.del.dn);
3877 /* we need the complete msg off disk, so we can work out which
3878 attributes need to be removed */
3879 ret = dsdb_module_search_dn(module, tmp_ctx, &res, old_dn, all_attrs,
3880 DSDB_FLAG_NEXT_MODULE |
3881 DSDB_SEARCH_SHOW_RECYCLED |
3882 DSDB_SEARCH_REVEAL_INTERNALS |
3883 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT, req);
3884 if (ret != LDB_SUCCESS) {
3885 ldb_asprintf_errstring(ldb_module_get_ctx(module),
3886 "repmd_delete: Failed to %s %s, because we failed to find it: %s",
3887 re_delete ? "re-delete" : "delete",
3888 ldb_dn_get_linearized(old_dn),
3889 ldb_errstring(ldb_module_get_ctx(module)));
3890 talloc_free(tmp_ctx);
3893 old_msg = res->msgs[0];
3895 replmd_deletion_state(module, old_msg,
3897 &next_deletion_state);
3899 /* This supports us noticing an incoming isDeleted and acting on it */
3901 SMB_ASSERT(deletion_state > OBJECT_NOT_DELETED);
3902 next_deletion_state = deletion_state;
3905 if (next_deletion_state == OBJECT_REMOVED) {
3907 * We have to prevent objects being deleted, even if
3908 * the administrator really wants them gone, as
3909 * without the tombstone, we can get a partial object
3910 * from the other DC, causing havoc.
3912 * The only other valid case is when the 180 day
3913 * timeout has expired, when relax is specified.
3915 if (ldb_request_get_control(req, LDB_CONTROL_RELAX_OID)) {
3916 /* it is already deleted - really remove it this time */
3917 talloc_free(tmp_ctx);
3918 return ldb_next_request(module, req);
3921 ldb_asprintf_errstring(ldb, "Refusing to delete tombstone object %s. "
3922 "This check is to prevent corruption of the replicated state.",
3923 ldb_dn_get_linearized(old_msg->dn));
3924 return LDB_ERR_UNWILLING_TO_PERFORM;
3927 rdn_name = ldb_dn_get_rdn_name(old_dn);
3928 rdn_value = ldb_dn_get_rdn_val(old_dn);
3929 if ((rdn_name == NULL) || (rdn_value == NULL)) {
3930 talloc_free(tmp_ctx);
3931 return ldb_operr(ldb);
3934 msg = ldb_msg_new(tmp_ctx);
3936 ldb_module_oom(module);
3937 talloc_free(tmp_ctx);
3938 return LDB_ERR_OPERATIONS_ERROR;
3943 /* consider the SYSTEM_FLAG_DISALLOW_MOVE_ON_DELETE flag */
3944 disallow_move_on_delete =
3945 (ldb_msg_find_attr_as_int(old_msg, "systemFlags", 0)
3946 & SYSTEM_FLAG_DISALLOW_MOVE_ON_DELETE);
3948 /* work out where we will be renaming this object to */
3949 if (!disallow_move_on_delete) {
3950 struct ldb_dn *deleted_objects_dn;
3951 ret = dsdb_get_deleted_objects_dn(ldb, tmp_ctx, old_dn,
3952 &deleted_objects_dn);
3955 * We should not move objects if we can't find the
3956 * deleted objects DN. Not moving (or otherwise
3957 * harming) the Deleted Objects DN itself is handled
3960 if (re_delete && (ret != LDB_SUCCESS)) {
3961 new_dn = ldb_dn_get_parent(tmp_ctx, old_dn);
3962 if (new_dn == NULL) {
3963 ldb_module_oom(module);
3964 talloc_free(tmp_ctx);
3965 return LDB_ERR_OPERATIONS_ERROR;
3967 } else if (ret != LDB_SUCCESS) {
3968 /* this is probably an attempted delete on a partition
3969 * that doesn't allow delete operations, such as the
3970 * schema partition */
3971 ldb_asprintf_errstring(ldb, "No Deleted Objects container for DN %s",
3972 ldb_dn_get_linearized(old_dn));
3973 talloc_free(tmp_ctx);
3974 return LDB_ERR_UNWILLING_TO_PERFORM;
3976 new_dn = deleted_objects_dn;
3979 new_dn = ldb_dn_get_parent(tmp_ctx, old_dn);
3980 if (new_dn == NULL) {
3981 ldb_module_oom(module);
3982 talloc_free(tmp_ctx);
3983 return LDB_ERR_OPERATIONS_ERROR;
3987 /* get the objects GUID from the search we just did */
3988 guid = samdb_result_guid(old_msg, "objectGUID");
3990 if (deletion_state == OBJECT_NOT_DELETED) {
3991 /* Add a formatted child */
3992 retb = ldb_dn_add_child_fmt(new_dn, "%s=%s\\0ADEL:%s",
3994 ldb_dn_escape_value(tmp_ctx, *rdn_value),
3995 GUID_string(tmp_ctx, &guid));
3997 ldb_asprintf_errstring(ldb, __location__
3998 ": Unable to add a formatted child to dn: %s",
3999 ldb_dn_get_linearized(new_dn));
4000 talloc_free(tmp_ctx);
4001 return LDB_ERR_OPERATIONS_ERROR;
4004 ret = ldb_msg_add_string(msg, "isDeleted", "TRUE");
4005 if (ret != LDB_SUCCESS) {
4006 ldb_asprintf_errstring(ldb, __location__
4007 ": Failed to add isDeleted string to the msg");
4008 talloc_free(tmp_ctx);
4011 msg->elements[el_count++].flags = LDB_FLAG_MOD_REPLACE;
4014 * No matter what has happened with other renames etc, try again to
4015 * get this to be under the deleted DN. See MS-DRSR 5.160 RemoveObj
4018 struct ldb_dn *rdn = ldb_dn_copy(tmp_ctx, old_dn);
4019 retb = ldb_dn_remove_base_components(rdn, ldb_dn_get_comp_num(rdn) - 1);
4021 ldb_asprintf_errstring(ldb, __location__
4022 ": Unable to add a prepare rdn of %s",
4023 ldb_dn_get_linearized(rdn));
4024 talloc_free(tmp_ctx);
4025 return LDB_ERR_OPERATIONS_ERROR;
4027 SMB_ASSERT(ldb_dn_get_comp_num(rdn) == 1);
4029 retb = ldb_dn_add_child(new_dn, rdn);
4031 ldb_asprintf_errstring(ldb, __location__
4032 ": Unable to add rdn %s to base dn: %s",
4033 ldb_dn_get_linearized(rdn),
4034 ldb_dn_get_linearized(new_dn));
4035 talloc_free(tmp_ctx);
4036 return LDB_ERR_OPERATIONS_ERROR;
4041 now we need to modify the object in the following ways:
4043 - add isDeleted=TRUE
4044 - update rDN and name, with new rDN
4045 - remove linked attributes
4046 - remove objectCategory and sAMAccountType
4047 - remove attribs not on the preserved list
4048 - preserved if in above list, or is rDN
4049 - remove all linked attribs from this object
4050 - remove all links from other objects to this object
4051 - add lastKnownParent
4052 - update replPropertyMetaData?
4054 see MS-ADTS "Tombstone Requirements" section 3.1.1.5.5.1.1
4057 if (deletion_state == OBJECT_NOT_DELETED) {
4058 struct ldb_dn *parent_dn = ldb_dn_get_parent(tmp_ctx, old_dn);
4059 char *parent_dn_str = NULL;
4061 /* we need the storage form of the parent GUID */
4062 ret = dsdb_module_search_dn(module, tmp_ctx, &parent_res,
4064 DSDB_FLAG_NEXT_MODULE |
4065 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT |
4066 DSDB_SEARCH_REVEAL_INTERNALS|
4067 DSDB_SEARCH_SHOW_RECYCLED, req);
4068 if (ret != LDB_SUCCESS) {
4069 ldb_asprintf_errstring(ldb_module_get_ctx(module),
4070 "repmd_delete: Failed to %s %s, "
4071 "because we failed to find it's parent (%s): %s",
4072 re_delete ? "re-delete" : "delete",
4073 ldb_dn_get_linearized(old_dn),
4074 ldb_dn_get_linearized(parent_dn),
4075 ldb_errstring(ldb_module_get_ctx(module)));
4076 talloc_free(tmp_ctx);
4081 * Now we can use the DB version,
4082 * it will have the extended DN info in it
4084 parent_dn = parent_res->msgs[0]->dn;
4085 parent_dn_str = ldb_dn_get_extended_linearized(tmp_ctx,
4088 if (parent_dn_str == NULL) {
4089 talloc_free(tmp_ctx);
4090 return ldb_module_oom(module);
4093 ret = ldb_msg_add_steal_string(msg, "lastKnownParent",
4095 if (ret != LDB_SUCCESS) {
4096 ldb_asprintf_errstring(ldb, __location__
4097 ": Failed to add lastKnownParent "
4098 "string when deleting %s",
4099 ldb_dn_get_linearized(old_dn));
4100 talloc_free(tmp_ctx);
4103 msg->elements[el_count++].flags = LDB_FLAG_MOD_REPLACE;
4105 if (next_deletion_state == OBJECT_DELETED) {
4106 ret = ldb_msg_add_value(msg, "msDS-LastKnownRDN", rdn_value, NULL);
4107 if (ret != LDB_SUCCESS) {
4108 ldb_asprintf_errstring(ldb, __location__
4109 ": Failed to add msDS-LastKnownRDN "
4110 "string when deleting %s",
4111 ldb_dn_get_linearized(old_dn));
4112 talloc_free(tmp_ctx);
4115 msg->elements[el_count++].flags = LDB_FLAG_MOD_ADD;
4119 switch (next_deletion_state) {
4121 case OBJECT_RECYCLED:
4122 case OBJECT_TOMBSTONE:
4125 * MS-ADTS 3.1.1.5.5.1.1 Tombstone Requirements
4126 * describes what must be removed from a tombstone
4129 * MS-ADTS 3.1.1.5.5.1.3 Recycled-Object Requirements
4130 * describes what must be removed from a recycled
4136 * we also mark it as recycled, meaning this object can't be
4137 * recovered (we are stripping its attributes).
4138 * This is done only if we have this schema object of course ...
4139 * This behavior is identical to the one of Windows 2008R2 which
4140 * always set the isRecycled attribute, even if the recycle-bin is
4141 * not activated and what ever the forest level is.
4143 if (dsdb_attribute_by_lDAPDisplayName(schema, "isRecycled") != NULL) {
4144 ret = ldb_msg_add_string(msg, "isRecycled", "TRUE");
4145 if (ret != LDB_SUCCESS) {
4146 DEBUG(0,(__location__ ": Failed to add isRecycled string to the msg\n"));
4147 ldb_module_oom(module);
4148 talloc_free(tmp_ctx);
4151 msg->elements[el_count++].flags = LDB_FLAG_MOD_REPLACE;
4154 replmd_private = talloc_get_type(ldb_module_get_private(module),
4155 struct replmd_private);
4156 /* work out which of the old attributes we will be removing */
4157 for (i=0; i<old_msg->num_elements; i++) {
4158 const struct dsdb_attribute *sa;
4159 el = &old_msg->elements[i];
4160 sa = dsdb_attribute_by_lDAPDisplayName(schema, el->name);
4162 talloc_free(tmp_ctx);
4163 return LDB_ERR_OPERATIONS_ERROR;
4165 if (ldb_attr_cmp(el->name, rdn_name) == 0) {
4166 /* don't remove the rDN */
4169 if (sa->linkID & 1) {
4171 we have a backlink in this object
4172 that needs to be removed. We're not
4173 allowed to remove it directly
4174 however, so we instead setup a
4175 modify to delete the corresponding
4178 ret = replmd_delete_remove_link(module, schema,
4182 if (ret != LDB_SUCCESS) {
4183 const char *old_dn_str
4184 = ldb_dn_get_linearized(old_dn);
4185 ldb_asprintf_errstring(ldb,
4187 ": Failed to remove backlink of "
4188 "%s when deleting %s: %s",
4191 ldb_errstring(ldb));
4192 talloc_free(tmp_ctx);
4193 return LDB_ERR_OPERATIONS_ERROR;
4195 /* now we continue, which means we
4196 won't remove this backlink
4200 } else if (sa->linkID == 0) {
4201 if (ldb_attr_in_list(preserved_attrs, el->name)) {
4204 if (sa->searchFlags & SEARCH_FLAG_PRESERVEONDELETE) {
4209 * Ensure that we tell the modification to vanish any linked
4210 * attributes (not simply mark them as isDeleted = TRUE)
4212 dsdb_flags |= DSDB_REPLMD_VANISH_LINKS;
4214 ret = ldb_msg_add_empty(msg, el->name, LDB_FLAG_MOD_DELETE, &el);
4215 if (ret != LDB_SUCCESS) {
4216 talloc_free(tmp_ctx);
4217 ldb_module_oom(module);
4224 case OBJECT_DELETED:
4226 * MS-ADTS 3.1.1.5.5.1.2 Deleted-Object Requirements
4227 * describes what must be removed from a deleted
4231 ret = ldb_msg_add_empty(msg, "objectCategory", LDB_FLAG_MOD_REPLACE, NULL);
4232 if (ret != LDB_SUCCESS) {
4233 talloc_free(tmp_ctx);
4234 ldb_module_oom(module);
4238 ret = ldb_msg_add_empty(msg, "sAMAccountType", LDB_FLAG_MOD_REPLACE, NULL);
4239 if (ret != LDB_SUCCESS) {
4240 talloc_free(tmp_ctx);
4241 ldb_module_oom(module);
4251 if (deletion_state == OBJECT_NOT_DELETED) {
4252 const struct dsdb_attribute *sa;
4254 /* work out what the new rdn value is, for updating the
4255 rDN and name fields */
4256 new_rdn_value = ldb_dn_get_rdn_val(new_dn);
4257 if (new_rdn_value == NULL) {
4258 talloc_free(tmp_ctx);
4259 return ldb_operr(ldb);
4262 sa = dsdb_attribute_by_lDAPDisplayName(schema, rdn_name);
4264 talloc_free(tmp_ctx);
4265 return LDB_ERR_OPERATIONS_ERROR;
4268 ret = ldb_msg_add_value(msg, sa->lDAPDisplayName, new_rdn_value,
4270 if (ret != LDB_SUCCESS) {
4271 talloc_free(tmp_ctx);
4274 el->flags = LDB_FLAG_MOD_REPLACE;
4276 el = ldb_msg_find_element(old_msg, "name");
4278 ret = ldb_msg_add_value(msg, "name", new_rdn_value, &el);
4279 if (ret != LDB_SUCCESS) {
4280 talloc_free(tmp_ctx);
4283 el->flags = LDB_FLAG_MOD_REPLACE;
4288 * TODO: Per MS-DRSR 5.160 RemoveObj we should remove links directly, not as an originating update!
4293 * No matter what has happned with other renames, try again to
4294 * get this to be under the deleted DN.
4296 if (strcmp(ldb_dn_get_linearized(old_dn), ldb_dn_get_linearized(new_dn)) != 0) {
4297 /* now rename onto the new DN */
4298 ret = dsdb_module_rename(module, old_dn, new_dn, DSDB_FLAG_NEXT_MODULE, req);
4299 if (ret != LDB_SUCCESS){
4300 DEBUG(0,(__location__ ": Failed to rename object from '%s' to '%s' - %s\n",
4301 ldb_dn_get_linearized(old_dn),
4302 ldb_dn_get_linearized(new_dn),
4303 ldb_errstring(ldb)));
4304 talloc_free(tmp_ctx);
4310 ret = dsdb_module_modify(module, msg, dsdb_flags|DSDB_FLAG_OWN_MODULE, req);
4311 if (ret != LDB_SUCCESS) {
4312 ldb_asprintf_errstring(ldb, "replmd_delete: Failed to modify object %s in delete - %s",
4313 ldb_dn_get_linearized(old_dn), ldb_errstring(ldb));
4314 talloc_free(tmp_ctx);
4318 talloc_free(tmp_ctx);
4320 return ldb_module_done(req, NULL, NULL, LDB_SUCCESS);
4323 static int replmd_delete(struct ldb_module *module, struct ldb_request *req)
4325 return replmd_delete_internals(module, req, false);
4329 static int replmd_replicated_request_error(struct replmd_replicated_request *ar, int ret)
4334 static int replmd_replicated_request_werror(struct replmd_replicated_request *ar, WERROR status)
4336 int ret = LDB_ERR_OTHER;
4337 /* TODO: do some error mapping */
4339 /* Let the caller know the full WERROR */
4340 ar->objs->error = status;
4346 static struct replPropertyMetaData1 *
4347 replmd_replPropertyMetaData1_find_attid(struct replPropertyMetaDataBlob *md_blob,
4348 enum drsuapi_DsAttributeId attid)
4351 struct replPropertyMetaDataCtr1 *rpmd_ctr = &md_blob->ctr.ctr1;
4353 for (i = 0; i < rpmd_ctr->count; i++) {
4354 if (rpmd_ctr->array[i].attid == attid) {
4355 return &rpmd_ctr->array[i];
4363 return true if an update is newer than an existing entry
4364 see section 5.11 of MS-ADTS
4366 static bool replmd_update_is_newer(const struct GUID *current_invocation_id,
4367 const struct GUID *update_invocation_id,
4368 uint32_t current_version,
4369 uint32_t update_version,
4370 NTTIME current_change_time,
4371 NTTIME update_change_time)
4373 if (update_version != current_version) {
4374 return update_version > current_version;
4376 if (update_change_time != current_change_time) {
4377 return update_change_time > current_change_time;
4379 return GUID_compare(update_invocation_id, current_invocation_id) > 0;
4382 static bool replmd_replPropertyMetaData1_is_newer(struct replPropertyMetaData1 *cur_m,
4383 struct replPropertyMetaData1 *new_m)
4385 return replmd_update_is_newer(&cur_m->originating_invocation_id,
4386 &new_m->originating_invocation_id,
4389 cur_m->originating_change_time,
4390 new_m->originating_change_time);
4393 static bool replmd_replPropertyMetaData1_new_should_be_taken(uint32_t dsdb_repl_flags,
4394 struct replPropertyMetaData1 *cur_m,
4395 struct replPropertyMetaData1 *new_m)
4400 * If the new replPropertyMetaData entry for this attribute is
4401 * not provided (this happens in the case where we look for
4402 * ATTID_name, but the name was not changed), then the local
4403 * state is clearly still current, as the remote
4404 * server didn't send it due to being older the high watermark
4407 if (new_m == NULL) {
4411 if (dsdb_repl_flags & DSDB_REPL_FLAG_PRIORITISE_INCOMING) {
4413 * if we compare equal then do an
4414 * update. This is used when a client
4415 * asks for a FULL_SYNC, and can be
4416 * used to recover a corrupt
4419 * This call is a bit tricky, what we
4420 * are doing it turning the 'is_newer'
4421 * call into a 'not is older' by
4422 * swapping cur_m and new_m, and negating the
4425 cmp = !replmd_replPropertyMetaData1_is_newer(new_m,
4428 cmp = replmd_replPropertyMetaData1_is_newer(cur_m,
4438 static struct ldb_dn *replmd_conflict_dn(TALLOC_CTX *mem_ctx, struct ldb_dn *dn, struct GUID *guid)
4440 const struct ldb_val *rdn_val;
4441 const char *rdn_name;
4442 struct ldb_dn *new_dn;
4444 rdn_val = ldb_dn_get_rdn_val(dn);
4445 rdn_name = ldb_dn_get_rdn_name(dn);
4446 if (!rdn_val || !rdn_name) {
4450 new_dn = ldb_dn_copy(mem_ctx, dn);
4455 if (!ldb_dn_remove_child_components(new_dn, 1)) {
4459 if (!ldb_dn_add_child_fmt(new_dn, "%s=%s\\0ACNF:%s",
4461 ldb_dn_escape_value(new_dn, *rdn_val),
4462 GUID_string(new_dn, guid))) {
4471 perform a modify operation which sets the rDN and name attributes to
4472 their current values. This has the effect of changing these
4473 attributes to have been last updated by the current DC. This is
4474 needed to ensure that renames performed as part of conflict
4475 resolution are propogated to other DCs
4477 static int replmd_name_modify(struct replmd_replicated_request *ar,
4478 struct ldb_request *req, struct ldb_dn *dn)
4480 struct ldb_message *msg;
4481 const char *rdn_name;
4482 const struct ldb_val *rdn_val;
4483 const struct dsdb_attribute *rdn_attr;
4486 msg = ldb_msg_new(req);
4492 rdn_name = ldb_dn_get_rdn_name(dn);
4493 if (rdn_name == NULL) {
4497 /* normalize the rdn attribute name */
4498 rdn_attr = dsdb_attribute_by_lDAPDisplayName(ar->schema, rdn_name);
4499 if (rdn_attr == NULL) {
4502 rdn_name = rdn_attr->lDAPDisplayName;
4504 rdn_val = ldb_dn_get_rdn_val(dn);
4505 if (rdn_val == NULL) {
4509 if (ldb_msg_add_empty(msg, rdn_name, LDB_FLAG_MOD_REPLACE, NULL) != 0) {
4512 if (ldb_msg_add_value(msg, rdn_name, rdn_val, NULL) != 0) {
4515 if (ldb_msg_add_empty(msg, "name", LDB_FLAG_MOD_REPLACE, NULL) != 0) {
4518 if (ldb_msg_add_value(msg, "name", rdn_val, NULL) != 0) {
4522 ret = dsdb_module_modify(ar->module, msg, DSDB_FLAG_OWN_MODULE, req);
4523 if (ret != LDB_SUCCESS) {
4524 DEBUG(0,(__location__ ": Failed to modify rDN/name of conflict DN '%s' - %s",
4525 ldb_dn_get_linearized(dn),
4526 ldb_errstring(ldb_module_get_ctx(ar->module))));
4536 DEBUG(0,(__location__ ": Failed to setup modify rDN/name of conflict DN '%s'",
4537 ldb_dn_get_linearized(dn)));
4538 return LDB_ERR_OPERATIONS_ERROR;
4543 callback for conflict DN handling where we have renamed the incoming
4544 record. After renaming it, we need to ensure the change of name and
4545 rDN for the incoming record is seen as an originating update by this DC.
4547 This also handles updating lastKnownParent for entries sent to lostAndFound
4549 static int replmd_op_name_modify_callback(struct ldb_request *req, struct ldb_reply *ares)
4551 struct replmd_replicated_request *ar =
4552 talloc_get_type_abort(req->context, struct replmd_replicated_request);
4553 struct ldb_dn *conflict_dn = NULL;
4556 if (ares->error != LDB_SUCCESS) {
4557 /* call the normal callback for everything except success */
4558 return replmd_op_callback(req, ares);
4561 switch (req->operation) {
4563 conflict_dn = req->op.add.message->dn;
4566 conflict_dn = req->op.mod.message->dn;
4569 smb_panic("replmd_op_name_modify_callback called in unknown circumstances");
4572 /* perform a modify of the rDN and name of the record */
4573 ret = replmd_name_modify(ar, req, conflict_dn);
4574 if (ret != LDB_SUCCESS) {
4576 return replmd_op_callback(req, ares);
4579 if (ar->objs->objects[ar->index_current].last_known_parent) {
4580 struct ldb_message *msg = ldb_msg_new(req);
4582 ldb_module_oom(ar->module);
4583 return LDB_ERR_OPERATIONS_ERROR;
4586 msg->dn = req->op.add.message->dn;
4588 ret = ldb_msg_add_steal_string(msg, "lastKnownParent",
4589 ldb_dn_get_extended_linearized(msg, ar->objs->objects[ar->index_current].last_known_parent, 1));
4590 if (ret != LDB_SUCCESS) {
4591 DEBUG(0,(__location__ ": Failed to add lastKnownParent string to the msg\n"));
4592 ldb_module_oom(ar->module);
4595 msg->elements[0].flags = LDB_FLAG_MOD_REPLACE;
4597 ret = dsdb_module_modify(ar->module, msg, DSDB_FLAG_OWN_MODULE, req);
4598 if (ret != LDB_SUCCESS) {
4599 DEBUG(0,(__location__ ": Failed to modify lastKnownParent of lostAndFound DN '%s' - %s",
4600 ldb_dn_get_linearized(msg->dn),
4601 ldb_errstring(ldb_module_get_ctx(ar->module))));
4607 return replmd_op_callback(req, ares);
4611 callback for replmd_replicated_apply_add()
4612 This copes with the creation of conflict records in the case where
4613 the DN exists, but with a different objectGUID
4615 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))
4617 struct ldb_dn *conflict_dn;
4618 struct replmd_replicated_request *ar =
4619 talloc_get_type_abort(req->context, struct replmd_replicated_request);
4620 struct ldb_result *res;
4621 const char *attrs[] = { "replPropertyMetaData", "objectGUID", NULL };
4623 const struct ldb_val *omd_value;
4624 struct replPropertyMetaDataBlob omd, *rmd;
4625 enum ndr_err_code ndr_err;
4626 bool rename_incoming_record, rodc;
4627 struct replPropertyMetaData1 *rmd_name, *omd_name;
4628 struct ldb_message *msg;
4629 struct ldb_request *down_req = NULL;
4631 /* call the normal callback for success */
4632 if (ares->error == LDB_SUCCESS) {
4633 return callback(req, ares);
4637 * we have a conflict, and need to decide if we will keep the
4638 * new record or the old record
4641 msg = ar->objs->objects[ar->index_current].msg;
4642 conflict_dn = msg->dn;
4644 /* For failures other than conflicts, fail the whole operation here */
4645 if (ares->error != LDB_ERR_ENTRY_ALREADY_EXISTS) {
4646 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module), "Failed to locally apply remote add of %s: %s",
4647 ldb_dn_get_linearized(conflict_dn),
4648 ldb_errstring(ldb_module_get_ctx(ar->module)));
4650 return ldb_module_done(ar->req, NULL, NULL,
4651 LDB_ERR_OPERATIONS_ERROR);
4654 ret = samdb_rodc(ldb_module_get_ctx(ar->module), &rodc);
4655 if (ret != LDB_SUCCESS) {
4656 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)));
4657 return ldb_module_done(ar->req, NULL, NULL,
4658 LDB_ERR_OPERATIONS_ERROR);
4664 * We are on an RODC, or were a GC for this
4665 * partition, so we have to fail this until
4666 * someone who owns the partition sorts it
4669 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
4670 "Conflict adding object '%s' from incoming replication as we are read only for the partition. \n"
4671 " - We must fail the operation until a master for this partition resolves the conflict",
4672 ldb_dn_get_linearized(conflict_dn));
4677 * first we need the replPropertyMetaData attribute from the
4678 * local, conflicting record
4680 ret = dsdb_module_search_dn(ar->module, req, &res, conflict_dn,
4682 DSDB_FLAG_NEXT_MODULE |
4683 DSDB_SEARCH_SHOW_DELETED |
4684 DSDB_SEARCH_SHOW_RECYCLED, req);
4685 if (ret != LDB_SUCCESS) {
4686 DEBUG(0,(__location__ ": Unable to find object for conflicting record '%s'\n",
4687 ldb_dn_get_linearized(conflict_dn)));
4691 omd_value = ldb_msg_find_ldb_val(res->msgs[0], "replPropertyMetaData");
4692 if (omd_value == NULL) {
4693 DEBUG(0,(__location__ ": Unable to find replPropertyMetaData for conflicting record '%s'\n",
4694 ldb_dn_get_linearized(conflict_dn)));
4698 ndr_err = ndr_pull_struct_blob(omd_value, res->msgs[0], &omd,
4699 (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
4700 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
4701 DEBUG(0,(__location__ ": Failed to parse old replPropertyMetaData for %s\n",
4702 ldb_dn_get_linearized(conflict_dn)));
4706 rmd = ar->objs->objects[ar->index_current].meta_data;
4709 * we decide which is newer based on the RPMD on the name
4710 * attribute. See [MS-DRSR] ResolveNameConflict.
4712 * We expect omd_name to be present, as this is from a local
4713 * search, but while rmd_name should have been given to us by
4714 * the remote server, if it is missing we just prefer the
4716 * replmd_replPropertyMetaData1_new_should_be_taken()
4718 rmd_name = replmd_replPropertyMetaData1_find_attid(rmd, DRSUAPI_ATTID_name);
4719 omd_name = replmd_replPropertyMetaData1_find_attid(&omd, DRSUAPI_ATTID_name);
4721 DEBUG(0,(__location__ ": Failed to find name attribute in local LDB replPropertyMetaData for %s\n",
4722 ldb_dn_get_linearized(conflict_dn)));
4727 * Should we preserve the current record, and so rename the
4728 * incoming record to be a conflict?
4730 rename_incoming_record
4731 = !replmd_replPropertyMetaData1_new_should_be_taken(ar->objs->dsdb_repl_flags & DSDB_REPL_FLAG_PRIORITISE_INCOMING,
4732 omd_name, rmd_name);
4734 if (rename_incoming_record) {
4736 struct ldb_dn *new_dn;
4738 guid = samdb_result_guid(msg, "objectGUID");
4739 if (GUID_all_zero(&guid)) {
4740 DEBUG(0,(__location__ ": Failed to find objectGUID for conflicting incoming record %s\n",
4741 ldb_dn_get_linearized(conflict_dn)));
4744 new_dn = replmd_conflict_dn(req, conflict_dn, &guid);
4745 if (new_dn == NULL) {
4746 DEBUG(0,(__location__ ": Failed to form conflict DN for %s\n",
4747 ldb_dn_get_linearized(conflict_dn)));
4751 DEBUG(2,(__location__ ": Resolving conflict record via incoming rename '%s' -> '%s'\n",
4752 ldb_dn_get_linearized(conflict_dn), ldb_dn_get_linearized(new_dn)));
4754 /* re-submit the request, but with the new DN */
4755 callback = replmd_op_name_modify_callback;
4758 /* we are renaming the existing record */
4760 struct ldb_dn *new_dn;
4762 guid = samdb_result_guid(res->msgs[0], "objectGUID");
4763 if (GUID_all_zero(&guid)) {
4764 DEBUG(0,(__location__ ": Failed to find objectGUID for existing conflict record %s\n",
4765 ldb_dn_get_linearized(conflict_dn)));
4769 new_dn = replmd_conflict_dn(req, conflict_dn, &guid);
4770 if (new_dn == NULL) {
4771 DEBUG(0,(__location__ ": Failed to form conflict DN for %s\n",
4772 ldb_dn_get_linearized(conflict_dn)));
4776 DEBUG(2,(__location__ ": Resolving conflict record via existing-record rename '%s' -> '%s'\n",
4777 ldb_dn_get_linearized(conflict_dn), ldb_dn_get_linearized(new_dn)));
4779 ret = dsdb_module_rename(ar->module, conflict_dn, new_dn,
4780 DSDB_FLAG_OWN_MODULE, req);
4781 if (ret != LDB_SUCCESS) {
4782 DEBUG(0,(__location__ ": Failed to rename conflict dn '%s' to '%s' - %s\n",
4783 ldb_dn_get_linearized(conflict_dn),
4784 ldb_dn_get_linearized(new_dn),
4785 ldb_errstring(ldb_module_get_ctx(ar->module))));
4790 * now we need to ensure that the rename is seen as an
4791 * originating update. We do that with a modify.
4793 ret = replmd_name_modify(ar, req, new_dn);
4794 if (ret != LDB_SUCCESS) {
4798 DEBUG(2,(__location__ ": With conflicting record renamed, re-apply replicated creation of '%s'\n",
4799 ldb_dn_get_linearized(req->op.add.message->dn)));
4802 ret = ldb_build_add_req(&down_req,
4803 ldb_module_get_ctx(ar->module),
4810 if (ret != LDB_SUCCESS) {
4813 LDB_REQ_SET_LOCATION(down_req);
4815 /* current partition control needed by "repmd_op_callback" */
4816 ret = ldb_request_add_control(down_req,
4817 DSDB_CONTROL_CURRENT_PARTITION_OID,
4819 if (ret != LDB_SUCCESS) {
4820 return replmd_replicated_request_error(ar, ret);
4823 if (ar->objs->dsdb_repl_flags & DSDB_REPL_FLAG_PARTIAL_REPLICA) {
4824 /* this tells the partition module to make it a
4825 partial replica if creating an NC */
4826 ret = ldb_request_add_control(down_req,
4827 DSDB_CONTROL_PARTIAL_REPLICA,
4829 if (ret != LDB_SUCCESS) {
4830 return replmd_replicated_request_error(ar, ret);
4835 * Finally we re-run the add, otherwise the new record won't
4836 * exist, as we are here because of that exact failure!
4838 return ldb_next_request(ar->module, down_req);
4841 /* on failure make the caller get the error. This means
4842 * replication will stop with an error, but there is not much
4845 return ldb_module_done(ar->req, NULL, NULL,
4850 callback for replmd_replicated_apply_add()
4851 This copes with the creation of conflict records in the case where
4852 the DN exists, but with a different objectGUID
4854 static int replmd_op_add_callback(struct ldb_request *req, struct ldb_reply *ares)
4856 struct replmd_replicated_request *ar =
4857 talloc_get_type_abort(req->context, struct replmd_replicated_request);
4859 if (ar->objs->objects[ar->index_current].last_known_parent) {
4860 /* This is like a conflict DN, where we put the object in LostAndFound
4861 see MS-DRSR 4.1.10.6.10 FindBestParentObject */
4862 return replmd_op_possible_conflict_callback(req, ares, replmd_op_name_modify_callback);
4865 return replmd_op_possible_conflict_callback(req, ares, replmd_op_callback);
4869 this is called when a new object comes in over DRS
4871 static int replmd_replicated_apply_add(struct replmd_replicated_request *ar)
4873 struct ldb_context *ldb;
4874 struct ldb_request *change_req;
4875 enum ndr_err_code ndr_err;
4876 struct ldb_message *msg;
4877 struct replPropertyMetaDataBlob *md;
4878 struct ldb_val md_value;
4881 bool remote_isDeleted = false;
4884 time_t t = time(NULL);
4885 const struct ldb_val *rdn_val;
4886 struct replmd_private *replmd_private =
4887 talloc_get_type(ldb_module_get_private(ar->module),
4888 struct replmd_private);
4889 unix_to_nt_time(&now, t);
4891 ldb = ldb_module_get_ctx(ar->module);
4892 msg = ar->objs->objects[ar->index_current].msg;
4893 md = ar->objs->objects[ar->index_current].meta_data;
4894 is_schema_nc = ldb_dn_compare_base(replmd_private->schema_dn, msg->dn) == 0;
4896 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &ar->seq_num);
4897 if (ret != LDB_SUCCESS) {
4898 return replmd_replicated_request_error(ar, ret);
4901 ret = dsdb_msg_add_guid(msg,
4902 &ar->objs->objects[ar->index_current].object_guid,
4904 if (ret != LDB_SUCCESS) {
4905 return replmd_replicated_request_error(ar, ret);
4908 ret = ldb_msg_add_string(msg, "whenChanged", ar->objs->objects[ar->index_current].when_changed);
4909 if (ret != LDB_SUCCESS) {
4910 return replmd_replicated_request_error(ar, ret);
4913 ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNCreated", ar->seq_num);
4914 if (ret != LDB_SUCCESS) {
4915 return replmd_replicated_request_error(ar, ret);
4918 ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNChanged", ar->seq_num);
4919 if (ret != LDB_SUCCESS) {
4920 return replmd_replicated_request_error(ar, ret);
4923 /* remove any message elements that have zero values */
4924 for (i=0; i<msg->num_elements; i++) {
4925 struct ldb_message_element *el = &msg->elements[i];
4927 if (el->num_values == 0) {
4928 if (ldb_attr_cmp(msg->elements[i].name, "objectClass") == 0) {
4929 ldb_asprintf_errstring(ldb, __location__
4930 ": empty objectClass sent on %s, aborting replication\n",
4931 ldb_dn_get_linearized(msg->dn));
4932 return replmd_replicated_request_error(ar, LDB_ERR_OBJECT_CLASS_VIOLATION);
4935 DEBUG(4,(__location__ ": Removing attribute %s with num_values==0\n",
4937 memmove(el, el+1, sizeof(*el)*(msg->num_elements - (i+1)));
4938 msg->num_elements--;
4945 struct GUID_txt_buf guid_txt;
4947 char *s = ldb_ldif_message_string(ldb, ar, LDB_CHANGETYPE_ADD, msg);
4948 DEBUG(4, ("DRS replication add message of %s:\n%s\n",
4949 GUID_buf_string(&ar->objs->objects[ar->index_current].object_guid, &guid_txt),
4954 remote_isDeleted = ldb_msg_find_attr_as_bool(msg,
4955 "isDeleted", false);
4958 * the meta data array is already sorted by the caller, except
4959 * for the RDN, which needs to be added.
4963 rdn_val = ldb_dn_get_rdn_val(msg->dn);
4964 ret = replmd_update_rpmd_rdn_attr(ldb, msg, rdn_val, NULL,
4965 md, ar, now, is_schema_nc,
4967 if (ret != LDB_SUCCESS) {
4968 ldb_asprintf_errstring(ldb, "%s: error during DRS repl ADD: %s", __func__, ldb_errstring(ldb));
4969 return replmd_replicated_request_error(ar, ret);
4972 ret = replmd_replPropertyMetaDataCtr1_sort_and_verify(ldb, &md->ctr.ctr1, msg->dn);
4973 if (ret != LDB_SUCCESS) {
4974 ldb_asprintf_errstring(ldb, "%s: error during DRS repl ADD: %s", __func__, ldb_errstring(ldb));
4975 return replmd_replicated_request_error(ar, ret);
4978 for (i=0; i < md->ctr.ctr1.count; i++) {
4979 md->ctr.ctr1.array[i].local_usn = ar->seq_num;
4981 ndr_err = ndr_push_struct_blob(&md_value, msg, md,
4982 (ndr_push_flags_fn_t)ndr_push_replPropertyMetaDataBlob);
4983 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
4984 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
4985 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
4987 ret = ldb_msg_add_value(msg, "replPropertyMetaData", &md_value, NULL);
4988 if (ret != LDB_SUCCESS) {
4989 return replmd_replicated_request_error(ar, ret);
4992 replmd_ldb_message_sort(msg, ar->schema);
4994 if (!remote_isDeleted) {
4995 ret = dsdb_module_schedule_sd_propagation(ar->module,
4996 ar->objs->partition_dn,
4998 if (ret != LDB_SUCCESS) {
4999 return replmd_replicated_request_error(ar, ret);
5003 ar->isDeleted = remote_isDeleted;
5005 ret = ldb_build_add_req(&change_req,
5011 replmd_op_add_callback,
5013 LDB_REQ_SET_LOCATION(change_req);
5014 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
5016 /* current partition control needed by "repmd_op_callback" */
5017 ret = ldb_request_add_control(change_req,
5018 DSDB_CONTROL_CURRENT_PARTITION_OID,
5020 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
5022 if (ar->objs->dsdb_repl_flags & DSDB_REPL_FLAG_PARTIAL_REPLICA) {
5023 /* this tells the partition module to make it a
5024 partial replica if creating an NC */
5025 ret = ldb_request_add_control(change_req,
5026 DSDB_CONTROL_PARTIAL_REPLICA,
5028 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
5031 return ldb_next_request(ar->module, change_req);
5034 static int replmd_replicated_apply_search_for_parent_callback(struct ldb_request *req,
5035 struct ldb_reply *ares)
5037 struct replmd_replicated_request *ar = talloc_get_type(req->context,
5038 struct replmd_replicated_request);
5042 return ldb_module_done(ar->req, NULL, NULL,
5043 LDB_ERR_OPERATIONS_ERROR);
5047 * The error NO_SUCH_OBJECT is not expected, unless the search
5048 * base is the partition DN, and that case doesn't happen here
5049 * because then we wouldn't get a parent_guid_value in any
5052 if (ares->error != LDB_SUCCESS) {
5053 return ldb_module_done(ar->req, ares->controls,
5054 ares->response, ares->error);
5057 switch (ares->type) {
5058 case LDB_REPLY_ENTRY:
5060 struct ldb_message *parent_msg = ares->message;
5061 struct ldb_message *msg = ar->objs->objects[ar->index_current].msg;
5062 struct ldb_dn *parent_dn;
5065 if (!ldb_msg_check_string_attribute(msg, "isDeleted", "TRUE")
5066 && ldb_msg_check_string_attribute(parent_msg, "isDeleted", "TRUE")) {
5067 /* Per MS-DRSR 4.1.10.6.10
5068 * FindBestParentObject we need to move this
5069 * new object under a deleted object to
5071 struct ldb_dn *nc_root;
5073 ret = dsdb_find_nc_root(ldb_module_get_ctx(ar->module), msg, msg->dn, &nc_root);
5074 if (ret == LDB_ERR_NO_SUCH_OBJECT) {
5075 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
5076 "No suitable NC root found for %s. "
5077 "We need to move this object because parent object %s "
5078 "is deleted, but this object is not.",
5079 ldb_dn_get_linearized(msg->dn),
5080 ldb_dn_get_linearized(parent_msg->dn));
5081 return ldb_module_done(ar->req, NULL, NULL, LDB_ERR_OPERATIONS_ERROR);
5082 } else if (ret != LDB_SUCCESS) {
5083 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
5084 "Unable to find NC root for %s: %s. "
5085 "We need to move this object because parent object %s "
5086 "is deleted, but this object is not.",
5087 ldb_dn_get_linearized(msg->dn),
5088 ldb_errstring(ldb_module_get_ctx(ar->module)),
5089 ldb_dn_get_linearized(parent_msg->dn));
5090 return ldb_module_done(ar->req, NULL, NULL, LDB_ERR_OPERATIONS_ERROR);
5093 ret = dsdb_wellknown_dn(ldb_module_get_ctx(ar->module), msg,
5095 DS_GUID_LOSTANDFOUND_CONTAINER,
5097 if (ret != LDB_SUCCESS) {
5098 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
5099 "Unable to find LostAndFound Container for %s "
5100 "in partition %s: %s. "
5101 "We need to move this object because parent object %s "
5102 "is deleted, but this object is not.",
5103 ldb_dn_get_linearized(msg->dn), ldb_dn_get_linearized(nc_root),
5104 ldb_errstring(ldb_module_get_ctx(ar->module)),
5105 ldb_dn_get_linearized(parent_msg->dn));
5106 return ldb_module_done(ar->req, NULL, NULL, LDB_ERR_OPERATIONS_ERROR);
5108 ar->objs->objects[ar->index_current].last_known_parent
5109 = talloc_steal(ar->objs->objects[ar->index_current].msg, parent_msg->dn);
5113 = talloc_steal(ar->objs->objects[ar->index_current].msg, parent_msg->dn);
5116 ar->objs->objects[ar->index_current].local_parent_dn = parent_dn;
5118 comp_num = ldb_dn_get_comp_num(msg->dn);
5120 if (!ldb_dn_remove_base_components(msg->dn, comp_num - 1)) {
5122 return ldb_module_done(ar->req, NULL, NULL, ldb_module_operr(ar->module));
5125 if (!ldb_dn_add_base(msg->dn, parent_dn)) {
5127 return ldb_module_done(ar->req, NULL, NULL, ldb_module_operr(ar->module));
5131 case LDB_REPLY_REFERRAL:
5132 /* we ignore referrals */
5135 case LDB_REPLY_DONE:
5137 if (ar->objs->objects[ar->index_current].local_parent_dn == NULL) {
5138 struct GUID_txt_buf str_buf;
5139 if (ar->search_msg != NULL) {
5140 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
5141 "No parent with GUID %s found for object locally known as %s",
5142 GUID_buf_string(ar->objs->objects[ar->index_current].parent_guid, &str_buf),
5143 ldb_dn_get_linearized(ar->search_msg->dn));
5145 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
5146 "No parent with GUID %s found for object remotely known as %s",
5147 GUID_buf_string(ar->objs->objects[ar->index_current].parent_guid, &str_buf),
5148 ldb_dn_get_linearized(ar->objs->objects[ar->index_current].msg->dn));
5152 * This error code is really important, as it
5153 * is the flag back to the callers to retry
5154 * this with DRSUAPI_DRS_GET_ANC, and so get
5155 * the parent objects before the child
5158 return ldb_module_done(ar->req, NULL, NULL,
5159 replmd_replicated_request_werror(ar, WERR_DS_DRA_MISSING_PARENT));
5162 if (ar->search_msg != NULL) {
5163 ret = replmd_replicated_apply_merge(ar);
5165 ret = replmd_replicated_apply_add(ar);
5167 if (ret != LDB_SUCCESS) {
5168 return ldb_module_done(ar->req, NULL, NULL, ret);
5177 * Look for the parent object, so we put the new object in the right
5178 * place This is akin to NameObject in MS-DRSR - this routine and the
5179 * callbacks find the right parent name, and correct name for this
5183 static int replmd_replicated_apply_search_for_parent(struct replmd_replicated_request *ar)
5185 struct ldb_context *ldb;
5189 struct ldb_request *search_req;
5190 static const char *attrs[] = {"isDeleted", NULL};
5191 struct GUID_txt_buf guid_str_buf;
5193 ldb = ldb_module_get_ctx(ar->module);
5195 if (ar->objs->objects[ar->index_current].parent_guid == NULL) {
5196 if (ar->search_msg != NULL) {
5197 return replmd_replicated_apply_merge(ar);
5199 return replmd_replicated_apply_add(ar);
5203 tmp_str = GUID_buf_string(ar->objs->objects[ar->index_current].parent_guid,
5206 filter = talloc_asprintf(ar, "(objectGUID=%s)", tmp_str);
5207 if (!filter) return replmd_replicated_request_werror(ar, WERR_NOT_ENOUGH_MEMORY);
5209 ret = ldb_build_search_req(&search_req,
5212 ar->objs->partition_dn,
5218 replmd_replicated_apply_search_for_parent_callback,
5220 LDB_REQ_SET_LOCATION(search_req);
5222 ret = dsdb_request_add_controls(search_req,
5223 DSDB_SEARCH_SHOW_RECYCLED|
5224 DSDB_SEARCH_SHOW_DELETED|
5225 DSDB_SEARCH_SHOW_EXTENDED_DN);
5226 if (ret != LDB_SUCCESS) {
5230 return ldb_next_request(ar->module, search_req);
5234 handle renames that come in over DRS replication
5236 static int replmd_replicated_handle_rename(struct replmd_replicated_request *ar,
5237 struct ldb_message *msg,
5238 struct ldb_request *parent,
5242 TALLOC_CTX *tmp_ctx = talloc_new(msg);
5243 struct ldb_result *res;
5244 struct ldb_dn *conflict_dn;
5245 const char *attrs[] = { "replPropertyMetaData", "objectGUID", NULL };
5246 const struct ldb_val *omd_value;
5247 struct replPropertyMetaDataBlob omd, *rmd;
5248 enum ndr_err_code ndr_err;
5249 bool rename_incoming_record, rodc;
5250 struct replPropertyMetaData1 *rmd_name, *omd_name;
5251 struct ldb_dn *new_dn;
5254 DEBUG(4,("replmd_replicated_request rename %s => %s\n",
5255 ldb_dn_get_linearized(ar->search_msg->dn),
5256 ldb_dn_get_linearized(msg->dn)));
5259 ret = dsdb_module_rename(ar->module, ar->search_msg->dn, msg->dn,
5260 DSDB_FLAG_NEXT_MODULE, ar->req);
5261 if (ret == LDB_SUCCESS) {
5262 talloc_free(tmp_ctx);
5267 if (ret != LDB_ERR_ENTRY_ALREADY_EXISTS) {
5268 talloc_free(tmp_ctx);
5269 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module), "Failed to locally apply remote rename from %s to %s: %s",
5270 ldb_dn_get_linearized(ar->search_msg->dn),
5271 ldb_dn_get_linearized(msg->dn),
5272 ldb_errstring(ldb_module_get_ctx(ar->module)));
5276 ret = samdb_rodc(ldb_module_get_ctx(ar->module), &rodc);
5277 if (ret != LDB_SUCCESS) {
5278 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
5279 "Failed to determine if we are an RODC when attempting to form conflict DN: %s",
5280 ldb_errstring(ldb_module_get_ctx(ar->module)));
5281 return LDB_ERR_OPERATIONS_ERROR;
5284 * we have a conflict, and need to decide if we will keep the
5285 * new record or the old record
5288 conflict_dn = msg->dn;
5292 * We are on an RODC, or were a GC for this
5293 * partition, so we have to fail this until
5294 * someone who owns the partition sorts it
5297 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
5298 "Conflict adding object '%s' from incoming replication but we are read only for the partition. \n"
5299 " - We must fail the operation until a master for this partition resolves the conflict",
5300 ldb_dn_get_linearized(conflict_dn));
5305 * first we need the replPropertyMetaData attribute from the
5308 ret = dsdb_module_search_dn(ar->module, tmp_ctx, &res, conflict_dn,
5310 DSDB_FLAG_NEXT_MODULE |
5311 DSDB_SEARCH_SHOW_DELETED |
5312 DSDB_SEARCH_SHOW_RECYCLED, ar->req);
5313 if (ret != LDB_SUCCESS) {
5314 DEBUG(0,(__location__ ": Unable to find object for conflicting record '%s'\n",
5315 ldb_dn_get_linearized(conflict_dn)));
5319 omd_value = ldb_msg_find_ldb_val(res->msgs[0], "replPropertyMetaData");
5320 if (omd_value == NULL) {
5321 DEBUG(0,(__location__ ": Unable to find replPropertyMetaData for conflicting record '%s'\n",
5322 ldb_dn_get_linearized(conflict_dn)));
5326 ndr_err = ndr_pull_struct_blob(omd_value, res->msgs[0], &omd,
5327 (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
5328 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
5329 DEBUG(0,(__location__ ": Failed to parse old replPropertyMetaData for %s\n",
5330 ldb_dn_get_linearized(conflict_dn)));
5334 rmd = ar->objs->objects[ar->index_current].meta_data;
5337 * we decide which is newer based on the RPMD on the name
5338 * attribute. See [MS-DRSR] ResolveNameConflict.
5340 * We expect omd_name to be present, as this is from a local
5341 * search, but while rmd_name should have been given to us by
5342 * the remote server, if it is missing we just prefer the
5344 * replmd_replPropertyMetaData1_new_should_be_taken()
5346 rmd_name = replmd_replPropertyMetaData1_find_attid(rmd, DRSUAPI_ATTID_name);
5347 omd_name = replmd_replPropertyMetaData1_find_attid(&omd, DRSUAPI_ATTID_name);
5349 DEBUG(0,(__location__ ": Failed to find name attribute in local LDB replPropertyMetaData for %s\n",
5350 ldb_dn_get_linearized(conflict_dn)));
5355 * Should we preserve the current record, and so rename the
5356 * incoming record to be a conflict?
5358 rename_incoming_record =
5359 !replmd_replPropertyMetaData1_new_should_be_taken(
5360 ar->objs->dsdb_repl_flags & DSDB_REPL_FLAG_PRIORITISE_INCOMING,
5361 omd_name, rmd_name);
5363 if (rename_incoming_record) {
5365 new_dn = replmd_conflict_dn(msg, msg->dn,
5366 &ar->objs->objects[ar->index_current].object_guid);
5367 if (new_dn == NULL) {
5368 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
5369 "Failed to form conflict DN for %s\n",
5370 ldb_dn_get_linearized(msg->dn));
5372 return replmd_replicated_request_werror(ar, WERR_NOT_ENOUGH_MEMORY);
5375 ret = dsdb_module_rename(ar->module, ar->search_msg->dn, new_dn,
5376 DSDB_FLAG_NEXT_MODULE, ar->req);
5377 if (ret != LDB_SUCCESS) {
5378 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
5379 "Failed to rename incoming conflicting dn '%s' (was '%s') to '%s' - %s\n",
5380 ldb_dn_get_linearized(conflict_dn),
5381 ldb_dn_get_linearized(ar->search_msg->dn),
5382 ldb_dn_get_linearized(new_dn),
5383 ldb_errstring(ldb_module_get_ctx(ar->module)));
5384 return replmd_replicated_request_werror(ar, WERR_DS_DRA_DB_ERROR);
5392 /* we are renaming the existing record */
5394 guid = samdb_result_guid(res->msgs[0], "objectGUID");
5395 if (GUID_all_zero(&guid)) {
5396 DEBUG(0,(__location__ ": Failed to find objectGUID for existing conflict record %s\n",
5397 ldb_dn_get_linearized(conflict_dn)));
5401 new_dn = replmd_conflict_dn(tmp_ctx, conflict_dn, &guid);
5402 if (new_dn == NULL) {
5403 DEBUG(0,(__location__ ": Failed to form conflict DN for %s\n",
5404 ldb_dn_get_linearized(conflict_dn)));
5408 DEBUG(2,(__location__ ": Resolving conflict record via existing-record rename '%s' -> '%s'\n",
5409 ldb_dn_get_linearized(conflict_dn), ldb_dn_get_linearized(new_dn)));
5411 ret = dsdb_module_rename(ar->module, conflict_dn, new_dn,
5412 DSDB_FLAG_OWN_MODULE, ar->req);
5413 if (ret != LDB_SUCCESS) {
5414 DEBUG(0,(__location__ ": Failed to rename conflict dn '%s' to '%s' - %s\n",
5415 ldb_dn_get_linearized(conflict_dn),
5416 ldb_dn_get_linearized(new_dn),
5417 ldb_errstring(ldb_module_get_ctx(ar->module))));
5422 * now we need to ensure that the rename is seen as an
5423 * originating update. We do that with a modify.
5425 ret = replmd_name_modify(ar, ar->req, new_dn);
5426 if (ret != LDB_SUCCESS) {
5430 DEBUG(2,(__location__ ": With conflicting record renamed, re-apply replicated rename '%s' -> '%s'\n",
5431 ldb_dn_get_linearized(ar->search_msg->dn),
5432 ldb_dn_get_linearized(msg->dn)));
5435 ret = dsdb_module_rename(ar->module, ar->search_msg->dn, msg->dn,
5436 DSDB_FLAG_NEXT_MODULE, ar->req);
5437 if (ret != LDB_SUCCESS) {
5438 DEBUG(0,(__location__ ": After conflict resolution, failed to rename dn '%s' to '%s' - %s\n",
5439 ldb_dn_get_linearized(ar->search_msg->dn),
5440 ldb_dn_get_linearized(msg->dn),
5441 ldb_errstring(ldb_module_get_ctx(ar->module))));
5447 * On failure make the caller get the error
5448 * This means replication will stop with an error,
5449 * but there is not much else we can do. In the
5450 * LDB_ERR_ENTRY_ALREADY_EXISTS case this is exactly what is
5454 talloc_free(tmp_ctx);
5459 static int replmd_replicated_apply_merge(struct replmd_replicated_request *ar)
5461 struct ldb_context *ldb;
5462 struct ldb_request *change_req;
5463 enum ndr_err_code ndr_err;
5464 struct ldb_message *msg;
5465 struct replPropertyMetaDataBlob *rmd;
5466 struct replPropertyMetaDataBlob omd;
5467 const struct ldb_val *omd_value;
5468 struct replPropertyMetaDataBlob nmd;
5469 struct ldb_val nmd_value;
5470 struct GUID remote_parent_guid;
5473 unsigned int removed_attrs = 0;
5475 int (*callback)(struct ldb_request *req, struct ldb_reply *ares) = replmd_op_callback;
5476 bool isDeleted = false;
5477 bool local_isDeleted = false;
5478 bool remote_isDeleted = false;
5479 bool take_remote_isDeleted = false;
5480 bool sd_updated = false;
5481 bool renamed = false;
5482 bool is_schema_nc = false;
5484 const struct ldb_val *old_rdn, *new_rdn;
5485 struct replmd_private *replmd_private =
5486 talloc_get_type(ldb_module_get_private(ar->module),
5487 struct replmd_private);
5489 time_t t = time(NULL);
5490 unix_to_nt_time(&now, t);
5492 ldb = ldb_module_get_ctx(ar->module);
5493 msg = ar->objs->objects[ar->index_current].msg;
5495 is_schema_nc = ldb_dn_compare_base(replmd_private->schema_dn, msg->dn) == 0;
5497 rmd = ar->objs->objects[ar->index_current].meta_data;
5501 /* find existing meta data */
5502 omd_value = ldb_msg_find_ldb_val(ar->search_msg, "replPropertyMetaData");
5504 ndr_err = ndr_pull_struct_blob(omd_value, ar, &omd,
5505 (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
5506 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
5507 nt_status = ndr_map_error2ntstatus(ndr_err);
5508 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
5511 if (omd.version != 1) {
5512 return replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
5517 struct GUID_txt_buf guid_txt;
5519 char *s = ldb_ldif_message_string(ldb, ar, LDB_CHANGETYPE_MODIFY, msg);
5520 DEBUG(5, ("Initial DRS replication modify message of %s is:\n%s\n"
5523 GUID_buf_string(&ar->objs->objects[ar->index_current].object_guid, &guid_txt),
5525 ndr_print_struct_string(s,
5526 (ndr_print_fn_t)ndr_print_replPropertyMetaDataBlob,
5527 "existing replPropertyMetaData",
5529 ndr_print_struct_string(s,
5530 (ndr_print_fn_t)ndr_print_replPropertyMetaDataBlob,
5531 "incoming replPropertyMetaData",
5536 local_isDeleted = ldb_msg_find_attr_as_bool(ar->search_msg,
5537 "isDeleted", false);
5538 remote_isDeleted = ldb_msg_find_attr_as_bool(msg,
5539 "isDeleted", false);
5542 * Fill in the remote_parent_guid with the GUID or an all-zero
5545 if (ar->objs->objects[ar->index_current].parent_guid != NULL) {
5546 remote_parent_guid = *ar->objs->objects[ar->index_current].parent_guid;
5548 remote_parent_guid = GUID_zero();
5552 * To ensure we follow a complex rename chain around, we have
5553 * to confirm that the DN is the same (mostly to confirm the
5554 * RDN) and the parentGUID is the same.
5556 * This ensures we keep things under the correct parent, which
5557 * replmd_replicated_handle_rename() will do.
5560 if (strcmp(ldb_dn_get_linearized(msg->dn), ldb_dn_get_linearized(ar->search_msg->dn)) == 0
5561 && GUID_equal(&remote_parent_guid, &ar->local_parent_guid)) {
5565 * handle renames, even just by case that come in over
5566 * DRS. Changes in the parent DN don't hit us here,
5567 * because the search for a parent will clean up those
5570 * We also have already filtered out the case where
5571 * the peer has an older name to what we have (see
5572 * replmd_replicated_apply_search_callback())
5574 ret = replmd_replicated_handle_rename(ar, msg, ar->req, &renamed);
5577 if (ret != LDB_SUCCESS) {
5578 ldb_debug(ldb, LDB_DEBUG_FATAL,
5579 "replmd_replicated_request rename %s => %s failed - %s\n",
5580 ldb_dn_get_linearized(ar->search_msg->dn),
5581 ldb_dn_get_linearized(msg->dn),
5582 ldb_errstring(ldb));
5583 return replmd_replicated_request_werror(ar, WERR_DS_DRA_DB_ERROR);
5586 if (renamed == true) {
5588 * Set the callback to one that will fix up the name
5589 * metadata on the new conflict DN
5591 callback = replmd_op_name_modify_callback;
5596 nmd.ctr.ctr1.count = omd.ctr.ctr1.count + rmd->ctr.ctr1.count;
5597 nmd.ctr.ctr1.array = talloc_array(ar,
5598 struct replPropertyMetaData1,
5599 nmd.ctr.ctr1.count);
5600 if (!nmd.ctr.ctr1.array) return replmd_replicated_request_werror(ar, WERR_NOT_ENOUGH_MEMORY);
5602 /* first copy the old meta data */
5603 for (i=0; i < omd.ctr.ctr1.count; i++) {
5604 nmd.ctr.ctr1.array[ni] = omd.ctr.ctr1.array[i];
5609 /* now merge in the new meta data */
5610 for (i=0; i < rmd->ctr.ctr1.count; i++) {
5613 for (j=0; j < ni; j++) {
5616 if (rmd->ctr.ctr1.array[i].attid != nmd.ctr.ctr1.array[j].attid) {
5620 cmp = replmd_replPropertyMetaData1_new_should_be_taken(
5621 ar->objs->dsdb_repl_flags,
5622 &nmd.ctr.ctr1.array[j],
5623 &rmd->ctr.ctr1.array[i]);
5625 /* replace the entry */
5626 nmd.ctr.ctr1.array[j] = rmd->ctr.ctr1.array[i];
5627 if (ar->seq_num == 0) {
5628 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &ar->seq_num);
5629 if (ret != LDB_SUCCESS) {
5630 return replmd_replicated_request_error(ar, ret);
5633 nmd.ctr.ctr1.array[j].local_usn = ar->seq_num;
5634 switch (nmd.ctr.ctr1.array[j].attid) {
5635 case DRSUAPI_ATTID_ntSecurityDescriptor:
5638 case DRSUAPI_ATTID_isDeleted:
5639 take_remote_isDeleted = true;
5648 if (rmd->ctr.ctr1.array[i].attid != DRSUAPI_ATTID_instanceType) {
5649 DEBUG(3,("Discarding older DRS attribute update to %s on %s from %s\n",
5650 msg->elements[i-removed_attrs].name,
5651 ldb_dn_get_linearized(msg->dn),
5652 GUID_string(ar, &rmd->ctr.ctr1.array[i].originating_invocation_id)));
5655 /* we don't want to apply this change so remove the attribute */
5656 ldb_msg_remove_element(msg, &msg->elements[i-removed_attrs]);
5663 if (found) continue;
5665 nmd.ctr.ctr1.array[ni] = rmd->ctr.ctr1.array[i];
5666 if (ar->seq_num == 0) {
5667 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &ar->seq_num);
5668 if (ret != LDB_SUCCESS) {
5669 return replmd_replicated_request_error(ar, ret);
5672 nmd.ctr.ctr1.array[ni].local_usn = ar->seq_num;
5673 switch (nmd.ctr.ctr1.array[ni].attid) {
5674 case DRSUAPI_ATTID_ntSecurityDescriptor:
5677 case DRSUAPI_ATTID_isDeleted:
5678 take_remote_isDeleted = true;
5687 * finally correct the size of the meta_data array
5689 nmd.ctr.ctr1.count = ni;
5691 new_rdn = ldb_dn_get_rdn_val(msg->dn);
5692 old_rdn = ldb_dn_get_rdn_val(ar->search_msg->dn);
5695 ret = replmd_update_rpmd_rdn_attr(ldb, msg, new_rdn, old_rdn,
5696 &nmd, ar, now, is_schema_nc,
5698 if (ret != LDB_SUCCESS) {
5699 ldb_asprintf_errstring(ldb, "%s: error during DRS repl merge: %s", __func__, ldb_errstring(ldb));
5700 return replmd_replicated_request_error(ar, ret);
5704 * sort the new meta data array
5706 ret = replmd_replPropertyMetaDataCtr1_sort_and_verify(ldb, &nmd.ctr.ctr1, msg->dn);
5707 if (ret != LDB_SUCCESS) {
5708 ldb_asprintf_errstring(ldb, "%s: error during DRS repl merge: %s", __func__, ldb_errstring(ldb));
5713 * Work out if this object is deleted, so we can prune any extra attributes. See MS-DRSR 4.1.10.6.9
5716 * This also controls SD propagation below
5718 if (take_remote_isDeleted) {
5719 isDeleted = remote_isDeleted;
5721 isDeleted = local_isDeleted;
5724 ar->isDeleted = isDeleted;
5727 * check if some replicated attributes left, otherwise skip the ldb_modify() call
5729 if (msg->num_elements == 0) {
5730 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_replicated_apply_merge[%u]: skip replace\n",
5733 return replmd_replicated_apply_isDeleted(ar);
5736 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_replicated_apply_merge[%u]: replace %u attributes\n",
5737 ar->index_current, msg->num_elements);
5743 if (sd_updated && !isDeleted) {
5744 ret = dsdb_module_schedule_sd_propagation(ar->module,
5745 ar->objs->partition_dn,
5747 if (ret != LDB_SUCCESS) {
5748 return ldb_operr(ldb);
5752 /* create the meta data value */
5753 ndr_err = ndr_push_struct_blob(&nmd_value, msg, &nmd,
5754 (ndr_push_flags_fn_t)ndr_push_replPropertyMetaDataBlob);
5755 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
5756 nt_status = ndr_map_error2ntstatus(ndr_err);
5757 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
5761 * when we know that we'll modify the record, add the whenChanged, uSNChanged
5762 * and replPopertyMetaData attributes
5764 ret = ldb_msg_add_string(msg, "whenChanged", ar->objs->objects[ar->index_current].when_changed);
5765 if (ret != LDB_SUCCESS) {
5766 return replmd_replicated_request_error(ar, ret);
5768 ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNChanged", ar->seq_num);
5769 if (ret != LDB_SUCCESS) {
5770 return replmd_replicated_request_error(ar, ret);
5772 ret = ldb_msg_add_value(msg, "replPropertyMetaData", &nmd_value, NULL);
5773 if (ret != LDB_SUCCESS) {
5774 return replmd_replicated_request_error(ar, ret);
5777 replmd_ldb_message_sort(msg, ar->schema);
5779 /* we want to replace the old values */
5780 for (i=0; i < msg->num_elements; i++) {
5781 msg->elements[i].flags = LDB_FLAG_MOD_REPLACE;
5782 if (ldb_attr_cmp(msg->elements[i].name, "objectClass") == 0) {
5783 if (msg->elements[i].num_values == 0) {
5784 ldb_asprintf_errstring(ldb, __location__
5785 ": objectClass removed on %s, aborting replication\n",
5786 ldb_dn_get_linearized(msg->dn));
5787 return replmd_replicated_request_error(ar, LDB_ERR_OBJECT_CLASS_VIOLATION);
5793 struct GUID_txt_buf guid_txt;
5795 char *s = ldb_ldif_message_string(ldb, ar, LDB_CHANGETYPE_MODIFY, msg);
5796 DEBUG(4, ("Final DRS replication modify message of %s:\n%s\n",
5797 GUID_buf_string(&ar->objs->objects[ar->index_current].object_guid, &guid_txt),
5802 ret = ldb_build_mod_req(&change_req,
5810 LDB_REQ_SET_LOCATION(change_req);
5811 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
5813 /* current partition control needed by "repmd_op_callback" */
5814 ret = ldb_request_add_control(change_req,
5815 DSDB_CONTROL_CURRENT_PARTITION_OID,
5817 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
5819 return ldb_next_request(ar->module, change_req);
5822 static int replmd_replicated_apply_search_callback(struct ldb_request *req,
5823 struct ldb_reply *ares)
5825 struct replmd_replicated_request *ar = talloc_get_type(req->context,
5826 struct replmd_replicated_request);
5830 return ldb_module_done(ar->req, NULL, NULL,
5831 LDB_ERR_OPERATIONS_ERROR);
5833 if (ares->error != LDB_SUCCESS &&
5834 ares->error != LDB_ERR_NO_SUCH_OBJECT) {
5835 return ldb_module_done(ar->req, ares->controls,
5836 ares->response, ares->error);
5839 switch (ares->type) {
5840 case LDB_REPLY_ENTRY:
5841 ar->search_msg = talloc_steal(ar, ares->message);
5844 case LDB_REPLY_REFERRAL:
5845 /* we ignore referrals */
5848 case LDB_REPLY_DONE:
5850 struct replPropertyMetaData1 *md_remote;
5851 struct replPropertyMetaData1 *md_local;
5853 struct replPropertyMetaDataBlob omd;
5854 const struct ldb_val *omd_value;
5855 struct replPropertyMetaDataBlob *rmd;
5856 struct ldb_message *msg;
5858 ar->objs->objects[ar->index_current].local_parent_dn = NULL;
5859 ar->objs->objects[ar->index_current].last_known_parent = NULL;
5862 * This is the ADD case, find the appropriate parent,
5863 * as this object doesn't exist locally:
5865 if (ar->search_msg == NULL) {
5866 ret = replmd_replicated_apply_search_for_parent(ar);
5867 if (ret != LDB_SUCCESS) {
5868 return ldb_module_done(ar->req, NULL, NULL, ret);
5875 * Otherwise, in the MERGE case, work out if we are
5876 * attempting a rename, and if so find the parent the
5877 * newly renamed object wants to belong under (which
5878 * may not be the parent in it's attached string DN
5880 rmd = ar->objs->objects[ar->index_current].meta_data;
5884 /* find existing meta data */
5885 omd_value = ldb_msg_find_ldb_val(ar->search_msg, "replPropertyMetaData");
5887 enum ndr_err_code ndr_err;
5888 ndr_err = ndr_pull_struct_blob(omd_value, ar, &omd,
5889 (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
5890 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
5891 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
5892 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
5895 if (omd.version != 1) {
5896 return replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
5900 ar->local_parent_guid = samdb_result_guid(ar->search_msg, "parentGUID");
5902 instanceType = ldb_msg_find_attr_as_int(ar->search_msg, "instanceType", 0);
5903 if (((instanceType & INSTANCE_TYPE_IS_NC_HEAD) == 0)
5904 && GUID_all_zero(&ar->local_parent_guid)) {
5905 DEBUG(0, ("Refusing to replicate new version of %s "
5906 "as local object has an all-zero parentGUID attribute, "
5907 "despite not being an NC root\n",
5908 ldb_dn_get_linearized(ar->search_msg->dn)));
5909 return replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
5913 * now we need to check for double renames. We could have a
5914 * local rename pending which our replication partner hasn't
5915 * received yet. We choose which one wins by looking at the
5916 * attribute stamps on the two objects, the newer one wins.
5918 * This also simply applies the correct algorithms for
5919 * determining if a change was made to name at all, or
5920 * if the object has just been renamed under the same
5923 md_remote = replmd_replPropertyMetaData1_find_attid(rmd, DRSUAPI_ATTID_name);
5924 md_local = replmd_replPropertyMetaData1_find_attid(&omd, DRSUAPI_ATTID_name);
5926 DEBUG(0,(__location__ ": Failed to find name attribute in local LDB replPropertyMetaData for %s\n",
5927 ldb_dn_get_linearized(ar->search_msg->dn)));
5928 return replmd_replicated_request_werror(ar, WERR_DS_DRA_DB_ERROR);
5932 * if there is no name attribute given then we have to assume the
5933 * object we've received has the older name
5935 if (replmd_replPropertyMetaData1_new_should_be_taken(
5936 ar->objs->dsdb_repl_flags & DSDB_REPL_FLAG_PRIORITISE_INCOMING,
5937 md_local, md_remote)) {
5938 struct GUID_txt_buf p_guid_local;
5939 struct GUID_txt_buf p_guid_remote;
5940 msg = ar->objs->objects[ar->index_current].msg;
5942 /* Merge on the existing object, with rename */
5944 DEBUG(4,(__location__ ": Looking for new parent for object %s currently under %s "
5945 "as incoming object changing to %s under %s\n",
5946 ldb_dn_get_linearized(ar->search_msg->dn),
5947 GUID_buf_string(&ar->local_parent_guid, &p_guid_local),
5948 ldb_dn_get_linearized(msg->dn),
5949 GUID_buf_string(ar->objs->objects[ar->index_current].parent_guid,
5951 ret = replmd_replicated_apply_search_for_parent(ar);
5953 struct GUID_txt_buf p_guid_local;
5954 struct GUID_txt_buf p_guid_remote;
5955 msg = ar->objs->objects[ar->index_current].msg;
5958 * Merge on the existing object, force no
5959 * rename (code below just to explain why in
5963 if (strcmp(ldb_dn_get_linearized(ar->search_msg->dn),
5964 ldb_dn_get_linearized(msg->dn)) == 0) {
5965 if (ar->objs->objects[ar->index_current].parent_guid != NULL &&
5966 GUID_equal(&ar->local_parent_guid,
5967 ar->objs->objects[ar->index_current].parent_guid)
5969 DEBUG(4,(__location__ ": Keeping object %s at under %s "
5970 "despite incoming object changing parent to %s\n",
5971 ldb_dn_get_linearized(ar->search_msg->dn),
5972 GUID_buf_string(&ar->local_parent_guid, &p_guid_local),
5973 GUID_buf_string(ar->objs->objects[ar->index_current].parent_guid,
5977 DEBUG(4,(__location__ ": Keeping object %s at under %s "
5978 " and rejecting older rename to %s under %s\n",
5979 ldb_dn_get_linearized(ar->search_msg->dn),
5980 GUID_buf_string(&ar->local_parent_guid, &p_guid_local),
5981 ldb_dn_get_linearized(msg->dn),
5982 GUID_buf_string(ar->objs->objects[ar->index_current].parent_guid,
5986 * This assignment ensures that the strcmp()
5987 * and GUID_equal() calls in
5988 * replmd_replicated_apply_merge() avoids the
5991 ar->objs->objects[ar->index_current].parent_guid =
5992 &ar->local_parent_guid;
5994 msg->dn = ar->search_msg->dn;
5995 ret = replmd_replicated_apply_merge(ar);
5997 if (ret != LDB_SUCCESS) {
5998 return ldb_module_done(ar->req, NULL, NULL, ret);
6007 static int replmd_replicated_uptodate_vector(struct replmd_replicated_request *ar);
6009 static int replmd_replicated_apply_next(struct replmd_replicated_request *ar)
6011 struct ldb_context *ldb;
6015 struct ldb_request *search_req;
6016 static const char *attrs[] = { "repsFrom", "replUpToDateVector",
6017 "parentGUID", "instanceType",
6018 "replPropertyMetaData", "nTSecurityDescriptor",
6019 "isDeleted", NULL };
6020 struct GUID_txt_buf guid_str_buf;
6022 if (ar->index_current >= ar->objs->num_objects) {
6023 /* done with it, go to next stage */
6024 return replmd_replicated_uptodate_vector(ar);
6027 ldb = ldb_module_get_ctx(ar->module);
6028 ar->search_msg = NULL;
6029 ar->isDeleted = false;
6031 tmp_str = GUID_buf_string(&ar->objs->objects[ar->index_current].object_guid,
6034 filter = talloc_asprintf(ar, "(objectGUID=%s)", tmp_str);
6035 if (!filter) return replmd_replicated_request_werror(ar, WERR_NOT_ENOUGH_MEMORY);
6037 ret = ldb_build_search_req(&search_req,
6040 ar->objs->partition_dn,
6046 replmd_replicated_apply_search_callback,
6048 LDB_REQ_SET_LOCATION(search_req);
6050 ret = dsdb_request_add_controls(search_req, DSDB_SEARCH_SHOW_RECYCLED);
6052 if (ret != LDB_SUCCESS) {
6056 return ldb_next_request(ar->module, search_req);
6060 * This is essentially a wrapper for replmd_replicated_apply_next()
6062 * This is needed to ensure that both codepaths call this handler.
6064 static int replmd_replicated_apply_isDeleted(struct replmd_replicated_request *ar)
6066 struct ldb_dn *deleted_objects_dn;
6067 struct ldb_message *msg = ar->objs->objects[ar->index_current].msg;
6068 int ret = dsdb_get_deleted_objects_dn(ldb_module_get_ctx(ar->module), msg, msg->dn,
6069 &deleted_objects_dn);
6070 if (ar->isDeleted && (ret != LDB_SUCCESS || ldb_dn_compare(msg->dn, deleted_objects_dn) != 0)) {
6072 * Do a delete here again, so that if there is
6073 * anything local that conflicts with this
6074 * object being deleted, it is removed. This
6075 * includes links. See MS-DRSR 4.1.10.6.9
6078 * If the object is already deleted, and there
6079 * is no more work required, it doesn't do
6083 /* This has been updated to point to the DN we eventually did the modify on */
6085 struct ldb_request *del_req;
6086 struct ldb_result *res;
6088 TALLOC_CTX *tmp_ctx = talloc_new(ar);
6090 ret = ldb_oom(ldb_module_get_ctx(ar->module));
6094 res = talloc_zero(tmp_ctx, struct ldb_result);
6096 ret = ldb_oom(ldb_module_get_ctx(ar->module));
6097 talloc_free(tmp_ctx);
6101 /* Build a delete request, which hopefully will artually turn into nothing */
6102 ret = ldb_build_del_req(&del_req, ldb_module_get_ctx(ar->module), tmp_ctx,
6106 ldb_modify_default_callback,
6108 LDB_REQ_SET_LOCATION(del_req);
6109 if (ret != LDB_SUCCESS) {
6110 talloc_free(tmp_ctx);
6115 * This is the guts of the call, call back
6116 * into our delete code, but setting the
6117 * re_delete flag so we delete anything that
6118 * shouldn't be there on a deleted or recycled
6121 ret = replmd_delete_internals(ar->module, del_req, true);
6122 if (ret == LDB_SUCCESS) {
6123 ret = ldb_wait(del_req->handle, LDB_WAIT_ALL);
6126 talloc_free(tmp_ctx);
6127 if (ret != LDB_SUCCESS) {
6132 ar->index_current++;
6133 return replmd_replicated_apply_next(ar);
6136 static int replmd_replicated_uptodate_modify_callback(struct ldb_request *req,
6137 struct ldb_reply *ares)
6139 struct ldb_context *ldb;
6140 struct replmd_replicated_request *ar = talloc_get_type(req->context,
6141 struct replmd_replicated_request);
6142 ldb = ldb_module_get_ctx(ar->module);
6145 return ldb_module_done(ar->req, NULL, NULL,
6146 LDB_ERR_OPERATIONS_ERROR);
6148 if (ares->error != LDB_SUCCESS) {
6149 return ldb_module_done(ar->req, ares->controls,
6150 ares->response, ares->error);
6153 if (ares->type != LDB_REPLY_DONE) {
6154 ldb_asprintf_errstring(ldb, "Invalid LDB reply type %d", ares->type);
6155 return ldb_module_done(ar->req, NULL, NULL,
6156 LDB_ERR_OPERATIONS_ERROR);
6161 return ldb_module_done(ar->req, NULL, NULL, LDB_SUCCESS);
6164 static int replmd_replicated_uptodate_modify(struct replmd_replicated_request *ar)
6166 struct ldb_context *ldb;
6167 struct ldb_request *change_req;
6168 enum ndr_err_code ndr_err;
6169 struct ldb_message *msg;
6170 struct replUpToDateVectorBlob ouv;
6171 const struct ldb_val *ouv_value;
6172 const struct drsuapi_DsReplicaCursor2CtrEx *ruv;
6173 struct replUpToDateVectorBlob nuv;
6174 struct ldb_val nuv_value;
6175 struct ldb_message_element *nuv_el = NULL;
6176 struct ldb_message_element *orf_el = NULL;
6177 struct repsFromToBlob nrf;
6178 struct ldb_val *nrf_value = NULL;
6179 struct ldb_message_element *nrf_el = NULL;
6183 time_t t = time(NULL);
6186 uint32_t instanceType;
6188 ldb = ldb_module_get_ctx(ar->module);
6189 ruv = ar->objs->uptodateness_vector;
6195 unix_to_nt_time(&now, t);
6197 if (ar->search_msg == NULL) {
6198 /* this happens for a REPL_OBJ call where we are
6199 creating the target object by replicating it. The
6200 subdomain join code does this for the partition DN
6202 DEBUG(4,(__location__ ": Skipping UDV and repsFrom update as no target DN\n"));
6203 return ldb_module_done(ar->req, NULL, NULL, LDB_SUCCESS);
6206 instanceType = ldb_msg_find_attr_as_uint(ar->search_msg, "instanceType", 0);
6207 if (! (instanceType & INSTANCE_TYPE_IS_NC_HEAD)) {
6208 DEBUG(4,(__location__ ": Skipping UDV and repsFrom update as not NC root: %s\n",
6209 ldb_dn_get_linearized(ar->search_msg->dn)));
6210 return ldb_module_done(ar->req, NULL, NULL, LDB_SUCCESS);
6214 * first create the new replUpToDateVector
6216 ouv_value = ldb_msg_find_ldb_val(ar->search_msg, "replUpToDateVector");
6218 ndr_err = ndr_pull_struct_blob(ouv_value, ar, &ouv,
6219 (ndr_pull_flags_fn_t)ndr_pull_replUpToDateVectorBlob);
6220 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
6221 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
6222 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
6225 if (ouv.version != 2) {
6226 return replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
6231 * the new uptodateness vector will at least
6232 * contain 1 entry, one for the source_dsa
6234 * plus optional values from our old vector and the one from the source_dsa
6236 nuv.ctr.ctr2.count = ouv.ctr.ctr2.count;
6237 if (ruv) nuv.ctr.ctr2.count += ruv->count;
6238 nuv.ctr.ctr2.cursors = talloc_array(ar,
6239 struct drsuapi_DsReplicaCursor2,
6240 nuv.ctr.ctr2.count);
6241 if (!nuv.ctr.ctr2.cursors) return replmd_replicated_request_werror(ar, WERR_NOT_ENOUGH_MEMORY);
6243 /* first copy the old vector */
6244 for (i=0; i < ouv.ctr.ctr2.count; i++) {
6245 nuv.ctr.ctr2.cursors[ni] = ouv.ctr.ctr2.cursors[i];
6249 /* merge in the source_dsa vector is available */
6250 for (i=0; (ruv && i < ruv->count); i++) {
6253 if (GUID_equal(&ruv->cursors[i].source_dsa_invocation_id,
6254 &ar->our_invocation_id)) {
6258 for (j=0; j < ni; j++) {
6259 if (!GUID_equal(&ruv->cursors[i].source_dsa_invocation_id,
6260 &nuv.ctr.ctr2.cursors[j].source_dsa_invocation_id)) {
6266 if (ruv->cursors[i].highest_usn > nuv.ctr.ctr2.cursors[j].highest_usn) {
6267 nuv.ctr.ctr2.cursors[j] = ruv->cursors[i];
6272 if (found) continue;
6274 /* if it's not there yet, add it */
6275 nuv.ctr.ctr2.cursors[ni] = ruv->cursors[i];
6280 * finally correct the size of the cursors array
6282 nuv.ctr.ctr2.count = ni;
6287 TYPESAFE_QSORT(nuv.ctr.ctr2.cursors, nuv.ctr.ctr2.count, drsuapi_DsReplicaCursor2_compare);
6290 * create the change ldb_message
6292 msg = ldb_msg_new(ar);
6293 if (!msg) return replmd_replicated_request_werror(ar, WERR_NOT_ENOUGH_MEMORY);
6294 msg->dn = ar->search_msg->dn;
6296 ndr_err = ndr_push_struct_blob(&nuv_value, msg, &nuv,
6297 (ndr_push_flags_fn_t)ndr_push_replUpToDateVectorBlob);
6298 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
6299 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
6300 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
6302 ret = ldb_msg_add_value(msg, "replUpToDateVector", &nuv_value, &nuv_el);
6303 if (ret != LDB_SUCCESS) {
6304 return replmd_replicated_request_error(ar, ret);
6306 nuv_el->flags = LDB_FLAG_MOD_REPLACE;
6309 * now create the new repsFrom value from the given repsFromTo1 structure
6313 nrf.ctr.ctr1 = *ar->objs->source_dsa;
6314 nrf.ctr.ctr1.last_attempt = now;
6315 nrf.ctr.ctr1.last_success = now;
6316 nrf.ctr.ctr1.result_last_attempt = WERR_OK;
6319 * first see if we already have a repsFrom value for the current source dsa
6320 * if so we'll later replace this value
6322 orf_el = ldb_msg_find_element(ar->search_msg, "repsFrom");
6324 for (i=0; i < orf_el->num_values; i++) {
6325 struct repsFromToBlob *trf;
6327 trf = talloc(ar, struct repsFromToBlob);
6328 if (!trf) return replmd_replicated_request_werror(ar, WERR_NOT_ENOUGH_MEMORY);
6330 ndr_err = ndr_pull_struct_blob(&orf_el->values[i], trf, trf,
6331 (ndr_pull_flags_fn_t)ndr_pull_repsFromToBlob);
6332 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
6333 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
6334 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
6337 if (trf->version != 1) {
6338 return replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
6342 * we compare the source dsa objectGUID not the invocation_id
6343 * because we want only one repsFrom value per source dsa
6344 * and when the invocation_id of the source dsa has changed we don't need
6345 * the old repsFrom with the old invocation_id
6347 if (!GUID_equal(&trf->ctr.ctr1.source_dsa_obj_guid,
6348 &ar->objs->source_dsa->source_dsa_obj_guid)) {
6354 nrf_value = &orf_el->values[i];
6359 * copy over all old values to the new ldb_message
6361 ret = ldb_msg_add_empty(msg, "repsFrom", 0, &nrf_el);
6362 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
6367 * if we haven't found an old repsFrom value for the current source dsa
6368 * we'll add a new value
6371 struct ldb_val zero_value;
6372 ZERO_STRUCT(zero_value);
6373 ret = ldb_msg_add_value(msg, "repsFrom", &zero_value, &nrf_el);
6374 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
6376 nrf_value = &nrf_el->values[nrf_el->num_values - 1];
6379 /* we now fill the value which is already attached to ldb_message */
6380 ndr_err = ndr_push_struct_blob(nrf_value, msg,
6382 (ndr_push_flags_fn_t)ndr_push_repsFromToBlob);
6383 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
6384 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
6385 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
6389 * the ldb_message_element for the attribute, has all the old values and the new one
6390 * so we'll replace the whole attribute with all values
6392 nrf_el->flags = LDB_FLAG_MOD_REPLACE;
6394 if (CHECK_DEBUGLVL(4)) {
6395 char *s = ldb_ldif_message_string(ldb, ar, LDB_CHANGETYPE_MODIFY, msg);
6396 DEBUG(4, ("DRS replication uptodate modify message:\n%s\n", s));
6400 /* prepare the ldb_modify() request */
6401 ret = ldb_build_mod_req(&change_req,
6407 replmd_replicated_uptodate_modify_callback,
6409 LDB_REQ_SET_LOCATION(change_req);
6410 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
6412 return ldb_next_request(ar->module, change_req);
6415 static int replmd_replicated_uptodate_search_callback(struct ldb_request *req,
6416 struct ldb_reply *ares)
6418 struct replmd_replicated_request *ar = talloc_get_type(req->context,
6419 struct replmd_replicated_request);
6423 return ldb_module_done(ar->req, NULL, NULL,
6424 LDB_ERR_OPERATIONS_ERROR);
6426 if (ares->error != LDB_SUCCESS &&
6427 ares->error != LDB_ERR_NO_SUCH_OBJECT) {
6428 return ldb_module_done(ar->req, ares->controls,
6429 ares->response, ares->error);
6432 switch (ares->type) {
6433 case LDB_REPLY_ENTRY:
6434 ar->search_msg = talloc_steal(ar, ares->message);
6437 case LDB_REPLY_REFERRAL:
6438 /* we ignore referrals */
6441 case LDB_REPLY_DONE:
6442 ret = replmd_replicated_uptodate_modify(ar);
6443 if (ret != LDB_SUCCESS) {
6444 return ldb_module_done(ar->req, NULL, NULL, ret);
6453 static int replmd_replicated_uptodate_vector(struct replmd_replicated_request *ar)
6455 struct ldb_context *ldb = ldb_module_get_ctx(ar->module);
6456 struct replmd_private *replmd_private =
6457 talloc_get_type_abort(ldb_module_get_private(ar->module),
6458 struct replmd_private);
6460 static const char *attrs[] = {
6461 "replUpToDateVector",
6466 struct ldb_request *search_req;
6468 ar->search_msg = NULL;
6471 * Let the caller know that we did an originating updates
6473 ar->objs->originating_updates = replmd_private->originating_updates;
6475 ret = ldb_build_search_req(&search_req,
6478 ar->objs->partition_dn,
6484 replmd_replicated_uptodate_search_callback,
6486 LDB_REQ_SET_LOCATION(search_req);
6487 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
6489 return ldb_next_request(ar->module, search_req);
6494 static int replmd_extended_replicated_objects(struct ldb_module *module, struct ldb_request *req)
6496 struct ldb_context *ldb;
6497 struct dsdb_extended_replicated_objects *objs;
6498 struct replmd_replicated_request *ar;
6499 struct ldb_control **ctrls;
6502 struct replmd_private *replmd_private =
6503 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
6505 ldb = ldb_module_get_ctx(module);
6507 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_extended_replicated_objects\n");
6509 objs = talloc_get_type(req->op.extended.data, struct dsdb_extended_replicated_objects);
6511 ldb_debug(ldb, LDB_DEBUG_FATAL, "replmd_extended_replicated_objects: invalid extended data\n");
6512 return LDB_ERR_PROTOCOL_ERROR;
6515 if (objs->version != DSDB_EXTENDED_REPLICATED_OBJECTS_VERSION) {
6516 ldb_debug(ldb, LDB_DEBUG_FATAL, "replmd_extended_replicated_objects: extended data invalid version [%u != %u]\n",
6517 objs->version, DSDB_EXTENDED_REPLICATED_OBJECTS_VERSION);
6518 return LDB_ERR_PROTOCOL_ERROR;
6521 ar = replmd_ctx_init(module, req);
6523 return LDB_ERR_OPERATIONS_ERROR;
6525 /* Set the flags to have the replmd_op_callback run over the full set of objects */
6526 ar->apply_mode = true;
6528 ar->schema = dsdb_get_schema(ldb, ar);
6530 ldb_debug_set(ldb, LDB_DEBUG_FATAL, "replmd_ctx_init: no loaded schema found\n");
6532 DEBUG(0,(__location__ ": %s\n", ldb_errstring(ldb)));
6533 return LDB_ERR_CONSTRAINT_VIOLATION;
6536 ctrls = req->controls;
6538 if (req->controls) {
6539 req->controls = talloc_memdup(ar, req->controls,
6540 talloc_get_size(req->controls));
6541 if (!req->controls) return replmd_replicated_request_werror(ar, WERR_NOT_ENOUGH_MEMORY);
6544 ret = ldb_request_add_control(req, DSDB_CONTROL_REPLICATED_UPDATE_OID, false, NULL);
6545 if (ret != LDB_SUCCESS) {
6549 /* If this change contained linked attributes in the body
6550 * (rather than in the links section) we need to update
6551 * backlinks in linked_attributes */
6552 ret = ldb_request_add_control(req, DSDB_CONTROL_APPLY_LINKS, false, NULL);
6553 if (ret != LDB_SUCCESS) {
6557 ar->controls = req->controls;
6558 req->controls = ctrls;
6560 DEBUG(4,("linked_attributes_count=%u\n", objs->linked_attributes_count));
6562 /* save away the linked attributes for the end of the
6564 for (i=0; i<ar->objs->linked_attributes_count; i++) {
6565 struct la_entry *la_entry;
6567 if (replmd_private->la_ctx == NULL) {
6568 replmd_private->la_ctx = talloc_new(replmd_private);
6570 la_entry = talloc(replmd_private->la_ctx, struct la_entry);
6571 if (la_entry == NULL) {
6573 return LDB_ERR_OPERATIONS_ERROR;
6575 la_entry->la = talloc(la_entry, struct drsuapi_DsReplicaLinkedAttribute);
6576 if (la_entry->la == NULL) {
6577 talloc_free(la_entry);
6579 return LDB_ERR_OPERATIONS_ERROR;
6581 *la_entry->la = ar->objs->linked_attributes[i];
6583 /* we need to steal the non-scalars so they stay
6584 around until the end of the transaction */
6585 talloc_steal(la_entry->la, la_entry->la->identifier);
6586 talloc_steal(la_entry->la, la_entry->la->value.blob);
6588 DLIST_ADD(replmd_private->la_list, la_entry);
6591 return replmd_replicated_apply_next(ar);
6595 process one linked attribute structure
6597 static int replmd_process_linked_attribute(struct ldb_module *module,
6598 struct replmd_private *replmd_private,
6599 struct la_entry *la_entry,
6600 struct ldb_request *parent)
6602 struct drsuapi_DsReplicaLinkedAttribute *la = la_entry->la;
6603 struct ldb_context *ldb = ldb_module_get_ctx(module);
6604 struct ldb_message *msg;
6605 struct ldb_message *target_msg = NULL;
6606 TALLOC_CTX *tmp_ctx = talloc_new(la_entry);
6607 const struct dsdb_schema *schema = dsdb_get_schema(ldb, tmp_ctx);
6609 const struct dsdb_attribute *attr;
6610 struct dsdb_dn *dsdb_dn;
6611 uint64_t seq_num = 0;
6612 struct ldb_message_element *old_el;
6614 time_t t = time(NULL);
6615 struct ldb_result *res;
6616 struct ldb_result *target_res;
6617 const char *attrs[4];
6618 const char *attrs2[] = { "isDeleted", "isRecycled", NULL };
6619 struct parsed_dn *pdn_list, *pdn, *next;
6620 struct GUID guid = GUID_zero();
6622 bool active = (la->flags & DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE)?true:false;
6624 enum deletion_state deletion_state = OBJECT_NOT_DELETED;
6625 enum deletion_state target_deletion_state = OBJECT_NOT_DELETED;
6628 linked_attributes[0]:
6629 &objs->linked_attributes[i]: struct drsuapi_DsReplicaLinkedAttribute
6631 identifier: struct drsuapi_DsReplicaObjectIdentifier
6632 __ndr_size : 0x0000003a (58)
6633 __ndr_size_sid : 0x00000000 (0)
6634 guid : 8e95b6a9-13dd-4158-89db-3220a5be5cc7
6636 __ndr_size_dn : 0x00000000 (0)
6638 attid : DRSUAPI_ATTID_member (0x1F)
6639 value: struct drsuapi_DsAttributeValue
6640 __ndr_size : 0x0000007e (126)
6642 blob : DATA_BLOB length=126
6643 flags : 0x00000001 (1)
6644 1: DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE
6645 originating_add_time : Wed Sep 2 22:20:01 2009 EST
6646 meta_data: struct drsuapi_DsReplicaMetaData
6647 version : 0x00000015 (21)
6648 originating_change_time : Wed Sep 2 23:39:07 2009 EST
6649 originating_invocation_id: 794640f3-18cf-40ee-a211-a93992b67a64
6650 originating_usn : 0x000000000001e19c (123292)
6652 (for cases where the link is to a normal DN)
6653 &target: struct drsuapi_DsReplicaObjectIdentifier3
6654 __ndr_size : 0x0000007e (126)
6655 __ndr_size_sid : 0x0000001c (28)
6656 guid : 7639e594-db75-4086-b0d4-67890ae46031
6657 sid : S-1-5-21-2848215498-2472035911-1947525656-19924
6658 __ndr_size_dn : 0x00000022 (34)
6659 dn : 'CN=UOne,OU=TestOU,DC=vsofs8,DC=com'
6662 /* find the attribute being modified */
6663 attr = dsdb_attribute_by_attributeID_id(schema, la->attid);
6665 struct GUID_txt_buf guid_str;
6666 ldb_asprintf_errstring(ldb, "Unable to find attributeID 0x%x for link on <GUID=%s>",
6668 GUID_buf_string(&la->identifier->guid,
6670 talloc_free(tmp_ctx);
6671 return LDB_ERR_OPERATIONS_ERROR;
6674 attrs[0] = attr->lDAPDisplayName;
6675 attrs[1] = "isDeleted";
6676 attrs[2] = "isRecycled";
6679 /* get the existing message from the db for the object with
6680 this GUID, returning attribute being modified. We will then
6681 use this msg as the basis for a modify call */
6682 ret = dsdb_module_search(module, tmp_ctx, &res, NULL, LDB_SCOPE_SUBTREE, attrs,
6683 DSDB_FLAG_NEXT_MODULE |
6684 DSDB_SEARCH_SEARCH_ALL_PARTITIONS |
6685 DSDB_SEARCH_SHOW_RECYCLED |
6686 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT |
6687 DSDB_SEARCH_REVEAL_INTERNALS,
6689 "objectGUID=%s", GUID_string(tmp_ctx, &la->identifier->guid));
6690 if (ret != LDB_SUCCESS) {
6691 talloc_free(tmp_ctx);
6694 if (res->count != 1) {
6695 ldb_asprintf_errstring(ldb, "DRS linked attribute for GUID %s - DN not found",
6696 GUID_string(tmp_ctx, &la->identifier->guid));
6697 talloc_free(tmp_ctx);
6698 return LDB_ERR_NO_SUCH_OBJECT;
6703 * Check for deleted objects per MS-DRSR 4.1.10.6.13
6704 * ProcessLinkValue, because link updates are not applied to
6705 * recycled and tombstone objects. We don't have to delete
6706 * any existing link, that should have happened when the
6707 * object deletion was replicated or initiated.
6710 replmd_deletion_state(module, msg, &deletion_state, NULL);
6712 if (deletion_state >= OBJECT_RECYCLED) {
6713 talloc_free(tmp_ctx);
6717 old_el = ldb_msg_find_element(msg, attr->lDAPDisplayName);
6718 if (old_el == NULL) {
6719 ret = ldb_msg_add_empty(msg, attr->lDAPDisplayName, LDB_FLAG_MOD_REPLACE, &old_el);
6720 if (ret != LDB_SUCCESS) {
6721 ldb_module_oom(module);
6722 talloc_free(tmp_ctx);
6723 return LDB_ERR_OPERATIONS_ERROR;
6726 old_el->flags = LDB_FLAG_MOD_REPLACE;
6729 /* parse the existing links */
6730 ret = get_parsed_dns_trusted(module, replmd_private, tmp_ctx, old_el, &pdn_list,
6731 attr->syntax->ldap_oid, parent);
6733 if (ret != LDB_SUCCESS) {
6734 talloc_free(tmp_ctx);
6738 status = dsdb_dn_la_from_blob(ldb, attr, schema, tmp_ctx, la->value.blob, &dsdb_dn);
6739 if (!W_ERROR_IS_OK(status)) {
6740 ldb_asprintf_errstring(ldb, "Failed to parsed linked attribute blob for %s on %s - %s\n",
6741 old_el->name, ldb_dn_get_linearized(msg->dn), win_errstr(status));
6742 talloc_free(tmp_ctx);
6743 return LDB_ERR_OPERATIONS_ERROR;
6746 ntstatus = dsdb_get_extended_dn_guid(dsdb_dn->dn, &guid, "GUID");
6747 if (!NT_STATUS_IS_OK(ntstatus) && !active) {
6749 * This strange behaviour (allowing a NULL/missing
6750 * GUID) originally comes from:
6752 * commit e3054ce0fe0f8f62d2f5b2a77893e7a1479128bd
6753 * Author: Andrew Tridgell <tridge@samba.org>
6754 * Date: Mon Dec 21 21:21:55 2009 +1100
6756 * s4-drs: cope better with NULL GUIDS from DRS
6758 * It is valid to get a NULL GUID over DRS for a deleted forward link. We
6759 * need to match by DN if possible when seeing if we should update an
6762 * Pair-Programmed-With: Andrew Bartlett <abartlet@samba.org>
6765 ret = dsdb_module_search_dn(module, tmp_ctx, &target_res,
6766 dsdb_dn->dn, attrs2,
6767 DSDB_FLAG_NEXT_MODULE |
6768 DSDB_SEARCH_SHOW_RECYCLED |
6769 DSDB_SEARCH_SEARCH_ALL_PARTITIONS |
6770 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT,
6772 } else if (!NT_STATUS_IS_OK(ntstatus)) {
6773 ldb_asprintf_errstring(ldb, "Failed to find GUID in linked attribute blob for %s on %s from %s",
6775 ldb_dn_get_linearized(dsdb_dn->dn),
6776 ldb_dn_get_linearized(msg->dn));
6777 talloc_free(tmp_ctx);
6778 return LDB_ERR_OPERATIONS_ERROR;
6780 ret = dsdb_module_search(module, tmp_ctx, &target_res,
6781 NULL, LDB_SCOPE_SUBTREE,
6783 DSDB_FLAG_NEXT_MODULE |
6784 DSDB_SEARCH_SHOW_RECYCLED |
6785 DSDB_SEARCH_SEARCH_ALL_PARTITIONS |
6786 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT,
6789 GUID_string(tmp_ctx, &guid));
6792 if (ret != LDB_SUCCESS) {
6793 ldb_asprintf_errstring(ldb_module_get_ctx(module), "Failed to re-resolve GUID %s: %s\n",
6794 GUID_string(tmp_ctx, &guid),
6795 ldb_errstring(ldb_module_get_ctx(module)));
6796 talloc_free(tmp_ctx);
6800 if (target_res->count == 0) {
6801 DEBUG(2,(__location__ ": WARNING: Failed to re-resolve GUID %s - using %s\n",
6802 GUID_string(tmp_ctx, &guid),
6803 ldb_dn_get_linearized(dsdb_dn->dn)));
6804 } else if (target_res->count != 1) {
6805 ldb_asprintf_errstring(ldb_module_get_ctx(module), "More than one object found matching objectGUID %s\n",
6806 GUID_string(tmp_ctx, &guid));
6807 talloc_free(tmp_ctx);
6808 return LDB_ERR_OPERATIONS_ERROR;
6810 target_msg = target_res->msgs[0];
6811 dsdb_dn->dn = talloc_steal(dsdb_dn, target_msg->dn);
6815 * Check for deleted objects per MS-DRSR 4.1.10.6.13
6816 * ProcessLinkValue, because link updates are not applied to
6817 * recycled and tombstone objects. We don't have to delete
6818 * any existing link, that should have happened when the
6819 * object deletion was replicated or initiated.
6821 replmd_deletion_state(module, target_msg,
6822 &target_deletion_state, NULL);
6824 if (target_deletion_state >= OBJECT_RECYCLED) {
6825 talloc_free(tmp_ctx);
6829 /* see if this link already exists */
6830 ret = parsed_dn_find(ldb, pdn_list, old_el->num_values,
6833 dsdb_dn->extra_part, 0,
6835 attr->syntax->ldap_oid,
6837 if (ret != LDB_SUCCESS) {
6838 talloc_free(tmp_ctx);
6844 /* see if this update is newer than what we have already */
6845 struct GUID invocation_id = GUID_zero();
6846 uint32_t version = 0;
6847 uint32_t originating_usn = 0;
6848 NTTIME change_time = 0;
6849 uint32_t rmd_flags = dsdb_dn_rmd_flags(pdn->dsdb_dn->dn);
6851 dsdb_get_extended_dn_guid(pdn->dsdb_dn->dn, &invocation_id, "RMD_INVOCID");
6852 dsdb_get_extended_dn_uint32(pdn->dsdb_dn->dn, &version, "RMD_VERSION");
6853 dsdb_get_extended_dn_uint32(pdn->dsdb_dn->dn, &originating_usn, "RMD_ORIGINATING_USN");
6854 dsdb_get_extended_dn_nttime(pdn->dsdb_dn->dn, &change_time, "RMD_CHANGETIME");
6856 if (!replmd_update_is_newer(&invocation_id,
6857 &la->meta_data.originating_invocation_id,
6859 la->meta_data.version,
6861 la->meta_data.originating_change_time)) {
6862 DEBUG(3,("Discarding older DRS linked attribute update to %s on %s from %s\n",
6863 old_el->name, ldb_dn_get_linearized(msg->dn),
6864 GUID_string(tmp_ctx, &la->meta_data.originating_invocation_id)));
6865 talloc_free(tmp_ctx);
6869 /* get a seq_num for this change */
6870 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &seq_num);
6871 if (ret != LDB_SUCCESS) {
6872 talloc_free(tmp_ctx);
6876 if (!(rmd_flags & DSDB_RMD_FLAG_DELETED)) {
6877 /* remove the existing backlink */
6878 ret = replmd_add_backlink(module, replmd_private,
6883 if (ret != LDB_SUCCESS) {
6884 talloc_free(tmp_ctx);
6889 ret = replmd_update_la_val(tmp_ctx, pdn->v, dsdb_dn, pdn->dsdb_dn,
6890 &la->meta_data.originating_invocation_id,
6891 la->meta_data.originating_usn, seq_num,
6892 la->meta_data.originating_change_time,
6893 la->meta_data.version,
6895 if (ret != LDB_SUCCESS) {
6896 talloc_free(tmp_ctx);
6901 /* add the new backlink */
6902 ret = replmd_add_backlink(module, replmd_private,
6907 if (ret != LDB_SUCCESS) {
6908 talloc_free(tmp_ctx);
6914 /* get a seq_num for this change */
6915 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &seq_num);
6916 if (ret != LDB_SUCCESS) {
6917 talloc_free(tmp_ctx);
6921 * We know where the new one needs to be, from the *next
6922 * pointer into pdn_list.
6925 offset = old_el->num_values;
6927 if (next->dsdb_dn == NULL) {
6928 ret = really_parse_trusted_dn(tmp_ctx, ldb, next,
6929 attr->syntax->ldap_oid);
6930 if (ret != LDB_SUCCESS) {
6934 offset = next - pdn_list;
6935 if (offset > old_el->num_values) {
6936 talloc_free(tmp_ctx);
6937 return LDB_ERR_OPERATIONS_ERROR;
6941 old_el->values = talloc_realloc(msg->elements, old_el->values,
6942 struct ldb_val, old_el->num_values+1);
6943 if (!old_el->values) {
6944 ldb_module_oom(module);
6945 return LDB_ERR_OPERATIONS_ERROR;
6948 if (offset != old_el->num_values) {
6949 memmove(&old_el->values[offset + 1], &old_el->values[offset],
6950 (old_el->num_values - offset) * sizeof(old_el->values[0]));
6953 old_el->num_values++;
6955 ret = replmd_build_la_val(tmp_ctx, &old_el->values[offset], dsdb_dn,
6956 &la->meta_data.originating_invocation_id,
6957 la->meta_data.originating_usn, seq_num,
6958 la->meta_data.originating_change_time,
6959 la->meta_data.version,
6961 if (ret != LDB_SUCCESS) {
6962 talloc_free(tmp_ctx);
6967 ret = replmd_add_backlink(module, replmd_private,
6972 if (ret != LDB_SUCCESS) {
6973 talloc_free(tmp_ctx);
6979 /* we only change whenChanged and uSNChanged if the seq_num
6981 ret = add_time_element(msg, "whenChanged", t);
6982 if (ret != LDB_SUCCESS) {
6983 talloc_free(tmp_ctx);
6988 ret = add_uint64_element(ldb, msg, "uSNChanged", seq_num);
6989 if (ret != LDB_SUCCESS) {
6990 talloc_free(tmp_ctx);
6995 old_el = ldb_msg_find_element(msg, attr->lDAPDisplayName);
6996 if (old_el == NULL) {
6997 talloc_free(tmp_ctx);
6998 return ldb_operr(ldb);
7001 ret = dsdb_check_single_valued_link(attr, old_el);
7002 if (ret != LDB_SUCCESS) {
7003 talloc_free(tmp_ctx);
7007 old_el->flags |= LDB_FLAG_INTERNAL_DISABLE_SINGLE_VALUE_CHECK;
7009 ret = linked_attr_modify(module, msg, parent);
7010 if (ret != LDB_SUCCESS) {
7011 ldb_debug(ldb, LDB_DEBUG_WARNING, "Failed to apply linked attribute change '%s'\n%s\n",
7013 ldb_ldif_message_string(ldb, tmp_ctx, LDB_CHANGETYPE_MODIFY, msg));
7014 talloc_free(tmp_ctx);
7018 talloc_free(tmp_ctx);
7023 static int replmd_extended(struct ldb_module *module, struct ldb_request *req)
7025 if (strcmp(req->op.extended.oid, DSDB_EXTENDED_REPLICATED_OBJECTS_OID) == 0) {
7026 return replmd_extended_replicated_objects(module, req);
7029 return ldb_next_request(module, req);
7034 we hook into the transaction operations to allow us to
7035 perform the linked attribute updates at the end of the whole
7036 transaction. This allows a forward linked attribute to be created
7037 before the object is created. During a vampire, w2k8 sends us linked
7038 attributes before the objects they are part of.
7040 static int replmd_start_transaction(struct ldb_module *module)
7042 /* create our private structure for this transaction */
7043 struct replmd_private *replmd_private = talloc_get_type(ldb_module_get_private(module),
7044 struct replmd_private);
7045 replmd_txn_cleanup(replmd_private);
7047 /* free any leftover mod_usn records from cancelled
7049 while (replmd_private->ncs) {
7050 struct nc_entry *e = replmd_private->ncs;
7051 DLIST_REMOVE(replmd_private->ncs, e);
7055 replmd_private->originating_updates = false;
7057 return ldb_next_start_trans(module);
7061 on prepare commit we loop over our queued la_context structures and
7064 static int replmd_prepare_commit(struct ldb_module *module)
7066 struct replmd_private *replmd_private =
7067 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
7068 struct la_entry *la, *prev;
7072 * Walk the list of linked attributes from DRS replication.
7074 * We walk backwards, to do the first entry first, as we
7075 * added the entries with DLIST_ADD() which puts them at the
7078 for (la = DLIST_TAIL(replmd_private->la_list); la; la=prev) {
7079 prev = DLIST_PREV(la);
7080 DLIST_REMOVE(replmd_private->la_list, la);
7081 ret = replmd_process_linked_attribute(module, replmd_private,
7083 if (ret != LDB_SUCCESS) {
7084 replmd_txn_cleanup(replmd_private);
7089 replmd_txn_cleanup(replmd_private);
7091 /* possibly change @REPLCHANGED */
7092 ret = replmd_notify_store(module, NULL);
7093 if (ret != LDB_SUCCESS) {
7097 return ldb_next_prepare_commit(module);
7100 static int replmd_del_transaction(struct ldb_module *module)
7102 struct replmd_private *replmd_private =
7103 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
7104 replmd_txn_cleanup(replmd_private);
7106 return ldb_next_del_trans(module);
7110 static const struct ldb_module_ops ldb_repl_meta_data_module_ops = {
7111 .name = "repl_meta_data",
7112 .init_context = replmd_init,
7114 .modify = replmd_modify,
7115 .rename = replmd_rename,
7116 .del = replmd_delete,
7117 .extended = replmd_extended,
7118 .start_transaction = replmd_start_transaction,
7119 .prepare_commit = replmd_prepare_commit,
7120 .del_transaction = replmd_del_transaction,
7123 int ldb_repl_meta_data_module_init(const char *version)
7125 LDB_MODULE_CHECK_VERSION(version);
7126 return ldb_register_module(&ldb_repl_meta_data_module_ops);