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) {
4523 * We have to mark this as a replicated update otherwise
4524 * schema_data may reject a rename in the schema partition
4527 ret = dsdb_module_modify(ar->module, msg,
4528 DSDB_FLAG_OWN_MODULE|DSDB_FLAG_REPLICATED_UPDATE,
4530 if (ret != LDB_SUCCESS) {
4531 DEBUG(0,(__location__ ": Failed to modify rDN/name of DN being DRS renamed '%s' - %s",
4532 ldb_dn_get_linearized(dn),
4533 ldb_errstring(ldb_module_get_ctx(ar->module))));
4543 DEBUG(0,(__location__ ": Failed to setup modify rDN/name of DN being DRS renamed '%s'",
4544 ldb_dn_get_linearized(dn)));
4545 return LDB_ERR_OPERATIONS_ERROR;
4550 callback for conflict DN handling where we have renamed the incoming
4551 record. After renaming it, we need to ensure the change of name and
4552 rDN for the incoming record is seen as an originating update by this DC.
4554 This also handles updating lastKnownParent for entries sent to lostAndFound
4556 static int replmd_op_name_modify_callback(struct ldb_request *req, struct ldb_reply *ares)
4558 struct replmd_replicated_request *ar =
4559 talloc_get_type_abort(req->context, struct replmd_replicated_request);
4560 struct ldb_dn *conflict_dn = NULL;
4563 if (ares->error != LDB_SUCCESS) {
4564 /* call the normal callback for everything except success */
4565 return replmd_op_callback(req, ares);
4568 switch (req->operation) {
4570 conflict_dn = req->op.add.message->dn;
4573 conflict_dn = req->op.mod.message->dn;
4576 smb_panic("replmd_op_name_modify_callback called in unknown circumstances");
4579 /* perform a modify of the rDN and name of the record */
4580 ret = replmd_name_modify(ar, req, conflict_dn);
4581 if (ret != LDB_SUCCESS) {
4583 return replmd_op_callback(req, ares);
4586 if (ar->objs->objects[ar->index_current].last_known_parent) {
4587 struct ldb_message *msg = ldb_msg_new(req);
4589 ldb_module_oom(ar->module);
4590 return LDB_ERR_OPERATIONS_ERROR;
4593 msg->dn = req->op.add.message->dn;
4595 ret = ldb_msg_add_steal_string(msg, "lastKnownParent",
4596 ldb_dn_get_extended_linearized(msg, ar->objs->objects[ar->index_current].last_known_parent, 1));
4597 if (ret != LDB_SUCCESS) {
4598 DEBUG(0,(__location__ ": Failed to add lastKnownParent string to the msg\n"));
4599 ldb_module_oom(ar->module);
4602 msg->elements[0].flags = LDB_FLAG_MOD_REPLACE;
4604 ret = dsdb_module_modify(ar->module, msg, DSDB_FLAG_OWN_MODULE, req);
4605 if (ret != LDB_SUCCESS) {
4606 DEBUG(0,(__location__ ": Failed to modify lastKnownParent of lostAndFound DN '%s' - %s",
4607 ldb_dn_get_linearized(msg->dn),
4608 ldb_errstring(ldb_module_get_ctx(ar->module))));
4614 return replmd_op_callback(req, ares);
4618 callback for replmd_replicated_apply_add()
4619 This copes with the creation of conflict records in the case where
4620 the DN exists, but with a different objectGUID
4622 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))
4624 struct ldb_dn *conflict_dn;
4625 struct replmd_replicated_request *ar =
4626 talloc_get_type_abort(req->context, struct replmd_replicated_request);
4627 struct ldb_result *res;
4628 const char *attrs[] = { "replPropertyMetaData", "objectGUID", NULL };
4630 const struct ldb_val *omd_value;
4631 struct replPropertyMetaDataBlob omd, *rmd;
4632 enum ndr_err_code ndr_err;
4633 bool rename_incoming_record, rodc;
4634 struct replPropertyMetaData1 *rmd_name, *omd_name;
4635 struct ldb_message *msg;
4636 struct ldb_request *down_req = NULL;
4638 /* call the normal callback for success */
4639 if (ares->error == LDB_SUCCESS) {
4640 return callback(req, ares);
4644 * we have a conflict, and need to decide if we will keep the
4645 * new record or the old record
4648 msg = ar->objs->objects[ar->index_current].msg;
4649 conflict_dn = msg->dn;
4651 /* For failures other than conflicts, fail the whole operation here */
4652 if (ares->error != LDB_ERR_ENTRY_ALREADY_EXISTS) {
4653 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module), "Failed to locally apply remote add of %s: %s",
4654 ldb_dn_get_linearized(conflict_dn),
4655 ldb_errstring(ldb_module_get_ctx(ar->module)));
4657 return ldb_module_done(ar->req, NULL, NULL,
4658 LDB_ERR_OPERATIONS_ERROR);
4661 ret = samdb_rodc(ldb_module_get_ctx(ar->module), &rodc);
4662 if (ret != LDB_SUCCESS) {
4663 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)));
4664 return ldb_module_done(ar->req, NULL, NULL,
4665 LDB_ERR_OPERATIONS_ERROR);
4671 * We are on an RODC, or were a GC for this
4672 * partition, so we have to fail this until
4673 * someone who owns the partition sorts it
4676 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
4677 "Conflict adding object '%s' from incoming replication as we are read only for the partition. \n"
4678 " - We must fail the operation until a master for this partition resolves the conflict",
4679 ldb_dn_get_linearized(conflict_dn));
4684 * first we need the replPropertyMetaData attribute from the
4685 * local, conflicting record
4687 ret = dsdb_module_search_dn(ar->module, req, &res, conflict_dn,
4689 DSDB_FLAG_NEXT_MODULE |
4690 DSDB_SEARCH_SHOW_DELETED |
4691 DSDB_SEARCH_SHOW_RECYCLED, req);
4692 if (ret != LDB_SUCCESS) {
4693 DEBUG(0,(__location__ ": Unable to find object for conflicting record '%s'\n",
4694 ldb_dn_get_linearized(conflict_dn)));
4698 omd_value = ldb_msg_find_ldb_val(res->msgs[0], "replPropertyMetaData");
4699 if (omd_value == NULL) {
4700 DEBUG(0,(__location__ ": Unable to find replPropertyMetaData for conflicting record '%s'\n",
4701 ldb_dn_get_linearized(conflict_dn)));
4705 ndr_err = ndr_pull_struct_blob(omd_value, res->msgs[0], &omd,
4706 (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
4707 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
4708 DEBUG(0,(__location__ ": Failed to parse old replPropertyMetaData for %s\n",
4709 ldb_dn_get_linearized(conflict_dn)));
4713 rmd = ar->objs->objects[ar->index_current].meta_data;
4716 * we decide which is newer based on the RPMD on the name
4717 * attribute. See [MS-DRSR] ResolveNameConflict.
4719 * We expect omd_name to be present, as this is from a local
4720 * search, but while rmd_name should have been given to us by
4721 * the remote server, if it is missing we just prefer the
4723 * replmd_replPropertyMetaData1_new_should_be_taken()
4725 rmd_name = replmd_replPropertyMetaData1_find_attid(rmd, DRSUAPI_ATTID_name);
4726 omd_name = replmd_replPropertyMetaData1_find_attid(&omd, DRSUAPI_ATTID_name);
4728 DEBUG(0,(__location__ ": Failed to find name attribute in local LDB replPropertyMetaData for %s\n",
4729 ldb_dn_get_linearized(conflict_dn)));
4734 * Should we preserve the current record, and so rename the
4735 * incoming record to be a conflict?
4737 rename_incoming_record
4738 = !replmd_replPropertyMetaData1_new_should_be_taken(ar->objs->dsdb_repl_flags & DSDB_REPL_FLAG_PRIORITISE_INCOMING,
4739 omd_name, rmd_name);
4741 if (rename_incoming_record) {
4743 struct ldb_dn *new_dn;
4745 guid = samdb_result_guid(msg, "objectGUID");
4746 if (GUID_all_zero(&guid)) {
4747 DEBUG(0,(__location__ ": Failed to find objectGUID for conflicting incoming record %s\n",
4748 ldb_dn_get_linearized(conflict_dn)));
4751 new_dn = replmd_conflict_dn(req, conflict_dn, &guid);
4752 if (new_dn == NULL) {
4753 DEBUG(0,(__location__ ": Failed to form conflict DN for %s\n",
4754 ldb_dn_get_linearized(conflict_dn)));
4758 DEBUG(2,(__location__ ": Resolving conflict record via incoming rename '%s' -> '%s'\n",
4759 ldb_dn_get_linearized(conflict_dn), ldb_dn_get_linearized(new_dn)));
4761 /* re-submit the request, but with the new DN */
4762 callback = replmd_op_name_modify_callback;
4765 /* we are renaming the existing record */
4767 struct ldb_dn *new_dn;
4769 guid = samdb_result_guid(res->msgs[0], "objectGUID");
4770 if (GUID_all_zero(&guid)) {
4771 DEBUG(0,(__location__ ": Failed to find objectGUID for existing conflict record %s\n",
4772 ldb_dn_get_linearized(conflict_dn)));
4776 new_dn = replmd_conflict_dn(req, conflict_dn, &guid);
4777 if (new_dn == NULL) {
4778 DEBUG(0,(__location__ ": Failed to form conflict DN for %s\n",
4779 ldb_dn_get_linearized(conflict_dn)));
4783 DEBUG(2,(__location__ ": Resolving conflict record via existing-record rename '%s' -> '%s'\n",
4784 ldb_dn_get_linearized(conflict_dn), ldb_dn_get_linearized(new_dn)));
4786 ret = dsdb_module_rename(ar->module, conflict_dn, new_dn,
4787 DSDB_FLAG_OWN_MODULE, req);
4788 if (ret != LDB_SUCCESS) {
4789 DEBUG(0,(__location__ ": Failed to rename conflict dn '%s' to '%s' - %s\n",
4790 ldb_dn_get_linearized(conflict_dn),
4791 ldb_dn_get_linearized(new_dn),
4792 ldb_errstring(ldb_module_get_ctx(ar->module))));
4797 * now we need to ensure that the rename is seen as an
4798 * originating update. We do that with a modify.
4800 ret = replmd_name_modify(ar, req, new_dn);
4801 if (ret != LDB_SUCCESS) {
4805 DEBUG(2,(__location__ ": With conflicting record renamed, re-apply replicated creation of '%s'\n",
4806 ldb_dn_get_linearized(req->op.add.message->dn)));
4809 ret = ldb_build_add_req(&down_req,
4810 ldb_module_get_ctx(ar->module),
4817 if (ret != LDB_SUCCESS) {
4820 LDB_REQ_SET_LOCATION(down_req);
4822 /* current partition control needed by "repmd_op_callback" */
4823 ret = ldb_request_add_control(down_req,
4824 DSDB_CONTROL_CURRENT_PARTITION_OID,
4826 if (ret != LDB_SUCCESS) {
4827 return replmd_replicated_request_error(ar, ret);
4830 if (ar->objs->dsdb_repl_flags & DSDB_REPL_FLAG_PARTIAL_REPLICA) {
4831 /* this tells the partition module to make it a
4832 partial replica if creating an NC */
4833 ret = ldb_request_add_control(down_req,
4834 DSDB_CONTROL_PARTIAL_REPLICA,
4836 if (ret != LDB_SUCCESS) {
4837 return replmd_replicated_request_error(ar, ret);
4842 * Finally we re-run the add, otherwise the new record won't
4843 * exist, as we are here because of that exact failure!
4845 return ldb_next_request(ar->module, down_req);
4848 /* on failure make the caller get the error. This means
4849 * replication will stop with an error, but there is not much
4852 return ldb_module_done(ar->req, NULL, NULL,
4857 callback for replmd_replicated_apply_add()
4858 This copes with the creation of conflict records in the case where
4859 the DN exists, but with a different objectGUID
4861 static int replmd_op_add_callback(struct ldb_request *req, struct ldb_reply *ares)
4863 struct replmd_replicated_request *ar =
4864 talloc_get_type_abort(req->context, struct replmd_replicated_request);
4866 if (ar->objs->objects[ar->index_current].last_known_parent) {
4867 /* This is like a conflict DN, where we put the object in LostAndFound
4868 see MS-DRSR 4.1.10.6.10 FindBestParentObject */
4869 return replmd_op_possible_conflict_callback(req, ares, replmd_op_name_modify_callback);
4872 return replmd_op_possible_conflict_callback(req, ares, replmd_op_callback);
4876 this is called when a new object comes in over DRS
4878 static int replmd_replicated_apply_add(struct replmd_replicated_request *ar)
4880 struct ldb_context *ldb;
4881 struct ldb_request *change_req;
4882 enum ndr_err_code ndr_err;
4883 struct ldb_message *msg;
4884 struct replPropertyMetaDataBlob *md;
4885 struct ldb_val md_value;
4888 bool remote_isDeleted = false;
4891 time_t t = time(NULL);
4892 const struct ldb_val *rdn_val;
4893 struct replmd_private *replmd_private =
4894 talloc_get_type(ldb_module_get_private(ar->module),
4895 struct replmd_private);
4896 unix_to_nt_time(&now, t);
4898 ldb = ldb_module_get_ctx(ar->module);
4899 msg = ar->objs->objects[ar->index_current].msg;
4900 md = ar->objs->objects[ar->index_current].meta_data;
4901 is_schema_nc = ldb_dn_compare_base(replmd_private->schema_dn, msg->dn) == 0;
4903 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &ar->seq_num);
4904 if (ret != LDB_SUCCESS) {
4905 return replmd_replicated_request_error(ar, ret);
4908 ret = dsdb_msg_add_guid(msg,
4909 &ar->objs->objects[ar->index_current].object_guid,
4911 if (ret != LDB_SUCCESS) {
4912 return replmd_replicated_request_error(ar, ret);
4915 ret = ldb_msg_add_string(msg, "whenChanged", ar->objs->objects[ar->index_current].when_changed);
4916 if (ret != LDB_SUCCESS) {
4917 return replmd_replicated_request_error(ar, ret);
4920 ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNCreated", ar->seq_num);
4921 if (ret != LDB_SUCCESS) {
4922 return replmd_replicated_request_error(ar, ret);
4925 ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNChanged", ar->seq_num);
4926 if (ret != LDB_SUCCESS) {
4927 return replmd_replicated_request_error(ar, ret);
4930 /* remove any message elements that have zero values */
4931 for (i=0; i<msg->num_elements; i++) {
4932 struct ldb_message_element *el = &msg->elements[i];
4934 if (el->num_values == 0) {
4935 if (ldb_attr_cmp(msg->elements[i].name, "objectClass") == 0) {
4936 ldb_asprintf_errstring(ldb, __location__
4937 ": empty objectClass sent on %s, aborting replication\n",
4938 ldb_dn_get_linearized(msg->dn));
4939 return replmd_replicated_request_error(ar, LDB_ERR_OBJECT_CLASS_VIOLATION);
4942 DEBUG(4,(__location__ ": Removing attribute %s with num_values==0\n",
4944 memmove(el, el+1, sizeof(*el)*(msg->num_elements - (i+1)));
4945 msg->num_elements--;
4952 struct GUID_txt_buf guid_txt;
4954 char *s = ldb_ldif_message_string(ldb, ar, LDB_CHANGETYPE_ADD, msg);
4955 DEBUG(4, ("DRS replication add message of %s:\n%s\n",
4956 GUID_buf_string(&ar->objs->objects[ar->index_current].object_guid, &guid_txt),
4961 remote_isDeleted = ldb_msg_find_attr_as_bool(msg,
4962 "isDeleted", false);
4965 * the meta data array is already sorted by the caller, except
4966 * for the RDN, which needs to be added.
4970 rdn_val = ldb_dn_get_rdn_val(msg->dn);
4971 ret = replmd_update_rpmd_rdn_attr(ldb, msg, rdn_val, NULL,
4972 md, ar, now, is_schema_nc,
4974 if (ret != LDB_SUCCESS) {
4975 ldb_asprintf_errstring(ldb, "%s: error during DRS repl ADD: %s", __func__, ldb_errstring(ldb));
4976 return replmd_replicated_request_error(ar, ret);
4979 ret = replmd_replPropertyMetaDataCtr1_sort_and_verify(ldb, &md->ctr.ctr1, msg->dn);
4980 if (ret != LDB_SUCCESS) {
4981 ldb_asprintf_errstring(ldb, "%s: error during DRS repl ADD: %s", __func__, ldb_errstring(ldb));
4982 return replmd_replicated_request_error(ar, ret);
4985 for (i=0; i < md->ctr.ctr1.count; i++) {
4986 md->ctr.ctr1.array[i].local_usn = ar->seq_num;
4988 ndr_err = ndr_push_struct_blob(&md_value, msg, md,
4989 (ndr_push_flags_fn_t)ndr_push_replPropertyMetaDataBlob);
4990 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
4991 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
4992 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
4994 ret = ldb_msg_add_value(msg, "replPropertyMetaData", &md_value, NULL);
4995 if (ret != LDB_SUCCESS) {
4996 return replmd_replicated_request_error(ar, ret);
4999 replmd_ldb_message_sort(msg, ar->schema);
5001 if (!remote_isDeleted) {
5002 ret = dsdb_module_schedule_sd_propagation(ar->module,
5003 ar->objs->partition_dn,
5005 if (ret != LDB_SUCCESS) {
5006 return replmd_replicated_request_error(ar, ret);
5010 ar->isDeleted = remote_isDeleted;
5012 ret = ldb_build_add_req(&change_req,
5018 replmd_op_add_callback,
5020 LDB_REQ_SET_LOCATION(change_req);
5021 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
5023 /* current partition control needed by "repmd_op_callback" */
5024 ret = ldb_request_add_control(change_req,
5025 DSDB_CONTROL_CURRENT_PARTITION_OID,
5027 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
5029 if (ar->objs->dsdb_repl_flags & DSDB_REPL_FLAG_PARTIAL_REPLICA) {
5030 /* this tells the partition module to make it a
5031 partial replica if creating an NC */
5032 ret = ldb_request_add_control(change_req,
5033 DSDB_CONTROL_PARTIAL_REPLICA,
5035 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
5038 return ldb_next_request(ar->module, change_req);
5041 static int replmd_replicated_apply_search_for_parent_callback(struct ldb_request *req,
5042 struct ldb_reply *ares)
5044 struct replmd_replicated_request *ar = talloc_get_type(req->context,
5045 struct replmd_replicated_request);
5049 return ldb_module_done(ar->req, NULL, NULL,
5050 LDB_ERR_OPERATIONS_ERROR);
5054 * The error NO_SUCH_OBJECT is not expected, unless the search
5055 * base is the partition DN, and that case doesn't happen here
5056 * because then we wouldn't get a parent_guid_value in any
5059 if (ares->error != LDB_SUCCESS) {
5060 return ldb_module_done(ar->req, ares->controls,
5061 ares->response, ares->error);
5064 switch (ares->type) {
5065 case LDB_REPLY_ENTRY:
5067 struct ldb_message *parent_msg = ares->message;
5068 struct ldb_message *msg = ar->objs->objects[ar->index_current].msg;
5069 struct ldb_dn *parent_dn;
5072 if (!ldb_msg_check_string_attribute(msg, "isDeleted", "TRUE")
5073 && ldb_msg_check_string_attribute(parent_msg, "isDeleted", "TRUE")) {
5074 /* Per MS-DRSR 4.1.10.6.10
5075 * FindBestParentObject we need to move this
5076 * new object under a deleted object to
5078 struct ldb_dn *nc_root;
5080 ret = dsdb_find_nc_root(ldb_module_get_ctx(ar->module), msg, msg->dn, &nc_root);
5081 if (ret == LDB_ERR_NO_SUCH_OBJECT) {
5082 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
5083 "No suitable NC root found for %s. "
5084 "We need to move this object because parent object %s "
5085 "is deleted, but this object is not.",
5086 ldb_dn_get_linearized(msg->dn),
5087 ldb_dn_get_linearized(parent_msg->dn));
5088 return ldb_module_done(ar->req, NULL, NULL, LDB_ERR_OPERATIONS_ERROR);
5089 } else if (ret != LDB_SUCCESS) {
5090 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
5091 "Unable to find NC root for %s: %s. "
5092 "We need to move this object because parent object %s "
5093 "is deleted, but this object is not.",
5094 ldb_dn_get_linearized(msg->dn),
5095 ldb_errstring(ldb_module_get_ctx(ar->module)),
5096 ldb_dn_get_linearized(parent_msg->dn));
5097 return ldb_module_done(ar->req, NULL, NULL, LDB_ERR_OPERATIONS_ERROR);
5100 ret = dsdb_wellknown_dn(ldb_module_get_ctx(ar->module), msg,
5102 DS_GUID_LOSTANDFOUND_CONTAINER,
5104 if (ret != LDB_SUCCESS) {
5105 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
5106 "Unable to find LostAndFound Container for %s "
5107 "in partition %s: %s. "
5108 "We need to move this object because parent object %s "
5109 "is deleted, but this object is not.",
5110 ldb_dn_get_linearized(msg->dn), ldb_dn_get_linearized(nc_root),
5111 ldb_errstring(ldb_module_get_ctx(ar->module)),
5112 ldb_dn_get_linearized(parent_msg->dn));
5113 return ldb_module_done(ar->req, NULL, NULL, LDB_ERR_OPERATIONS_ERROR);
5115 ar->objs->objects[ar->index_current].last_known_parent
5116 = talloc_steal(ar->objs->objects[ar->index_current].msg, parent_msg->dn);
5120 = talloc_steal(ar->objs->objects[ar->index_current].msg, parent_msg->dn);
5123 ar->objs->objects[ar->index_current].local_parent_dn = parent_dn;
5125 comp_num = ldb_dn_get_comp_num(msg->dn);
5127 if (!ldb_dn_remove_base_components(msg->dn, comp_num - 1)) {
5129 return ldb_module_done(ar->req, NULL, NULL, ldb_module_operr(ar->module));
5132 if (!ldb_dn_add_base(msg->dn, parent_dn)) {
5134 return ldb_module_done(ar->req, NULL, NULL, ldb_module_operr(ar->module));
5138 case LDB_REPLY_REFERRAL:
5139 /* we ignore referrals */
5142 case LDB_REPLY_DONE:
5144 if (ar->objs->objects[ar->index_current].local_parent_dn == NULL) {
5145 struct GUID_txt_buf str_buf;
5146 if (ar->search_msg != NULL) {
5147 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
5148 "No parent with GUID %s found for object locally known as %s",
5149 GUID_buf_string(ar->objs->objects[ar->index_current].parent_guid, &str_buf),
5150 ldb_dn_get_linearized(ar->search_msg->dn));
5152 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
5153 "No parent with GUID %s found for object remotely known as %s",
5154 GUID_buf_string(ar->objs->objects[ar->index_current].parent_guid, &str_buf),
5155 ldb_dn_get_linearized(ar->objs->objects[ar->index_current].msg->dn));
5159 * This error code is really important, as it
5160 * is the flag back to the callers to retry
5161 * this with DRSUAPI_DRS_GET_ANC, and so get
5162 * the parent objects before the child
5165 return ldb_module_done(ar->req, NULL, NULL,
5166 replmd_replicated_request_werror(ar, WERR_DS_DRA_MISSING_PARENT));
5169 if (ar->search_msg != NULL) {
5170 ret = replmd_replicated_apply_merge(ar);
5172 ret = replmd_replicated_apply_add(ar);
5174 if (ret != LDB_SUCCESS) {
5175 return ldb_module_done(ar->req, NULL, NULL, ret);
5184 * Look for the parent object, so we put the new object in the right
5185 * place This is akin to NameObject in MS-DRSR - this routine and the
5186 * callbacks find the right parent name, and correct name for this
5190 static int replmd_replicated_apply_search_for_parent(struct replmd_replicated_request *ar)
5192 struct ldb_context *ldb;
5196 struct ldb_request *search_req;
5197 static const char *attrs[] = {"isDeleted", NULL};
5198 struct GUID_txt_buf guid_str_buf;
5200 ldb = ldb_module_get_ctx(ar->module);
5202 if (ar->objs->objects[ar->index_current].parent_guid == NULL) {
5203 if (ar->search_msg != NULL) {
5204 return replmd_replicated_apply_merge(ar);
5206 return replmd_replicated_apply_add(ar);
5210 tmp_str = GUID_buf_string(ar->objs->objects[ar->index_current].parent_guid,
5213 filter = talloc_asprintf(ar, "(objectGUID=%s)", tmp_str);
5214 if (!filter) return replmd_replicated_request_werror(ar, WERR_NOT_ENOUGH_MEMORY);
5216 ret = ldb_build_search_req(&search_req,
5219 ar->objs->partition_dn,
5225 replmd_replicated_apply_search_for_parent_callback,
5227 LDB_REQ_SET_LOCATION(search_req);
5229 ret = dsdb_request_add_controls(search_req,
5230 DSDB_SEARCH_SHOW_RECYCLED|
5231 DSDB_SEARCH_SHOW_DELETED|
5232 DSDB_SEARCH_SHOW_EXTENDED_DN);
5233 if (ret != LDB_SUCCESS) {
5237 return ldb_next_request(ar->module, search_req);
5241 handle renames that come in over DRS replication
5243 static int replmd_replicated_handle_rename(struct replmd_replicated_request *ar,
5244 struct ldb_message *msg,
5245 struct ldb_request *parent,
5249 TALLOC_CTX *tmp_ctx = talloc_new(msg);
5250 struct ldb_result *res;
5251 struct ldb_dn *conflict_dn;
5252 const char *attrs[] = { "replPropertyMetaData", "objectGUID", NULL };
5253 const struct ldb_val *omd_value;
5254 struct replPropertyMetaDataBlob omd, *rmd;
5255 enum ndr_err_code ndr_err;
5256 bool rename_incoming_record, rodc;
5257 struct replPropertyMetaData1 *rmd_name, *omd_name;
5258 struct ldb_dn *new_dn;
5261 DEBUG(4,("replmd_replicated_request rename %s => %s\n",
5262 ldb_dn_get_linearized(ar->search_msg->dn),
5263 ldb_dn_get_linearized(msg->dn)));
5266 ret = dsdb_module_rename(ar->module, ar->search_msg->dn, msg->dn,
5267 DSDB_FLAG_NEXT_MODULE, ar->req);
5268 if (ret == LDB_SUCCESS) {
5269 talloc_free(tmp_ctx);
5274 if (ret != LDB_ERR_ENTRY_ALREADY_EXISTS) {
5275 talloc_free(tmp_ctx);
5276 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module), "Failed to locally apply remote rename from %s to %s: %s",
5277 ldb_dn_get_linearized(ar->search_msg->dn),
5278 ldb_dn_get_linearized(msg->dn),
5279 ldb_errstring(ldb_module_get_ctx(ar->module)));
5283 ret = samdb_rodc(ldb_module_get_ctx(ar->module), &rodc);
5284 if (ret != LDB_SUCCESS) {
5285 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
5286 "Failed to determine if we are an RODC when attempting to form conflict DN: %s",
5287 ldb_errstring(ldb_module_get_ctx(ar->module)));
5288 return LDB_ERR_OPERATIONS_ERROR;
5291 * we have a conflict, and need to decide if we will keep the
5292 * new record or the old record
5295 conflict_dn = msg->dn;
5299 * We are on an RODC, or were a GC for this
5300 * partition, so we have to fail this until
5301 * someone who owns the partition sorts it
5304 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
5305 "Conflict adding object '%s' from incoming replication but we are read only for the partition. \n"
5306 " - We must fail the operation until a master for this partition resolves the conflict",
5307 ldb_dn_get_linearized(conflict_dn));
5312 * first we need the replPropertyMetaData attribute from the
5315 ret = dsdb_module_search_dn(ar->module, tmp_ctx, &res, conflict_dn,
5317 DSDB_FLAG_NEXT_MODULE |
5318 DSDB_SEARCH_SHOW_DELETED |
5319 DSDB_SEARCH_SHOW_RECYCLED, ar->req);
5320 if (ret != LDB_SUCCESS) {
5321 DEBUG(0,(__location__ ": Unable to find object for conflicting record '%s'\n",
5322 ldb_dn_get_linearized(conflict_dn)));
5326 omd_value = ldb_msg_find_ldb_val(res->msgs[0], "replPropertyMetaData");
5327 if (omd_value == NULL) {
5328 DEBUG(0,(__location__ ": Unable to find replPropertyMetaData for conflicting record '%s'\n",
5329 ldb_dn_get_linearized(conflict_dn)));
5333 ndr_err = ndr_pull_struct_blob(omd_value, res->msgs[0], &omd,
5334 (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
5335 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
5336 DEBUG(0,(__location__ ": Failed to parse old replPropertyMetaData for %s\n",
5337 ldb_dn_get_linearized(conflict_dn)));
5341 rmd = ar->objs->objects[ar->index_current].meta_data;
5344 * we decide which is newer based on the RPMD on the name
5345 * attribute. See [MS-DRSR] ResolveNameConflict.
5347 * We expect omd_name to be present, as this is from a local
5348 * search, but while rmd_name should have been given to us by
5349 * the remote server, if it is missing we just prefer the
5351 * replmd_replPropertyMetaData1_new_should_be_taken()
5353 rmd_name = replmd_replPropertyMetaData1_find_attid(rmd, DRSUAPI_ATTID_name);
5354 omd_name = replmd_replPropertyMetaData1_find_attid(&omd, DRSUAPI_ATTID_name);
5356 DEBUG(0,(__location__ ": Failed to find name attribute in local LDB replPropertyMetaData for %s\n",
5357 ldb_dn_get_linearized(conflict_dn)));
5362 * Should we preserve the current record, and so rename the
5363 * incoming record to be a conflict?
5365 rename_incoming_record =
5366 !replmd_replPropertyMetaData1_new_should_be_taken(
5367 ar->objs->dsdb_repl_flags & DSDB_REPL_FLAG_PRIORITISE_INCOMING,
5368 omd_name, rmd_name);
5370 if (rename_incoming_record) {
5372 new_dn = replmd_conflict_dn(msg, msg->dn,
5373 &ar->objs->objects[ar->index_current].object_guid);
5374 if (new_dn == NULL) {
5375 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
5376 "Failed to form conflict DN for %s\n",
5377 ldb_dn_get_linearized(msg->dn));
5379 return replmd_replicated_request_werror(ar, WERR_NOT_ENOUGH_MEMORY);
5382 ret = dsdb_module_rename(ar->module, ar->search_msg->dn, new_dn,
5383 DSDB_FLAG_NEXT_MODULE, ar->req);
5384 if (ret != LDB_SUCCESS) {
5385 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
5386 "Failed to rename incoming conflicting dn '%s' (was '%s') to '%s' - %s\n",
5387 ldb_dn_get_linearized(conflict_dn),
5388 ldb_dn_get_linearized(ar->search_msg->dn),
5389 ldb_dn_get_linearized(new_dn),
5390 ldb_errstring(ldb_module_get_ctx(ar->module)));
5391 return replmd_replicated_request_werror(ar, WERR_DS_DRA_DB_ERROR);
5399 /* we are renaming the existing record */
5401 guid = samdb_result_guid(res->msgs[0], "objectGUID");
5402 if (GUID_all_zero(&guid)) {
5403 DEBUG(0,(__location__ ": Failed to find objectGUID for existing conflict record %s\n",
5404 ldb_dn_get_linearized(conflict_dn)));
5408 new_dn = replmd_conflict_dn(tmp_ctx, conflict_dn, &guid);
5409 if (new_dn == NULL) {
5410 DEBUG(0,(__location__ ": Failed to form conflict DN for %s\n",
5411 ldb_dn_get_linearized(conflict_dn)));
5415 DEBUG(2,(__location__ ": Resolving conflict record via existing-record rename '%s' -> '%s'\n",
5416 ldb_dn_get_linearized(conflict_dn), ldb_dn_get_linearized(new_dn)));
5418 ret = dsdb_module_rename(ar->module, conflict_dn, new_dn,
5419 DSDB_FLAG_OWN_MODULE, ar->req);
5420 if (ret != LDB_SUCCESS) {
5421 DEBUG(0,(__location__ ": Failed to rename conflict dn '%s' to '%s' - %s\n",
5422 ldb_dn_get_linearized(conflict_dn),
5423 ldb_dn_get_linearized(new_dn),
5424 ldb_errstring(ldb_module_get_ctx(ar->module))));
5429 * now we need to ensure that the rename is seen as an
5430 * originating update. We do that with a modify.
5432 ret = replmd_name_modify(ar, ar->req, new_dn);
5433 if (ret != LDB_SUCCESS) {
5437 DEBUG(2,(__location__ ": With conflicting record renamed, re-apply replicated rename '%s' -> '%s'\n",
5438 ldb_dn_get_linearized(ar->search_msg->dn),
5439 ldb_dn_get_linearized(msg->dn)));
5442 ret = dsdb_module_rename(ar->module, ar->search_msg->dn, msg->dn,
5443 DSDB_FLAG_NEXT_MODULE, ar->req);
5444 if (ret != LDB_SUCCESS) {
5445 DEBUG(0,(__location__ ": After conflict resolution, failed to rename dn '%s' to '%s' - %s\n",
5446 ldb_dn_get_linearized(ar->search_msg->dn),
5447 ldb_dn_get_linearized(msg->dn),
5448 ldb_errstring(ldb_module_get_ctx(ar->module))));
5454 * On failure make the caller get the error
5455 * This means replication will stop with an error,
5456 * but there is not much else we can do. In the
5457 * LDB_ERR_ENTRY_ALREADY_EXISTS case this is exactly what is
5461 talloc_free(tmp_ctx);
5466 static int replmd_replicated_apply_merge(struct replmd_replicated_request *ar)
5468 struct ldb_context *ldb;
5469 struct ldb_request *change_req;
5470 enum ndr_err_code ndr_err;
5471 struct ldb_message *msg;
5472 struct replPropertyMetaDataBlob *rmd;
5473 struct replPropertyMetaDataBlob omd;
5474 const struct ldb_val *omd_value;
5475 struct replPropertyMetaDataBlob nmd;
5476 struct ldb_val nmd_value;
5477 struct GUID remote_parent_guid;
5480 unsigned int removed_attrs = 0;
5482 int (*callback)(struct ldb_request *req, struct ldb_reply *ares) = replmd_op_callback;
5483 bool isDeleted = false;
5484 bool local_isDeleted = false;
5485 bool remote_isDeleted = false;
5486 bool take_remote_isDeleted = false;
5487 bool sd_updated = false;
5488 bool renamed = false;
5489 bool is_schema_nc = false;
5491 const struct ldb_val *old_rdn, *new_rdn;
5492 struct replmd_private *replmd_private =
5493 talloc_get_type(ldb_module_get_private(ar->module),
5494 struct replmd_private);
5496 time_t t = time(NULL);
5497 unix_to_nt_time(&now, t);
5499 ldb = ldb_module_get_ctx(ar->module);
5500 msg = ar->objs->objects[ar->index_current].msg;
5502 is_schema_nc = ldb_dn_compare_base(replmd_private->schema_dn, msg->dn) == 0;
5504 rmd = ar->objs->objects[ar->index_current].meta_data;
5508 /* find existing meta data */
5509 omd_value = ldb_msg_find_ldb_val(ar->search_msg, "replPropertyMetaData");
5511 ndr_err = ndr_pull_struct_blob(omd_value, ar, &omd,
5512 (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
5513 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
5514 nt_status = ndr_map_error2ntstatus(ndr_err);
5515 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
5518 if (omd.version != 1) {
5519 return replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
5524 struct GUID_txt_buf guid_txt;
5526 char *s = ldb_ldif_message_string(ldb, ar, LDB_CHANGETYPE_MODIFY, msg);
5527 DEBUG(5, ("Initial DRS replication modify message of %s is:\n%s\n"
5530 GUID_buf_string(&ar->objs->objects[ar->index_current].object_guid, &guid_txt),
5532 ndr_print_struct_string(s,
5533 (ndr_print_fn_t)ndr_print_replPropertyMetaDataBlob,
5534 "existing replPropertyMetaData",
5536 ndr_print_struct_string(s,
5537 (ndr_print_fn_t)ndr_print_replPropertyMetaDataBlob,
5538 "incoming replPropertyMetaData",
5543 local_isDeleted = ldb_msg_find_attr_as_bool(ar->search_msg,
5544 "isDeleted", false);
5545 remote_isDeleted = ldb_msg_find_attr_as_bool(msg,
5546 "isDeleted", false);
5549 * Fill in the remote_parent_guid with the GUID or an all-zero
5552 if (ar->objs->objects[ar->index_current].parent_guid != NULL) {
5553 remote_parent_guid = *ar->objs->objects[ar->index_current].parent_guid;
5555 remote_parent_guid = GUID_zero();
5559 * To ensure we follow a complex rename chain around, we have
5560 * to confirm that the DN is the same (mostly to confirm the
5561 * RDN) and the parentGUID is the same.
5563 * This ensures we keep things under the correct parent, which
5564 * replmd_replicated_handle_rename() will do.
5567 if (strcmp(ldb_dn_get_linearized(msg->dn), ldb_dn_get_linearized(ar->search_msg->dn)) == 0
5568 && GUID_equal(&remote_parent_guid, &ar->local_parent_guid)) {
5572 * handle renames, even just by case that come in over
5573 * DRS. Changes in the parent DN don't hit us here,
5574 * because the search for a parent will clean up those
5577 * We also have already filtered out the case where
5578 * the peer has an older name to what we have (see
5579 * replmd_replicated_apply_search_callback())
5581 ret = replmd_replicated_handle_rename(ar, msg, ar->req, &renamed);
5584 if (ret != LDB_SUCCESS) {
5585 ldb_debug(ldb, LDB_DEBUG_FATAL,
5586 "replmd_replicated_request rename %s => %s failed - %s\n",
5587 ldb_dn_get_linearized(ar->search_msg->dn),
5588 ldb_dn_get_linearized(msg->dn),
5589 ldb_errstring(ldb));
5590 return replmd_replicated_request_werror(ar, WERR_DS_DRA_DB_ERROR);
5593 if (renamed == true) {
5595 * Set the callback to one that will fix up the name
5596 * metadata on the new conflict DN
5598 callback = replmd_op_name_modify_callback;
5603 nmd.ctr.ctr1.count = omd.ctr.ctr1.count + rmd->ctr.ctr1.count;
5604 nmd.ctr.ctr1.array = talloc_array(ar,
5605 struct replPropertyMetaData1,
5606 nmd.ctr.ctr1.count);
5607 if (!nmd.ctr.ctr1.array) return replmd_replicated_request_werror(ar, WERR_NOT_ENOUGH_MEMORY);
5609 /* first copy the old meta data */
5610 for (i=0; i < omd.ctr.ctr1.count; i++) {
5611 nmd.ctr.ctr1.array[ni] = omd.ctr.ctr1.array[i];
5616 /* now merge in the new meta data */
5617 for (i=0; i < rmd->ctr.ctr1.count; i++) {
5620 for (j=0; j < ni; j++) {
5623 if (rmd->ctr.ctr1.array[i].attid != nmd.ctr.ctr1.array[j].attid) {
5627 cmp = replmd_replPropertyMetaData1_new_should_be_taken(
5628 ar->objs->dsdb_repl_flags,
5629 &nmd.ctr.ctr1.array[j],
5630 &rmd->ctr.ctr1.array[i]);
5632 /* replace the entry */
5633 nmd.ctr.ctr1.array[j] = rmd->ctr.ctr1.array[i];
5634 if (ar->seq_num == 0) {
5635 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &ar->seq_num);
5636 if (ret != LDB_SUCCESS) {
5637 return replmd_replicated_request_error(ar, ret);
5640 nmd.ctr.ctr1.array[j].local_usn = ar->seq_num;
5641 switch (nmd.ctr.ctr1.array[j].attid) {
5642 case DRSUAPI_ATTID_ntSecurityDescriptor:
5645 case DRSUAPI_ATTID_isDeleted:
5646 take_remote_isDeleted = true;
5655 if (rmd->ctr.ctr1.array[i].attid != DRSUAPI_ATTID_instanceType) {
5656 DEBUG(3,("Discarding older DRS attribute update to %s on %s from %s\n",
5657 msg->elements[i-removed_attrs].name,
5658 ldb_dn_get_linearized(msg->dn),
5659 GUID_string(ar, &rmd->ctr.ctr1.array[i].originating_invocation_id)));
5662 /* we don't want to apply this change so remove the attribute */
5663 ldb_msg_remove_element(msg, &msg->elements[i-removed_attrs]);
5670 if (found) continue;
5672 nmd.ctr.ctr1.array[ni] = rmd->ctr.ctr1.array[i];
5673 if (ar->seq_num == 0) {
5674 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &ar->seq_num);
5675 if (ret != LDB_SUCCESS) {
5676 return replmd_replicated_request_error(ar, ret);
5679 nmd.ctr.ctr1.array[ni].local_usn = ar->seq_num;
5680 switch (nmd.ctr.ctr1.array[ni].attid) {
5681 case DRSUAPI_ATTID_ntSecurityDescriptor:
5684 case DRSUAPI_ATTID_isDeleted:
5685 take_remote_isDeleted = true;
5694 * finally correct the size of the meta_data array
5696 nmd.ctr.ctr1.count = ni;
5698 new_rdn = ldb_dn_get_rdn_val(msg->dn);
5699 old_rdn = ldb_dn_get_rdn_val(ar->search_msg->dn);
5702 ret = replmd_update_rpmd_rdn_attr(ldb, msg, new_rdn, old_rdn,
5703 &nmd, ar, now, is_schema_nc,
5705 if (ret != LDB_SUCCESS) {
5706 ldb_asprintf_errstring(ldb, "%s: error during DRS repl merge: %s", __func__, ldb_errstring(ldb));
5707 return replmd_replicated_request_error(ar, ret);
5711 * sort the new meta data array
5713 ret = replmd_replPropertyMetaDataCtr1_sort_and_verify(ldb, &nmd.ctr.ctr1, msg->dn);
5714 if (ret != LDB_SUCCESS) {
5715 ldb_asprintf_errstring(ldb, "%s: error during DRS repl merge: %s", __func__, ldb_errstring(ldb));
5720 * Work out if this object is deleted, so we can prune any extra attributes. See MS-DRSR 4.1.10.6.9
5723 * This also controls SD propagation below
5725 if (take_remote_isDeleted) {
5726 isDeleted = remote_isDeleted;
5728 isDeleted = local_isDeleted;
5731 ar->isDeleted = isDeleted;
5734 * check if some replicated attributes left, otherwise skip the ldb_modify() call
5736 if (msg->num_elements == 0) {
5737 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_replicated_apply_merge[%u]: skip replace\n",
5740 return replmd_replicated_apply_isDeleted(ar);
5743 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_replicated_apply_merge[%u]: replace %u attributes\n",
5744 ar->index_current, msg->num_elements);
5750 if (sd_updated && !isDeleted) {
5751 ret = dsdb_module_schedule_sd_propagation(ar->module,
5752 ar->objs->partition_dn,
5754 if (ret != LDB_SUCCESS) {
5755 return ldb_operr(ldb);
5759 /* create the meta data value */
5760 ndr_err = ndr_push_struct_blob(&nmd_value, msg, &nmd,
5761 (ndr_push_flags_fn_t)ndr_push_replPropertyMetaDataBlob);
5762 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
5763 nt_status = ndr_map_error2ntstatus(ndr_err);
5764 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
5768 * when we know that we'll modify the record, add the whenChanged, uSNChanged
5769 * and replPopertyMetaData attributes
5771 ret = ldb_msg_add_string(msg, "whenChanged", ar->objs->objects[ar->index_current].when_changed);
5772 if (ret != LDB_SUCCESS) {
5773 return replmd_replicated_request_error(ar, ret);
5775 ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNChanged", ar->seq_num);
5776 if (ret != LDB_SUCCESS) {
5777 return replmd_replicated_request_error(ar, ret);
5779 ret = ldb_msg_add_value(msg, "replPropertyMetaData", &nmd_value, NULL);
5780 if (ret != LDB_SUCCESS) {
5781 return replmd_replicated_request_error(ar, ret);
5784 replmd_ldb_message_sort(msg, ar->schema);
5786 /* we want to replace the old values */
5787 for (i=0; i < msg->num_elements; i++) {
5788 msg->elements[i].flags = LDB_FLAG_MOD_REPLACE;
5789 if (ldb_attr_cmp(msg->elements[i].name, "objectClass") == 0) {
5790 if (msg->elements[i].num_values == 0) {
5791 ldb_asprintf_errstring(ldb, __location__
5792 ": objectClass removed on %s, aborting replication\n",
5793 ldb_dn_get_linearized(msg->dn));
5794 return replmd_replicated_request_error(ar, LDB_ERR_OBJECT_CLASS_VIOLATION);
5800 struct GUID_txt_buf guid_txt;
5802 char *s = ldb_ldif_message_string(ldb, ar, LDB_CHANGETYPE_MODIFY, msg);
5803 DEBUG(4, ("Final DRS replication modify message of %s:\n%s\n",
5804 GUID_buf_string(&ar->objs->objects[ar->index_current].object_guid, &guid_txt),
5809 ret = ldb_build_mod_req(&change_req,
5817 LDB_REQ_SET_LOCATION(change_req);
5818 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
5820 /* current partition control needed by "repmd_op_callback" */
5821 ret = ldb_request_add_control(change_req,
5822 DSDB_CONTROL_CURRENT_PARTITION_OID,
5824 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
5826 return ldb_next_request(ar->module, change_req);
5829 static int replmd_replicated_apply_search_callback(struct ldb_request *req,
5830 struct ldb_reply *ares)
5832 struct replmd_replicated_request *ar = talloc_get_type(req->context,
5833 struct replmd_replicated_request);
5837 return ldb_module_done(ar->req, NULL, NULL,
5838 LDB_ERR_OPERATIONS_ERROR);
5840 if (ares->error != LDB_SUCCESS &&
5841 ares->error != LDB_ERR_NO_SUCH_OBJECT) {
5842 return ldb_module_done(ar->req, ares->controls,
5843 ares->response, ares->error);
5846 switch (ares->type) {
5847 case LDB_REPLY_ENTRY:
5848 ar->search_msg = talloc_steal(ar, ares->message);
5851 case LDB_REPLY_REFERRAL:
5852 /* we ignore referrals */
5855 case LDB_REPLY_DONE:
5857 struct replPropertyMetaData1 *md_remote;
5858 struct replPropertyMetaData1 *md_local;
5860 struct replPropertyMetaDataBlob omd;
5861 const struct ldb_val *omd_value;
5862 struct replPropertyMetaDataBlob *rmd;
5863 struct ldb_message *msg;
5865 ar->objs->objects[ar->index_current].local_parent_dn = NULL;
5866 ar->objs->objects[ar->index_current].last_known_parent = NULL;
5869 * This is the ADD case, find the appropriate parent,
5870 * as this object doesn't exist locally:
5872 if (ar->search_msg == NULL) {
5873 ret = replmd_replicated_apply_search_for_parent(ar);
5874 if (ret != LDB_SUCCESS) {
5875 return ldb_module_done(ar->req, NULL, NULL, ret);
5882 * Otherwise, in the MERGE case, work out if we are
5883 * attempting a rename, and if so find the parent the
5884 * newly renamed object wants to belong under (which
5885 * may not be the parent in it's attached string DN
5887 rmd = ar->objs->objects[ar->index_current].meta_data;
5891 /* find existing meta data */
5892 omd_value = ldb_msg_find_ldb_val(ar->search_msg, "replPropertyMetaData");
5894 enum ndr_err_code ndr_err;
5895 ndr_err = ndr_pull_struct_blob(omd_value, ar, &omd,
5896 (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
5897 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
5898 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
5899 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
5902 if (omd.version != 1) {
5903 return replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
5907 ar->local_parent_guid = samdb_result_guid(ar->search_msg, "parentGUID");
5909 instanceType = ldb_msg_find_attr_as_int(ar->search_msg, "instanceType", 0);
5910 if (((instanceType & INSTANCE_TYPE_IS_NC_HEAD) == 0)
5911 && GUID_all_zero(&ar->local_parent_guid)) {
5912 DEBUG(0, ("Refusing to replicate new version of %s "
5913 "as local object has an all-zero parentGUID attribute, "
5914 "despite not being an NC root\n",
5915 ldb_dn_get_linearized(ar->search_msg->dn)));
5916 return replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
5920 * now we need to check for double renames. We could have a
5921 * local rename pending which our replication partner hasn't
5922 * received yet. We choose which one wins by looking at the
5923 * attribute stamps on the two objects, the newer one wins.
5925 * This also simply applies the correct algorithms for
5926 * determining if a change was made to name at all, or
5927 * if the object has just been renamed under the same
5930 md_remote = replmd_replPropertyMetaData1_find_attid(rmd, DRSUAPI_ATTID_name);
5931 md_local = replmd_replPropertyMetaData1_find_attid(&omd, DRSUAPI_ATTID_name);
5933 DEBUG(0,(__location__ ": Failed to find name attribute in local LDB replPropertyMetaData for %s\n",
5934 ldb_dn_get_linearized(ar->search_msg->dn)));
5935 return replmd_replicated_request_werror(ar, WERR_DS_DRA_DB_ERROR);
5939 * if there is no name attribute given then we have to assume the
5940 * object we've received has the older name
5942 if (replmd_replPropertyMetaData1_new_should_be_taken(
5943 ar->objs->dsdb_repl_flags & DSDB_REPL_FLAG_PRIORITISE_INCOMING,
5944 md_local, md_remote)) {
5945 struct GUID_txt_buf p_guid_local;
5946 struct GUID_txt_buf p_guid_remote;
5947 msg = ar->objs->objects[ar->index_current].msg;
5949 /* Merge on the existing object, with rename */
5951 DEBUG(4,(__location__ ": Looking for new parent for object %s currently under %s "
5952 "as incoming object changing to %s under %s\n",
5953 ldb_dn_get_linearized(ar->search_msg->dn),
5954 GUID_buf_string(&ar->local_parent_guid, &p_guid_local),
5955 ldb_dn_get_linearized(msg->dn),
5956 GUID_buf_string(ar->objs->objects[ar->index_current].parent_guid,
5958 ret = replmd_replicated_apply_search_for_parent(ar);
5960 struct GUID_txt_buf p_guid_local;
5961 struct GUID_txt_buf p_guid_remote;
5962 msg = ar->objs->objects[ar->index_current].msg;
5965 * Merge on the existing object, force no
5966 * rename (code below just to explain why in
5970 if (strcmp(ldb_dn_get_linearized(ar->search_msg->dn),
5971 ldb_dn_get_linearized(msg->dn)) == 0) {
5972 if (ar->objs->objects[ar->index_current].parent_guid != NULL &&
5973 GUID_equal(&ar->local_parent_guid,
5974 ar->objs->objects[ar->index_current].parent_guid)
5976 DEBUG(4,(__location__ ": Keeping object %s at under %s "
5977 "despite incoming object changing parent to %s\n",
5978 ldb_dn_get_linearized(ar->search_msg->dn),
5979 GUID_buf_string(&ar->local_parent_guid, &p_guid_local),
5980 GUID_buf_string(ar->objs->objects[ar->index_current].parent_guid,
5984 DEBUG(4,(__location__ ": Keeping object %s at under %s "
5985 " and rejecting older rename to %s under %s\n",
5986 ldb_dn_get_linearized(ar->search_msg->dn),
5987 GUID_buf_string(&ar->local_parent_guid, &p_guid_local),
5988 ldb_dn_get_linearized(msg->dn),
5989 GUID_buf_string(ar->objs->objects[ar->index_current].parent_guid,
5993 * This assignment ensures that the strcmp()
5994 * and GUID_equal() calls in
5995 * replmd_replicated_apply_merge() avoids the
5998 ar->objs->objects[ar->index_current].parent_guid =
5999 &ar->local_parent_guid;
6001 msg->dn = ar->search_msg->dn;
6002 ret = replmd_replicated_apply_merge(ar);
6004 if (ret != LDB_SUCCESS) {
6005 return ldb_module_done(ar->req, NULL, NULL, ret);
6014 static int replmd_replicated_uptodate_vector(struct replmd_replicated_request *ar);
6016 static int replmd_replicated_apply_next(struct replmd_replicated_request *ar)
6018 struct ldb_context *ldb;
6022 struct ldb_request *search_req;
6023 static const char *attrs[] = { "repsFrom", "replUpToDateVector",
6024 "parentGUID", "instanceType",
6025 "replPropertyMetaData", "nTSecurityDescriptor",
6026 "isDeleted", NULL };
6027 struct GUID_txt_buf guid_str_buf;
6029 if (ar->index_current >= ar->objs->num_objects) {
6030 /* done with it, go to next stage */
6031 return replmd_replicated_uptodate_vector(ar);
6034 ldb = ldb_module_get_ctx(ar->module);
6035 ar->search_msg = NULL;
6036 ar->isDeleted = false;
6038 tmp_str = GUID_buf_string(&ar->objs->objects[ar->index_current].object_guid,
6041 filter = talloc_asprintf(ar, "(objectGUID=%s)", tmp_str);
6042 if (!filter) return replmd_replicated_request_werror(ar, WERR_NOT_ENOUGH_MEMORY);
6044 ret = ldb_build_search_req(&search_req,
6047 ar->objs->partition_dn,
6053 replmd_replicated_apply_search_callback,
6055 LDB_REQ_SET_LOCATION(search_req);
6057 ret = dsdb_request_add_controls(search_req, DSDB_SEARCH_SHOW_RECYCLED);
6059 if (ret != LDB_SUCCESS) {
6063 return ldb_next_request(ar->module, search_req);
6067 * This is essentially a wrapper for replmd_replicated_apply_next()
6069 * This is needed to ensure that both codepaths call this handler.
6071 static int replmd_replicated_apply_isDeleted(struct replmd_replicated_request *ar)
6073 struct ldb_dn *deleted_objects_dn;
6074 struct ldb_message *msg = ar->objs->objects[ar->index_current].msg;
6075 int ret = dsdb_get_deleted_objects_dn(ldb_module_get_ctx(ar->module), msg, msg->dn,
6076 &deleted_objects_dn);
6077 if (ar->isDeleted && (ret != LDB_SUCCESS || ldb_dn_compare(msg->dn, deleted_objects_dn) != 0)) {
6079 * Do a delete here again, so that if there is
6080 * anything local that conflicts with this
6081 * object being deleted, it is removed. This
6082 * includes links. See MS-DRSR 4.1.10.6.9
6085 * If the object is already deleted, and there
6086 * is no more work required, it doesn't do
6090 /* This has been updated to point to the DN we eventually did the modify on */
6092 struct ldb_request *del_req;
6093 struct ldb_result *res;
6095 TALLOC_CTX *tmp_ctx = talloc_new(ar);
6097 ret = ldb_oom(ldb_module_get_ctx(ar->module));
6101 res = talloc_zero(tmp_ctx, struct ldb_result);
6103 ret = ldb_oom(ldb_module_get_ctx(ar->module));
6104 talloc_free(tmp_ctx);
6108 /* Build a delete request, which hopefully will artually turn into nothing */
6109 ret = ldb_build_del_req(&del_req, ldb_module_get_ctx(ar->module), tmp_ctx,
6113 ldb_modify_default_callback,
6115 LDB_REQ_SET_LOCATION(del_req);
6116 if (ret != LDB_SUCCESS) {
6117 talloc_free(tmp_ctx);
6122 * This is the guts of the call, call back
6123 * into our delete code, but setting the
6124 * re_delete flag so we delete anything that
6125 * shouldn't be there on a deleted or recycled
6128 ret = replmd_delete_internals(ar->module, del_req, true);
6129 if (ret == LDB_SUCCESS) {
6130 ret = ldb_wait(del_req->handle, LDB_WAIT_ALL);
6133 talloc_free(tmp_ctx);
6134 if (ret != LDB_SUCCESS) {
6139 ar->index_current++;
6140 return replmd_replicated_apply_next(ar);
6143 static int replmd_replicated_uptodate_modify_callback(struct ldb_request *req,
6144 struct ldb_reply *ares)
6146 struct ldb_context *ldb;
6147 struct replmd_replicated_request *ar = talloc_get_type(req->context,
6148 struct replmd_replicated_request);
6149 ldb = ldb_module_get_ctx(ar->module);
6152 return ldb_module_done(ar->req, NULL, NULL,
6153 LDB_ERR_OPERATIONS_ERROR);
6155 if (ares->error != LDB_SUCCESS) {
6156 return ldb_module_done(ar->req, ares->controls,
6157 ares->response, ares->error);
6160 if (ares->type != LDB_REPLY_DONE) {
6161 ldb_asprintf_errstring(ldb, "Invalid LDB reply type %d", ares->type);
6162 return ldb_module_done(ar->req, NULL, NULL,
6163 LDB_ERR_OPERATIONS_ERROR);
6168 return ldb_module_done(ar->req, NULL, NULL, LDB_SUCCESS);
6171 static int replmd_replicated_uptodate_modify(struct replmd_replicated_request *ar)
6173 struct ldb_context *ldb;
6174 struct ldb_request *change_req;
6175 enum ndr_err_code ndr_err;
6176 struct ldb_message *msg;
6177 struct replUpToDateVectorBlob ouv;
6178 const struct ldb_val *ouv_value;
6179 const struct drsuapi_DsReplicaCursor2CtrEx *ruv;
6180 struct replUpToDateVectorBlob nuv;
6181 struct ldb_val nuv_value;
6182 struct ldb_message_element *nuv_el = NULL;
6183 struct ldb_message_element *orf_el = NULL;
6184 struct repsFromToBlob nrf;
6185 struct ldb_val *nrf_value = NULL;
6186 struct ldb_message_element *nrf_el = NULL;
6190 time_t t = time(NULL);
6193 uint32_t instanceType;
6195 ldb = ldb_module_get_ctx(ar->module);
6196 ruv = ar->objs->uptodateness_vector;
6202 unix_to_nt_time(&now, t);
6204 if (ar->search_msg == NULL) {
6205 /* this happens for a REPL_OBJ call where we are
6206 creating the target object by replicating it. The
6207 subdomain join code does this for the partition DN
6209 DEBUG(4,(__location__ ": Skipping UDV and repsFrom update as no target DN\n"));
6210 return ldb_module_done(ar->req, NULL, NULL, LDB_SUCCESS);
6213 instanceType = ldb_msg_find_attr_as_uint(ar->search_msg, "instanceType", 0);
6214 if (! (instanceType & INSTANCE_TYPE_IS_NC_HEAD)) {
6215 DEBUG(4,(__location__ ": Skipping UDV and repsFrom update as not NC root: %s\n",
6216 ldb_dn_get_linearized(ar->search_msg->dn)));
6217 return ldb_module_done(ar->req, NULL, NULL, LDB_SUCCESS);
6221 * first create the new replUpToDateVector
6223 ouv_value = ldb_msg_find_ldb_val(ar->search_msg, "replUpToDateVector");
6225 ndr_err = ndr_pull_struct_blob(ouv_value, ar, &ouv,
6226 (ndr_pull_flags_fn_t)ndr_pull_replUpToDateVectorBlob);
6227 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
6228 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
6229 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
6232 if (ouv.version != 2) {
6233 return replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
6238 * the new uptodateness vector will at least
6239 * contain 1 entry, one for the source_dsa
6241 * plus optional values from our old vector and the one from the source_dsa
6243 nuv.ctr.ctr2.count = ouv.ctr.ctr2.count;
6244 if (ruv) nuv.ctr.ctr2.count += ruv->count;
6245 nuv.ctr.ctr2.cursors = talloc_array(ar,
6246 struct drsuapi_DsReplicaCursor2,
6247 nuv.ctr.ctr2.count);
6248 if (!nuv.ctr.ctr2.cursors) return replmd_replicated_request_werror(ar, WERR_NOT_ENOUGH_MEMORY);
6250 /* first copy the old vector */
6251 for (i=0; i < ouv.ctr.ctr2.count; i++) {
6252 nuv.ctr.ctr2.cursors[ni] = ouv.ctr.ctr2.cursors[i];
6256 /* merge in the source_dsa vector is available */
6257 for (i=0; (ruv && i < ruv->count); i++) {
6260 if (GUID_equal(&ruv->cursors[i].source_dsa_invocation_id,
6261 &ar->our_invocation_id)) {
6265 for (j=0; j < ni; j++) {
6266 if (!GUID_equal(&ruv->cursors[i].source_dsa_invocation_id,
6267 &nuv.ctr.ctr2.cursors[j].source_dsa_invocation_id)) {
6273 if (ruv->cursors[i].highest_usn > nuv.ctr.ctr2.cursors[j].highest_usn) {
6274 nuv.ctr.ctr2.cursors[j] = ruv->cursors[i];
6279 if (found) continue;
6281 /* if it's not there yet, add it */
6282 nuv.ctr.ctr2.cursors[ni] = ruv->cursors[i];
6287 * finally correct the size of the cursors array
6289 nuv.ctr.ctr2.count = ni;
6294 TYPESAFE_QSORT(nuv.ctr.ctr2.cursors, nuv.ctr.ctr2.count, drsuapi_DsReplicaCursor2_compare);
6297 * create the change ldb_message
6299 msg = ldb_msg_new(ar);
6300 if (!msg) return replmd_replicated_request_werror(ar, WERR_NOT_ENOUGH_MEMORY);
6301 msg->dn = ar->search_msg->dn;
6303 ndr_err = ndr_push_struct_blob(&nuv_value, msg, &nuv,
6304 (ndr_push_flags_fn_t)ndr_push_replUpToDateVectorBlob);
6305 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
6306 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
6307 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
6309 ret = ldb_msg_add_value(msg, "replUpToDateVector", &nuv_value, &nuv_el);
6310 if (ret != LDB_SUCCESS) {
6311 return replmd_replicated_request_error(ar, ret);
6313 nuv_el->flags = LDB_FLAG_MOD_REPLACE;
6316 * now create the new repsFrom value from the given repsFromTo1 structure
6320 nrf.ctr.ctr1 = *ar->objs->source_dsa;
6321 nrf.ctr.ctr1.last_attempt = now;
6322 nrf.ctr.ctr1.last_success = now;
6323 nrf.ctr.ctr1.result_last_attempt = WERR_OK;
6326 * first see if we already have a repsFrom value for the current source dsa
6327 * if so we'll later replace this value
6329 orf_el = ldb_msg_find_element(ar->search_msg, "repsFrom");
6331 for (i=0; i < orf_el->num_values; i++) {
6332 struct repsFromToBlob *trf;
6334 trf = talloc(ar, struct repsFromToBlob);
6335 if (!trf) return replmd_replicated_request_werror(ar, WERR_NOT_ENOUGH_MEMORY);
6337 ndr_err = ndr_pull_struct_blob(&orf_el->values[i], trf, trf,
6338 (ndr_pull_flags_fn_t)ndr_pull_repsFromToBlob);
6339 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
6340 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
6341 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
6344 if (trf->version != 1) {
6345 return replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
6349 * we compare the source dsa objectGUID not the invocation_id
6350 * because we want only one repsFrom value per source dsa
6351 * and when the invocation_id of the source dsa has changed we don't need
6352 * the old repsFrom with the old invocation_id
6354 if (!GUID_equal(&trf->ctr.ctr1.source_dsa_obj_guid,
6355 &ar->objs->source_dsa->source_dsa_obj_guid)) {
6361 nrf_value = &orf_el->values[i];
6366 * copy over all old values to the new ldb_message
6368 ret = ldb_msg_add_empty(msg, "repsFrom", 0, &nrf_el);
6369 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
6374 * if we haven't found an old repsFrom value for the current source dsa
6375 * we'll add a new value
6378 struct ldb_val zero_value;
6379 ZERO_STRUCT(zero_value);
6380 ret = ldb_msg_add_value(msg, "repsFrom", &zero_value, &nrf_el);
6381 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
6383 nrf_value = &nrf_el->values[nrf_el->num_values - 1];
6386 /* we now fill the value which is already attached to ldb_message */
6387 ndr_err = ndr_push_struct_blob(nrf_value, msg,
6389 (ndr_push_flags_fn_t)ndr_push_repsFromToBlob);
6390 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
6391 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
6392 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
6396 * the ldb_message_element for the attribute, has all the old values and the new one
6397 * so we'll replace the whole attribute with all values
6399 nrf_el->flags = LDB_FLAG_MOD_REPLACE;
6401 if (CHECK_DEBUGLVL(4)) {
6402 char *s = ldb_ldif_message_string(ldb, ar, LDB_CHANGETYPE_MODIFY, msg);
6403 DEBUG(4, ("DRS replication uptodate modify message:\n%s\n", s));
6407 /* prepare the ldb_modify() request */
6408 ret = ldb_build_mod_req(&change_req,
6414 replmd_replicated_uptodate_modify_callback,
6416 LDB_REQ_SET_LOCATION(change_req);
6417 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
6419 return ldb_next_request(ar->module, change_req);
6422 static int replmd_replicated_uptodate_search_callback(struct ldb_request *req,
6423 struct ldb_reply *ares)
6425 struct replmd_replicated_request *ar = talloc_get_type(req->context,
6426 struct replmd_replicated_request);
6430 return ldb_module_done(ar->req, NULL, NULL,
6431 LDB_ERR_OPERATIONS_ERROR);
6433 if (ares->error != LDB_SUCCESS &&
6434 ares->error != LDB_ERR_NO_SUCH_OBJECT) {
6435 return ldb_module_done(ar->req, ares->controls,
6436 ares->response, ares->error);
6439 switch (ares->type) {
6440 case LDB_REPLY_ENTRY:
6441 ar->search_msg = talloc_steal(ar, ares->message);
6444 case LDB_REPLY_REFERRAL:
6445 /* we ignore referrals */
6448 case LDB_REPLY_DONE:
6449 ret = replmd_replicated_uptodate_modify(ar);
6450 if (ret != LDB_SUCCESS) {
6451 return ldb_module_done(ar->req, NULL, NULL, ret);
6460 static int replmd_replicated_uptodate_vector(struct replmd_replicated_request *ar)
6462 struct ldb_context *ldb = ldb_module_get_ctx(ar->module);
6463 struct replmd_private *replmd_private =
6464 talloc_get_type_abort(ldb_module_get_private(ar->module),
6465 struct replmd_private);
6467 static const char *attrs[] = {
6468 "replUpToDateVector",
6473 struct ldb_request *search_req;
6475 ar->search_msg = NULL;
6478 * Let the caller know that we did an originating updates
6480 ar->objs->originating_updates = replmd_private->originating_updates;
6482 ret = ldb_build_search_req(&search_req,
6485 ar->objs->partition_dn,
6491 replmd_replicated_uptodate_search_callback,
6493 LDB_REQ_SET_LOCATION(search_req);
6494 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
6496 return ldb_next_request(ar->module, search_req);
6501 static int replmd_extended_replicated_objects(struct ldb_module *module, struct ldb_request *req)
6503 struct ldb_context *ldb;
6504 struct dsdb_extended_replicated_objects *objs;
6505 struct replmd_replicated_request *ar;
6506 struct ldb_control **ctrls;
6509 struct replmd_private *replmd_private =
6510 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
6512 ldb = ldb_module_get_ctx(module);
6514 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_extended_replicated_objects\n");
6516 objs = talloc_get_type(req->op.extended.data, struct dsdb_extended_replicated_objects);
6518 ldb_debug(ldb, LDB_DEBUG_FATAL, "replmd_extended_replicated_objects: invalid extended data\n");
6519 return LDB_ERR_PROTOCOL_ERROR;
6522 if (objs->version != DSDB_EXTENDED_REPLICATED_OBJECTS_VERSION) {
6523 ldb_debug(ldb, LDB_DEBUG_FATAL, "replmd_extended_replicated_objects: extended data invalid version [%u != %u]\n",
6524 objs->version, DSDB_EXTENDED_REPLICATED_OBJECTS_VERSION);
6525 return LDB_ERR_PROTOCOL_ERROR;
6528 ar = replmd_ctx_init(module, req);
6530 return LDB_ERR_OPERATIONS_ERROR;
6532 /* Set the flags to have the replmd_op_callback run over the full set of objects */
6533 ar->apply_mode = true;
6535 ar->schema = dsdb_get_schema(ldb, ar);
6537 ldb_debug_set(ldb, LDB_DEBUG_FATAL, "replmd_ctx_init: no loaded schema found\n");
6539 DEBUG(0,(__location__ ": %s\n", ldb_errstring(ldb)));
6540 return LDB_ERR_CONSTRAINT_VIOLATION;
6543 ctrls = req->controls;
6545 if (req->controls) {
6546 req->controls = talloc_memdup(ar, req->controls,
6547 talloc_get_size(req->controls));
6548 if (!req->controls) return replmd_replicated_request_werror(ar, WERR_NOT_ENOUGH_MEMORY);
6551 ret = ldb_request_add_control(req, DSDB_CONTROL_REPLICATED_UPDATE_OID, false, NULL);
6552 if (ret != LDB_SUCCESS) {
6556 /* If this change contained linked attributes in the body
6557 * (rather than in the links section) we need to update
6558 * backlinks in linked_attributes */
6559 ret = ldb_request_add_control(req, DSDB_CONTROL_APPLY_LINKS, false, NULL);
6560 if (ret != LDB_SUCCESS) {
6564 ar->controls = req->controls;
6565 req->controls = ctrls;
6567 DEBUG(4,("linked_attributes_count=%u\n", objs->linked_attributes_count));
6569 /* save away the linked attributes for the end of the
6571 for (i=0; i<ar->objs->linked_attributes_count; i++) {
6572 struct la_entry *la_entry;
6574 if (replmd_private->la_ctx == NULL) {
6575 replmd_private->la_ctx = talloc_new(replmd_private);
6577 la_entry = talloc(replmd_private->la_ctx, struct la_entry);
6578 if (la_entry == NULL) {
6580 return LDB_ERR_OPERATIONS_ERROR;
6582 la_entry->la = talloc(la_entry, struct drsuapi_DsReplicaLinkedAttribute);
6583 if (la_entry->la == NULL) {
6584 talloc_free(la_entry);
6586 return LDB_ERR_OPERATIONS_ERROR;
6588 *la_entry->la = ar->objs->linked_attributes[i];
6590 /* we need to steal the non-scalars so they stay
6591 around until the end of the transaction */
6592 talloc_steal(la_entry->la, la_entry->la->identifier);
6593 talloc_steal(la_entry->la, la_entry->la->value.blob);
6595 DLIST_ADD(replmd_private->la_list, la_entry);
6598 return replmd_replicated_apply_next(ar);
6602 process one linked attribute structure
6604 static int replmd_process_linked_attribute(struct ldb_module *module,
6605 struct replmd_private *replmd_private,
6606 struct la_entry *la_entry,
6607 struct ldb_request *parent)
6609 struct drsuapi_DsReplicaLinkedAttribute *la = la_entry->la;
6610 struct ldb_context *ldb = ldb_module_get_ctx(module);
6611 struct ldb_message *msg;
6612 struct ldb_message *target_msg = NULL;
6613 TALLOC_CTX *tmp_ctx = talloc_new(la_entry);
6614 const struct dsdb_schema *schema = dsdb_get_schema(ldb, tmp_ctx);
6616 const struct dsdb_attribute *attr;
6617 struct dsdb_dn *dsdb_dn;
6618 uint64_t seq_num = 0;
6619 struct ldb_message_element *old_el;
6621 time_t t = time(NULL);
6622 struct ldb_result *res;
6623 struct ldb_result *target_res;
6624 const char *attrs[4];
6625 const char *attrs2[] = { "isDeleted", "isRecycled", NULL };
6626 struct parsed_dn *pdn_list, *pdn, *next;
6627 struct GUID guid = GUID_zero();
6629 bool active = (la->flags & DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE)?true:false;
6631 enum deletion_state deletion_state = OBJECT_NOT_DELETED;
6632 enum deletion_state target_deletion_state = OBJECT_NOT_DELETED;
6635 linked_attributes[0]:
6636 &objs->linked_attributes[i]: struct drsuapi_DsReplicaLinkedAttribute
6638 identifier: struct drsuapi_DsReplicaObjectIdentifier
6639 __ndr_size : 0x0000003a (58)
6640 __ndr_size_sid : 0x00000000 (0)
6641 guid : 8e95b6a9-13dd-4158-89db-3220a5be5cc7
6643 __ndr_size_dn : 0x00000000 (0)
6645 attid : DRSUAPI_ATTID_member (0x1F)
6646 value: struct drsuapi_DsAttributeValue
6647 __ndr_size : 0x0000007e (126)
6649 blob : DATA_BLOB length=126
6650 flags : 0x00000001 (1)
6651 1: DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE
6652 originating_add_time : Wed Sep 2 22:20:01 2009 EST
6653 meta_data: struct drsuapi_DsReplicaMetaData
6654 version : 0x00000015 (21)
6655 originating_change_time : Wed Sep 2 23:39:07 2009 EST
6656 originating_invocation_id: 794640f3-18cf-40ee-a211-a93992b67a64
6657 originating_usn : 0x000000000001e19c (123292)
6659 (for cases where the link is to a normal DN)
6660 &target: struct drsuapi_DsReplicaObjectIdentifier3
6661 __ndr_size : 0x0000007e (126)
6662 __ndr_size_sid : 0x0000001c (28)
6663 guid : 7639e594-db75-4086-b0d4-67890ae46031
6664 sid : S-1-5-21-2848215498-2472035911-1947525656-19924
6665 __ndr_size_dn : 0x00000022 (34)
6666 dn : 'CN=UOne,OU=TestOU,DC=vsofs8,DC=com'
6669 /* find the attribute being modified */
6670 attr = dsdb_attribute_by_attributeID_id(schema, la->attid);
6672 struct GUID_txt_buf guid_str;
6673 ldb_asprintf_errstring(ldb, "Unable to find attributeID 0x%x for link on <GUID=%s>",
6675 GUID_buf_string(&la->identifier->guid,
6677 talloc_free(tmp_ctx);
6678 return LDB_ERR_OPERATIONS_ERROR;
6681 attrs[0] = attr->lDAPDisplayName;
6682 attrs[1] = "isDeleted";
6683 attrs[2] = "isRecycled";
6686 /* get the existing message from the db for the object with
6687 this GUID, returning attribute being modified. We will then
6688 use this msg as the basis for a modify call */
6689 ret = dsdb_module_search(module, tmp_ctx, &res, NULL, LDB_SCOPE_SUBTREE, attrs,
6690 DSDB_FLAG_NEXT_MODULE |
6691 DSDB_SEARCH_SEARCH_ALL_PARTITIONS |
6692 DSDB_SEARCH_SHOW_RECYCLED |
6693 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT |
6694 DSDB_SEARCH_REVEAL_INTERNALS,
6696 "objectGUID=%s", GUID_string(tmp_ctx, &la->identifier->guid));
6697 if (ret != LDB_SUCCESS) {
6698 talloc_free(tmp_ctx);
6701 if (res->count != 1) {
6702 ldb_asprintf_errstring(ldb, "DRS linked attribute for GUID %s - DN not found",
6703 GUID_string(tmp_ctx, &la->identifier->guid));
6704 talloc_free(tmp_ctx);
6705 return LDB_ERR_NO_SUCH_OBJECT;
6710 * Check for deleted objects per MS-DRSR 4.1.10.6.13
6711 * ProcessLinkValue, because link updates are not applied to
6712 * recycled and tombstone objects. We don't have to delete
6713 * any existing link, that should have happened when the
6714 * object deletion was replicated or initiated.
6717 replmd_deletion_state(module, msg, &deletion_state, NULL);
6719 if (deletion_state >= OBJECT_RECYCLED) {
6720 talloc_free(tmp_ctx);
6724 old_el = ldb_msg_find_element(msg, attr->lDAPDisplayName);
6725 if (old_el == NULL) {
6726 ret = ldb_msg_add_empty(msg, attr->lDAPDisplayName, LDB_FLAG_MOD_REPLACE, &old_el);
6727 if (ret != LDB_SUCCESS) {
6728 ldb_module_oom(module);
6729 talloc_free(tmp_ctx);
6730 return LDB_ERR_OPERATIONS_ERROR;
6733 old_el->flags = LDB_FLAG_MOD_REPLACE;
6736 /* parse the existing links */
6737 ret = get_parsed_dns_trusted(module, replmd_private, tmp_ctx, old_el, &pdn_list,
6738 attr->syntax->ldap_oid, parent);
6740 if (ret != LDB_SUCCESS) {
6741 talloc_free(tmp_ctx);
6745 status = dsdb_dn_la_from_blob(ldb, attr, schema, tmp_ctx, la->value.blob, &dsdb_dn);
6746 if (!W_ERROR_IS_OK(status)) {
6747 ldb_asprintf_errstring(ldb, "Failed to parsed linked attribute blob for %s on %s - %s\n",
6748 old_el->name, ldb_dn_get_linearized(msg->dn), win_errstr(status));
6749 talloc_free(tmp_ctx);
6750 return LDB_ERR_OPERATIONS_ERROR;
6753 ntstatus = dsdb_get_extended_dn_guid(dsdb_dn->dn, &guid, "GUID");
6754 if (!NT_STATUS_IS_OK(ntstatus) && !active) {
6756 * This strange behaviour (allowing a NULL/missing
6757 * GUID) originally comes from:
6759 * commit e3054ce0fe0f8f62d2f5b2a77893e7a1479128bd
6760 * Author: Andrew Tridgell <tridge@samba.org>
6761 * Date: Mon Dec 21 21:21:55 2009 +1100
6763 * s4-drs: cope better with NULL GUIDS from DRS
6765 * It is valid to get a NULL GUID over DRS for a deleted forward link. We
6766 * need to match by DN if possible when seeing if we should update an
6769 * Pair-Programmed-With: Andrew Bartlett <abartlet@samba.org>
6772 ret = dsdb_module_search_dn(module, tmp_ctx, &target_res,
6773 dsdb_dn->dn, attrs2,
6774 DSDB_FLAG_NEXT_MODULE |
6775 DSDB_SEARCH_SHOW_RECYCLED |
6776 DSDB_SEARCH_SEARCH_ALL_PARTITIONS |
6777 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT,
6779 } else if (!NT_STATUS_IS_OK(ntstatus)) {
6780 ldb_asprintf_errstring(ldb, "Failed to find GUID in linked attribute blob for %s on %s from %s",
6782 ldb_dn_get_linearized(dsdb_dn->dn),
6783 ldb_dn_get_linearized(msg->dn));
6784 talloc_free(tmp_ctx);
6785 return LDB_ERR_OPERATIONS_ERROR;
6787 ret = dsdb_module_search(module, tmp_ctx, &target_res,
6788 NULL, LDB_SCOPE_SUBTREE,
6790 DSDB_FLAG_NEXT_MODULE |
6791 DSDB_SEARCH_SHOW_RECYCLED |
6792 DSDB_SEARCH_SEARCH_ALL_PARTITIONS |
6793 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT,
6796 GUID_string(tmp_ctx, &guid));
6799 if (ret != LDB_SUCCESS) {
6800 ldb_asprintf_errstring(ldb_module_get_ctx(module), "Failed to re-resolve GUID %s: %s\n",
6801 GUID_string(tmp_ctx, &guid),
6802 ldb_errstring(ldb_module_get_ctx(module)));
6803 talloc_free(tmp_ctx);
6807 if (target_res->count == 0) {
6808 DEBUG(2,(__location__ ": WARNING: Failed to re-resolve GUID %s - using %s\n",
6809 GUID_string(tmp_ctx, &guid),
6810 ldb_dn_get_linearized(dsdb_dn->dn)));
6811 } else if (target_res->count != 1) {
6812 ldb_asprintf_errstring(ldb_module_get_ctx(module), "More than one object found matching objectGUID %s\n",
6813 GUID_string(tmp_ctx, &guid));
6814 talloc_free(tmp_ctx);
6815 return LDB_ERR_OPERATIONS_ERROR;
6817 target_msg = target_res->msgs[0];
6818 dsdb_dn->dn = talloc_steal(dsdb_dn, target_msg->dn);
6822 * Check for deleted objects per MS-DRSR 4.1.10.6.13
6823 * ProcessLinkValue, because link updates are not applied to
6824 * recycled and tombstone objects. We don't have to delete
6825 * any existing link, that should have happened when the
6826 * object deletion was replicated or initiated.
6828 replmd_deletion_state(module, target_msg,
6829 &target_deletion_state, NULL);
6831 if (target_deletion_state >= OBJECT_RECYCLED) {
6832 talloc_free(tmp_ctx);
6836 /* see if this link already exists */
6837 ret = parsed_dn_find(ldb, pdn_list, old_el->num_values,
6840 dsdb_dn->extra_part, 0,
6842 attr->syntax->ldap_oid,
6844 if (ret != LDB_SUCCESS) {
6845 talloc_free(tmp_ctx);
6851 /* see if this update is newer than what we have already */
6852 struct GUID invocation_id = GUID_zero();
6853 uint32_t version = 0;
6854 uint32_t originating_usn = 0;
6855 NTTIME change_time = 0;
6856 uint32_t rmd_flags = dsdb_dn_rmd_flags(pdn->dsdb_dn->dn);
6858 dsdb_get_extended_dn_guid(pdn->dsdb_dn->dn, &invocation_id, "RMD_INVOCID");
6859 dsdb_get_extended_dn_uint32(pdn->dsdb_dn->dn, &version, "RMD_VERSION");
6860 dsdb_get_extended_dn_uint32(pdn->dsdb_dn->dn, &originating_usn, "RMD_ORIGINATING_USN");
6861 dsdb_get_extended_dn_nttime(pdn->dsdb_dn->dn, &change_time, "RMD_CHANGETIME");
6863 if (!replmd_update_is_newer(&invocation_id,
6864 &la->meta_data.originating_invocation_id,
6866 la->meta_data.version,
6868 la->meta_data.originating_change_time)) {
6869 DEBUG(3,("Discarding older DRS linked attribute update to %s on %s from %s\n",
6870 old_el->name, ldb_dn_get_linearized(msg->dn),
6871 GUID_string(tmp_ctx, &la->meta_data.originating_invocation_id)));
6872 talloc_free(tmp_ctx);
6876 /* get a seq_num for this change */
6877 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &seq_num);
6878 if (ret != LDB_SUCCESS) {
6879 talloc_free(tmp_ctx);
6883 if (!(rmd_flags & DSDB_RMD_FLAG_DELETED)) {
6884 /* remove the existing backlink */
6885 ret = replmd_add_backlink(module, replmd_private,
6890 if (ret != LDB_SUCCESS) {
6891 talloc_free(tmp_ctx);
6896 ret = replmd_update_la_val(tmp_ctx, pdn->v, dsdb_dn, pdn->dsdb_dn,
6897 &la->meta_data.originating_invocation_id,
6898 la->meta_data.originating_usn, seq_num,
6899 la->meta_data.originating_change_time,
6900 la->meta_data.version,
6902 if (ret != LDB_SUCCESS) {
6903 talloc_free(tmp_ctx);
6908 /* add the new backlink */
6909 ret = replmd_add_backlink(module, replmd_private,
6914 if (ret != LDB_SUCCESS) {
6915 talloc_free(tmp_ctx);
6921 /* get a seq_num for this change */
6922 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &seq_num);
6923 if (ret != LDB_SUCCESS) {
6924 talloc_free(tmp_ctx);
6928 * We know where the new one needs to be, from the *next
6929 * pointer into pdn_list.
6932 offset = old_el->num_values;
6934 if (next->dsdb_dn == NULL) {
6935 ret = really_parse_trusted_dn(tmp_ctx, ldb, next,
6936 attr->syntax->ldap_oid);
6937 if (ret != LDB_SUCCESS) {
6941 offset = next - pdn_list;
6942 if (offset > old_el->num_values) {
6943 talloc_free(tmp_ctx);
6944 return LDB_ERR_OPERATIONS_ERROR;
6948 old_el->values = talloc_realloc(msg->elements, old_el->values,
6949 struct ldb_val, old_el->num_values+1);
6950 if (!old_el->values) {
6951 ldb_module_oom(module);
6952 return LDB_ERR_OPERATIONS_ERROR;
6955 if (offset != old_el->num_values) {
6956 memmove(&old_el->values[offset + 1], &old_el->values[offset],
6957 (old_el->num_values - offset) * sizeof(old_el->values[0]));
6960 old_el->num_values++;
6962 ret = replmd_build_la_val(tmp_ctx, &old_el->values[offset], dsdb_dn,
6963 &la->meta_data.originating_invocation_id,
6964 la->meta_data.originating_usn, seq_num,
6965 la->meta_data.originating_change_time,
6966 la->meta_data.version,
6968 if (ret != LDB_SUCCESS) {
6969 talloc_free(tmp_ctx);
6974 ret = replmd_add_backlink(module, replmd_private,
6979 if (ret != LDB_SUCCESS) {
6980 talloc_free(tmp_ctx);
6986 /* we only change whenChanged and uSNChanged if the seq_num
6988 ret = add_time_element(msg, "whenChanged", t);
6989 if (ret != LDB_SUCCESS) {
6990 talloc_free(tmp_ctx);
6995 ret = add_uint64_element(ldb, msg, "uSNChanged", seq_num);
6996 if (ret != LDB_SUCCESS) {
6997 talloc_free(tmp_ctx);
7002 old_el = ldb_msg_find_element(msg, attr->lDAPDisplayName);
7003 if (old_el == NULL) {
7004 talloc_free(tmp_ctx);
7005 return ldb_operr(ldb);
7008 ret = dsdb_check_single_valued_link(attr, old_el);
7009 if (ret != LDB_SUCCESS) {
7010 talloc_free(tmp_ctx);
7014 old_el->flags |= LDB_FLAG_INTERNAL_DISABLE_SINGLE_VALUE_CHECK;
7016 ret = linked_attr_modify(module, msg, parent);
7017 if (ret != LDB_SUCCESS) {
7018 ldb_debug(ldb, LDB_DEBUG_WARNING, "Failed to apply linked attribute change '%s'\n%s\n",
7020 ldb_ldif_message_string(ldb, tmp_ctx, LDB_CHANGETYPE_MODIFY, msg));
7021 talloc_free(tmp_ctx);
7025 talloc_free(tmp_ctx);
7030 static int replmd_extended(struct ldb_module *module, struct ldb_request *req)
7032 if (strcmp(req->op.extended.oid, DSDB_EXTENDED_REPLICATED_OBJECTS_OID) == 0) {
7033 return replmd_extended_replicated_objects(module, req);
7036 return ldb_next_request(module, req);
7041 we hook into the transaction operations to allow us to
7042 perform the linked attribute updates at the end of the whole
7043 transaction. This allows a forward linked attribute to be created
7044 before the object is created. During a vampire, w2k8 sends us linked
7045 attributes before the objects they are part of.
7047 static int replmd_start_transaction(struct ldb_module *module)
7049 /* create our private structure for this transaction */
7050 struct replmd_private *replmd_private = talloc_get_type(ldb_module_get_private(module),
7051 struct replmd_private);
7052 replmd_txn_cleanup(replmd_private);
7054 /* free any leftover mod_usn records from cancelled
7056 while (replmd_private->ncs) {
7057 struct nc_entry *e = replmd_private->ncs;
7058 DLIST_REMOVE(replmd_private->ncs, e);
7062 replmd_private->originating_updates = false;
7064 return ldb_next_start_trans(module);
7068 on prepare commit we loop over our queued la_context structures and
7071 static int replmd_prepare_commit(struct ldb_module *module)
7073 struct replmd_private *replmd_private =
7074 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
7075 struct la_entry *la, *prev;
7079 * Walk the list of linked attributes from DRS replication.
7081 * We walk backwards, to do the first entry first, as we
7082 * added the entries with DLIST_ADD() which puts them at the
7085 for (la = DLIST_TAIL(replmd_private->la_list); la; la=prev) {
7086 prev = DLIST_PREV(la);
7087 DLIST_REMOVE(replmd_private->la_list, la);
7088 ret = replmd_process_linked_attribute(module, replmd_private,
7090 if (ret != LDB_SUCCESS) {
7091 replmd_txn_cleanup(replmd_private);
7096 replmd_txn_cleanup(replmd_private);
7098 /* possibly change @REPLCHANGED */
7099 ret = replmd_notify_store(module, NULL);
7100 if (ret != LDB_SUCCESS) {
7104 return ldb_next_prepare_commit(module);
7107 static int replmd_del_transaction(struct ldb_module *module)
7109 struct replmd_private *replmd_private =
7110 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
7111 replmd_txn_cleanup(replmd_private);
7113 return ldb_next_del_trans(module);
7117 static const struct ldb_module_ops ldb_repl_meta_data_module_ops = {
7118 .name = "repl_meta_data",
7119 .init_context = replmd_init,
7121 .modify = replmd_modify,
7122 .rename = replmd_rename,
7123 .del = replmd_delete,
7124 .extended = replmd_extended,
7125 .start_transaction = replmd_start_transaction,
7126 .prepare_commit = replmd_prepare_commit,
7127 .del_transaction = replmd_del_transaction,
7130 int ldb_repl_meta_data_module_init(const char *version)
7132 LDB_MODULE_CHECK_VERSION(version);
7133 return ldb_register_module(&ldb_repl_meta_data_module_ops);