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 parsed_dn_compare(struct parsed_dn *pdn1, struct parsed_dn *pdn2);
891 static int get_parsed_dns(struct ldb_module *module, TALLOC_CTX *mem_ctx,
892 struct ldb_message_element *el, struct parsed_dn **pdn,
893 const char *ldap_oid, struct ldb_request *parent);
896 fix up linked attributes in replmd_add.
897 This involves setting up the right meta-data in extended DN
898 components, and creating backlinks to the object
900 static int replmd_add_fix_la(struct ldb_module *module, TALLOC_CTX *mem_ctx,
901 struct replmd_private *replmd_private,
902 struct ldb_message_element *el,
903 struct replmd_replicated_request *ac,
905 struct ldb_dn *forward_dn,
906 const struct dsdb_attribute *sa,
907 struct ldb_request *parent)
910 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
911 struct ldb_context *ldb = ldb_module_get_ctx(module);
912 struct parsed_dn *pdn;
913 /* We will take a reference to the schema in replmd_add_backlink */
914 const struct dsdb_schema *schema = dsdb_get_schema(ldb, NULL);
915 struct ldb_val *new_values = NULL;
918 if (dsdb_check_single_valued_link(sa, el) == LDB_SUCCESS) {
919 el->flags |= LDB_FLAG_INTERNAL_DISABLE_SINGLE_VALUE_CHECK;
921 ldb_asprintf_errstring(ldb,
922 "Attribute %s is single valued but "
923 "more than one value has been supplied",
925 talloc_free(tmp_ctx);
926 return LDB_ERR_CONSTRAINT_VIOLATION;
929 ret = get_parsed_dns(module, tmp_ctx, el, &pdn,
930 sa->syntax->ldap_oid, parent);
931 if (ret != LDB_SUCCESS) {
932 talloc_free(tmp_ctx);
936 new_values = talloc_array(tmp_ctx, struct ldb_val, el->num_values);
937 if (new_values == NULL) {
938 ldb_module_oom(module);
939 talloc_free(tmp_ctx);
940 return LDB_ERR_OPERATIONS_ERROR;
943 for (i = 0; i < el->num_values; i++) {
944 struct parsed_dn *p = &pdn[i];
945 if (i > 0 && parsed_dn_compare(p, &pdn[i - 1]) == 0) {
946 ldb_asprintf_errstring(ldb,
947 "Linked attribute %s has "
948 "multiple identical values", el->name);
949 talloc_free(tmp_ctx);
950 return LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS;
952 ret = replmd_build_la_val(el->values, p->v, p->dsdb_dn,
953 &ac->our_invocation_id,
954 ac->seq_num, ac->seq_num, now, 0, false);
955 if (ret != LDB_SUCCESS) {
956 talloc_free(tmp_ctx);
960 ret = replmd_defer_add_backlink(module, replmd_private,
962 forward_dn, &p->guid, true, sa,
964 if (ret != LDB_SUCCESS) {
965 talloc_free(tmp_ctx);
969 new_values[i] = *p->v;
971 el->values = talloc_steal(mem_ctx, new_values);
973 talloc_free(tmp_ctx);
977 static int replmd_add_make_extended_dn(struct ldb_request *req,
978 const DATA_BLOB *guid_blob,
979 struct ldb_dn **_extended_dn)
982 const DATA_BLOB *sid_blob;
983 /* Calculate an extended DN for any linked attributes */
984 struct ldb_dn *extended_dn = ldb_dn_copy(req, req->op.add.message->dn);
986 return LDB_ERR_OPERATIONS_ERROR;
988 ret = ldb_dn_set_extended_component(extended_dn, "GUID", guid_blob);
989 if (ret != LDB_SUCCESS) {
993 sid_blob = ldb_msg_find_ldb_val(req->op.add.message, "objectSID");
994 if (sid_blob != NULL) {
995 ret = ldb_dn_set_extended_component(extended_dn, "SID", sid_blob);
996 if (ret != LDB_SUCCESS) {
1000 *_extended_dn = extended_dn;
1005 intercept add requests
1007 static int replmd_add(struct ldb_module *module, struct ldb_request *req)
1009 struct ldb_context *ldb;
1010 struct ldb_control *control;
1011 struct replmd_replicated_request *ac;
1012 enum ndr_err_code ndr_err;
1013 struct ldb_request *down_req;
1014 struct ldb_message *msg;
1015 const DATA_BLOB *guid_blob;
1016 DATA_BLOB guid_blob_stack;
1018 uint8_t guid_data[16];
1019 struct replPropertyMetaDataBlob nmd;
1020 struct ldb_val nmd_value;
1021 struct ldb_dn *extended_dn = NULL;
1024 * The use of a time_t here seems odd, but as the NTTIME
1025 * elements are actually declared as NTTIME_1sec in the IDL,
1026 * getting a higher resolution timestamp is not required.
1028 time_t t = time(NULL);
1033 unsigned int functional_level;
1035 bool allow_add_guid = false;
1036 bool remove_current_guid = false;
1037 bool is_urgent = false;
1038 bool is_schema_nc = false;
1039 struct ldb_message_element *objectclass_el;
1040 struct replmd_private *replmd_private =
1041 talloc_get_type_abort(ldb_module_get_private(module), struct replmd_private);
1043 /* check if there's a show relax control (used by provision to say 'I know what I'm doing') */
1044 control = ldb_request_get_control(req, LDB_CONTROL_RELAX_OID);
1046 allow_add_guid = true;
1049 /* do not manipulate our control entries */
1050 if (ldb_dn_is_special(req->op.add.message->dn)) {
1051 return ldb_next_request(module, req);
1054 ldb = ldb_module_get_ctx(module);
1056 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_add\n");
1058 guid_blob = ldb_msg_find_ldb_val(req->op.add.message, "objectGUID");
1059 if (guid_blob != NULL) {
1060 if (!allow_add_guid) {
1061 ldb_set_errstring(ldb,
1062 "replmd_add: it's not allowed to add an object with objectGUID!");
1063 return LDB_ERR_UNWILLING_TO_PERFORM;
1065 NTSTATUS status = GUID_from_data_blob(guid_blob,&guid);
1066 if (!NT_STATUS_IS_OK(status)) {
1067 ldb_set_errstring(ldb,
1068 "replmd_add: Unable to parse the 'objectGUID' as a GUID!");
1069 return LDB_ERR_UNWILLING_TO_PERFORM;
1071 /* we remove this attribute as it can be a string and
1072 * will not be treated correctly and then we will re-add
1073 * it later on in the good format */
1074 remove_current_guid = true;
1078 guid = GUID_random();
1080 guid_blob_stack = data_blob_const(guid_data, sizeof(guid_data));
1082 /* This can't fail */
1083 ndr_push_struct_into_fixed_blob(&guid_blob_stack, &guid,
1084 (ndr_push_flags_fn_t)ndr_push_GUID);
1085 guid_blob = &guid_blob_stack;
1088 ac = replmd_ctx_init(module, req);
1090 return ldb_module_oom(module);
1093 functional_level = dsdb_functional_level(ldb);
1095 /* Get a sequence number from the backend */
1096 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &ac->seq_num);
1097 if (ret != LDB_SUCCESS) {
1102 /* we have to copy the message as the caller might have it as a const */
1103 msg = ldb_msg_copy_shallow(ac, req->op.add.message);
1107 return LDB_ERR_OPERATIONS_ERROR;
1110 /* generated times */
1111 unix_to_nt_time(&now, t);
1112 time_str = ldb_timestring(msg, t);
1116 return LDB_ERR_OPERATIONS_ERROR;
1118 if (remove_current_guid) {
1119 ldb_msg_remove_attr(msg,"objectGUID");
1123 * remove autogenerated attributes
1125 ldb_msg_remove_attr(msg, "whenCreated");
1126 ldb_msg_remove_attr(msg, "whenChanged");
1127 ldb_msg_remove_attr(msg, "uSNCreated");
1128 ldb_msg_remove_attr(msg, "uSNChanged");
1129 ldb_msg_remove_attr(msg, "replPropertyMetaData");
1132 * readd replicated attributes
1134 ret = ldb_msg_add_string(msg, "whenCreated", time_str);
1135 if (ret != LDB_SUCCESS) {
1141 /* build the replication meta_data */
1144 nmd.ctr.ctr1.count = msg->num_elements;
1145 nmd.ctr.ctr1.array = talloc_array(msg,
1146 struct replPropertyMetaData1,
1147 nmd.ctr.ctr1.count);
1148 if (!nmd.ctr.ctr1.array) {
1151 return LDB_ERR_OPERATIONS_ERROR;
1154 is_schema_nc = ldb_dn_compare_base(replmd_private->schema_dn, msg->dn) == 0;
1156 for (i=0; i < msg->num_elements;) {
1157 struct ldb_message_element *e = &msg->elements[i];
1158 struct replPropertyMetaData1 *m = &nmd.ctr.ctr1.array[ni];
1159 const struct dsdb_attribute *sa;
1161 if (e->name[0] == '@') {
1166 sa = dsdb_attribute_by_lDAPDisplayName(ac->schema, e->name);
1168 ldb_debug_set(ldb, LDB_DEBUG_ERROR,
1169 "replmd_add: attribute '%s' not defined in schema\n",
1172 return LDB_ERR_NO_SUCH_ATTRIBUTE;
1175 if ((sa->systemFlags & DS_FLAG_ATTR_NOT_REPLICATED) || (sa->systemFlags & DS_FLAG_ATTR_IS_CONSTRUCTED)) {
1176 /* if the attribute is not replicated (0x00000001)
1177 * or constructed (0x00000004) it has no metadata
1183 if (sa->linkID != 0 && functional_level > DS_DOMAIN_FUNCTION_2000) {
1184 if (extended_dn == NULL) {
1185 ret = replmd_add_make_extended_dn(req,
1188 if (ret != LDB_SUCCESS) {
1195 * Prepare the context for the backlinks and
1196 * create metadata for the forward links. The
1197 * backlinks are created in
1198 * replmd_op_callback() after the successful
1199 * ADD of the object.
1201 ret = replmd_add_fix_la(module, msg->elements,
1206 if (ret != LDB_SUCCESS) {
1210 /* linked attributes are not stored in
1211 replPropertyMetaData in FL above w2k */
1216 m->attid = dsdb_attribute_get_attid(sa, is_schema_nc);
1218 if (m->attid == DRSUAPI_ATTID_isDeleted) {
1219 const struct ldb_val *rdn_val = ldb_dn_get_rdn_val(msg->dn);
1222 if (rdn_val == NULL) {
1225 return LDB_ERR_OPERATIONS_ERROR;
1228 rdn = (const char*)rdn_val->data;
1229 if (strcmp(rdn, "Deleted Objects") == 0) {
1231 * Set the originating_change_time to 29/12/9999 at 23:59:59
1232 * as specified in MS-ADTS 7.1.1.4.2 Deleted Objects Container
1234 m->originating_change_time = DELETED_OBJECT_CONTAINER_CHANGE_TIME;
1236 m->originating_change_time = now;
1239 m->originating_change_time = now;
1241 m->originating_invocation_id = ac->our_invocation_id;
1242 m->originating_usn = ac->seq_num;
1243 m->local_usn = ac->seq_num;
1246 if (!(e->flags & DSDB_FLAG_INTERNAL_FORCE_META_DATA)) {
1251 e->flags &= ~DSDB_FLAG_INTERNAL_FORCE_META_DATA;
1253 if (e->num_values != 0) {
1258 ldb_msg_remove_element(msg, e);
1261 /* fix meta data count */
1262 nmd.ctr.ctr1.count = ni;
1265 * sort meta data array
1267 ret = replmd_replPropertyMetaDataCtr1_sort_and_verify(ldb, &nmd.ctr.ctr1, msg->dn);
1268 if (ret != LDB_SUCCESS) {
1269 ldb_asprintf_errstring(ldb, "%s: error during direct ADD: %s", __func__, ldb_errstring(ldb));
1274 /* generated NDR encoded values */
1275 ndr_err = ndr_push_struct_blob(&nmd_value, msg,
1277 (ndr_push_flags_fn_t)ndr_push_replPropertyMetaDataBlob);
1278 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1281 return LDB_ERR_OPERATIONS_ERROR;
1285 * add the autogenerated values
1287 ret = dsdb_msg_add_guid(msg, &guid, "objectGUID");
1288 if (ret != LDB_SUCCESS) {
1293 ret = ldb_msg_add_string(msg, "whenChanged", time_str);
1294 if (ret != LDB_SUCCESS) {
1299 ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNCreated", ac->seq_num);
1300 if (ret != LDB_SUCCESS) {
1305 ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNChanged", ac->seq_num);
1306 if (ret != LDB_SUCCESS) {
1311 ret = ldb_msg_add_value(msg, "replPropertyMetaData", &nmd_value, NULL);
1312 if (ret != LDB_SUCCESS) {
1319 * sort the attributes by attid before storing the object
1321 replmd_ldb_message_sort(msg, ac->schema);
1324 * Assert that we do have an objectClass
1326 objectclass_el = ldb_msg_find_element(msg, "objectClass");
1327 if (objectclass_el == NULL) {
1328 ldb_asprintf_errstring(ldb, __location__
1329 ": objectClass missing on %s\n",
1330 ldb_dn_get_linearized(msg->dn));
1332 return LDB_ERR_OBJECT_CLASS_VIOLATION;
1334 is_urgent = replmd_check_urgent_objectclass(objectclass_el,
1335 REPL_URGENT_ON_CREATE);
1337 ac->is_urgent = is_urgent;
1338 ret = ldb_build_add_req(&down_req, ldb, ac,
1341 ac, replmd_op_callback,
1344 LDB_REQ_SET_LOCATION(down_req);
1345 if (ret != LDB_SUCCESS) {
1350 /* current partition control is needed by "replmd_op_callback" */
1351 if (ldb_request_get_control(req, DSDB_CONTROL_CURRENT_PARTITION_OID) == NULL) {
1352 ret = ldb_request_add_control(down_req,
1353 DSDB_CONTROL_CURRENT_PARTITION_OID,
1355 if (ret != LDB_SUCCESS) {
1361 if (functional_level == DS_DOMAIN_FUNCTION_2000) {
1362 ret = ldb_request_add_control(down_req, DSDB_CONTROL_APPLY_LINKS, false, NULL);
1363 if (ret != LDB_SUCCESS) {
1369 /* mark the control done */
1371 control->critical = 0;
1373 /* go on with the call chain */
1374 return ldb_next_request(module, down_req);
1379 * update the replPropertyMetaData for one element
1381 static int replmd_update_rpmd_element(struct ldb_context *ldb,
1382 struct ldb_message *msg,
1383 struct ldb_message_element *el,
1384 struct ldb_message_element *old_el,
1385 struct replPropertyMetaDataBlob *omd,
1386 const struct dsdb_schema *schema,
1388 const struct GUID *our_invocation_id,
1391 bool is_forced_rodc,
1392 struct ldb_request *req)
1395 const struct dsdb_attribute *a;
1396 struct replPropertyMetaData1 *md1;
1397 bool may_skip = false;
1400 a = dsdb_attribute_by_lDAPDisplayName(schema, el->name);
1402 if (ldb_request_get_control(req, LDB_CONTROL_RELAX_OID)) {
1403 /* allow this to make it possible for dbcheck
1404 to remove bad attributes */
1408 DEBUG(0,(__location__ ": Unable to find attribute %s in schema\n",
1410 return LDB_ERR_OPERATIONS_ERROR;
1413 attid = dsdb_attribute_get_attid(a, is_schema_nc);
1415 if ((a->systemFlags & DS_FLAG_ATTR_NOT_REPLICATED) || (a->systemFlags & DS_FLAG_ATTR_IS_CONSTRUCTED)) {
1420 * if the attribute's value haven't changed, and this isn't
1421 * just a delete of everything then return LDB_SUCCESS Unless
1422 * we have the provision control or if the attribute is
1423 * interSiteTopologyGenerator as this page explain:
1424 * http://support.microsoft.com/kb/224815 this attribute is
1425 * periodicaly written by the DC responsible for the intersite
1426 * generation in a given site
1428 * Unchanged could be deleting or replacing an already-gone
1429 * thing with an unconstrained delete/empty replace or a
1430 * replace with the same value, but not an add with the same
1431 * value because that could be about adding a duplicate (which
1432 * is for someone else to error out on).
1434 if (old_el != NULL && ldb_msg_element_equal_ordered(el, old_el)) {
1435 if (LDB_FLAG_MOD_TYPE(el->flags) == LDB_FLAG_MOD_REPLACE) {
1438 } else if (old_el == NULL && el->num_values == 0) {
1439 if (LDB_FLAG_MOD_TYPE(el->flags) == LDB_FLAG_MOD_REPLACE) {
1441 } else if (LDB_FLAG_MOD_TYPE(el->flags) == LDB_FLAG_MOD_DELETE) {
1444 } else if (a->linkID != 0 && LDB_FLAG_MOD_TYPE(el->flags) == LDB_FLAG_MOD_DELETE &&
1445 ldb_request_get_control(req, DSDB_CONTROL_REPLMD_VANISH_LINKS) != NULL) {
1447 * We intentionally skip the version bump when attempting to
1450 * The control is set by dbcheck and expunge-tombstones which
1451 * both attempt to be non-replicating. Otherwise, making an
1452 * alteration to the replication state would trigger a
1453 * broadcast of all expunged objects.
1458 if (el->flags & DSDB_FLAG_INTERNAL_FORCE_META_DATA) {
1460 el->flags &= ~DSDB_FLAG_INTERNAL_FORCE_META_DATA;
1464 if (strcmp(el->name, "interSiteTopologyGenerator") != 0 &&
1465 !ldb_request_get_control(req, LDB_CONTROL_PROVISION_OID)) {
1467 * allow this to make it possible for dbcheck
1468 * to rebuild broken metadata
1474 for (i=0; i<omd->ctr.ctr1.count; i++) {
1476 * First check if we find it under the msDS-IntID,
1477 * then check if we find it under the OID and
1480 * This allows the administrator to simply re-write
1481 * the attributes and so restore replication, which is
1482 * likely what they will try to do.
1484 if (attid == omd->ctr.ctr1.array[i].attid) {
1488 if (a->attributeID_id == omd->ctr.ctr1.array[i].attid) {
1493 if (a->linkID != 0 && dsdb_functional_level(ldb) > DS_DOMAIN_FUNCTION_2000) {
1494 /* linked attributes are not stored in
1495 replPropertyMetaData in FL above w2k, but we do
1496 raise the seqnum for the object */
1497 if (*seq_num == 0 &&
1498 ldb_sequence_number(ldb, LDB_SEQ_NEXT, seq_num) != LDB_SUCCESS) {
1499 return LDB_ERR_OPERATIONS_ERROR;
1504 if (i == omd->ctr.ctr1.count) {
1505 /* we need to add a new one */
1506 omd->ctr.ctr1.array = talloc_realloc(msg, omd->ctr.ctr1.array,
1507 struct replPropertyMetaData1, omd->ctr.ctr1.count+1);
1508 if (omd->ctr.ctr1.array == NULL) {
1510 return LDB_ERR_OPERATIONS_ERROR;
1512 omd->ctr.ctr1.count++;
1513 ZERO_STRUCT(omd->ctr.ctr1.array[i]);
1516 /* Get a new sequence number from the backend. We only do this
1517 * if we have a change that requires a new
1518 * replPropertyMetaData element
1520 if (*seq_num == 0) {
1521 int ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, seq_num);
1522 if (ret != LDB_SUCCESS) {
1523 return LDB_ERR_OPERATIONS_ERROR;
1527 md1 = &omd->ctr.ctr1.array[i];
1531 if (md1->attid == DRSUAPI_ATTID_isDeleted) {
1532 const struct ldb_val *rdn_val = ldb_dn_get_rdn_val(msg->dn);
1535 if (rdn_val == NULL) {
1537 return LDB_ERR_OPERATIONS_ERROR;
1540 rdn = (const char*)rdn_val->data;
1541 if (strcmp(rdn, "Deleted Objects") == 0) {
1543 * Set the originating_change_time to 29/12/9999 at 23:59:59
1544 * as specified in MS-ADTS 7.1.1.4.2 Deleted Objects Container
1546 md1->originating_change_time = DELETED_OBJECT_CONTAINER_CHANGE_TIME;
1548 md1->originating_change_time = now;
1551 md1->originating_change_time = now;
1553 md1->originating_invocation_id = *our_invocation_id;
1554 md1->originating_usn = *seq_num;
1555 md1->local_usn = *seq_num;
1557 if (is_forced_rodc) {
1558 /* Force version to 0 to be overriden later via replication */
1566 * Bump the replPropertyMetaData version on an attribute, and if it
1567 * has changed (or forced by leaving rdn_old NULL), update the value
1570 * This is important, as calling a modify operation may not change the
1571 * version number if the values appear unchanged, but a rename between
1572 * parents bumps this value.
1575 static int replmd_update_rpmd_rdn_attr(struct ldb_context *ldb,
1576 struct ldb_message *msg,
1577 const struct ldb_val *rdn_new,
1578 const struct ldb_val *rdn_old,
1579 struct replPropertyMetaDataBlob *omd,
1580 struct replmd_replicated_request *ar,
1583 bool is_forced_rodc)
1585 const char *rdn_name = ldb_dn_get_rdn_name(msg->dn);
1586 const struct dsdb_attribute *rdn_attr =
1587 dsdb_attribute_by_lDAPDisplayName(ar->schema, rdn_name);
1588 const char *attr_name = rdn_attr != NULL ?
1589 rdn_attr->lDAPDisplayName :
1591 struct ldb_message_element new_el = {
1592 .flags = LDB_FLAG_MOD_REPLACE,
1595 .values = discard_const_p(struct ldb_val, rdn_new)
1597 struct ldb_message_element old_el = {
1598 .flags = LDB_FLAG_MOD_REPLACE,
1600 .num_values = rdn_old ? 1 : 0,
1601 .values = discard_const_p(struct ldb_val, rdn_old)
1604 if (ldb_msg_element_equal_ordered(&new_el, &old_el) == false) {
1605 int ret = ldb_msg_add(msg, &new_el, LDB_FLAG_MOD_REPLACE);
1606 if (ret != LDB_SUCCESS) {
1607 return ldb_oom(ldb);
1611 return replmd_update_rpmd_element(ldb, msg, &new_el, NULL,
1612 omd, ar->schema, &ar->seq_num,
1613 &ar->our_invocation_id,
1614 now, is_schema_nc, is_forced_rodc,
1619 static uint64_t find_max_local_usn(struct replPropertyMetaDataBlob omd)
1621 uint32_t count = omd.ctr.ctr1.count;
1624 for (i=0; i < count; i++) {
1625 struct replPropertyMetaData1 m = omd.ctr.ctr1.array[i];
1626 if (max < m.local_usn) {
1634 * update the replPropertyMetaData object each time we modify an
1635 * object. This is needed for DRS replication, as the merge on the
1636 * client is based on this object
1638 static int replmd_update_rpmd(struct ldb_module *module,
1639 const struct dsdb_schema *schema,
1640 struct ldb_request *req,
1641 const char * const *rename_attrs,
1642 struct ldb_message *msg, uint64_t *seq_num,
1643 time_t t, bool is_schema_nc,
1644 bool *is_urgent, bool *rodc)
1646 const struct ldb_val *omd_value;
1647 enum ndr_err_code ndr_err;
1648 struct replPropertyMetaDataBlob omd;
1651 const struct GUID *our_invocation_id;
1653 const char * const *attrs = NULL;
1654 const char * const attrs2[] = { "uSNChanged", "objectClass", "instanceType", NULL };
1655 struct ldb_result *res;
1656 struct ldb_context *ldb;
1657 struct ldb_message_element *objectclass_el;
1658 enum urgent_situation situation;
1659 bool rmd_is_provided;
1660 bool rmd_is_just_resorted = false;
1661 const char *not_rename_attrs[4 + msg->num_elements];
1662 bool is_forced_rodc = false;
1665 attrs = rename_attrs;
1667 for (i = 0; i < msg->num_elements; i++) {
1668 not_rename_attrs[i] = msg->elements[i].name;
1670 not_rename_attrs[i] = "replPropertyMetaData";
1671 not_rename_attrs[i+1] = "objectClass";
1672 not_rename_attrs[i+2] = "instanceType";
1673 not_rename_attrs[i+3] = NULL;
1674 attrs = not_rename_attrs;
1677 ldb = ldb_module_get_ctx(module);
1679 ret = samdb_rodc(ldb, rodc);
1680 if (ret != LDB_SUCCESS) {
1681 DEBUG(4, (__location__ ": unable to tell if we are an RODC\n"));
1686 ldb_request_get_control(req, DSDB_CONTROL_FORCE_RODC_LOCAL_CHANGE)) {
1687 is_forced_rodc = true;
1690 our_invocation_id = samdb_ntds_invocation_id(ldb);
1691 if (!our_invocation_id) {
1692 /* this happens during an initial vampire while
1693 updating the schema */
1694 DEBUG(5,("No invocationID - skipping replPropertyMetaData update\n"));
1698 unix_to_nt_time(&now, t);
1700 if (ldb_request_get_control(req, DSDB_CONTROL_CHANGEREPLMETADATA_OID)) {
1701 rmd_is_provided = true;
1702 if (ldb_request_get_control(req, DSDB_CONTROL_CHANGEREPLMETADATA_RESORT_OID)) {
1703 rmd_is_just_resorted = true;
1706 rmd_is_provided = false;
1709 /* if isDeleted is present and is TRUE, then we consider we are deleting,
1710 * otherwise we consider we are updating */
1711 if (ldb_msg_check_string_attribute(msg, "isDeleted", "TRUE")) {
1712 situation = REPL_URGENT_ON_DELETE;
1713 } else if (rename_attrs) {
1714 situation = REPL_URGENT_ON_CREATE | REPL_URGENT_ON_DELETE;
1716 situation = REPL_URGENT_ON_UPDATE;
1719 if (rmd_is_provided) {
1720 /* In this case the change_replmetadata control was supplied */
1721 /* We check that it's the only attribute that is provided
1722 * (it's a rare case so it's better to keep the code simplier)
1723 * We also check that the highest local_usn is bigger or the same as
1726 if( msg->num_elements != 1 ||
1727 strncmp(msg->elements[0].name,
1728 "replPropertyMetaData", 20) ) {
1729 DEBUG(0,(__location__ ": changereplmetada control called without "\
1730 "a specified replPropertyMetaData attribute or with others\n"));
1731 return LDB_ERR_OPERATIONS_ERROR;
1733 if (situation != REPL_URGENT_ON_UPDATE) {
1734 DEBUG(0,(__location__ ": changereplmetada control can't be called when deleting an object\n"));
1735 return LDB_ERR_OPERATIONS_ERROR;
1737 omd_value = ldb_msg_find_ldb_val(msg, "replPropertyMetaData");
1739 DEBUG(0,(__location__ ": replPropertyMetaData was not specified for Object %s\n",
1740 ldb_dn_get_linearized(msg->dn)));
1741 return LDB_ERR_OPERATIONS_ERROR;
1743 ndr_err = ndr_pull_struct_blob(omd_value, msg, &omd,
1744 (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
1745 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1746 DEBUG(0,(__location__ ": Failed to parse replPropertyMetaData for %s\n",
1747 ldb_dn_get_linearized(msg->dn)));
1748 return LDB_ERR_OPERATIONS_ERROR;
1751 ret = dsdb_module_search_dn(module, msg, &res, msg->dn, attrs2,
1752 DSDB_FLAG_NEXT_MODULE |
1753 DSDB_SEARCH_SHOW_RECYCLED |
1754 DSDB_SEARCH_SHOW_EXTENDED_DN |
1755 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT |
1756 DSDB_SEARCH_REVEAL_INTERNALS, req);
1758 if (ret != LDB_SUCCESS) {
1762 if (rmd_is_just_resorted == false) {
1763 *seq_num = find_max_local_usn(omd);
1765 db_seq = ldb_msg_find_attr_as_uint64(res->msgs[0], "uSNChanged", 0);
1768 * The test here now allows for a new
1769 * replPropertyMetaData with no change, if was
1770 * just dbcheck re-sorting the values.
1772 if (*seq_num <= db_seq) {
1773 DEBUG(0,(__location__ ": changereplmetada control provided but max(local_usn)" \
1774 " is less than uSNChanged (max = %lld uSNChanged = %lld)\n",
1775 (long long)*seq_num, (long long)db_seq));
1776 return LDB_ERR_OPERATIONS_ERROR;
1781 /* search for the existing replPropertyMetaDataBlob. We need
1782 * to use REVEAL and ask for DNs in storage format to support
1783 * the check for values being the same in
1784 * replmd_update_rpmd_element()
1786 ret = dsdb_module_search_dn(module, msg, &res, msg->dn, attrs,
1787 DSDB_FLAG_NEXT_MODULE |
1788 DSDB_SEARCH_SHOW_RECYCLED |
1789 DSDB_SEARCH_SHOW_EXTENDED_DN |
1790 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT |
1791 DSDB_SEARCH_REVEAL_INTERNALS, req);
1792 if (ret != LDB_SUCCESS) {
1796 omd_value = ldb_msg_find_ldb_val(res->msgs[0], "replPropertyMetaData");
1798 DEBUG(0,(__location__ ": Object %s does not have a replPropertyMetaData attribute\n",
1799 ldb_dn_get_linearized(msg->dn)));
1800 return LDB_ERR_OPERATIONS_ERROR;
1803 ndr_err = ndr_pull_struct_blob(omd_value, msg, &omd,
1804 (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
1805 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1806 DEBUG(0,(__location__ ": Failed to parse replPropertyMetaData for %s\n",
1807 ldb_dn_get_linearized(msg->dn)));
1808 return LDB_ERR_OPERATIONS_ERROR;
1811 if (omd.version != 1) {
1812 DEBUG(0,(__location__ ": bad version %u in replPropertyMetaData for %s\n",
1813 omd.version, ldb_dn_get_linearized(msg->dn)));
1814 return LDB_ERR_OPERATIONS_ERROR;
1817 for (i=0; i<msg->num_elements;) {
1818 struct ldb_message_element *el = &msg->elements[i];
1819 struct ldb_message_element *old_el;
1821 old_el = ldb_msg_find_element(res->msgs[0], el->name);
1822 ret = replmd_update_rpmd_element(ldb, msg, el, old_el,
1823 &omd, schema, seq_num,
1828 if (ret != LDB_SUCCESS) {
1832 if (!*is_urgent && (situation == REPL_URGENT_ON_UPDATE)) {
1833 *is_urgent = replmd_check_urgent_attribute(el);
1836 if (!(el->flags & DSDB_FLAG_INTERNAL_FORCE_META_DATA)) {
1841 el->flags &= ~DSDB_FLAG_INTERNAL_FORCE_META_DATA;
1843 if (el->num_values != 0) {
1848 ldb_msg_remove_element(msg, el);
1853 * Assert that we have an objectClass attribute - this is major
1854 * corruption if we don't have this!
1856 objectclass_el = ldb_msg_find_element(res->msgs[0], "objectClass");
1857 if (objectclass_el != NULL) {
1859 * Now check if this objectClass means we need to do urgent replication
1861 if (!*is_urgent && replmd_check_urgent_objectclass(objectclass_el,
1865 } else if (!ldb_request_get_control(req, DSDB_CONTROL_DBCHECK)) {
1866 ldb_asprintf_errstring(ldb, __location__
1867 ": objectClass missing on %s\n",
1868 ldb_dn_get_linearized(msg->dn));
1869 return LDB_ERR_OBJECT_CLASS_VIOLATION;
1873 * replmd_update_rpmd_element has done an update if the
1876 if (*seq_num != 0 || rmd_is_just_resorted == true) {
1877 struct ldb_val *md_value;
1878 struct ldb_message_element *el;
1880 /*if we are RODC and this is a DRSR update then its ok*/
1881 if (!ldb_request_get_control(req, DSDB_CONTROL_REPLICATED_UPDATE_OID)
1882 && !ldb_request_get_control(req, DSDB_CONTROL_DBCHECK_MODIFY_RO_REPLICA)
1883 && !is_forced_rodc) {
1884 unsigned instanceType;
1887 ldb_set_errstring(ldb, "RODC modify is forbidden!");
1888 return LDB_ERR_REFERRAL;
1891 instanceType = ldb_msg_find_attr_as_uint(res->msgs[0], "instanceType", INSTANCE_TYPE_WRITE);
1892 if (!(instanceType & INSTANCE_TYPE_WRITE)) {
1893 return ldb_error(ldb, LDB_ERR_UNWILLING_TO_PERFORM,
1894 "cannot change replicated attribute on partial replica");
1898 md_value = talloc(msg, struct ldb_val);
1899 if (md_value == NULL) {
1901 return LDB_ERR_OPERATIONS_ERROR;
1904 ret = replmd_replPropertyMetaDataCtr1_sort_and_verify(ldb, &omd.ctr.ctr1, msg->dn);
1905 if (ret != LDB_SUCCESS) {
1906 ldb_asprintf_errstring(ldb, "%s: %s", __func__, ldb_errstring(ldb));
1910 ndr_err = ndr_push_struct_blob(md_value, msg, &omd,
1911 (ndr_push_flags_fn_t)ndr_push_replPropertyMetaDataBlob);
1912 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1913 DEBUG(0,(__location__ ": Failed to marshall replPropertyMetaData for %s\n",
1914 ldb_dn_get_linearized(msg->dn)));
1915 return LDB_ERR_OPERATIONS_ERROR;
1918 ret = ldb_msg_add_empty(msg, "replPropertyMetaData", LDB_FLAG_MOD_REPLACE, &el);
1919 if (ret != LDB_SUCCESS) {
1920 DEBUG(0,(__location__ ": Failed to add updated replPropertyMetaData %s\n",
1921 ldb_dn_get_linearized(msg->dn)));
1926 el->values = md_value;
1932 static int parsed_dn_compare(struct parsed_dn *pdn1, struct parsed_dn *pdn2)
1934 int ret = ndr_guid_compare(&pdn1->guid, &pdn2->guid);
1936 return data_blob_cmp(&pdn1->dsdb_dn->extra_part,
1937 &pdn2->dsdb_dn->extra_part);
1943 get a series of message element values as an array of DNs and GUIDs
1944 the result is sorted by GUID
1946 static int get_parsed_dns(struct ldb_module *module, TALLOC_CTX *mem_ctx,
1947 struct ldb_message_element *el, struct parsed_dn **pdn,
1948 const char *ldap_oid, struct ldb_request *parent)
1951 bool values_are_sorted = true;
1952 struct ldb_context *ldb = ldb_module_get_ctx(module);
1959 (*pdn) = talloc_array(mem_ctx, struct parsed_dn, el->num_values);
1961 ldb_module_oom(module);
1962 return LDB_ERR_OPERATIONS_ERROR;
1965 for (i=0; i<el->num_values; i++) {
1966 struct ldb_val *v = &el->values[i];
1969 struct parsed_dn *p;
1973 p->dsdb_dn = dsdb_dn_parse(*pdn, ldb, v, ldap_oid);
1974 if (p->dsdb_dn == NULL) {
1975 return LDB_ERR_INVALID_DN_SYNTAX;
1978 dn = p->dsdb_dn->dn;
1980 status = dsdb_get_extended_dn_guid(dn, &p->guid, "GUID");
1981 if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND) ||
1982 unlikely(GUID_all_zero(&p->guid))) {
1983 /* we got a DN without a GUID - go find the GUID */
1984 int ret = dsdb_module_guid_by_dn(module, dn, &p->guid, parent);
1985 if (ret != LDB_SUCCESS) {
1986 ldb_asprintf_errstring(ldb, "Unable to find GUID for DN %s\n",
1987 ldb_dn_get_linearized(dn));
1988 if (ret == LDB_ERR_NO_SUCH_OBJECT &&
1989 LDB_FLAG_MOD_TYPE(el->flags) == LDB_FLAG_MOD_DELETE &&
1990 ldb_attr_cmp(el->name, "member") == 0) {
1991 return LDB_ERR_UNWILLING_TO_PERFORM;
1995 ret = dsdb_set_extended_dn_guid(dn, &p->guid, "GUID");
1996 if (ret != LDB_SUCCESS) {
1999 } else if (!NT_STATUS_IS_OK(status)) {
2000 return LDB_ERR_OPERATIONS_ERROR;
2002 if (i > 0 && values_are_sorted) {
2003 int cmp = parsed_dn_compare(p, &(*pdn)[i - 1]);
2005 values_are_sorted = false;
2008 /* keep a pointer to the original ldb_val */
2011 if (! values_are_sorted) {
2012 TYPESAFE_QSORT(*pdn, el->num_values, parsed_dn_compare);
2018 * Get a series of trusted message element values. The result is sorted by
2019 * GUID, even though the GUIDs might not be known. That works because we trust
2020 * the database to give us the elements like that if the
2021 * replmd_private->sorted_links flag is set.
2023 * We also ensure that the links are in the Functional Level 2003
2024 * linked attributes format.
2026 static int get_parsed_dns_trusted(struct ldb_module *module,
2027 struct replmd_private *replmd_private,
2028 TALLOC_CTX *mem_ctx,
2029 struct ldb_message_element *el,
2030 struct parsed_dn **pdn,
2031 const char *ldap_oid,
2032 struct ldb_request *parent)
2041 if (!replmd_private->sorted_links) {
2042 /* We need to sort the list. This is the slow old path we want
2045 ret = get_parsed_dns(module, mem_ctx, el, pdn, ldap_oid,
2047 if (ret != LDB_SUCCESS) {
2051 /* Here we get a list of 'struct parsed_dns' without the parsing */
2052 *pdn = talloc_zero_array(mem_ctx, struct parsed_dn,
2055 ldb_module_oom(module);
2056 return LDB_ERR_OPERATIONS_ERROR;
2059 for (i = 0; i < el->num_values; i++) {
2060 (*pdn)[i].v = &el->values[i];
2065 * This upgrades links to FL2003 style, and sorts the result
2066 * if that was needed.
2068 * TODO: Add a database feature that asserts we have no FL2000
2069 * style links to avoid this check or add a feature that
2070 * uses a similar check to find sorted/unsorted links
2071 * for an on-the-fly upgrade.
2074 ret = replmd_check_upgrade_links(ldb_module_get_ctx(module),
2075 *pdn, el->num_values,
2078 if (ret != LDB_SUCCESS) {
2086 build a new extended DN, including all meta data fields
2088 RMD_FLAGS = DSDB_RMD_FLAG_* bits
2089 RMD_ADDTIME = originating_add_time
2090 RMD_INVOCID = originating_invocation_id
2091 RMD_CHANGETIME = originating_change_time
2092 RMD_ORIGINATING_USN = originating_usn
2093 RMD_LOCAL_USN = local_usn
2094 RMD_VERSION = version
2096 static int replmd_build_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct dsdb_dn *dsdb_dn,
2097 const struct GUID *invocation_id, uint64_t seq_num,
2098 uint64_t local_usn, NTTIME nttime, uint32_t version, bool deleted)
2100 struct ldb_dn *dn = dsdb_dn->dn;
2101 const char *tstring, *usn_string, *flags_string;
2102 struct ldb_val tval;
2104 struct ldb_val usnv, local_usnv;
2105 struct ldb_val vers, flagsv;
2108 const char *dnstring;
2110 uint32_t rmd_flags = deleted?DSDB_RMD_FLAG_DELETED:0;
2112 tstring = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)nttime);
2114 return LDB_ERR_OPERATIONS_ERROR;
2116 tval = data_blob_string_const(tstring);
2118 usn_string = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)seq_num);
2120 return LDB_ERR_OPERATIONS_ERROR;
2122 usnv = data_blob_string_const(usn_string);
2124 usn_string = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)local_usn);
2126 return LDB_ERR_OPERATIONS_ERROR;
2128 local_usnv = data_blob_string_const(usn_string);
2130 vstring = talloc_asprintf(mem_ctx, "%lu", (unsigned long)version);
2132 return LDB_ERR_OPERATIONS_ERROR;
2134 vers = data_blob_string_const(vstring);
2136 status = GUID_to_ndr_blob(invocation_id, dn, &iid);
2137 if (!NT_STATUS_IS_OK(status)) {
2138 return LDB_ERR_OPERATIONS_ERROR;
2141 flags_string = talloc_asprintf(mem_ctx, "%u", rmd_flags);
2142 if (!flags_string) {
2143 return LDB_ERR_OPERATIONS_ERROR;
2145 flagsv = data_blob_string_const(flags_string);
2147 ret = ldb_dn_set_extended_component(dn, "RMD_FLAGS", &flagsv);
2148 if (ret != LDB_SUCCESS) return ret;
2149 ret = ldb_dn_set_extended_component(dn, "RMD_ADDTIME", &tval);
2150 if (ret != LDB_SUCCESS) return ret;
2151 ret = ldb_dn_set_extended_component(dn, "RMD_INVOCID", &iid);
2152 if (ret != LDB_SUCCESS) return ret;
2153 ret = ldb_dn_set_extended_component(dn, "RMD_CHANGETIME", &tval);
2154 if (ret != LDB_SUCCESS) return ret;
2155 ret = ldb_dn_set_extended_component(dn, "RMD_LOCAL_USN", &local_usnv);
2156 if (ret != LDB_SUCCESS) return ret;
2157 ret = ldb_dn_set_extended_component(dn, "RMD_ORIGINATING_USN", &usnv);
2158 if (ret != LDB_SUCCESS) return ret;
2159 ret = ldb_dn_set_extended_component(dn, "RMD_VERSION", &vers);
2160 if (ret != LDB_SUCCESS) return ret;
2162 dnstring = dsdb_dn_get_extended_linearized(mem_ctx, dsdb_dn, 1);
2163 if (dnstring == NULL) {
2164 return LDB_ERR_OPERATIONS_ERROR;
2166 *v = data_blob_string_const(dnstring);
2171 static int replmd_update_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct dsdb_dn *dsdb_dn,
2172 struct dsdb_dn *old_dsdb_dn, const struct GUID *invocation_id,
2173 uint64_t seq_num, uint64_t local_usn, NTTIME nttime,
2174 uint32_t version, bool deleted);
2177 check if any links need upgrading from w2k format
2179 static int replmd_check_upgrade_links(struct ldb_context *ldb,
2180 struct parsed_dn *dns, uint32_t count,
2181 struct ldb_message_element *el,
2182 const char *ldap_oid)
2185 const struct GUID *invocation_id = NULL;
2186 for (i=0; i<count; i++) {
2190 if (dns[i].dsdb_dn == NULL) {
2191 ret = really_parse_trusted_dn(dns, ldb, &dns[i],
2193 if (ret != LDB_SUCCESS) {
2194 return LDB_ERR_INVALID_DN_SYNTAX;
2198 status = dsdb_get_extended_dn_uint32(dns[i].dsdb_dn->dn,
2199 &version, "RMD_VERSION");
2200 if (!NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
2202 * We optimistically assume they are all the same; if
2203 * the first one is fixed, they are all fixed.
2205 * If the first one was *not* fixed and we find a
2206 * later one that is, that is an occasion to shout
2212 DEBUG(0, ("Mixed w2k and fixed format "
2213 "linked attributes\n"));
2217 if (invocation_id == NULL) {
2218 invocation_id = samdb_ntds_invocation_id(ldb);
2219 if (invocation_id == NULL) {
2220 return LDB_ERR_OPERATIONS_ERROR;
2225 /* it's an old one that needs upgrading */
2226 ret = replmd_update_la_val(el->values, dns[i].v,
2227 dns[i].dsdb_dn, dns[i].dsdb_dn,
2228 invocation_id, 1, 1, 0, 0, false);
2229 if (ret != LDB_SUCCESS) {
2235 * This sort() is critical for the operation of
2236 * get_parsed_dns_trusted() because callers of this function
2237 * expect a sorted list, and FL2000 style links are not
2238 * sorted. In particular, as well as the upgrade case,
2239 * get_parsed_dns_trusted() is called from
2240 * replmd_delete_remove_link() even in FL2000 mode
2242 * We do not normally pay the cost of the qsort() due to the
2243 * early return in the RMD_VERSION found case.
2245 TYPESAFE_QSORT(dns, count, parsed_dn_compare);
2250 update an extended DN, including all meta data fields
2252 see replmd_build_la_val for value names
2254 static int replmd_update_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct dsdb_dn *dsdb_dn,
2255 struct dsdb_dn *old_dsdb_dn, const struct GUID *invocation_id,
2256 uint64_t usn, uint64_t local_usn, NTTIME nttime,
2257 uint32_t version, bool deleted)
2259 struct ldb_dn *dn = dsdb_dn->dn;
2260 const char *tstring, *usn_string, *flags_string;
2261 struct ldb_val tval;
2263 struct ldb_val usnv, local_usnv;
2264 struct ldb_val vers, flagsv;
2265 const struct ldb_val *old_addtime;
2266 uint32_t old_version;
2269 const char *dnstring;
2271 uint32_t rmd_flags = deleted?DSDB_RMD_FLAG_DELETED:0;
2273 tstring = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)nttime);
2275 return LDB_ERR_OPERATIONS_ERROR;
2277 tval = data_blob_string_const(tstring);
2279 usn_string = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)usn);
2281 return LDB_ERR_OPERATIONS_ERROR;
2283 usnv = data_blob_string_const(usn_string);
2285 usn_string = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)local_usn);
2287 return LDB_ERR_OPERATIONS_ERROR;
2289 local_usnv = data_blob_string_const(usn_string);
2291 status = GUID_to_ndr_blob(invocation_id, dn, &iid);
2292 if (!NT_STATUS_IS_OK(status)) {
2293 return LDB_ERR_OPERATIONS_ERROR;
2296 flags_string = talloc_asprintf(mem_ctx, "%u", rmd_flags);
2297 if (!flags_string) {
2298 return LDB_ERR_OPERATIONS_ERROR;
2300 flagsv = data_blob_string_const(flags_string);
2302 ret = ldb_dn_set_extended_component(dn, "RMD_FLAGS", &flagsv);
2303 if (ret != LDB_SUCCESS) return ret;
2305 /* get the ADDTIME from the original */
2306 old_addtime = ldb_dn_get_extended_component(old_dsdb_dn->dn, "RMD_ADDTIME");
2307 if (old_addtime == NULL) {
2308 old_addtime = &tval;
2310 if (dsdb_dn != old_dsdb_dn ||
2311 ldb_dn_get_extended_component(dn, "RMD_ADDTIME") == NULL) {
2312 ret = ldb_dn_set_extended_component(dn, "RMD_ADDTIME", old_addtime);
2313 if (ret != LDB_SUCCESS) return ret;
2316 /* use our invocation id */
2317 ret = ldb_dn_set_extended_component(dn, "RMD_INVOCID", &iid);
2318 if (ret != LDB_SUCCESS) return ret;
2320 /* changetime is the current time */
2321 ret = ldb_dn_set_extended_component(dn, "RMD_CHANGETIME", &tval);
2322 if (ret != LDB_SUCCESS) return ret;
2324 /* update the USN */
2325 ret = ldb_dn_set_extended_component(dn, "RMD_ORIGINATING_USN", &usnv);
2326 if (ret != LDB_SUCCESS) return ret;
2328 ret = ldb_dn_set_extended_component(dn, "RMD_LOCAL_USN", &local_usnv);
2329 if (ret != LDB_SUCCESS) return ret;
2331 /* increase the version by 1 */
2332 status = dsdb_get_extended_dn_uint32(old_dsdb_dn->dn, &old_version, "RMD_VERSION");
2333 if (NT_STATUS_IS_OK(status) && old_version >= version) {
2334 version = old_version+1;
2336 vstring = talloc_asprintf(dn, "%lu", (unsigned long)version);
2337 vers = data_blob_string_const(vstring);
2338 ret = ldb_dn_set_extended_component(dn, "RMD_VERSION", &vers);
2339 if (ret != LDB_SUCCESS) return ret;
2341 dnstring = dsdb_dn_get_extended_linearized(mem_ctx, dsdb_dn, 1);
2342 if (dnstring == NULL) {
2343 return LDB_ERR_OPERATIONS_ERROR;
2345 *v = data_blob_string_const(dnstring);
2351 handle adding a linked attribute
2353 static int replmd_modify_la_add(struct ldb_module *module,
2354 struct replmd_private *replmd_private,
2355 const struct dsdb_schema *schema,
2356 struct ldb_message *msg,
2357 struct ldb_message_element *el,
2358 struct ldb_message_element *old_el,
2359 const struct dsdb_attribute *schema_attr,
2362 struct ldb_dn *msg_dn,
2363 struct ldb_request *parent)
2366 struct parsed_dn *dns, *old_dns;
2367 TALLOC_CTX *tmp_ctx = talloc_new(msg);
2369 struct ldb_val *new_values = NULL;
2370 unsigned old_num_values = old_el ? old_el->num_values : 0;
2371 unsigned num_values = 0;
2372 unsigned max_num_values;
2373 const struct GUID *invocation_id;
2374 struct ldb_context *ldb = ldb_module_get_ctx(module);
2376 unix_to_nt_time(&now, t);
2378 invocation_id = samdb_ntds_invocation_id(ldb);
2379 if (!invocation_id) {
2380 talloc_free(tmp_ctx);
2381 return LDB_ERR_OPERATIONS_ERROR;
2384 /* get the DNs to be added, fully parsed.
2386 * We need full parsing because they came off the wire and we don't
2387 * trust them, besides which we need their details to know where to put
2390 ret = get_parsed_dns(module, tmp_ctx, el, &dns,
2391 schema_attr->syntax->ldap_oid, parent);
2392 if (ret != LDB_SUCCESS) {
2393 talloc_free(tmp_ctx);
2397 /* get the existing DNs, lazily parsed */
2398 ret = get_parsed_dns_trusted(module, replmd_private,
2399 tmp_ctx, old_el, &old_dns,
2400 schema_attr->syntax->ldap_oid, parent);
2402 if (ret != LDB_SUCCESS) {
2403 talloc_free(tmp_ctx);
2407 max_num_values = old_num_values + el->num_values;
2408 if (max_num_values < old_num_values) {
2409 DEBUG(0, ("we seem to have overflow in replmd_modify_la_add. "
2410 "old values: %u, new values: %u, sum: %u",
2411 old_num_values, el->num_values, max_num_values));
2412 talloc_free(tmp_ctx);
2413 return LDB_ERR_OPERATIONS_ERROR;
2416 new_values = talloc_zero_array(tmp_ctx, struct ldb_val, max_num_values);
2418 if (new_values == NULL) {
2419 ldb_module_oom(module);
2420 talloc_free(tmp_ctx);
2421 return LDB_ERR_OPERATIONS_ERROR;
2425 * For each new value, find where it would go in the list. If there is
2426 * a matching GUID there, we update the existing value; otherwise we
2430 for (i = 0; i < el->num_values; i++) {
2431 struct parsed_dn *exact;
2432 struct parsed_dn *next;
2434 int err = parsed_dn_find(ldb, old_dns, old_num_values,
2437 dns[i].dsdb_dn->extra_part, 0,
2439 schema_attr->syntax->ldap_oid,
2441 if (err != LDB_SUCCESS) {
2442 talloc_free(tmp_ctx);
2446 if (exact != NULL) {
2448 * We are trying to add one that exists, which is only
2449 * allowed if it was previously deleted.
2451 * When we do undelete a link we change it in place.
2452 * It will be copied across into the right spot in due
2456 rmd_flags = dsdb_dn_rmd_flags(exact->dsdb_dn->dn);
2458 if (!(rmd_flags & DSDB_RMD_FLAG_DELETED)) {
2459 struct GUID_txt_buf guid_str;
2460 ldb_asprintf_errstring(ldb,
2461 "Attribute %s already "
2462 "exists for target GUID %s",
2464 GUID_buf_string(&exact->guid,
2466 talloc_free(tmp_ctx);
2467 /* error codes for 'member' need to be
2469 if (ldb_attr_cmp(el->name, "member") == 0) {
2470 return LDB_ERR_ENTRY_ALREADY_EXISTS;
2472 return LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS;
2476 ret = replmd_update_la_val(new_values, exact->v,
2479 invocation_id, seq_num,
2480 seq_num, now, 0, false);
2481 if (ret != LDB_SUCCESS) {
2482 talloc_free(tmp_ctx);
2486 ret = replmd_add_backlink(module, replmd_private,
2493 if (ret != LDB_SUCCESS) {
2494 talloc_free(tmp_ctx);
2500 * Here we don't have an exact match.
2502 * If next is NULL, this one goes beyond the end of the
2503 * existing list, so we need to add all of those ones first.
2505 * If next is not NULL, we need to add all the ones before
2509 offset = old_num_values;
2511 /* next should have been parsed, but let's make sure */
2512 if (next->dsdb_dn == NULL) {
2513 ret = really_parse_trusted_dn(tmp_ctx, ldb, next,
2514 schema_attr->syntax->ldap_oid);
2515 if (ret != LDB_SUCCESS) {
2519 offset = MIN(next - old_dns, old_num_values);
2522 /* put all the old ones before next on the list */
2523 for (; j < offset; j++) {
2524 new_values[num_values] = *old_dns[j].v;
2528 ret = replmd_add_backlink(module, replmd_private,
2533 /* Make the new linked attribute ldb_val. */
2534 ret = replmd_build_la_val(new_values, &new_values[num_values],
2535 dns[i].dsdb_dn, invocation_id,
2538 if (ret != LDB_SUCCESS) {
2539 talloc_free(tmp_ctx);
2543 if (ret != LDB_SUCCESS) {
2544 talloc_free(tmp_ctx);
2548 /* copy the rest of the old ones (if any) */
2549 for (; j < old_num_values; j++) {
2550 new_values[num_values] = *old_dns[j].v;
2554 talloc_steal(msg->elements, new_values);
2555 if (old_el != NULL) {
2556 talloc_steal(msg->elements, old_el->values);
2558 el->values = new_values;
2559 el->num_values = num_values;
2561 talloc_free(tmp_ctx);
2563 /* we now tell the backend to replace all existing values
2564 with the one we have constructed */
2565 el->flags = LDB_FLAG_MOD_REPLACE;
2572 handle deleting all active linked attributes
2574 static int replmd_modify_la_delete(struct ldb_module *module,
2575 struct replmd_private *replmd_private,
2576 const struct dsdb_schema *schema,
2577 struct ldb_message *msg,
2578 struct ldb_message_element *el,
2579 struct ldb_message_element *old_el,
2580 const struct dsdb_attribute *schema_attr,
2583 struct ldb_dn *msg_dn,
2584 struct ldb_request *parent)
2587 struct parsed_dn *dns, *old_dns;
2588 TALLOC_CTX *tmp_ctx = NULL;
2590 struct ldb_context *ldb = ldb_module_get_ctx(module);
2591 struct ldb_control *vanish_links_ctrl = NULL;
2592 bool vanish_links = false;
2593 unsigned int num_to_delete = el->num_values;
2595 const struct GUID *invocation_id;
2598 unix_to_nt_time(&now, t);
2600 invocation_id = samdb_ntds_invocation_id(ldb);
2601 if (!invocation_id) {
2602 return LDB_ERR_OPERATIONS_ERROR;
2605 if (old_el == NULL || old_el->num_values == 0) {
2606 /* there is nothing to delete... */
2607 if (num_to_delete == 0) {
2608 /* and we're deleting nothing, so that's OK */
2611 return LDB_ERR_NO_SUCH_ATTRIBUTE;
2614 tmp_ctx = talloc_new(msg);
2615 if (tmp_ctx == NULL) {
2616 return LDB_ERR_OPERATIONS_ERROR;
2619 ret = get_parsed_dns(module, tmp_ctx, el, &dns,
2620 schema_attr->syntax->ldap_oid, parent);
2621 if (ret != LDB_SUCCESS) {
2622 talloc_free(tmp_ctx);
2626 ret = get_parsed_dns_trusted(module, replmd_private,
2627 tmp_ctx, old_el, &old_dns,
2628 schema_attr->syntax->ldap_oid, parent);
2630 if (ret != LDB_SUCCESS) {
2631 talloc_free(tmp_ctx);
2636 vanish_links_ctrl = ldb_request_get_control(parent, DSDB_CONTROL_REPLMD_VANISH_LINKS);
2637 if (vanish_links_ctrl) {
2638 vanish_links = true;
2639 vanish_links_ctrl->critical = false;
2643 /* we empty out el->values here to avoid damage if we return early. */
2648 * If vanish links is set, we are actually removing members of
2649 * old_el->values; otherwise we are just marking them deleted.
2651 * There is a special case when no values are given: we remove them
2652 * all. When we have the vanish_links control we just have to remove
2653 * the backlinks and change our element to replace the existing values
2654 * with the empty list.
2657 if (num_to_delete == 0) {
2658 for (i = 0; i < old_el->num_values; i++) {
2659 struct parsed_dn *p = &old_dns[i];
2660 if (p->dsdb_dn == NULL) {
2661 ret = really_parse_trusted_dn(tmp_ctx, ldb, p,
2662 schema_attr->syntax->ldap_oid);
2663 if (ret != LDB_SUCCESS) {
2667 ret = replmd_add_backlink(module, replmd_private,
2668 schema, msg_dn, &p->guid,
2671 if (ret != LDB_SUCCESS) {
2672 talloc_free(tmp_ctx);
2679 rmd_flags = dsdb_dn_rmd_flags(p->dsdb_dn->dn);
2680 if (rmd_flags & DSDB_RMD_FLAG_DELETED) {
2684 ret = replmd_update_la_val(old_el->values, p->v,
2685 p->dsdb_dn, p->dsdb_dn,
2686 invocation_id, seq_num,
2687 seq_num, now, 0, true);
2688 if (ret != LDB_SUCCESS) {
2689 talloc_free(tmp_ctx);
2695 el->flags = LDB_FLAG_MOD_REPLACE;
2696 talloc_free(tmp_ctx);
2702 for (i = 0; i < num_to_delete; i++) {
2703 struct parsed_dn *p = &dns[i];
2704 struct parsed_dn *exact = NULL;
2705 struct parsed_dn *next = NULL;
2706 ret = parsed_dn_find(ldb, old_dns, old_el->num_values,
2709 p->dsdb_dn->extra_part, 0,
2711 schema_attr->syntax->ldap_oid,
2713 if (ret != LDB_SUCCESS) {
2714 talloc_free(tmp_ctx);
2717 if (exact == NULL) {
2718 struct GUID_txt_buf buf;
2719 ldb_asprintf_errstring(ldb, "Attribute %s doesn't "
2720 "exist for target GUID %s",
2722 GUID_buf_string(&p->guid, &buf));
2723 if (ldb_attr_cmp(el->name, "member") == 0) {
2724 talloc_free(tmp_ctx);
2725 return LDB_ERR_UNWILLING_TO_PERFORM;
2727 talloc_free(tmp_ctx);
2728 return LDB_ERR_NO_SUCH_ATTRIBUTE;
2733 if (CHECK_DEBUGLVL(5)) {
2734 rmd_flags = dsdb_dn_rmd_flags(exact->dsdb_dn->dn);
2735 if ((rmd_flags & DSDB_RMD_FLAG_DELETED)) {
2736 struct GUID_txt_buf buf;
2737 const char *guid_str = \
2738 GUID_buf_string(&p->guid, &buf);
2739 DEBUG(5, ("Deleting deleted linked "
2740 "attribute %s to %s, because "
2741 "vanish_links control is set\n",
2742 el->name, guid_str));
2746 /* remove the backlink */
2747 ret = replmd_add_backlink(module,
2754 if (ret != LDB_SUCCESS) {
2755 talloc_free(tmp_ctx);
2759 /* We flag the deletion and tidy it up later. */
2764 rmd_flags = dsdb_dn_rmd_flags(exact->dsdb_dn->dn);
2766 if (rmd_flags & DSDB_RMD_FLAG_DELETED) {
2767 struct GUID_txt_buf buf;
2768 const char *guid_str = GUID_buf_string(&p->guid, &buf);
2769 ldb_asprintf_errstring(ldb, "Attribute %s already "
2770 "deleted for target GUID %s",
2771 el->name, guid_str);
2772 if (ldb_attr_cmp(el->name, "member") == 0) {
2773 talloc_free(tmp_ctx);
2774 return LDB_ERR_UNWILLING_TO_PERFORM;
2776 talloc_free(tmp_ctx);
2777 return LDB_ERR_NO_SUCH_ATTRIBUTE;
2781 ret = replmd_update_la_val(old_el->values, exact->v,
2782 exact->dsdb_dn, exact->dsdb_dn,
2783 invocation_id, seq_num, seq_num,
2785 if (ret != LDB_SUCCESS) {
2786 talloc_free(tmp_ctx);
2789 ret = replmd_add_backlink(module, replmd_private,
2794 if (ret != LDB_SUCCESS) {
2795 talloc_free(tmp_ctx);
2802 for (i = 0; i < old_el->num_values; i++) {
2803 if (old_dns[i].v != NULL) {
2804 old_el->values[j] = *old_dns[i].v;
2808 old_el->num_values = j;
2811 el->values = talloc_steal(msg->elements, old_el->values);
2812 el->num_values = old_el->num_values;
2814 talloc_free(tmp_ctx);
2816 /* we now tell the backend to replace all existing values
2817 with the one we have constructed */
2818 el->flags = LDB_FLAG_MOD_REPLACE;
2824 handle replacing a linked attribute
2826 static int replmd_modify_la_replace(struct ldb_module *module,
2827 struct replmd_private *replmd_private,
2828 const struct dsdb_schema *schema,
2829 struct ldb_message *msg,
2830 struct ldb_message_element *el,
2831 struct ldb_message_element *old_el,
2832 const struct dsdb_attribute *schema_attr,
2835 struct ldb_dn *msg_dn,
2836 struct ldb_request *parent)
2838 unsigned int i, old_i, new_i;
2839 struct parsed_dn *dns, *old_dns;
2840 TALLOC_CTX *tmp_ctx = talloc_new(msg);
2842 const struct GUID *invocation_id;
2843 struct ldb_context *ldb = ldb_module_get_ctx(module);
2844 struct ldb_val *new_values = NULL;
2845 const char *ldap_oid = schema_attr->syntax->ldap_oid;
2846 unsigned int old_num_values;
2847 unsigned int repl_num_values;
2848 unsigned int max_num_values;
2851 unix_to_nt_time(&now, t);
2853 invocation_id = samdb_ntds_invocation_id(ldb);
2854 if (!invocation_id) {
2855 return LDB_ERR_OPERATIONS_ERROR;
2859 * The replace operation is unlike the replace and delete cases in that
2860 * we need to look at every existing link to see whether it is being
2861 * retained or deleted. In other words, we can't avoid parsing the GUIDs.
2863 * As we are trying to combine two sorted lists, the algorithm we use
2864 * is akin to the merge phase of a merge sort. We interleave the two
2865 * lists, doing different things depending on which side the current
2868 * There are three main cases, with some sub-cases.
2870 * - a DN is in the old list but not the new one. It needs to be
2871 * marked as deleted (but left in the list).
2872 * - maybe it is already deleted, and we have less to do.
2874 * - a DN is in both lists. The old data gets replaced by the new,
2875 * and the list doesn't grow. The old link may have been marked as
2876 * deleted, in which case we undelete it.
2878 * - a DN is in the new list only. We add it in the right place.
2881 old_num_values = old_el ? old_el->num_values : 0;
2882 repl_num_values = el->num_values;
2883 max_num_values = old_num_values + repl_num_values;
2885 if (max_num_values == 0) {
2886 /* There is nothing to do! */
2890 ret = get_parsed_dns(module, tmp_ctx, el, &dns, ldap_oid, parent);
2891 if (ret != LDB_SUCCESS) {
2892 talloc_free(tmp_ctx);
2896 ret = get_parsed_dns(module, tmp_ctx, old_el, &old_dns,
2898 if (ret != LDB_SUCCESS) {
2899 talloc_free(tmp_ctx);
2903 ret = replmd_check_upgrade_links(ldb, old_dns, old_num_values,
2905 if (ret != LDB_SUCCESS) {
2906 talloc_free(tmp_ctx);
2910 new_values = talloc_array(tmp_ctx, struct ldb_val, max_num_values);
2911 if (new_values == NULL) {
2912 ldb_module_oom(module);
2913 talloc_free(tmp_ctx);
2914 return LDB_ERR_OPERATIONS_ERROR;
2919 for (i = 0; i < max_num_values; i++) {
2921 struct parsed_dn *old_p, *new_p;
2922 if (old_i < old_num_values && new_i < repl_num_values) {
2923 old_p = &old_dns[old_i];
2924 new_p = &dns[new_i];
2925 cmp = parsed_dn_compare(old_p, new_p);
2926 } else if (old_i < old_num_values) {
2927 /* the new list is empty, read the old list */
2928 old_p = &old_dns[old_i];
2931 } else if (new_i < repl_num_values) {
2932 /* the old list is empty, read new list */
2934 new_p = &dns[new_i];
2942 * An old ones that come before the next replacement
2943 * (if any). We mark it as deleted and add it to the
2946 uint32_t rmd_flags = dsdb_dn_rmd_flags(old_p->dsdb_dn->dn);
2947 if ((rmd_flags & DSDB_RMD_FLAG_DELETED) == 0) {
2948 ret = replmd_update_la_val(new_values, old_p->v,
2954 if (ret != LDB_SUCCESS) {
2955 talloc_free(tmp_ctx);
2959 ret = replmd_add_backlink(module, replmd_private,
2962 &old_p->guid, false,
2965 if (ret != LDB_SUCCESS) {
2966 talloc_free(tmp_ctx);
2970 new_values[i] = *old_p->v;
2972 } else if (cmp == 0) {
2974 * We are overwriting one. If it was previously
2975 * deleted, we need to add a backlink.
2977 * Note that if any RMD_FLAGs in an extended new DN
2982 ret = replmd_update_la_val(new_values, old_p->v,
2988 if (ret != LDB_SUCCESS) {
2989 talloc_free(tmp_ctx);
2993 rmd_flags = dsdb_dn_rmd_flags(old_p->dsdb_dn->dn);
2994 if ((rmd_flags & DSDB_RMD_FLAG_DELETED) != 0) {
2995 ret = replmd_add_backlink(module, replmd_private,
3001 if (ret != LDB_SUCCESS) {
3002 talloc_free(tmp_ctx);
3007 new_values[i] = *old_p->v;
3012 * Replacements that don't match an existing one. We
3013 * just add them to the final list.
3015 ret = replmd_build_la_val(new_values,
3021 if (ret != LDB_SUCCESS) {
3022 talloc_free(tmp_ctx);
3025 ret = replmd_add_backlink(module, replmd_private,
3031 if (ret != LDB_SUCCESS) {
3032 talloc_free(tmp_ctx);
3035 new_values[i] = *new_p->v;
3039 if (old_el != NULL) {
3040 talloc_steal(msg->elements, old_el->values);
3042 el->values = talloc_steal(msg->elements, new_values);
3044 talloc_free(tmp_ctx);
3046 el->flags = LDB_FLAG_MOD_REPLACE;
3053 handle linked attributes in modify requests
3055 static int replmd_modify_handle_linked_attribs(struct ldb_module *module,
3056 struct replmd_private *replmd_private,
3057 struct ldb_message *msg,
3058 uint64_t seq_num, time_t t,
3059 struct ldb_request *parent)
3061 struct ldb_result *res;
3064 struct ldb_context *ldb = ldb_module_get_ctx(module);
3065 struct ldb_message *old_msg;
3067 const struct dsdb_schema *schema;
3069 if (dsdb_functional_level(ldb) == DS_DOMAIN_FUNCTION_2000) {
3071 * Nothing special is required for modifying or vanishing links
3072 * in fl2000 since they are just strings in a multi-valued
3075 struct ldb_control *ctrl = ldb_request_get_control(parent,
3076 DSDB_CONTROL_REPLMD_VANISH_LINKS);
3078 ctrl->critical = false;
3086 * We should restrict this to the intersection of the list of
3087 * linked attributes in the schema and the list of attributes
3090 * This will help performance a little, as otherwise we have
3091 * to allocate the entire object value-by-value.
3093 ret = dsdb_module_search_dn(module, msg, &res, msg->dn, NULL,
3094 DSDB_FLAG_NEXT_MODULE |
3095 DSDB_SEARCH_SHOW_RECYCLED |
3096 DSDB_SEARCH_REVEAL_INTERNALS |
3097 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT,
3099 if (ret != LDB_SUCCESS) {
3102 schema = dsdb_get_schema(ldb, res);
3104 return LDB_ERR_OPERATIONS_ERROR;
3107 old_msg = res->msgs[0];
3109 for (i=0; i<msg->num_elements; i++) {
3110 struct ldb_message_element *el = &msg->elements[i];
3111 struct ldb_message_element *old_el, *new_el;
3112 const struct dsdb_attribute *schema_attr
3113 = dsdb_attribute_by_lDAPDisplayName(schema, el->name);
3115 ldb_asprintf_errstring(ldb,
3116 "%s: attribute %s is not a valid attribute in schema",
3117 __FUNCTION__, el->name);
3118 return LDB_ERR_OBJECT_CLASS_VIOLATION;
3120 if (schema_attr->linkID == 0) {
3123 if ((schema_attr->linkID & 1) == 1) {
3124 if (parent && ldb_request_get_control(parent, DSDB_CONTROL_DBCHECK)) {
3127 /* Odd is for the target. Illegal to modify */
3128 ldb_asprintf_errstring(ldb,
3129 "attribute %s must not be modified directly, it is a linked attribute", el->name);
3130 return LDB_ERR_UNWILLING_TO_PERFORM;
3132 old_el = ldb_msg_find_element(old_msg, el->name);
3133 switch (el->flags & LDB_FLAG_MOD_MASK) {
3134 case LDB_FLAG_MOD_REPLACE:
3135 ret = replmd_modify_la_replace(module, replmd_private,
3136 schema, msg, el, old_el,
3137 schema_attr, seq_num, t,
3141 case LDB_FLAG_MOD_DELETE:
3142 ret = replmd_modify_la_delete(module, replmd_private,
3143 schema, msg, el, old_el,
3144 schema_attr, seq_num, t,
3148 case LDB_FLAG_MOD_ADD:
3149 ret = replmd_modify_la_add(module, replmd_private,
3150 schema, msg, el, old_el,
3151 schema_attr, seq_num, t,
3156 ldb_asprintf_errstring(ldb,
3157 "invalid flags 0x%x for %s linked attribute",
3158 el->flags, el->name);
3159 return LDB_ERR_UNWILLING_TO_PERFORM;
3161 if (dsdb_check_single_valued_link(schema_attr, el) != LDB_SUCCESS) {
3162 ldb_asprintf_errstring(ldb,
3163 "Attribute %s is single valued but more than one value has been supplied",
3165 return LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS;
3167 el->flags |= LDB_FLAG_INTERNAL_DISABLE_SINGLE_VALUE_CHECK;
3172 if (ret != LDB_SUCCESS) {
3176 ldb_msg_remove_attr(old_msg, el->name);
3178 ldb_msg_add_empty(old_msg, el->name, 0, &new_el);
3179 new_el->num_values = el->num_values;
3180 new_el->values = talloc_steal(msg->elements, el->values);
3182 /* TODO: this relises a bit too heavily on the exact
3183 behaviour of ldb_msg_find_element and
3184 ldb_msg_remove_element */
3185 old_el = ldb_msg_find_element(msg, el->name);
3187 ldb_msg_remove_element(msg, old_el);
3197 static int send_rodc_referral(struct ldb_request *req,
3198 struct ldb_context *ldb,
3201 char *referral = NULL;
3202 struct loadparm_context *lp_ctx = NULL;
3203 struct ldb_dn *fsmo_role_dn = NULL;
3204 struct ldb_dn *role_owner_dn = NULL;
3205 const char *domain = NULL;
3208 lp_ctx = talloc_get_type(ldb_get_opaque(ldb, "loadparm"),
3209 struct loadparm_context);
3211 werr = dsdb_get_fsmo_role_info(req, ldb, DREPL_PDC_MASTER,
3212 &fsmo_role_dn, &role_owner_dn);
3214 if (W_ERROR_IS_OK(werr)) {
3215 struct ldb_dn *server_dn = ldb_dn_copy(req, role_owner_dn);
3216 if (server_dn != NULL) {
3217 ldb_dn_remove_child_components(server_dn, 1);
3218 domain = samdb_dn_to_dnshostname(ldb, req,
3223 if (domain == NULL) {
3224 domain = lpcfg_dnsdomain(lp_ctx);
3227 referral = talloc_asprintf(req, "ldap://%s/%s",
3229 ldb_dn_get_linearized(dn));
3230 if (referral == NULL) {
3232 return LDB_ERR_OPERATIONS_ERROR;
3235 return ldb_module_send_referral(req, referral);
3239 static int replmd_modify(struct ldb_module *module, struct ldb_request *req)
3241 struct ldb_context *ldb;
3242 struct replmd_replicated_request *ac;
3243 struct ldb_request *down_req;
3244 struct ldb_message *msg;
3245 time_t t = time(NULL);
3247 bool is_urgent = false, rodc = false;
3248 bool is_schema_nc = false;
3249 unsigned int functional_level;
3250 const struct ldb_message_element *guid_el = NULL;
3251 struct ldb_control *sd_propagation_control;
3252 struct replmd_private *replmd_private =
3253 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
3255 /* do not manipulate our control entries */
3256 if (ldb_dn_is_special(req->op.mod.message->dn)) {
3257 return ldb_next_request(module, req);
3260 sd_propagation_control = ldb_request_get_control(req,
3261 DSDB_CONTROL_SEC_DESC_PROPAGATION_OID);
3262 if (sd_propagation_control != NULL) {
3263 if (req->op.mod.message->num_elements != 1) {
3264 return ldb_module_operr(module);
3266 ret = strcmp(req->op.mod.message->elements[0].name,
3267 "nTSecurityDescriptor");
3269 return ldb_module_operr(module);
3272 return ldb_next_request(module, req);
3275 ldb = ldb_module_get_ctx(module);
3277 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_modify\n");
3279 guid_el = ldb_msg_find_element(req->op.mod.message, "objectGUID");
3280 if (guid_el != NULL) {
3281 ldb_set_errstring(ldb,
3282 "replmd_modify: it's not allowed to change the objectGUID!");
3283 return LDB_ERR_CONSTRAINT_VIOLATION;
3286 ac = replmd_ctx_init(module, req);
3288 return ldb_module_oom(module);
3291 functional_level = dsdb_functional_level(ldb);
3293 /* we have to copy the message as the caller might have it as a const */
3294 msg = ldb_msg_copy_shallow(ac, req->op.mod.message);
3298 return LDB_ERR_OPERATIONS_ERROR;
3301 ldb_msg_remove_attr(msg, "whenChanged");
3302 ldb_msg_remove_attr(msg, "uSNChanged");
3304 is_schema_nc = ldb_dn_compare_base(replmd_private->schema_dn, msg->dn) == 0;
3306 ret = replmd_update_rpmd(module, ac->schema, req, NULL,
3307 msg, &ac->seq_num, t, is_schema_nc,
3309 if (rodc && (ret == LDB_ERR_REFERRAL)) {
3310 ret = send_rodc_referral(req, ldb, msg->dn);
3316 if (ret != LDB_SUCCESS) {
3321 ret = replmd_modify_handle_linked_attribs(module, replmd_private,
3322 msg, ac->seq_num, t, req);
3323 if (ret != LDB_SUCCESS) {
3329 * - replace the old object with the newly constructed one
3332 ac->is_urgent = is_urgent;
3334 ret = ldb_build_mod_req(&down_req, ldb, ac,
3337 ac, replmd_op_callback,
3339 LDB_REQ_SET_LOCATION(down_req);
3340 if (ret != LDB_SUCCESS) {
3345 /* current partition control is needed by "replmd_op_callback" */
3346 if (ldb_request_get_control(req, DSDB_CONTROL_CURRENT_PARTITION_OID) == NULL) {
3347 ret = ldb_request_add_control(down_req,
3348 DSDB_CONTROL_CURRENT_PARTITION_OID,
3350 if (ret != LDB_SUCCESS) {
3356 /* If we are in functional level 2000, then
3357 * replmd_modify_handle_linked_attribs will have done
3359 if (functional_level == DS_DOMAIN_FUNCTION_2000) {
3360 ret = ldb_request_add_control(down_req, DSDB_CONTROL_APPLY_LINKS, false, NULL);
3361 if (ret != LDB_SUCCESS) {
3367 talloc_steal(down_req, msg);
3369 /* we only change whenChanged and uSNChanged if the seq_num
3371 if (ac->seq_num != 0) {
3372 ret = add_time_element(msg, "whenChanged", t);
3373 if (ret != LDB_SUCCESS) {
3379 ret = add_uint64_element(ldb, msg, "uSNChanged", ac->seq_num);
3380 if (ret != LDB_SUCCESS) {
3387 /* go on with the call chain */
3388 return ldb_next_request(module, down_req);
3391 static int replmd_rename_callback(struct ldb_request *req, struct ldb_reply *ares);
3394 handle a rename request
3396 On a rename we need to do an extra ldb_modify which sets the
3397 whenChanged and uSNChanged attributes. We do this in a callback after the success.
3399 static int replmd_rename(struct ldb_module *module, struct ldb_request *req)
3401 struct ldb_context *ldb;
3402 struct replmd_replicated_request *ac;
3404 struct ldb_request *down_req;
3406 /* do not manipulate our control entries */
3407 if (ldb_dn_is_special(req->op.mod.message->dn)) {
3408 return ldb_next_request(module, req);
3411 ldb = ldb_module_get_ctx(module);
3413 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_rename\n");
3415 ac = replmd_ctx_init(module, req);
3417 return ldb_module_oom(module);
3420 ret = ldb_build_rename_req(&down_req, ldb, ac,
3421 ac->req->op.rename.olddn,
3422 ac->req->op.rename.newdn,
3424 ac, replmd_rename_callback,
3426 LDB_REQ_SET_LOCATION(down_req);
3427 if (ret != LDB_SUCCESS) {
3432 /* go on with the call chain */
3433 return ldb_next_request(module, down_req);
3436 /* After the rename is compleated, update the whenchanged etc */
3437 static int replmd_rename_callback(struct ldb_request *req, struct ldb_reply *ares)
3439 struct ldb_context *ldb;
3440 struct ldb_request *down_req;
3441 struct ldb_message *msg;
3442 const struct dsdb_attribute *rdn_attr;
3443 const char *rdn_name;
3444 const struct ldb_val *rdn_val;
3445 const char *attrs[5] = { NULL, };
3446 time_t t = time(NULL);
3448 bool is_urgent = false, rodc = false;
3450 struct replmd_replicated_request *ac =
3451 talloc_get_type(req->context, struct replmd_replicated_request);
3452 struct replmd_private *replmd_private =
3453 talloc_get_type(ldb_module_get_private(ac->module),
3454 struct replmd_private);
3456 ldb = ldb_module_get_ctx(ac->module);
3458 if (ares->error != LDB_SUCCESS) {
3459 return ldb_module_done(ac->req, ares->controls,
3460 ares->response, ares->error);
3463 if (ares->type != LDB_REPLY_DONE) {
3464 ldb_set_errstring(ldb,
3465 "invalid ldb_reply_type in callback");
3467 return ldb_module_done(ac->req, NULL, NULL,
3468 LDB_ERR_OPERATIONS_ERROR);
3472 * - replace the old object with the newly constructed one
3475 msg = ldb_msg_new(ac);
3478 return LDB_ERR_OPERATIONS_ERROR;
3481 msg->dn = ac->req->op.rename.newdn;
3483 is_schema_nc = ldb_dn_compare_base(replmd_private->schema_dn, msg->dn) == 0;
3485 rdn_name = ldb_dn_get_rdn_name(msg->dn);
3486 if (rdn_name == NULL) {
3488 return ldb_module_done(ac->req, NULL, NULL,
3492 /* normalize the rdn attribute name */
3493 rdn_attr = dsdb_attribute_by_lDAPDisplayName(ac->schema, rdn_name);
3494 if (rdn_attr == NULL) {
3496 return ldb_module_done(ac->req, NULL, NULL,
3499 rdn_name = rdn_attr->lDAPDisplayName;
3501 rdn_val = ldb_dn_get_rdn_val(msg->dn);
3502 if (rdn_val == NULL) {
3504 return ldb_module_done(ac->req, NULL, NULL,
3508 if (ldb_msg_add_empty(msg, rdn_name, LDB_FLAG_MOD_REPLACE, NULL) != 0) {
3510 return ldb_module_done(ac->req, NULL, NULL,
3513 if (ldb_msg_add_value(msg, rdn_name, rdn_val, NULL) != 0) {
3515 return ldb_module_done(ac->req, NULL, NULL,
3518 if (ldb_msg_add_empty(msg, "name", LDB_FLAG_MOD_REPLACE, NULL) != 0) {
3520 return ldb_module_done(ac->req, NULL, NULL,
3523 if (ldb_msg_add_value(msg, "name", rdn_val, NULL) != 0) {
3525 return ldb_module_done(ac->req, NULL, NULL,
3530 * here we let replmd_update_rpmd() only search for
3531 * the existing "replPropertyMetaData" and rdn_name attributes.
3533 * We do not want the existing "name" attribute as
3534 * the "name" attribute needs to get the version
3535 * updated on rename even if the rdn value hasn't changed.
3537 * This is the diff of the meta data, for a moved user
3538 * on a w2k8r2 server:
3541 * -dn: CN=sdf df,CN=Users,DC=bla,DC=base
3542 * +dn: CN=sdf df,OU=TestOU,DC=bla,DC=base
3543 * replPropertyMetaData: NDR: struct replPropertyMetaDataBlob
3544 * version : 0x00000001 (1)
3545 * reserved : 0x00000000 (0)
3546 * @@ -66,11 +66,11 @@ replPropertyMetaData: NDR: struct re
3547 * local_usn : 0x00000000000037a5 (14245)
3548 * array: struct replPropertyMetaData1
3549 * attid : DRSUAPI_ATTID_name (0x90001)
3550 * - version : 0x00000001 (1)
3551 * - originating_change_time : Wed Feb 9 17:20:49 2011 CET
3552 * + version : 0x00000002 (2)
3553 * + originating_change_time : Wed Apr 6 15:21:01 2011 CEST
3554 * originating_invocation_id: 0d36ca05-5507-4e62-aca3-354bab0d39e1
3555 * - originating_usn : 0x00000000000037a5 (14245)
3556 * - local_usn : 0x00000000000037a5 (14245)
3557 * + originating_usn : 0x0000000000003834 (14388)
3558 * + local_usn : 0x0000000000003834 (14388)
3559 * array: struct replPropertyMetaData1
3560 * attid : DRSUAPI_ATTID_userAccountControl (0x90008)
3561 * version : 0x00000004 (4)
3563 attrs[0] = "replPropertyMetaData";
3564 attrs[1] = "objectClass";
3565 attrs[2] = "instanceType";
3566 attrs[3] = rdn_name;
3569 ret = replmd_update_rpmd(ac->module, ac->schema, req, attrs,
3570 msg, &ac->seq_num, t,
3571 is_schema_nc, &is_urgent, &rodc);
3572 if (rodc && (ret == LDB_ERR_REFERRAL)) {
3573 ret = send_rodc_referral(req, ldb, ac->req->op.rename.olddn);
3575 return ldb_module_done(req, NULL, NULL, ret);
3578 if (ret != LDB_SUCCESS) {
3580 return ldb_module_done(ac->req, NULL, NULL, ret);
3583 if (ac->seq_num == 0) {
3585 return ldb_module_done(ac->req, NULL, NULL,
3587 "internal error seq_num == 0"));
3589 ac->is_urgent = is_urgent;
3591 ret = ldb_build_mod_req(&down_req, ldb, ac,
3594 ac, replmd_op_callback,
3596 LDB_REQ_SET_LOCATION(down_req);
3597 if (ret != LDB_SUCCESS) {
3602 /* current partition control is needed by "replmd_op_callback" */
3603 if (ldb_request_get_control(req, DSDB_CONTROL_CURRENT_PARTITION_OID) == NULL) {
3604 ret = ldb_request_add_control(down_req,
3605 DSDB_CONTROL_CURRENT_PARTITION_OID,
3607 if (ret != LDB_SUCCESS) {
3613 talloc_steal(down_req, msg);
3615 ret = add_time_element(msg, "whenChanged", t);
3616 if (ret != LDB_SUCCESS) {
3622 ret = add_uint64_element(ldb, msg, "uSNChanged", ac->seq_num);
3623 if (ret != LDB_SUCCESS) {
3629 /* go on with the call chain - do the modify after the rename */
3630 return ldb_next_request(ac->module, down_req);
3634 * remove links from objects that point at this object when an object
3635 * is deleted. We remove it from the NEXT module per MS-DRSR 5.160
3636 * RemoveObj which states that link removal due to the object being
3637 * deleted is NOT an originating update - they just go away!
3640 static int replmd_delete_remove_link(struct ldb_module *module,
3641 const struct dsdb_schema *schema,
3642 struct replmd_private *replmd_private,
3645 struct ldb_message_element *el,
3646 const struct dsdb_attribute *sa,
3647 struct ldb_request *parent)
3650 TALLOC_CTX *tmp_ctx = talloc_new(module);
3651 struct ldb_context *ldb = ldb_module_get_ctx(module);
3653 for (i=0; i<el->num_values; i++) {
3654 struct dsdb_dn *dsdb_dn;
3656 struct ldb_message *msg;
3657 const struct dsdb_attribute *target_attr;
3658 struct ldb_message_element *el2;
3660 struct ldb_val dn_val;
3661 uint32_t dsdb_flags = 0;
3662 const char *attrs[] = { NULL, NULL };
3663 struct ldb_result *link_res;
3664 struct ldb_message *link_msg;
3665 struct ldb_message_element *link_el;
3666 struct parsed_dn *link_dns;
3667 struct parsed_dn *p = NULL, *unused = NULL;
3669 if (dsdb_dn_is_deleted_val(&el->values[i])) {
3673 dsdb_dn = dsdb_dn_parse(tmp_ctx, ldb, &el->values[i], sa->syntax->ldap_oid);
3675 talloc_free(tmp_ctx);
3676 return LDB_ERR_OPERATIONS_ERROR;
3679 /* remove the link */
3680 msg = ldb_msg_new(tmp_ctx);
3682 ldb_module_oom(module);
3683 talloc_free(tmp_ctx);
3684 return LDB_ERR_OPERATIONS_ERROR;
3688 msg->dn = dsdb_dn->dn;
3690 target_attr = dsdb_attribute_by_linkID(schema, sa->linkID ^ 1);
3691 if (target_attr == NULL) {
3694 attrs[0] = target_attr->lDAPDisplayName;
3696 ret = ldb_msg_add_empty(msg, target_attr->lDAPDisplayName,
3697 LDB_FLAG_MOD_DELETE, &el2);
3698 if (ret != LDB_SUCCESS) {
3699 ldb_module_oom(module);
3700 talloc_free(tmp_ctx);
3701 return LDB_ERR_OPERATIONS_ERROR;
3704 ret = dsdb_module_search_dn(module, tmp_ctx, &link_res,
3706 DSDB_FLAG_NEXT_MODULE |
3707 DSDB_SEARCH_SHOW_EXTENDED_DN,
3710 if (ret != LDB_SUCCESS) {
3711 talloc_free(tmp_ctx);
3715 link_msg = link_res->msgs[0];
3716 link_el = ldb_msg_find_element(link_msg,
3717 target_attr->lDAPDisplayName);
3718 if (link_el == NULL) {
3719 talloc_free(tmp_ctx);
3720 return LDB_ERR_NO_SUCH_ATTRIBUTE;
3724 * This call 'upgrades' the links in link_dns, but we
3725 * do not commit the result back into the database, so
3726 * this is safe to call in FL2000 or on databases that
3727 * have been run at that level in the past.
3729 ret = get_parsed_dns_trusted(module, replmd_private, tmp_ctx,
3731 target_attr->syntax->ldap_oid, parent);
3732 if (ret != LDB_SUCCESS) {
3733 talloc_free(tmp_ctx);
3737 ret = parsed_dn_find(ldb, link_dns, link_el->num_values,
3741 target_attr->syntax->ldap_oid, false);
3742 if (ret != LDB_SUCCESS) {
3743 talloc_free(tmp_ctx);
3748 ldb_asprintf_errstring(ldb_module_get_ctx(module),
3749 "Failed to find forward link on %s "
3750 "as %s to remove backlink %s on %s",
3751 ldb_dn_get_linearized(msg->dn),
3752 target_attr->lDAPDisplayName,
3753 sa->lDAPDisplayName,
3754 ldb_dn_get_linearized(dn));
3755 talloc_free(tmp_ctx);
3756 return LDB_ERR_NO_SUCH_ATTRIBUTE;
3760 /* This needs to get the Binary DN, by first searching */
3761 dn_str = dsdb_dn_get_linearized(tmp_ctx,
3764 dn_val = data_blob_string_const(dn_str);
3765 el2->values = &dn_val;
3766 el2->num_values = 1;
3769 * Ensure that we tell the modification to vanish any linked
3770 * attributes (not simply mark them as isDeleted = TRUE)
3772 dsdb_flags |= DSDB_REPLMD_VANISH_LINKS;
3774 ret = dsdb_module_modify(module, msg, dsdb_flags|DSDB_FLAG_OWN_MODULE, parent);
3775 if (ret != LDB_SUCCESS) {
3776 talloc_free(tmp_ctx);
3780 talloc_free(tmp_ctx);
3786 handle update of replication meta data for deletion of objects
3788 This also handles the mapping of delete to a rename operation
3789 to allow deletes to be replicated.
3791 It also handles the incoming deleted objects, to ensure they are
3792 fully deleted here. In that case re_delete is true, and we do not
3793 use this as a signal to change the deleted state, just reinforce it.
3796 static int replmd_delete_internals(struct ldb_module *module, struct ldb_request *req, bool re_delete)
3798 int ret = LDB_ERR_OTHER;
3799 bool retb, disallow_move_on_delete;
3800 struct ldb_dn *old_dn, *new_dn;
3801 const char *rdn_name;
3802 const struct ldb_val *rdn_value, *new_rdn_value;
3804 struct ldb_context *ldb = ldb_module_get_ctx(module);
3805 const struct dsdb_schema *schema;
3806 struct ldb_message *msg, *old_msg;
3807 struct ldb_message_element *el;
3808 TALLOC_CTX *tmp_ctx;
3809 struct ldb_result *res, *parent_res;
3810 static const char * const preserved_attrs[] = {
3811 /* yes, this really is a hard coded list. See MS-ADTS
3812 section 3.1.1.5.5.1.1 */
3815 "dNReferenceUpdate",
3826 "msDS-LastKnownRDN",
3832 "distinguishedName",
3836 "proxiedObjectName",
3838 "nTSecurityDescriptor",
3839 "replPropertyMetaData",
3841 "securityIdentifier",
3849 "userAccountControl",
3856 static const char * const all_attrs[] = {
3857 DSDB_SECRET_ATTRIBUTES,
3861 unsigned int i, el_count = 0;
3862 uint32_t dsdb_flags = 0;
3863 struct replmd_private *replmd_private;
3864 enum deletion_state deletion_state, next_deletion_state;
3866 if (ldb_dn_is_special(req->op.del.dn)) {
3867 return ldb_next_request(module, req);
3871 * We have to allow dbcheck to remove an object that
3872 * is beyond repair, and to do so totally. This could
3873 * mean we we can get a partial object from the other
3874 * DC, causing havoc, so dbcheck suggests
3875 * re-replication first. dbcheck sets both DBCHECK
3876 * and RELAX in this situation.
3878 if (ldb_request_get_control(req, LDB_CONTROL_RELAX_OID)
3879 && ldb_request_get_control(req, DSDB_CONTROL_DBCHECK)) {
3880 /* really, really remove it */
3881 return ldb_next_request(module, req);
3884 tmp_ctx = talloc_new(ldb);
3887 return LDB_ERR_OPERATIONS_ERROR;
3890 schema = dsdb_get_schema(ldb, tmp_ctx);
3892 talloc_free(tmp_ctx);
3893 return LDB_ERR_OPERATIONS_ERROR;
3896 old_dn = ldb_dn_copy(tmp_ctx, req->op.del.dn);
3898 /* we need the complete msg off disk, so we can work out which
3899 attributes need to be removed */
3900 ret = dsdb_module_search_dn(module, tmp_ctx, &res, old_dn, all_attrs,
3901 DSDB_FLAG_NEXT_MODULE |
3902 DSDB_SEARCH_SHOW_RECYCLED |
3903 DSDB_SEARCH_REVEAL_INTERNALS |
3904 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT, req);
3905 if (ret != LDB_SUCCESS) {
3906 ldb_asprintf_errstring(ldb_module_get_ctx(module),
3907 "repmd_delete: Failed to %s %s, because we failed to find it: %s",
3908 re_delete ? "re-delete" : "delete",
3909 ldb_dn_get_linearized(old_dn),
3910 ldb_errstring(ldb_module_get_ctx(module)));
3911 talloc_free(tmp_ctx);
3914 old_msg = res->msgs[0];
3916 replmd_deletion_state(module, old_msg,
3918 &next_deletion_state);
3920 /* This supports us noticing an incoming isDeleted and acting on it */
3922 SMB_ASSERT(deletion_state > OBJECT_NOT_DELETED);
3923 next_deletion_state = deletion_state;
3926 if (next_deletion_state == OBJECT_REMOVED) {
3928 * We have to prevent objects being deleted, even if
3929 * the administrator really wants them gone, as
3930 * without the tombstone, we can get a partial object
3931 * from the other DC, causing havoc.
3933 * The only other valid case is when the 180 day
3934 * timeout has expired, when relax is specified.
3936 if (ldb_request_get_control(req, LDB_CONTROL_RELAX_OID)) {
3937 /* it is already deleted - really remove it this time */
3938 talloc_free(tmp_ctx);
3939 return ldb_next_request(module, req);
3942 ldb_asprintf_errstring(ldb, "Refusing to delete tombstone object %s. "
3943 "This check is to prevent corruption of the replicated state.",
3944 ldb_dn_get_linearized(old_msg->dn));
3945 return LDB_ERR_UNWILLING_TO_PERFORM;
3948 rdn_name = ldb_dn_get_rdn_name(old_dn);
3949 rdn_value = ldb_dn_get_rdn_val(old_dn);
3950 if ((rdn_name == NULL) || (rdn_value == NULL)) {
3951 talloc_free(tmp_ctx);
3952 return ldb_operr(ldb);
3955 msg = ldb_msg_new(tmp_ctx);
3957 ldb_module_oom(module);
3958 talloc_free(tmp_ctx);
3959 return LDB_ERR_OPERATIONS_ERROR;
3964 /* consider the SYSTEM_FLAG_DISALLOW_MOVE_ON_DELETE flag */
3965 disallow_move_on_delete =
3966 (ldb_msg_find_attr_as_int(old_msg, "systemFlags", 0)
3967 & SYSTEM_FLAG_DISALLOW_MOVE_ON_DELETE);
3969 /* work out where we will be renaming this object to */
3970 if (!disallow_move_on_delete) {
3971 struct ldb_dn *deleted_objects_dn;
3972 ret = dsdb_get_deleted_objects_dn(ldb, tmp_ctx, old_dn,
3973 &deleted_objects_dn);
3976 * We should not move objects if we can't find the
3977 * deleted objects DN. Not moving (or otherwise
3978 * harming) the Deleted Objects DN itself is handled
3981 if (re_delete && (ret != LDB_SUCCESS)) {
3982 new_dn = ldb_dn_get_parent(tmp_ctx, old_dn);
3983 if (new_dn == NULL) {
3984 ldb_module_oom(module);
3985 talloc_free(tmp_ctx);
3986 return LDB_ERR_OPERATIONS_ERROR;
3988 } else if (ret != LDB_SUCCESS) {
3989 /* this is probably an attempted delete on a partition
3990 * that doesn't allow delete operations, such as the
3991 * schema partition */
3992 ldb_asprintf_errstring(ldb, "No Deleted Objects container for DN %s",
3993 ldb_dn_get_linearized(old_dn));
3994 talloc_free(tmp_ctx);
3995 return LDB_ERR_UNWILLING_TO_PERFORM;
3997 new_dn = deleted_objects_dn;
4000 new_dn = ldb_dn_get_parent(tmp_ctx, old_dn);
4001 if (new_dn == NULL) {
4002 ldb_module_oom(module);
4003 talloc_free(tmp_ctx);
4004 return LDB_ERR_OPERATIONS_ERROR;
4008 /* get the objects GUID from the search we just did */
4009 guid = samdb_result_guid(old_msg, "objectGUID");
4011 if (deletion_state == OBJECT_NOT_DELETED) {
4012 /* Add a formatted child */
4013 retb = ldb_dn_add_child_fmt(new_dn, "%s=%s\\0ADEL:%s",
4015 ldb_dn_escape_value(tmp_ctx, *rdn_value),
4016 GUID_string(tmp_ctx, &guid));
4018 ldb_asprintf_errstring(ldb, __location__
4019 ": Unable to add a formatted child to dn: %s",
4020 ldb_dn_get_linearized(new_dn));
4021 talloc_free(tmp_ctx);
4022 return LDB_ERR_OPERATIONS_ERROR;
4025 ret = ldb_msg_add_string(msg, "isDeleted", "TRUE");
4026 if (ret != LDB_SUCCESS) {
4027 ldb_asprintf_errstring(ldb, __location__
4028 ": Failed to add isDeleted string to the msg");
4029 talloc_free(tmp_ctx);
4032 msg->elements[el_count++].flags = LDB_FLAG_MOD_REPLACE;
4035 * No matter what has happened with other renames etc, try again to
4036 * get this to be under the deleted DN. See MS-DRSR 5.160 RemoveObj
4039 struct ldb_dn *rdn = ldb_dn_copy(tmp_ctx, old_dn);
4040 retb = ldb_dn_remove_base_components(rdn, ldb_dn_get_comp_num(rdn) - 1);
4042 ldb_asprintf_errstring(ldb, __location__
4043 ": Unable to add a prepare rdn of %s",
4044 ldb_dn_get_linearized(rdn));
4045 talloc_free(tmp_ctx);
4046 return LDB_ERR_OPERATIONS_ERROR;
4048 SMB_ASSERT(ldb_dn_get_comp_num(rdn) == 1);
4050 retb = ldb_dn_add_child(new_dn, rdn);
4052 ldb_asprintf_errstring(ldb, __location__
4053 ": Unable to add rdn %s to base dn: %s",
4054 ldb_dn_get_linearized(rdn),
4055 ldb_dn_get_linearized(new_dn));
4056 talloc_free(tmp_ctx);
4057 return LDB_ERR_OPERATIONS_ERROR;
4062 now we need to modify the object in the following ways:
4064 - add isDeleted=TRUE
4065 - update rDN and name, with new rDN
4066 - remove linked attributes
4067 - remove objectCategory and sAMAccountType
4068 - remove attribs not on the preserved list
4069 - preserved if in above list, or is rDN
4070 - remove all linked attribs from this object
4071 - remove all links from other objects to this object
4072 - add lastKnownParent
4073 - update replPropertyMetaData?
4075 see MS-ADTS "Tombstone Requirements" section 3.1.1.5.5.1.1
4078 if (deletion_state == OBJECT_NOT_DELETED) {
4079 struct ldb_dn *parent_dn = ldb_dn_get_parent(tmp_ctx, old_dn);
4080 char *parent_dn_str = NULL;
4082 /* we need the storage form of the parent GUID */
4083 ret = dsdb_module_search_dn(module, tmp_ctx, &parent_res,
4085 DSDB_FLAG_NEXT_MODULE |
4086 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT |
4087 DSDB_SEARCH_REVEAL_INTERNALS|
4088 DSDB_SEARCH_SHOW_RECYCLED, req);
4089 if (ret != LDB_SUCCESS) {
4090 ldb_asprintf_errstring(ldb_module_get_ctx(module),
4091 "repmd_delete: Failed to %s %s, "
4092 "because we failed to find it's parent (%s): %s",
4093 re_delete ? "re-delete" : "delete",
4094 ldb_dn_get_linearized(old_dn),
4095 ldb_dn_get_linearized(parent_dn),
4096 ldb_errstring(ldb_module_get_ctx(module)));
4097 talloc_free(tmp_ctx);
4102 * Now we can use the DB version,
4103 * it will have the extended DN info in it
4105 parent_dn = parent_res->msgs[0]->dn;
4106 parent_dn_str = ldb_dn_get_extended_linearized(tmp_ctx,
4109 if (parent_dn_str == NULL) {
4110 talloc_free(tmp_ctx);
4111 return ldb_module_oom(module);
4114 ret = ldb_msg_add_steal_string(msg, "lastKnownParent",
4116 if (ret != LDB_SUCCESS) {
4117 ldb_asprintf_errstring(ldb, __location__
4118 ": Failed to add lastKnownParent "
4119 "string when deleting %s",
4120 ldb_dn_get_linearized(old_dn));
4121 talloc_free(tmp_ctx);
4124 msg->elements[el_count++].flags = LDB_FLAG_MOD_REPLACE;
4126 if (next_deletion_state == OBJECT_DELETED) {
4127 ret = ldb_msg_add_value(msg, "msDS-LastKnownRDN", rdn_value, NULL);
4128 if (ret != LDB_SUCCESS) {
4129 ldb_asprintf_errstring(ldb, __location__
4130 ": Failed to add msDS-LastKnownRDN "
4131 "string when deleting %s",
4132 ldb_dn_get_linearized(old_dn));
4133 talloc_free(tmp_ctx);
4136 msg->elements[el_count++].flags = LDB_FLAG_MOD_ADD;
4140 switch (next_deletion_state) {
4142 case OBJECT_RECYCLED:
4143 case OBJECT_TOMBSTONE:
4146 * MS-ADTS 3.1.1.5.5.1.1 Tombstone Requirements
4147 * describes what must be removed from a tombstone
4150 * MS-ADTS 3.1.1.5.5.1.3 Recycled-Object Requirements
4151 * describes what must be removed from a recycled
4157 * we also mark it as recycled, meaning this object can't be
4158 * recovered (we are stripping its attributes).
4159 * This is done only if we have this schema object of course ...
4160 * This behavior is identical to the one of Windows 2008R2 which
4161 * always set the isRecycled attribute, even if the recycle-bin is
4162 * not activated and what ever the forest level is.
4164 if (dsdb_attribute_by_lDAPDisplayName(schema, "isRecycled") != NULL) {
4165 ret = ldb_msg_add_string(msg, "isRecycled", "TRUE");
4166 if (ret != LDB_SUCCESS) {
4167 DEBUG(0,(__location__ ": Failed to add isRecycled string to the msg\n"));
4168 ldb_module_oom(module);
4169 talloc_free(tmp_ctx);
4172 msg->elements[el_count++].flags = LDB_FLAG_MOD_REPLACE;
4175 replmd_private = talloc_get_type(ldb_module_get_private(module),
4176 struct replmd_private);
4177 /* work out which of the old attributes we will be removing */
4178 for (i=0; i<old_msg->num_elements; i++) {
4179 const struct dsdb_attribute *sa;
4180 el = &old_msg->elements[i];
4181 sa = dsdb_attribute_by_lDAPDisplayName(schema, el->name);
4183 talloc_free(tmp_ctx);
4184 return LDB_ERR_OPERATIONS_ERROR;
4186 if (ldb_attr_cmp(el->name, rdn_name) == 0) {
4187 /* don't remove the rDN */
4190 if (sa->linkID & 1) {
4192 we have a backlink in this object
4193 that needs to be removed. We're not
4194 allowed to remove it directly
4195 however, so we instead setup a
4196 modify to delete the corresponding
4199 ret = replmd_delete_remove_link(module, schema,
4203 if (ret != LDB_SUCCESS) {
4204 const char *old_dn_str
4205 = ldb_dn_get_linearized(old_dn);
4206 ldb_asprintf_errstring(ldb,
4208 ": Failed to remove backlink of "
4209 "%s when deleting %s: %s",
4212 ldb_errstring(ldb));
4213 talloc_free(tmp_ctx);
4214 return LDB_ERR_OPERATIONS_ERROR;
4216 /* now we continue, which means we
4217 won't remove this backlink
4221 } else if (sa->linkID == 0) {
4222 if (ldb_attr_in_list(preserved_attrs, el->name)) {
4225 if (sa->searchFlags & SEARCH_FLAG_PRESERVEONDELETE) {
4230 * Ensure that we tell the modification to vanish any linked
4231 * attributes (not simply mark them as isDeleted = TRUE)
4233 dsdb_flags |= DSDB_REPLMD_VANISH_LINKS;
4235 ret = ldb_msg_add_empty(msg, el->name, LDB_FLAG_MOD_DELETE, &el);
4236 if (ret != LDB_SUCCESS) {
4237 talloc_free(tmp_ctx);
4238 ldb_module_oom(module);
4245 case OBJECT_DELETED:
4247 * MS-ADTS 3.1.1.5.5.1.2 Deleted-Object Requirements
4248 * describes what must be removed from a deleted
4252 ret = ldb_msg_add_empty(msg, "objectCategory", LDB_FLAG_MOD_REPLACE, NULL);
4253 if (ret != LDB_SUCCESS) {
4254 talloc_free(tmp_ctx);
4255 ldb_module_oom(module);
4259 ret = ldb_msg_add_empty(msg, "sAMAccountType", LDB_FLAG_MOD_REPLACE, NULL);
4260 if (ret != LDB_SUCCESS) {
4261 talloc_free(tmp_ctx);
4262 ldb_module_oom(module);
4272 if (deletion_state == OBJECT_NOT_DELETED) {
4273 const struct dsdb_attribute *sa;
4275 /* work out what the new rdn value is, for updating the
4276 rDN and name fields */
4277 new_rdn_value = ldb_dn_get_rdn_val(new_dn);
4278 if (new_rdn_value == NULL) {
4279 talloc_free(tmp_ctx);
4280 return ldb_operr(ldb);
4283 sa = dsdb_attribute_by_lDAPDisplayName(schema, rdn_name);
4285 talloc_free(tmp_ctx);
4286 return LDB_ERR_OPERATIONS_ERROR;
4289 ret = ldb_msg_add_value(msg, sa->lDAPDisplayName, new_rdn_value,
4291 if (ret != LDB_SUCCESS) {
4292 talloc_free(tmp_ctx);
4295 el->flags = LDB_FLAG_MOD_REPLACE;
4297 el = ldb_msg_find_element(old_msg, "name");
4299 ret = ldb_msg_add_value(msg, "name", new_rdn_value, &el);
4300 if (ret != LDB_SUCCESS) {
4301 talloc_free(tmp_ctx);
4304 el->flags = LDB_FLAG_MOD_REPLACE;
4309 * TODO: Per MS-DRSR 5.160 RemoveObj we should remove links directly, not as an originating update!
4314 * No matter what has happned with other renames, try again to
4315 * get this to be under the deleted DN.
4317 if (strcmp(ldb_dn_get_linearized(old_dn), ldb_dn_get_linearized(new_dn)) != 0) {
4318 /* now rename onto the new DN */
4319 ret = dsdb_module_rename(module, old_dn, new_dn, DSDB_FLAG_NEXT_MODULE, req);
4320 if (ret != LDB_SUCCESS){
4321 DEBUG(0,(__location__ ": Failed to rename object from '%s' to '%s' - %s\n",
4322 ldb_dn_get_linearized(old_dn),
4323 ldb_dn_get_linearized(new_dn),
4324 ldb_errstring(ldb)));
4325 talloc_free(tmp_ctx);
4331 ret = dsdb_module_modify(module, msg, dsdb_flags|DSDB_FLAG_OWN_MODULE, req);
4332 if (ret != LDB_SUCCESS) {
4333 ldb_asprintf_errstring(ldb, "replmd_delete: Failed to modify object %s in delete - %s",
4334 ldb_dn_get_linearized(old_dn), ldb_errstring(ldb));
4335 talloc_free(tmp_ctx);
4339 talloc_free(tmp_ctx);
4341 return ldb_module_done(req, NULL, NULL, LDB_SUCCESS);
4344 static int replmd_delete(struct ldb_module *module, struct ldb_request *req)
4346 return replmd_delete_internals(module, req, false);
4350 static int replmd_replicated_request_error(struct replmd_replicated_request *ar, int ret)
4355 static int replmd_replicated_request_werror(struct replmd_replicated_request *ar, WERROR status)
4357 int ret = LDB_ERR_OTHER;
4358 /* TODO: do some error mapping */
4360 /* Let the caller know the full WERROR */
4361 ar->objs->error = status;
4367 static struct replPropertyMetaData1 *
4368 replmd_replPropertyMetaData1_find_attid(struct replPropertyMetaDataBlob *md_blob,
4369 enum drsuapi_DsAttributeId attid)
4372 struct replPropertyMetaDataCtr1 *rpmd_ctr = &md_blob->ctr.ctr1;
4374 for (i = 0; i < rpmd_ctr->count; i++) {
4375 if (rpmd_ctr->array[i].attid == attid) {
4376 return &rpmd_ctr->array[i];
4384 return true if an update is newer than an existing entry
4385 see section 5.11 of MS-ADTS
4387 static bool replmd_update_is_newer(const struct GUID *current_invocation_id,
4388 const struct GUID *update_invocation_id,
4389 uint32_t current_version,
4390 uint32_t update_version,
4391 NTTIME current_change_time,
4392 NTTIME update_change_time)
4394 if (update_version != current_version) {
4395 return update_version > current_version;
4397 if (update_change_time != current_change_time) {
4398 return update_change_time > current_change_time;
4400 return GUID_compare(update_invocation_id, current_invocation_id) > 0;
4403 static bool replmd_replPropertyMetaData1_is_newer(struct replPropertyMetaData1 *cur_m,
4404 struct replPropertyMetaData1 *new_m)
4406 return replmd_update_is_newer(&cur_m->originating_invocation_id,
4407 &new_m->originating_invocation_id,
4410 cur_m->originating_change_time,
4411 new_m->originating_change_time);
4414 static bool replmd_replPropertyMetaData1_new_should_be_taken(uint32_t dsdb_repl_flags,
4415 struct replPropertyMetaData1 *cur_m,
4416 struct replPropertyMetaData1 *new_m)
4421 * If the new replPropertyMetaData entry for this attribute is
4422 * not provided (this happens in the case where we look for
4423 * ATTID_name, but the name was not changed), then the local
4424 * state is clearly still current, as the remote
4425 * server didn't send it due to being older the high watermark
4428 if (new_m == NULL) {
4432 if (dsdb_repl_flags & DSDB_REPL_FLAG_PRIORITISE_INCOMING) {
4434 * if we compare equal then do an
4435 * update. This is used when a client
4436 * asks for a FULL_SYNC, and can be
4437 * used to recover a corrupt
4440 * This call is a bit tricky, what we
4441 * are doing it turning the 'is_newer'
4442 * call into a 'not is older' by
4443 * swapping cur_m and new_m, and negating the
4446 cmp = !replmd_replPropertyMetaData1_is_newer(new_m,
4449 cmp = replmd_replPropertyMetaData1_is_newer(cur_m,
4459 static struct ldb_dn *replmd_conflict_dn(TALLOC_CTX *mem_ctx, struct ldb_dn *dn, struct GUID *guid)
4461 const struct ldb_val *rdn_val;
4462 const char *rdn_name;
4463 struct ldb_dn *new_dn;
4465 rdn_val = ldb_dn_get_rdn_val(dn);
4466 rdn_name = ldb_dn_get_rdn_name(dn);
4467 if (!rdn_val || !rdn_name) {
4471 new_dn = ldb_dn_copy(mem_ctx, dn);
4476 if (!ldb_dn_remove_child_components(new_dn, 1)) {
4480 if (!ldb_dn_add_child_fmt(new_dn, "%s=%s\\0ACNF:%s",
4482 ldb_dn_escape_value(new_dn, *rdn_val),
4483 GUID_string(new_dn, guid))) {
4492 perform a modify operation which sets the rDN and name attributes to
4493 their current values. This has the effect of changing these
4494 attributes to have been last updated by the current DC. This is
4495 needed to ensure that renames performed as part of conflict
4496 resolution are propogated to other DCs
4498 static int replmd_name_modify(struct replmd_replicated_request *ar,
4499 struct ldb_request *req, struct ldb_dn *dn)
4501 struct ldb_message *msg;
4502 const char *rdn_name;
4503 const struct ldb_val *rdn_val;
4504 const struct dsdb_attribute *rdn_attr;
4507 msg = ldb_msg_new(req);
4513 rdn_name = ldb_dn_get_rdn_name(dn);
4514 if (rdn_name == NULL) {
4518 /* normalize the rdn attribute name */
4519 rdn_attr = dsdb_attribute_by_lDAPDisplayName(ar->schema, rdn_name);
4520 if (rdn_attr == NULL) {
4523 rdn_name = rdn_attr->lDAPDisplayName;
4525 rdn_val = ldb_dn_get_rdn_val(dn);
4526 if (rdn_val == NULL) {
4530 if (ldb_msg_add_empty(msg, rdn_name, LDB_FLAG_MOD_REPLACE, NULL) != 0) {
4533 if (ldb_msg_add_value(msg, rdn_name, rdn_val, NULL) != 0) {
4536 if (ldb_msg_add_empty(msg, "name", LDB_FLAG_MOD_REPLACE, NULL) != 0) {
4539 if (ldb_msg_add_value(msg, "name", rdn_val, NULL) != 0) {
4544 * We have to mark this as a replicated update otherwise
4545 * schema_data may reject a rename in the schema partition
4548 ret = dsdb_module_modify(ar->module, msg,
4549 DSDB_FLAG_OWN_MODULE|DSDB_FLAG_REPLICATED_UPDATE,
4551 if (ret != LDB_SUCCESS) {
4552 DEBUG(0,(__location__ ": Failed to modify rDN/name of DN being DRS renamed '%s' - %s",
4553 ldb_dn_get_linearized(dn),
4554 ldb_errstring(ldb_module_get_ctx(ar->module))));
4564 DEBUG(0,(__location__ ": Failed to setup modify rDN/name of DN being DRS renamed '%s'",
4565 ldb_dn_get_linearized(dn)));
4566 return LDB_ERR_OPERATIONS_ERROR;
4571 callback for conflict DN handling where we have renamed the incoming
4572 record. After renaming it, we need to ensure the change of name and
4573 rDN for the incoming record is seen as an originating update by this DC.
4575 This also handles updating lastKnownParent for entries sent to lostAndFound
4577 static int replmd_op_name_modify_callback(struct ldb_request *req, struct ldb_reply *ares)
4579 struct replmd_replicated_request *ar =
4580 talloc_get_type_abort(req->context, struct replmd_replicated_request);
4581 struct ldb_dn *conflict_dn = NULL;
4584 if (ares->error != LDB_SUCCESS) {
4585 /* call the normal callback for everything except success */
4586 return replmd_op_callback(req, ares);
4589 switch (req->operation) {
4591 conflict_dn = req->op.add.message->dn;
4594 conflict_dn = req->op.mod.message->dn;
4597 smb_panic("replmd_op_name_modify_callback called in unknown circumstances");
4600 /* perform a modify of the rDN and name of the record */
4601 ret = replmd_name_modify(ar, req, conflict_dn);
4602 if (ret != LDB_SUCCESS) {
4604 return replmd_op_callback(req, ares);
4607 if (ar->objs->objects[ar->index_current].last_known_parent) {
4608 struct ldb_message *msg = ldb_msg_new(req);
4610 ldb_module_oom(ar->module);
4611 return LDB_ERR_OPERATIONS_ERROR;
4614 msg->dn = req->op.add.message->dn;
4616 ret = ldb_msg_add_steal_string(msg, "lastKnownParent",
4617 ldb_dn_get_extended_linearized(msg, ar->objs->objects[ar->index_current].last_known_parent, 1));
4618 if (ret != LDB_SUCCESS) {
4619 DEBUG(0,(__location__ ": Failed to add lastKnownParent string to the msg\n"));
4620 ldb_module_oom(ar->module);
4623 msg->elements[0].flags = LDB_FLAG_MOD_REPLACE;
4625 ret = dsdb_module_modify(ar->module, msg, DSDB_FLAG_OWN_MODULE, req);
4626 if (ret != LDB_SUCCESS) {
4627 DEBUG(0,(__location__ ": Failed to modify lastKnownParent of lostAndFound DN '%s' - %s",
4628 ldb_dn_get_linearized(msg->dn),
4629 ldb_errstring(ldb_module_get_ctx(ar->module))));
4635 return replmd_op_callback(req, ares);
4639 callback for replmd_replicated_apply_add()
4640 This copes with the creation of conflict records in the case where
4641 the DN exists, but with a different objectGUID
4643 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))
4645 struct ldb_dn *conflict_dn;
4646 struct replmd_replicated_request *ar =
4647 talloc_get_type_abort(req->context, struct replmd_replicated_request);
4648 struct ldb_result *res;
4649 const char *attrs[] = { "replPropertyMetaData", "objectGUID", NULL };
4651 const struct ldb_val *omd_value;
4652 struct replPropertyMetaDataBlob omd, *rmd;
4653 enum ndr_err_code ndr_err;
4654 bool rename_incoming_record, rodc;
4655 struct replPropertyMetaData1 *rmd_name, *omd_name;
4656 struct ldb_message *msg;
4657 struct ldb_request *down_req = NULL;
4659 /* call the normal callback for success */
4660 if (ares->error == LDB_SUCCESS) {
4661 return callback(req, ares);
4665 * we have a conflict, and need to decide if we will keep the
4666 * new record or the old record
4669 msg = ar->objs->objects[ar->index_current].msg;
4670 conflict_dn = msg->dn;
4672 /* For failures other than conflicts, fail the whole operation here */
4673 if (ares->error != LDB_ERR_ENTRY_ALREADY_EXISTS) {
4674 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module), "Failed to locally apply remote add of %s: %s",
4675 ldb_dn_get_linearized(conflict_dn),
4676 ldb_errstring(ldb_module_get_ctx(ar->module)));
4678 return ldb_module_done(ar->req, NULL, NULL,
4679 LDB_ERR_OPERATIONS_ERROR);
4682 ret = samdb_rodc(ldb_module_get_ctx(ar->module), &rodc);
4683 if (ret != LDB_SUCCESS) {
4684 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)));
4685 return ldb_module_done(ar->req, NULL, NULL,
4686 LDB_ERR_OPERATIONS_ERROR);
4692 * We are on an RODC, or were a GC for this
4693 * partition, so we have to fail this until
4694 * someone who owns the partition sorts it
4697 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
4698 "Conflict adding object '%s' from incoming replication as we are read only for the partition. \n"
4699 " - We must fail the operation until a master for this partition resolves the conflict",
4700 ldb_dn_get_linearized(conflict_dn));
4705 * first we need the replPropertyMetaData attribute from the
4706 * local, conflicting record
4708 ret = dsdb_module_search_dn(ar->module, req, &res, conflict_dn,
4710 DSDB_FLAG_NEXT_MODULE |
4711 DSDB_SEARCH_SHOW_DELETED |
4712 DSDB_SEARCH_SHOW_RECYCLED, req);
4713 if (ret != LDB_SUCCESS) {
4714 DEBUG(0,(__location__ ": Unable to find object for conflicting record '%s'\n",
4715 ldb_dn_get_linearized(conflict_dn)));
4719 omd_value = ldb_msg_find_ldb_val(res->msgs[0], "replPropertyMetaData");
4720 if (omd_value == NULL) {
4721 DEBUG(0,(__location__ ": Unable to find replPropertyMetaData for conflicting record '%s'\n",
4722 ldb_dn_get_linearized(conflict_dn)));
4726 ndr_err = ndr_pull_struct_blob(omd_value, res->msgs[0], &omd,
4727 (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
4728 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
4729 DEBUG(0,(__location__ ": Failed to parse old replPropertyMetaData for %s\n",
4730 ldb_dn_get_linearized(conflict_dn)));
4734 rmd = ar->objs->objects[ar->index_current].meta_data;
4737 * we decide which is newer based on the RPMD on the name
4738 * attribute. See [MS-DRSR] ResolveNameConflict.
4740 * We expect omd_name to be present, as this is from a local
4741 * search, but while rmd_name should have been given to us by
4742 * the remote server, if it is missing we just prefer the
4744 * replmd_replPropertyMetaData1_new_should_be_taken()
4746 rmd_name = replmd_replPropertyMetaData1_find_attid(rmd, DRSUAPI_ATTID_name);
4747 omd_name = replmd_replPropertyMetaData1_find_attid(&omd, DRSUAPI_ATTID_name);
4749 DEBUG(0,(__location__ ": Failed to find name attribute in local LDB replPropertyMetaData for %s\n",
4750 ldb_dn_get_linearized(conflict_dn)));
4755 * Should we preserve the current record, and so rename the
4756 * incoming record to be a conflict?
4758 rename_incoming_record
4759 = !replmd_replPropertyMetaData1_new_should_be_taken(ar->objs->dsdb_repl_flags & DSDB_REPL_FLAG_PRIORITISE_INCOMING,
4760 omd_name, rmd_name);
4762 if (rename_incoming_record) {
4764 struct ldb_dn *new_dn;
4766 guid = samdb_result_guid(msg, "objectGUID");
4767 if (GUID_all_zero(&guid)) {
4768 DEBUG(0,(__location__ ": Failed to find objectGUID for conflicting incoming record %s\n",
4769 ldb_dn_get_linearized(conflict_dn)));
4772 new_dn = replmd_conflict_dn(req, conflict_dn, &guid);
4773 if (new_dn == NULL) {
4774 DEBUG(0,(__location__ ": Failed to form conflict DN for %s\n",
4775 ldb_dn_get_linearized(conflict_dn)));
4779 DEBUG(2,(__location__ ": Resolving conflict record via incoming rename '%s' -> '%s'\n",
4780 ldb_dn_get_linearized(conflict_dn), ldb_dn_get_linearized(new_dn)));
4782 /* re-submit the request, but with the new DN */
4783 callback = replmd_op_name_modify_callback;
4786 /* we are renaming the existing record */
4788 struct ldb_dn *new_dn;
4790 guid = samdb_result_guid(res->msgs[0], "objectGUID");
4791 if (GUID_all_zero(&guid)) {
4792 DEBUG(0,(__location__ ": Failed to find objectGUID for existing conflict record %s\n",
4793 ldb_dn_get_linearized(conflict_dn)));
4797 new_dn = replmd_conflict_dn(req, conflict_dn, &guid);
4798 if (new_dn == NULL) {
4799 DEBUG(0,(__location__ ": Failed to form conflict DN for %s\n",
4800 ldb_dn_get_linearized(conflict_dn)));
4804 DEBUG(2,(__location__ ": Resolving conflict record via existing-record rename '%s' -> '%s'\n",
4805 ldb_dn_get_linearized(conflict_dn), ldb_dn_get_linearized(new_dn)));
4807 ret = dsdb_module_rename(ar->module, conflict_dn, new_dn,
4808 DSDB_FLAG_OWN_MODULE, req);
4809 if (ret != LDB_SUCCESS) {
4810 DEBUG(0,(__location__ ": Failed to rename conflict dn '%s' to '%s' - %s\n",
4811 ldb_dn_get_linearized(conflict_dn),
4812 ldb_dn_get_linearized(new_dn),
4813 ldb_errstring(ldb_module_get_ctx(ar->module))));
4818 * now we need to ensure that the rename is seen as an
4819 * originating update. We do that with a modify.
4821 ret = replmd_name_modify(ar, req, new_dn);
4822 if (ret != LDB_SUCCESS) {
4826 DEBUG(2,(__location__ ": With conflicting record renamed, re-apply replicated creation of '%s'\n",
4827 ldb_dn_get_linearized(req->op.add.message->dn)));
4830 ret = ldb_build_add_req(&down_req,
4831 ldb_module_get_ctx(ar->module),
4838 if (ret != LDB_SUCCESS) {
4841 LDB_REQ_SET_LOCATION(down_req);
4843 /* current partition control needed by "repmd_op_callback" */
4844 ret = ldb_request_add_control(down_req,
4845 DSDB_CONTROL_CURRENT_PARTITION_OID,
4847 if (ret != LDB_SUCCESS) {
4848 return replmd_replicated_request_error(ar, ret);
4851 if (ar->objs->dsdb_repl_flags & DSDB_REPL_FLAG_PARTIAL_REPLICA) {
4852 /* this tells the partition module to make it a
4853 partial replica if creating an NC */
4854 ret = ldb_request_add_control(down_req,
4855 DSDB_CONTROL_PARTIAL_REPLICA,
4857 if (ret != LDB_SUCCESS) {
4858 return replmd_replicated_request_error(ar, ret);
4863 * Finally we re-run the add, otherwise the new record won't
4864 * exist, as we are here because of that exact failure!
4866 return ldb_next_request(ar->module, down_req);
4869 /* on failure make the caller get the error. This means
4870 * replication will stop with an error, but there is not much
4873 return ldb_module_done(ar->req, NULL, NULL,
4878 callback for replmd_replicated_apply_add()
4879 This copes with the creation of conflict records in the case where
4880 the DN exists, but with a different objectGUID
4882 static int replmd_op_add_callback(struct ldb_request *req, struct ldb_reply *ares)
4884 struct replmd_replicated_request *ar =
4885 talloc_get_type_abort(req->context, struct replmd_replicated_request);
4887 if (ar->objs->objects[ar->index_current].last_known_parent) {
4888 /* This is like a conflict DN, where we put the object in LostAndFound
4889 see MS-DRSR 4.1.10.6.10 FindBestParentObject */
4890 return replmd_op_possible_conflict_callback(req, ares, replmd_op_name_modify_callback);
4893 return replmd_op_possible_conflict_callback(req, ares, replmd_op_callback);
4897 this is called when a new object comes in over DRS
4899 static int replmd_replicated_apply_add(struct replmd_replicated_request *ar)
4901 struct ldb_context *ldb;
4902 struct ldb_request *change_req;
4903 enum ndr_err_code ndr_err;
4904 struct ldb_message *msg;
4905 struct replPropertyMetaDataBlob *md;
4906 struct ldb_val md_value;
4909 bool remote_isDeleted = false;
4912 time_t t = time(NULL);
4913 const struct ldb_val *rdn_val;
4914 struct replmd_private *replmd_private =
4915 talloc_get_type(ldb_module_get_private(ar->module),
4916 struct replmd_private);
4917 unix_to_nt_time(&now, t);
4919 ldb = ldb_module_get_ctx(ar->module);
4920 msg = ar->objs->objects[ar->index_current].msg;
4921 md = ar->objs->objects[ar->index_current].meta_data;
4922 is_schema_nc = ldb_dn_compare_base(replmd_private->schema_dn, msg->dn) == 0;
4924 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &ar->seq_num);
4925 if (ret != LDB_SUCCESS) {
4926 return replmd_replicated_request_error(ar, ret);
4929 ret = dsdb_msg_add_guid(msg,
4930 &ar->objs->objects[ar->index_current].object_guid,
4932 if (ret != LDB_SUCCESS) {
4933 return replmd_replicated_request_error(ar, ret);
4936 ret = ldb_msg_add_string(msg, "whenChanged", ar->objs->objects[ar->index_current].when_changed);
4937 if (ret != LDB_SUCCESS) {
4938 return replmd_replicated_request_error(ar, ret);
4941 ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNCreated", ar->seq_num);
4942 if (ret != LDB_SUCCESS) {
4943 return replmd_replicated_request_error(ar, ret);
4946 ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNChanged", ar->seq_num);
4947 if (ret != LDB_SUCCESS) {
4948 return replmd_replicated_request_error(ar, ret);
4951 /* remove any message elements that have zero values */
4952 for (i=0; i<msg->num_elements; i++) {
4953 struct ldb_message_element *el = &msg->elements[i];
4955 if (el->num_values == 0) {
4956 if (ldb_attr_cmp(msg->elements[i].name, "objectClass") == 0) {
4957 ldb_asprintf_errstring(ldb, __location__
4958 ": empty objectClass sent on %s, aborting replication\n",
4959 ldb_dn_get_linearized(msg->dn));
4960 return replmd_replicated_request_error(ar, LDB_ERR_OBJECT_CLASS_VIOLATION);
4963 DEBUG(4,(__location__ ": Removing attribute %s with num_values==0\n",
4965 memmove(el, el+1, sizeof(*el)*(msg->num_elements - (i+1)));
4966 msg->num_elements--;
4973 struct GUID_txt_buf guid_txt;
4975 char *s = ldb_ldif_message_string(ldb, ar, LDB_CHANGETYPE_ADD, msg);
4976 DEBUG(4, ("DRS replication add message of %s:\n%s\n",
4977 GUID_buf_string(&ar->objs->objects[ar->index_current].object_guid, &guid_txt),
4982 remote_isDeleted = ldb_msg_find_attr_as_bool(msg,
4983 "isDeleted", false);
4986 * the meta data array is already sorted by the caller, except
4987 * for the RDN, which needs to be added.
4991 rdn_val = ldb_dn_get_rdn_val(msg->dn);
4992 ret = replmd_update_rpmd_rdn_attr(ldb, msg, rdn_val, NULL,
4993 md, ar, now, is_schema_nc,
4995 if (ret != LDB_SUCCESS) {
4996 ldb_asprintf_errstring(ldb, "%s: error during DRS repl ADD: %s", __func__, ldb_errstring(ldb));
4997 return replmd_replicated_request_error(ar, ret);
5000 ret = replmd_replPropertyMetaDataCtr1_sort_and_verify(ldb, &md->ctr.ctr1, msg->dn);
5001 if (ret != LDB_SUCCESS) {
5002 ldb_asprintf_errstring(ldb, "%s: error during DRS repl ADD: %s", __func__, ldb_errstring(ldb));
5003 return replmd_replicated_request_error(ar, ret);
5006 for (i=0; i < md->ctr.ctr1.count; i++) {
5007 md->ctr.ctr1.array[i].local_usn = ar->seq_num;
5009 ndr_err = ndr_push_struct_blob(&md_value, msg, md,
5010 (ndr_push_flags_fn_t)ndr_push_replPropertyMetaDataBlob);
5011 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
5012 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
5013 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
5015 ret = ldb_msg_add_value(msg, "replPropertyMetaData", &md_value, NULL);
5016 if (ret != LDB_SUCCESS) {
5017 return replmd_replicated_request_error(ar, ret);
5020 replmd_ldb_message_sort(msg, ar->schema);
5022 if (!remote_isDeleted) {
5023 ret = dsdb_module_schedule_sd_propagation(ar->module,
5024 ar->objs->partition_dn,
5026 if (ret != LDB_SUCCESS) {
5027 return replmd_replicated_request_error(ar, ret);
5031 ar->isDeleted = remote_isDeleted;
5033 ret = ldb_build_add_req(&change_req,
5039 replmd_op_add_callback,
5041 LDB_REQ_SET_LOCATION(change_req);
5042 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
5044 /* current partition control needed by "repmd_op_callback" */
5045 ret = ldb_request_add_control(change_req,
5046 DSDB_CONTROL_CURRENT_PARTITION_OID,
5048 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
5050 if (ar->objs->dsdb_repl_flags & DSDB_REPL_FLAG_PARTIAL_REPLICA) {
5051 /* this tells the partition module to make it a
5052 partial replica if creating an NC */
5053 ret = ldb_request_add_control(change_req,
5054 DSDB_CONTROL_PARTIAL_REPLICA,
5056 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
5059 return ldb_next_request(ar->module, change_req);
5062 static int replmd_replicated_apply_search_for_parent_callback(struct ldb_request *req,
5063 struct ldb_reply *ares)
5065 struct replmd_replicated_request *ar = talloc_get_type(req->context,
5066 struct replmd_replicated_request);
5070 return ldb_module_done(ar->req, NULL, NULL,
5071 LDB_ERR_OPERATIONS_ERROR);
5075 * The error NO_SUCH_OBJECT is not expected, unless the search
5076 * base is the partition DN, and that case doesn't happen here
5077 * because then we wouldn't get a parent_guid_value in any
5080 if (ares->error != LDB_SUCCESS) {
5081 return ldb_module_done(ar->req, ares->controls,
5082 ares->response, ares->error);
5085 switch (ares->type) {
5086 case LDB_REPLY_ENTRY:
5088 struct ldb_message *parent_msg = ares->message;
5089 struct ldb_message *msg = ar->objs->objects[ar->index_current].msg;
5090 struct ldb_dn *parent_dn;
5093 if (!ldb_msg_check_string_attribute(msg, "isDeleted", "TRUE")
5094 && ldb_msg_check_string_attribute(parent_msg, "isDeleted", "TRUE")) {
5095 /* Per MS-DRSR 4.1.10.6.10
5096 * FindBestParentObject we need to move this
5097 * new object under a deleted object to
5099 struct ldb_dn *nc_root;
5101 ret = dsdb_find_nc_root(ldb_module_get_ctx(ar->module), msg, msg->dn, &nc_root);
5102 if (ret == LDB_ERR_NO_SUCH_OBJECT) {
5103 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
5104 "No suitable NC root found for %s. "
5105 "We need to move this object because parent object %s "
5106 "is deleted, but this object is not.",
5107 ldb_dn_get_linearized(msg->dn),
5108 ldb_dn_get_linearized(parent_msg->dn));
5109 return ldb_module_done(ar->req, NULL, NULL, LDB_ERR_OPERATIONS_ERROR);
5110 } else if (ret != LDB_SUCCESS) {
5111 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
5112 "Unable to find NC root for %s: %s. "
5113 "We need to move this object because parent object %s "
5114 "is deleted, but this object is not.",
5115 ldb_dn_get_linearized(msg->dn),
5116 ldb_errstring(ldb_module_get_ctx(ar->module)),
5117 ldb_dn_get_linearized(parent_msg->dn));
5118 return ldb_module_done(ar->req, NULL, NULL, LDB_ERR_OPERATIONS_ERROR);
5121 ret = dsdb_wellknown_dn(ldb_module_get_ctx(ar->module), msg,
5123 DS_GUID_LOSTANDFOUND_CONTAINER,
5125 if (ret != LDB_SUCCESS) {
5126 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
5127 "Unable to find LostAndFound Container for %s "
5128 "in partition %s: %s. "
5129 "We need to move this object because parent object %s "
5130 "is deleted, but this object is not.",
5131 ldb_dn_get_linearized(msg->dn), ldb_dn_get_linearized(nc_root),
5132 ldb_errstring(ldb_module_get_ctx(ar->module)),
5133 ldb_dn_get_linearized(parent_msg->dn));
5134 return ldb_module_done(ar->req, NULL, NULL, LDB_ERR_OPERATIONS_ERROR);
5136 ar->objs->objects[ar->index_current].last_known_parent
5137 = talloc_steal(ar->objs->objects[ar->index_current].msg, parent_msg->dn);
5141 = talloc_steal(ar->objs->objects[ar->index_current].msg, parent_msg->dn);
5144 ar->objs->objects[ar->index_current].local_parent_dn = parent_dn;
5146 comp_num = ldb_dn_get_comp_num(msg->dn);
5148 if (!ldb_dn_remove_base_components(msg->dn, comp_num - 1)) {
5150 return ldb_module_done(ar->req, NULL, NULL, ldb_module_operr(ar->module));
5153 if (!ldb_dn_add_base(msg->dn, parent_dn)) {
5155 return ldb_module_done(ar->req, NULL, NULL, ldb_module_operr(ar->module));
5159 case LDB_REPLY_REFERRAL:
5160 /* we ignore referrals */
5163 case LDB_REPLY_DONE:
5165 if (ar->objs->objects[ar->index_current].local_parent_dn == NULL) {
5166 struct GUID_txt_buf str_buf;
5167 if (ar->search_msg != NULL) {
5168 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
5169 "No parent with GUID %s found for object locally known as %s",
5170 GUID_buf_string(ar->objs->objects[ar->index_current].parent_guid, &str_buf),
5171 ldb_dn_get_linearized(ar->search_msg->dn));
5173 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
5174 "No parent with GUID %s found for object remotely known as %s",
5175 GUID_buf_string(ar->objs->objects[ar->index_current].parent_guid, &str_buf),
5176 ldb_dn_get_linearized(ar->objs->objects[ar->index_current].msg->dn));
5180 * This error code is really important, as it
5181 * is the flag back to the callers to retry
5182 * this with DRSUAPI_DRS_GET_ANC, and so get
5183 * the parent objects before the child
5186 return ldb_module_done(ar->req, NULL, NULL,
5187 replmd_replicated_request_werror(ar, WERR_DS_DRA_MISSING_PARENT));
5190 if (ar->search_msg != NULL) {
5191 ret = replmd_replicated_apply_merge(ar);
5193 ret = replmd_replicated_apply_add(ar);
5195 if (ret != LDB_SUCCESS) {
5196 return ldb_module_done(ar->req, NULL, NULL, ret);
5205 * Look for the parent object, so we put the new object in the right
5206 * place This is akin to NameObject in MS-DRSR - this routine and the
5207 * callbacks find the right parent name, and correct name for this
5211 static int replmd_replicated_apply_search_for_parent(struct replmd_replicated_request *ar)
5213 struct ldb_context *ldb;
5217 struct ldb_request *search_req;
5218 static const char *attrs[] = {"isDeleted", NULL};
5219 struct GUID_txt_buf guid_str_buf;
5221 ldb = ldb_module_get_ctx(ar->module);
5223 if (ar->objs->objects[ar->index_current].parent_guid == NULL) {
5224 if (ar->search_msg != NULL) {
5225 return replmd_replicated_apply_merge(ar);
5227 return replmd_replicated_apply_add(ar);
5231 tmp_str = GUID_buf_string(ar->objs->objects[ar->index_current].parent_guid,
5234 filter = talloc_asprintf(ar, "(objectGUID=%s)", tmp_str);
5235 if (!filter) return replmd_replicated_request_werror(ar, WERR_NOT_ENOUGH_MEMORY);
5237 ret = ldb_build_search_req(&search_req,
5240 ar->objs->partition_dn,
5246 replmd_replicated_apply_search_for_parent_callback,
5248 LDB_REQ_SET_LOCATION(search_req);
5250 ret = dsdb_request_add_controls(search_req,
5251 DSDB_SEARCH_SHOW_RECYCLED|
5252 DSDB_SEARCH_SHOW_DELETED|
5253 DSDB_SEARCH_SHOW_EXTENDED_DN);
5254 if (ret != LDB_SUCCESS) {
5258 return ldb_next_request(ar->module, search_req);
5262 handle renames that come in over DRS replication
5264 static int replmd_replicated_handle_rename(struct replmd_replicated_request *ar,
5265 struct ldb_message *msg,
5266 struct ldb_request *parent,
5270 TALLOC_CTX *tmp_ctx = talloc_new(msg);
5271 struct ldb_result *res;
5272 struct ldb_dn *conflict_dn;
5273 const char *attrs[] = { "replPropertyMetaData", "objectGUID", NULL };
5274 const struct ldb_val *omd_value;
5275 struct replPropertyMetaDataBlob omd, *rmd;
5276 enum ndr_err_code ndr_err;
5277 bool rename_incoming_record, rodc;
5278 struct replPropertyMetaData1 *rmd_name, *omd_name;
5279 struct ldb_dn *new_dn;
5282 DEBUG(4,("replmd_replicated_request rename %s => %s\n",
5283 ldb_dn_get_linearized(ar->search_msg->dn),
5284 ldb_dn_get_linearized(msg->dn)));
5287 ret = dsdb_module_rename(ar->module, ar->search_msg->dn, msg->dn,
5288 DSDB_FLAG_NEXT_MODULE, ar->req);
5289 if (ret == LDB_SUCCESS) {
5290 talloc_free(tmp_ctx);
5295 if (ret != LDB_ERR_ENTRY_ALREADY_EXISTS) {
5296 talloc_free(tmp_ctx);
5297 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module), "Failed to locally apply remote rename from %s to %s: %s",
5298 ldb_dn_get_linearized(ar->search_msg->dn),
5299 ldb_dn_get_linearized(msg->dn),
5300 ldb_errstring(ldb_module_get_ctx(ar->module)));
5304 ret = samdb_rodc(ldb_module_get_ctx(ar->module), &rodc);
5305 if (ret != LDB_SUCCESS) {
5306 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
5307 "Failed to determine if we are an RODC when attempting to form conflict DN: %s",
5308 ldb_errstring(ldb_module_get_ctx(ar->module)));
5309 return LDB_ERR_OPERATIONS_ERROR;
5312 * we have a conflict, and need to decide if we will keep the
5313 * new record or the old record
5316 conflict_dn = msg->dn;
5320 * We are on an RODC, or were a GC for this
5321 * partition, so we have to fail this until
5322 * someone who owns the partition sorts it
5325 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
5326 "Conflict adding object '%s' from incoming replication but we are read only for the partition. \n"
5327 " - We must fail the operation until a master for this partition resolves the conflict",
5328 ldb_dn_get_linearized(conflict_dn));
5333 * first we need the replPropertyMetaData attribute from the
5336 ret = dsdb_module_search_dn(ar->module, tmp_ctx, &res, conflict_dn,
5338 DSDB_FLAG_NEXT_MODULE |
5339 DSDB_SEARCH_SHOW_DELETED |
5340 DSDB_SEARCH_SHOW_RECYCLED, ar->req);
5341 if (ret != LDB_SUCCESS) {
5342 DEBUG(0,(__location__ ": Unable to find object for conflicting record '%s'\n",
5343 ldb_dn_get_linearized(conflict_dn)));
5347 omd_value = ldb_msg_find_ldb_val(res->msgs[0], "replPropertyMetaData");
5348 if (omd_value == NULL) {
5349 DEBUG(0,(__location__ ": Unable to find replPropertyMetaData for conflicting record '%s'\n",
5350 ldb_dn_get_linearized(conflict_dn)));
5354 ndr_err = ndr_pull_struct_blob(omd_value, res->msgs[0], &omd,
5355 (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
5356 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
5357 DEBUG(0,(__location__ ": Failed to parse old replPropertyMetaData for %s\n",
5358 ldb_dn_get_linearized(conflict_dn)));
5362 rmd = ar->objs->objects[ar->index_current].meta_data;
5365 * we decide which is newer based on the RPMD on the name
5366 * attribute. See [MS-DRSR] ResolveNameConflict.
5368 * We expect omd_name to be present, as this is from a local
5369 * search, but while rmd_name should have been given to us by
5370 * the remote server, if it is missing we just prefer the
5372 * replmd_replPropertyMetaData1_new_should_be_taken()
5374 rmd_name = replmd_replPropertyMetaData1_find_attid(rmd, DRSUAPI_ATTID_name);
5375 omd_name = replmd_replPropertyMetaData1_find_attid(&omd, DRSUAPI_ATTID_name);
5377 DEBUG(0,(__location__ ": Failed to find name attribute in local LDB replPropertyMetaData for %s\n",
5378 ldb_dn_get_linearized(conflict_dn)));
5383 * Should we preserve the current record, and so rename the
5384 * incoming record to be a conflict?
5386 rename_incoming_record =
5387 !replmd_replPropertyMetaData1_new_should_be_taken(
5388 ar->objs->dsdb_repl_flags & DSDB_REPL_FLAG_PRIORITISE_INCOMING,
5389 omd_name, rmd_name);
5391 if (rename_incoming_record) {
5393 new_dn = replmd_conflict_dn(msg, msg->dn,
5394 &ar->objs->objects[ar->index_current].object_guid);
5395 if (new_dn == NULL) {
5396 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
5397 "Failed to form conflict DN for %s\n",
5398 ldb_dn_get_linearized(msg->dn));
5400 return replmd_replicated_request_werror(ar, WERR_NOT_ENOUGH_MEMORY);
5403 ret = dsdb_module_rename(ar->module, ar->search_msg->dn, new_dn,
5404 DSDB_FLAG_NEXT_MODULE, ar->req);
5405 if (ret != LDB_SUCCESS) {
5406 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
5407 "Failed to rename incoming conflicting dn '%s' (was '%s') to '%s' - %s\n",
5408 ldb_dn_get_linearized(conflict_dn),
5409 ldb_dn_get_linearized(ar->search_msg->dn),
5410 ldb_dn_get_linearized(new_dn),
5411 ldb_errstring(ldb_module_get_ctx(ar->module)));
5412 return replmd_replicated_request_werror(ar, WERR_DS_DRA_DB_ERROR);
5420 /* we are renaming the existing record */
5422 guid = samdb_result_guid(res->msgs[0], "objectGUID");
5423 if (GUID_all_zero(&guid)) {
5424 DEBUG(0,(__location__ ": Failed to find objectGUID for existing conflict record %s\n",
5425 ldb_dn_get_linearized(conflict_dn)));
5429 new_dn = replmd_conflict_dn(tmp_ctx, conflict_dn, &guid);
5430 if (new_dn == NULL) {
5431 DEBUG(0,(__location__ ": Failed to form conflict DN for %s\n",
5432 ldb_dn_get_linearized(conflict_dn)));
5436 DEBUG(2,(__location__ ": Resolving conflict record via existing-record rename '%s' -> '%s'\n",
5437 ldb_dn_get_linearized(conflict_dn), ldb_dn_get_linearized(new_dn)));
5439 ret = dsdb_module_rename(ar->module, conflict_dn, new_dn,
5440 DSDB_FLAG_OWN_MODULE, ar->req);
5441 if (ret != LDB_SUCCESS) {
5442 DEBUG(0,(__location__ ": Failed to rename conflict dn '%s' to '%s' - %s\n",
5443 ldb_dn_get_linearized(conflict_dn),
5444 ldb_dn_get_linearized(new_dn),
5445 ldb_errstring(ldb_module_get_ctx(ar->module))));
5450 * now we need to ensure that the rename is seen as an
5451 * originating update. We do that with a modify.
5453 ret = replmd_name_modify(ar, ar->req, new_dn);
5454 if (ret != LDB_SUCCESS) {
5458 DEBUG(2,(__location__ ": With conflicting record renamed, re-apply replicated rename '%s' -> '%s'\n",
5459 ldb_dn_get_linearized(ar->search_msg->dn),
5460 ldb_dn_get_linearized(msg->dn)));
5463 ret = dsdb_module_rename(ar->module, ar->search_msg->dn, msg->dn,
5464 DSDB_FLAG_NEXT_MODULE, ar->req);
5465 if (ret != LDB_SUCCESS) {
5466 DEBUG(0,(__location__ ": After conflict resolution, failed to rename dn '%s' to '%s' - %s\n",
5467 ldb_dn_get_linearized(ar->search_msg->dn),
5468 ldb_dn_get_linearized(msg->dn),
5469 ldb_errstring(ldb_module_get_ctx(ar->module))));
5475 * On failure make the caller get the error
5476 * This means replication will stop with an error,
5477 * but there is not much else we can do. In the
5478 * LDB_ERR_ENTRY_ALREADY_EXISTS case this is exactly what is
5482 talloc_free(tmp_ctx);
5487 static int replmd_replicated_apply_merge(struct replmd_replicated_request *ar)
5489 struct ldb_context *ldb;
5490 struct ldb_request *change_req;
5491 enum ndr_err_code ndr_err;
5492 struct ldb_message *msg;
5493 struct replPropertyMetaDataBlob *rmd;
5494 struct replPropertyMetaDataBlob omd;
5495 const struct ldb_val *omd_value;
5496 struct replPropertyMetaDataBlob nmd;
5497 struct ldb_val nmd_value;
5498 struct GUID remote_parent_guid;
5501 unsigned int removed_attrs = 0;
5503 int (*callback)(struct ldb_request *req, struct ldb_reply *ares) = replmd_op_callback;
5504 bool isDeleted = false;
5505 bool local_isDeleted = false;
5506 bool remote_isDeleted = false;
5507 bool take_remote_isDeleted = false;
5508 bool sd_updated = false;
5509 bool renamed = false;
5510 bool is_schema_nc = false;
5512 const struct ldb_val *old_rdn, *new_rdn;
5513 struct replmd_private *replmd_private =
5514 talloc_get_type(ldb_module_get_private(ar->module),
5515 struct replmd_private);
5517 time_t t = time(NULL);
5518 unix_to_nt_time(&now, t);
5520 ldb = ldb_module_get_ctx(ar->module);
5521 msg = ar->objs->objects[ar->index_current].msg;
5523 is_schema_nc = ldb_dn_compare_base(replmd_private->schema_dn, msg->dn) == 0;
5525 rmd = ar->objs->objects[ar->index_current].meta_data;
5529 /* find existing meta data */
5530 omd_value = ldb_msg_find_ldb_val(ar->search_msg, "replPropertyMetaData");
5532 ndr_err = ndr_pull_struct_blob(omd_value, ar, &omd,
5533 (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
5534 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
5535 nt_status = ndr_map_error2ntstatus(ndr_err);
5536 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
5539 if (omd.version != 1) {
5540 return replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
5545 struct GUID_txt_buf guid_txt;
5547 char *s = ldb_ldif_message_string(ldb, ar, LDB_CHANGETYPE_MODIFY, msg);
5548 DEBUG(5, ("Initial DRS replication modify message of %s is:\n%s\n"
5551 GUID_buf_string(&ar->objs->objects[ar->index_current].object_guid, &guid_txt),
5553 ndr_print_struct_string(s,
5554 (ndr_print_fn_t)ndr_print_replPropertyMetaDataBlob,
5555 "existing replPropertyMetaData",
5557 ndr_print_struct_string(s,
5558 (ndr_print_fn_t)ndr_print_replPropertyMetaDataBlob,
5559 "incoming replPropertyMetaData",
5564 local_isDeleted = ldb_msg_find_attr_as_bool(ar->search_msg,
5565 "isDeleted", false);
5566 remote_isDeleted = ldb_msg_find_attr_as_bool(msg,
5567 "isDeleted", false);
5570 * Fill in the remote_parent_guid with the GUID or an all-zero
5573 if (ar->objs->objects[ar->index_current].parent_guid != NULL) {
5574 remote_parent_guid = *ar->objs->objects[ar->index_current].parent_guid;
5576 remote_parent_guid = GUID_zero();
5580 * To ensure we follow a complex rename chain around, we have
5581 * to confirm that the DN is the same (mostly to confirm the
5582 * RDN) and the parentGUID is the same.
5584 * This ensures we keep things under the correct parent, which
5585 * replmd_replicated_handle_rename() will do.
5588 if (strcmp(ldb_dn_get_linearized(msg->dn), ldb_dn_get_linearized(ar->search_msg->dn)) == 0
5589 && GUID_equal(&remote_parent_guid, &ar->local_parent_guid)) {
5593 * handle renames, even just by case that come in over
5594 * DRS. Changes in the parent DN don't hit us here,
5595 * because the search for a parent will clean up those
5598 * We also have already filtered out the case where
5599 * the peer has an older name to what we have (see
5600 * replmd_replicated_apply_search_callback())
5602 ret = replmd_replicated_handle_rename(ar, msg, ar->req, &renamed);
5605 if (ret != LDB_SUCCESS) {
5606 ldb_debug(ldb, LDB_DEBUG_FATAL,
5607 "replmd_replicated_request rename %s => %s failed - %s\n",
5608 ldb_dn_get_linearized(ar->search_msg->dn),
5609 ldb_dn_get_linearized(msg->dn),
5610 ldb_errstring(ldb));
5611 return replmd_replicated_request_werror(ar, WERR_DS_DRA_DB_ERROR);
5614 if (renamed == true) {
5616 * Set the callback to one that will fix up the name
5617 * metadata on the new conflict DN
5619 callback = replmd_op_name_modify_callback;
5624 nmd.ctr.ctr1.count = omd.ctr.ctr1.count + rmd->ctr.ctr1.count;
5625 nmd.ctr.ctr1.array = talloc_array(ar,
5626 struct replPropertyMetaData1,
5627 nmd.ctr.ctr1.count);
5628 if (!nmd.ctr.ctr1.array) return replmd_replicated_request_werror(ar, WERR_NOT_ENOUGH_MEMORY);
5630 /* first copy the old meta data */
5631 for (i=0; i < omd.ctr.ctr1.count; i++) {
5632 nmd.ctr.ctr1.array[ni] = omd.ctr.ctr1.array[i];
5637 /* now merge in the new meta data */
5638 for (i=0; i < rmd->ctr.ctr1.count; i++) {
5641 for (j=0; j < ni; j++) {
5644 if (rmd->ctr.ctr1.array[i].attid != nmd.ctr.ctr1.array[j].attid) {
5648 cmp = replmd_replPropertyMetaData1_new_should_be_taken(
5649 ar->objs->dsdb_repl_flags,
5650 &nmd.ctr.ctr1.array[j],
5651 &rmd->ctr.ctr1.array[i]);
5653 /* replace the entry */
5654 nmd.ctr.ctr1.array[j] = rmd->ctr.ctr1.array[i];
5655 if (ar->seq_num == 0) {
5656 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &ar->seq_num);
5657 if (ret != LDB_SUCCESS) {
5658 return replmd_replicated_request_error(ar, ret);
5661 nmd.ctr.ctr1.array[j].local_usn = ar->seq_num;
5662 switch (nmd.ctr.ctr1.array[j].attid) {
5663 case DRSUAPI_ATTID_ntSecurityDescriptor:
5666 case DRSUAPI_ATTID_isDeleted:
5667 take_remote_isDeleted = true;
5676 if (rmd->ctr.ctr1.array[i].attid != DRSUAPI_ATTID_instanceType) {
5677 DEBUG(3,("Discarding older DRS attribute update to %s on %s from %s\n",
5678 msg->elements[i-removed_attrs].name,
5679 ldb_dn_get_linearized(msg->dn),
5680 GUID_string(ar, &rmd->ctr.ctr1.array[i].originating_invocation_id)));
5683 /* we don't want to apply this change so remove the attribute */
5684 ldb_msg_remove_element(msg, &msg->elements[i-removed_attrs]);
5691 if (found) continue;
5693 nmd.ctr.ctr1.array[ni] = rmd->ctr.ctr1.array[i];
5694 if (ar->seq_num == 0) {
5695 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &ar->seq_num);
5696 if (ret != LDB_SUCCESS) {
5697 return replmd_replicated_request_error(ar, ret);
5700 nmd.ctr.ctr1.array[ni].local_usn = ar->seq_num;
5701 switch (nmd.ctr.ctr1.array[ni].attid) {
5702 case DRSUAPI_ATTID_ntSecurityDescriptor:
5705 case DRSUAPI_ATTID_isDeleted:
5706 take_remote_isDeleted = true;
5715 * finally correct the size of the meta_data array
5717 nmd.ctr.ctr1.count = ni;
5719 new_rdn = ldb_dn_get_rdn_val(msg->dn);
5720 old_rdn = ldb_dn_get_rdn_val(ar->search_msg->dn);
5723 ret = replmd_update_rpmd_rdn_attr(ldb, msg, new_rdn, old_rdn,
5724 &nmd, ar, now, is_schema_nc,
5726 if (ret != LDB_SUCCESS) {
5727 ldb_asprintf_errstring(ldb, "%s: error during DRS repl merge: %s", __func__, ldb_errstring(ldb));
5728 return replmd_replicated_request_error(ar, ret);
5732 * sort the new meta data array
5734 ret = replmd_replPropertyMetaDataCtr1_sort_and_verify(ldb, &nmd.ctr.ctr1, msg->dn);
5735 if (ret != LDB_SUCCESS) {
5736 ldb_asprintf_errstring(ldb, "%s: error during DRS repl merge: %s", __func__, ldb_errstring(ldb));
5741 * Work out if this object is deleted, so we can prune any extra attributes. See MS-DRSR 4.1.10.6.9
5744 * This also controls SD propagation below
5746 if (take_remote_isDeleted) {
5747 isDeleted = remote_isDeleted;
5749 isDeleted = local_isDeleted;
5752 ar->isDeleted = isDeleted;
5755 * check if some replicated attributes left, otherwise skip the ldb_modify() call
5757 if (msg->num_elements == 0) {
5758 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_replicated_apply_merge[%u]: skip replace\n",
5761 return replmd_replicated_apply_isDeleted(ar);
5764 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_replicated_apply_merge[%u]: replace %u attributes\n",
5765 ar->index_current, msg->num_elements);
5771 if (sd_updated && !isDeleted) {
5772 ret = dsdb_module_schedule_sd_propagation(ar->module,
5773 ar->objs->partition_dn,
5775 if (ret != LDB_SUCCESS) {
5776 return ldb_operr(ldb);
5780 /* create the meta data value */
5781 ndr_err = ndr_push_struct_blob(&nmd_value, msg, &nmd,
5782 (ndr_push_flags_fn_t)ndr_push_replPropertyMetaDataBlob);
5783 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
5784 nt_status = ndr_map_error2ntstatus(ndr_err);
5785 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
5789 * when we know that we'll modify the record, add the whenChanged, uSNChanged
5790 * and replPopertyMetaData attributes
5792 ret = ldb_msg_add_string(msg, "whenChanged", ar->objs->objects[ar->index_current].when_changed);
5793 if (ret != LDB_SUCCESS) {
5794 return replmd_replicated_request_error(ar, ret);
5796 ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNChanged", ar->seq_num);
5797 if (ret != LDB_SUCCESS) {
5798 return replmd_replicated_request_error(ar, ret);
5800 ret = ldb_msg_add_value(msg, "replPropertyMetaData", &nmd_value, NULL);
5801 if (ret != LDB_SUCCESS) {
5802 return replmd_replicated_request_error(ar, ret);
5805 replmd_ldb_message_sort(msg, ar->schema);
5807 /* we want to replace the old values */
5808 for (i=0; i < msg->num_elements; i++) {
5809 msg->elements[i].flags = LDB_FLAG_MOD_REPLACE;
5810 if (ldb_attr_cmp(msg->elements[i].name, "objectClass") == 0) {
5811 if (msg->elements[i].num_values == 0) {
5812 ldb_asprintf_errstring(ldb, __location__
5813 ": objectClass removed on %s, aborting replication\n",
5814 ldb_dn_get_linearized(msg->dn));
5815 return replmd_replicated_request_error(ar, LDB_ERR_OBJECT_CLASS_VIOLATION);
5821 struct GUID_txt_buf guid_txt;
5823 char *s = ldb_ldif_message_string(ldb, ar, LDB_CHANGETYPE_MODIFY, msg);
5824 DEBUG(4, ("Final DRS replication modify message of %s:\n%s\n",
5825 GUID_buf_string(&ar->objs->objects[ar->index_current].object_guid, &guid_txt),
5830 ret = ldb_build_mod_req(&change_req,
5838 LDB_REQ_SET_LOCATION(change_req);
5839 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
5841 /* current partition control needed by "repmd_op_callback" */
5842 ret = ldb_request_add_control(change_req,
5843 DSDB_CONTROL_CURRENT_PARTITION_OID,
5845 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
5847 return ldb_next_request(ar->module, change_req);
5850 static int replmd_replicated_apply_search_callback(struct ldb_request *req,
5851 struct ldb_reply *ares)
5853 struct replmd_replicated_request *ar = talloc_get_type(req->context,
5854 struct replmd_replicated_request);
5858 return ldb_module_done(ar->req, NULL, NULL,
5859 LDB_ERR_OPERATIONS_ERROR);
5861 if (ares->error != LDB_SUCCESS &&
5862 ares->error != LDB_ERR_NO_SUCH_OBJECT) {
5863 return ldb_module_done(ar->req, ares->controls,
5864 ares->response, ares->error);
5867 switch (ares->type) {
5868 case LDB_REPLY_ENTRY:
5869 ar->search_msg = talloc_steal(ar, ares->message);
5872 case LDB_REPLY_REFERRAL:
5873 /* we ignore referrals */
5876 case LDB_REPLY_DONE:
5878 struct replPropertyMetaData1 *md_remote;
5879 struct replPropertyMetaData1 *md_local;
5881 struct replPropertyMetaDataBlob omd;
5882 const struct ldb_val *omd_value;
5883 struct replPropertyMetaDataBlob *rmd;
5884 struct ldb_message *msg;
5886 ar->objs->objects[ar->index_current].local_parent_dn = NULL;
5887 ar->objs->objects[ar->index_current].last_known_parent = NULL;
5890 * This is the ADD case, find the appropriate parent,
5891 * as this object doesn't exist locally:
5893 if (ar->search_msg == NULL) {
5894 ret = replmd_replicated_apply_search_for_parent(ar);
5895 if (ret != LDB_SUCCESS) {
5896 return ldb_module_done(ar->req, NULL, NULL, ret);
5903 * Otherwise, in the MERGE case, work out if we are
5904 * attempting a rename, and if so find the parent the
5905 * newly renamed object wants to belong under (which
5906 * may not be the parent in it's attached string DN
5908 rmd = ar->objs->objects[ar->index_current].meta_data;
5912 /* find existing meta data */
5913 omd_value = ldb_msg_find_ldb_val(ar->search_msg, "replPropertyMetaData");
5915 enum ndr_err_code ndr_err;
5916 ndr_err = ndr_pull_struct_blob(omd_value, ar, &omd,
5917 (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
5918 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
5919 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
5920 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
5923 if (omd.version != 1) {
5924 return replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
5928 ar->local_parent_guid = samdb_result_guid(ar->search_msg, "parentGUID");
5930 instanceType = ldb_msg_find_attr_as_int(ar->search_msg, "instanceType", 0);
5931 if (((instanceType & INSTANCE_TYPE_IS_NC_HEAD) == 0)
5932 && GUID_all_zero(&ar->local_parent_guid)) {
5933 DEBUG(0, ("Refusing to replicate new version of %s "
5934 "as local object has an all-zero parentGUID attribute, "
5935 "despite not being an NC root\n",
5936 ldb_dn_get_linearized(ar->search_msg->dn)));
5937 return replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
5941 * now we need to check for double renames. We could have a
5942 * local rename pending which our replication partner hasn't
5943 * received yet. We choose which one wins by looking at the
5944 * attribute stamps on the two objects, the newer one wins.
5946 * This also simply applies the correct algorithms for
5947 * determining if a change was made to name at all, or
5948 * if the object has just been renamed under the same
5951 md_remote = replmd_replPropertyMetaData1_find_attid(rmd, DRSUAPI_ATTID_name);
5952 md_local = replmd_replPropertyMetaData1_find_attid(&omd, DRSUAPI_ATTID_name);
5954 DEBUG(0,(__location__ ": Failed to find name attribute in local LDB replPropertyMetaData for %s\n",
5955 ldb_dn_get_linearized(ar->search_msg->dn)));
5956 return replmd_replicated_request_werror(ar, WERR_DS_DRA_DB_ERROR);
5960 * if there is no name attribute given then we have to assume the
5961 * object we've received has the older name
5963 if (replmd_replPropertyMetaData1_new_should_be_taken(
5964 ar->objs->dsdb_repl_flags & DSDB_REPL_FLAG_PRIORITISE_INCOMING,
5965 md_local, md_remote)) {
5966 struct GUID_txt_buf p_guid_local;
5967 struct GUID_txt_buf p_guid_remote;
5968 msg = ar->objs->objects[ar->index_current].msg;
5970 /* Merge on the existing object, with rename */
5972 DEBUG(4,(__location__ ": Looking for new parent for object %s currently under %s "
5973 "as incoming object changing to %s under %s\n",
5974 ldb_dn_get_linearized(ar->search_msg->dn),
5975 GUID_buf_string(&ar->local_parent_guid, &p_guid_local),
5976 ldb_dn_get_linearized(msg->dn),
5977 GUID_buf_string(ar->objs->objects[ar->index_current].parent_guid,
5979 ret = replmd_replicated_apply_search_for_parent(ar);
5981 struct GUID_txt_buf p_guid_local;
5982 struct GUID_txt_buf p_guid_remote;
5983 msg = ar->objs->objects[ar->index_current].msg;
5986 * Merge on the existing object, force no
5987 * rename (code below just to explain why in
5991 if (strcmp(ldb_dn_get_linearized(ar->search_msg->dn),
5992 ldb_dn_get_linearized(msg->dn)) == 0) {
5993 if (ar->objs->objects[ar->index_current].parent_guid != NULL &&
5994 GUID_equal(&ar->local_parent_guid,
5995 ar->objs->objects[ar->index_current].parent_guid)
5997 DEBUG(4,(__location__ ": Keeping object %s at under %s "
5998 "despite incoming object changing parent to %s\n",
5999 ldb_dn_get_linearized(ar->search_msg->dn),
6000 GUID_buf_string(&ar->local_parent_guid, &p_guid_local),
6001 GUID_buf_string(ar->objs->objects[ar->index_current].parent_guid,
6005 DEBUG(4,(__location__ ": Keeping object %s at under %s "
6006 " and rejecting older rename to %s under %s\n",
6007 ldb_dn_get_linearized(ar->search_msg->dn),
6008 GUID_buf_string(&ar->local_parent_guid, &p_guid_local),
6009 ldb_dn_get_linearized(msg->dn),
6010 GUID_buf_string(ar->objs->objects[ar->index_current].parent_guid,
6014 * This assignment ensures that the strcmp()
6015 * and GUID_equal() calls in
6016 * replmd_replicated_apply_merge() avoids the
6019 ar->objs->objects[ar->index_current].parent_guid =
6020 &ar->local_parent_guid;
6022 msg->dn = ar->search_msg->dn;
6023 ret = replmd_replicated_apply_merge(ar);
6025 if (ret != LDB_SUCCESS) {
6026 return ldb_module_done(ar->req, NULL, NULL, ret);
6035 static int replmd_replicated_uptodate_vector(struct replmd_replicated_request *ar);
6037 static int replmd_replicated_apply_next(struct replmd_replicated_request *ar)
6039 struct ldb_context *ldb;
6043 struct ldb_request *search_req;
6044 static const char *attrs[] = { "repsFrom", "replUpToDateVector",
6045 "parentGUID", "instanceType",
6046 "replPropertyMetaData", "nTSecurityDescriptor",
6047 "isDeleted", NULL };
6048 struct GUID_txt_buf guid_str_buf;
6050 if (ar->index_current >= ar->objs->num_objects) {
6051 /* done with it, go to next stage */
6052 return replmd_replicated_uptodate_vector(ar);
6055 ldb = ldb_module_get_ctx(ar->module);
6056 ar->search_msg = NULL;
6057 ar->isDeleted = false;
6059 tmp_str = GUID_buf_string(&ar->objs->objects[ar->index_current].object_guid,
6062 filter = talloc_asprintf(ar, "(objectGUID=%s)", tmp_str);
6063 if (!filter) return replmd_replicated_request_werror(ar, WERR_NOT_ENOUGH_MEMORY);
6065 ret = ldb_build_search_req(&search_req,
6068 ar->objs->partition_dn,
6074 replmd_replicated_apply_search_callback,
6076 LDB_REQ_SET_LOCATION(search_req);
6078 ret = dsdb_request_add_controls(search_req, DSDB_SEARCH_SHOW_RECYCLED);
6080 if (ret != LDB_SUCCESS) {
6084 return ldb_next_request(ar->module, search_req);
6088 * This is essentially a wrapper for replmd_replicated_apply_next()
6090 * This is needed to ensure that both codepaths call this handler.
6092 static int replmd_replicated_apply_isDeleted(struct replmd_replicated_request *ar)
6094 struct ldb_dn *deleted_objects_dn;
6095 struct ldb_message *msg = ar->objs->objects[ar->index_current].msg;
6096 int ret = dsdb_get_deleted_objects_dn(ldb_module_get_ctx(ar->module), msg, msg->dn,
6097 &deleted_objects_dn);
6098 if (ar->isDeleted && (ret != LDB_SUCCESS || ldb_dn_compare(msg->dn, deleted_objects_dn) != 0)) {
6100 * Do a delete here again, so that if there is
6101 * anything local that conflicts with this
6102 * object being deleted, it is removed. This
6103 * includes links. See MS-DRSR 4.1.10.6.9
6106 * If the object is already deleted, and there
6107 * is no more work required, it doesn't do
6111 /* This has been updated to point to the DN we eventually did the modify on */
6113 struct ldb_request *del_req;
6114 struct ldb_result *res;
6116 TALLOC_CTX *tmp_ctx = talloc_new(ar);
6118 ret = ldb_oom(ldb_module_get_ctx(ar->module));
6122 res = talloc_zero(tmp_ctx, struct ldb_result);
6124 ret = ldb_oom(ldb_module_get_ctx(ar->module));
6125 talloc_free(tmp_ctx);
6129 /* Build a delete request, which hopefully will artually turn into nothing */
6130 ret = ldb_build_del_req(&del_req, ldb_module_get_ctx(ar->module), tmp_ctx,
6134 ldb_modify_default_callback,
6136 LDB_REQ_SET_LOCATION(del_req);
6137 if (ret != LDB_SUCCESS) {
6138 talloc_free(tmp_ctx);
6143 * This is the guts of the call, call back
6144 * into our delete code, but setting the
6145 * re_delete flag so we delete anything that
6146 * shouldn't be there on a deleted or recycled
6149 ret = replmd_delete_internals(ar->module, del_req, true);
6150 if (ret == LDB_SUCCESS) {
6151 ret = ldb_wait(del_req->handle, LDB_WAIT_ALL);
6154 talloc_free(tmp_ctx);
6155 if (ret != LDB_SUCCESS) {
6160 ar->index_current++;
6161 return replmd_replicated_apply_next(ar);
6164 static int replmd_replicated_uptodate_modify_callback(struct ldb_request *req,
6165 struct ldb_reply *ares)
6167 struct ldb_context *ldb;
6168 struct replmd_replicated_request *ar = talloc_get_type(req->context,
6169 struct replmd_replicated_request);
6170 ldb = ldb_module_get_ctx(ar->module);
6173 return ldb_module_done(ar->req, NULL, NULL,
6174 LDB_ERR_OPERATIONS_ERROR);
6176 if (ares->error != LDB_SUCCESS) {
6177 return ldb_module_done(ar->req, ares->controls,
6178 ares->response, ares->error);
6181 if (ares->type != LDB_REPLY_DONE) {
6182 ldb_asprintf_errstring(ldb, "Invalid LDB reply type %d", ares->type);
6183 return ldb_module_done(ar->req, NULL, NULL,
6184 LDB_ERR_OPERATIONS_ERROR);
6189 return ldb_module_done(ar->req, NULL, NULL, LDB_SUCCESS);
6192 static int replmd_replicated_uptodate_modify(struct replmd_replicated_request *ar)
6194 struct ldb_context *ldb;
6195 struct ldb_request *change_req;
6196 enum ndr_err_code ndr_err;
6197 struct ldb_message *msg;
6198 struct replUpToDateVectorBlob ouv;
6199 const struct ldb_val *ouv_value;
6200 const struct drsuapi_DsReplicaCursor2CtrEx *ruv;
6201 struct replUpToDateVectorBlob nuv;
6202 struct ldb_val nuv_value;
6203 struct ldb_message_element *nuv_el = NULL;
6204 struct ldb_message_element *orf_el = NULL;
6205 struct repsFromToBlob nrf;
6206 struct ldb_val *nrf_value = NULL;
6207 struct ldb_message_element *nrf_el = NULL;
6211 time_t t = time(NULL);
6214 uint32_t instanceType;
6216 ldb = ldb_module_get_ctx(ar->module);
6217 ruv = ar->objs->uptodateness_vector;
6223 unix_to_nt_time(&now, t);
6225 if (ar->search_msg == NULL) {
6226 /* this happens for a REPL_OBJ call where we are
6227 creating the target object by replicating it. The
6228 subdomain join code does this for the partition DN
6230 DEBUG(4,(__location__ ": Skipping UDV and repsFrom update as no target DN\n"));
6231 return ldb_module_done(ar->req, NULL, NULL, LDB_SUCCESS);
6234 instanceType = ldb_msg_find_attr_as_uint(ar->search_msg, "instanceType", 0);
6235 if (! (instanceType & INSTANCE_TYPE_IS_NC_HEAD)) {
6236 DEBUG(4,(__location__ ": Skipping UDV and repsFrom update as not NC root: %s\n",
6237 ldb_dn_get_linearized(ar->search_msg->dn)));
6238 return ldb_module_done(ar->req, NULL, NULL, LDB_SUCCESS);
6242 * first create the new replUpToDateVector
6244 ouv_value = ldb_msg_find_ldb_val(ar->search_msg, "replUpToDateVector");
6246 ndr_err = ndr_pull_struct_blob(ouv_value, ar, &ouv,
6247 (ndr_pull_flags_fn_t)ndr_pull_replUpToDateVectorBlob);
6248 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
6249 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
6250 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
6253 if (ouv.version != 2) {
6254 return replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
6259 * the new uptodateness vector will at least
6260 * contain 1 entry, one for the source_dsa
6262 * plus optional values from our old vector and the one from the source_dsa
6264 nuv.ctr.ctr2.count = ouv.ctr.ctr2.count;
6265 if (ruv) nuv.ctr.ctr2.count += ruv->count;
6266 nuv.ctr.ctr2.cursors = talloc_array(ar,
6267 struct drsuapi_DsReplicaCursor2,
6268 nuv.ctr.ctr2.count);
6269 if (!nuv.ctr.ctr2.cursors) return replmd_replicated_request_werror(ar, WERR_NOT_ENOUGH_MEMORY);
6271 /* first copy the old vector */
6272 for (i=0; i < ouv.ctr.ctr2.count; i++) {
6273 nuv.ctr.ctr2.cursors[ni] = ouv.ctr.ctr2.cursors[i];
6277 /* merge in the source_dsa vector is available */
6278 for (i=0; (ruv && i < ruv->count); i++) {
6281 if (GUID_equal(&ruv->cursors[i].source_dsa_invocation_id,
6282 &ar->our_invocation_id)) {
6286 for (j=0; j < ni; j++) {
6287 if (!GUID_equal(&ruv->cursors[i].source_dsa_invocation_id,
6288 &nuv.ctr.ctr2.cursors[j].source_dsa_invocation_id)) {
6294 if (ruv->cursors[i].highest_usn > nuv.ctr.ctr2.cursors[j].highest_usn) {
6295 nuv.ctr.ctr2.cursors[j] = ruv->cursors[i];
6300 if (found) continue;
6302 /* if it's not there yet, add it */
6303 nuv.ctr.ctr2.cursors[ni] = ruv->cursors[i];
6308 * finally correct the size of the cursors array
6310 nuv.ctr.ctr2.count = ni;
6315 TYPESAFE_QSORT(nuv.ctr.ctr2.cursors, nuv.ctr.ctr2.count, drsuapi_DsReplicaCursor2_compare);
6318 * create the change ldb_message
6320 msg = ldb_msg_new(ar);
6321 if (!msg) return replmd_replicated_request_werror(ar, WERR_NOT_ENOUGH_MEMORY);
6322 msg->dn = ar->search_msg->dn;
6324 ndr_err = ndr_push_struct_blob(&nuv_value, msg, &nuv,
6325 (ndr_push_flags_fn_t)ndr_push_replUpToDateVectorBlob);
6326 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
6327 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
6328 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
6330 ret = ldb_msg_add_value(msg, "replUpToDateVector", &nuv_value, &nuv_el);
6331 if (ret != LDB_SUCCESS) {
6332 return replmd_replicated_request_error(ar, ret);
6334 nuv_el->flags = LDB_FLAG_MOD_REPLACE;
6337 * now create the new repsFrom value from the given repsFromTo1 structure
6341 nrf.ctr.ctr1 = *ar->objs->source_dsa;
6342 nrf.ctr.ctr1.last_attempt = now;
6343 nrf.ctr.ctr1.last_success = now;
6344 nrf.ctr.ctr1.result_last_attempt = WERR_OK;
6347 * first see if we already have a repsFrom value for the current source dsa
6348 * if so we'll later replace this value
6350 orf_el = ldb_msg_find_element(ar->search_msg, "repsFrom");
6352 for (i=0; i < orf_el->num_values; i++) {
6353 struct repsFromToBlob *trf;
6355 trf = talloc(ar, struct repsFromToBlob);
6356 if (!trf) return replmd_replicated_request_werror(ar, WERR_NOT_ENOUGH_MEMORY);
6358 ndr_err = ndr_pull_struct_blob(&orf_el->values[i], trf, trf,
6359 (ndr_pull_flags_fn_t)ndr_pull_repsFromToBlob);
6360 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
6361 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
6362 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
6365 if (trf->version != 1) {
6366 return replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
6370 * we compare the source dsa objectGUID not the invocation_id
6371 * because we want only one repsFrom value per source dsa
6372 * and when the invocation_id of the source dsa has changed we don't need
6373 * the old repsFrom with the old invocation_id
6375 if (!GUID_equal(&trf->ctr.ctr1.source_dsa_obj_guid,
6376 &ar->objs->source_dsa->source_dsa_obj_guid)) {
6382 nrf_value = &orf_el->values[i];
6387 * copy over all old values to the new ldb_message
6389 ret = ldb_msg_add_empty(msg, "repsFrom", 0, &nrf_el);
6390 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
6395 * if we haven't found an old repsFrom value for the current source dsa
6396 * we'll add a new value
6399 struct ldb_val zero_value;
6400 ZERO_STRUCT(zero_value);
6401 ret = ldb_msg_add_value(msg, "repsFrom", &zero_value, &nrf_el);
6402 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
6404 nrf_value = &nrf_el->values[nrf_el->num_values - 1];
6407 /* we now fill the value which is already attached to ldb_message */
6408 ndr_err = ndr_push_struct_blob(nrf_value, msg,
6410 (ndr_push_flags_fn_t)ndr_push_repsFromToBlob);
6411 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
6412 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
6413 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
6417 * the ldb_message_element for the attribute, has all the old values and the new one
6418 * so we'll replace the whole attribute with all values
6420 nrf_el->flags = LDB_FLAG_MOD_REPLACE;
6422 if (CHECK_DEBUGLVL(4)) {
6423 char *s = ldb_ldif_message_string(ldb, ar, LDB_CHANGETYPE_MODIFY, msg);
6424 DEBUG(4, ("DRS replication uptodate modify message:\n%s\n", s));
6428 /* prepare the ldb_modify() request */
6429 ret = ldb_build_mod_req(&change_req,
6435 replmd_replicated_uptodate_modify_callback,
6437 LDB_REQ_SET_LOCATION(change_req);
6438 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
6440 return ldb_next_request(ar->module, change_req);
6443 static int replmd_replicated_uptodate_search_callback(struct ldb_request *req,
6444 struct ldb_reply *ares)
6446 struct replmd_replicated_request *ar = talloc_get_type(req->context,
6447 struct replmd_replicated_request);
6451 return ldb_module_done(ar->req, NULL, NULL,
6452 LDB_ERR_OPERATIONS_ERROR);
6454 if (ares->error != LDB_SUCCESS &&
6455 ares->error != LDB_ERR_NO_SUCH_OBJECT) {
6456 return ldb_module_done(ar->req, ares->controls,
6457 ares->response, ares->error);
6460 switch (ares->type) {
6461 case LDB_REPLY_ENTRY:
6462 ar->search_msg = talloc_steal(ar, ares->message);
6465 case LDB_REPLY_REFERRAL:
6466 /* we ignore referrals */
6469 case LDB_REPLY_DONE:
6470 ret = replmd_replicated_uptodate_modify(ar);
6471 if (ret != LDB_SUCCESS) {
6472 return ldb_module_done(ar->req, NULL, NULL, ret);
6481 static int replmd_replicated_uptodate_vector(struct replmd_replicated_request *ar)
6483 struct ldb_context *ldb = ldb_module_get_ctx(ar->module);
6484 struct replmd_private *replmd_private =
6485 talloc_get_type_abort(ldb_module_get_private(ar->module),
6486 struct replmd_private);
6488 static const char *attrs[] = {
6489 "replUpToDateVector",
6494 struct ldb_request *search_req;
6496 ar->search_msg = NULL;
6499 * Let the caller know that we did an originating updates
6501 ar->objs->originating_updates = replmd_private->originating_updates;
6503 ret = ldb_build_search_req(&search_req,
6506 ar->objs->partition_dn,
6512 replmd_replicated_uptodate_search_callback,
6514 LDB_REQ_SET_LOCATION(search_req);
6515 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
6517 return ldb_next_request(ar->module, search_req);
6522 static int replmd_extended_replicated_objects(struct ldb_module *module, struct ldb_request *req)
6524 struct ldb_context *ldb;
6525 struct dsdb_extended_replicated_objects *objs;
6526 struct replmd_replicated_request *ar;
6527 struct ldb_control **ctrls;
6530 struct replmd_private *replmd_private =
6531 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
6533 ldb = ldb_module_get_ctx(module);
6535 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_extended_replicated_objects\n");
6537 objs = talloc_get_type(req->op.extended.data, struct dsdb_extended_replicated_objects);
6539 ldb_debug(ldb, LDB_DEBUG_FATAL, "replmd_extended_replicated_objects: invalid extended data\n");
6540 return LDB_ERR_PROTOCOL_ERROR;
6543 if (objs->version != DSDB_EXTENDED_REPLICATED_OBJECTS_VERSION) {
6544 ldb_debug(ldb, LDB_DEBUG_FATAL, "replmd_extended_replicated_objects: extended data invalid version [%u != %u]\n",
6545 objs->version, DSDB_EXTENDED_REPLICATED_OBJECTS_VERSION);
6546 return LDB_ERR_PROTOCOL_ERROR;
6549 ar = replmd_ctx_init(module, req);
6551 return LDB_ERR_OPERATIONS_ERROR;
6553 /* Set the flags to have the replmd_op_callback run over the full set of objects */
6554 ar->apply_mode = true;
6556 ar->schema = dsdb_get_schema(ldb, ar);
6558 ldb_debug_set(ldb, LDB_DEBUG_FATAL, "replmd_ctx_init: no loaded schema found\n");
6560 DEBUG(0,(__location__ ": %s\n", ldb_errstring(ldb)));
6561 return LDB_ERR_CONSTRAINT_VIOLATION;
6564 ctrls = req->controls;
6566 if (req->controls) {
6567 req->controls = talloc_memdup(ar, req->controls,
6568 talloc_get_size(req->controls));
6569 if (!req->controls) return replmd_replicated_request_werror(ar, WERR_NOT_ENOUGH_MEMORY);
6572 ret = ldb_request_add_control(req, DSDB_CONTROL_REPLICATED_UPDATE_OID, false, NULL);
6573 if (ret != LDB_SUCCESS) {
6577 /* If this change contained linked attributes in the body
6578 * (rather than in the links section) we need to update
6579 * backlinks in linked_attributes */
6580 ret = ldb_request_add_control(req, DSDB_CONTROL_APPLY_LINKS, false, NULL);
6581 if (ret != LDB_SUCCESS) {
6585 ar->controls = req->controls;
6586 req->controls = ctrls;
6588 DEBUG(4,("linked_attributes_count=%u\n", objs->linked_attributes_count));
6590 /* save away the linked attributes for the end of the
6592 for (i=0; i<ar->objs->linked_attributes_count; i++) {
6593 struct la_entry *la_entry;
6595 if (replmd_private->la_ctx == NULL) {
6596 replmd_private->la_ctx = talloc_new(replmd_private);
6598 la_entry = talloc(replmd_private->la_ctx, struct la_entry);
6599 if (la_entry == NULL) {
6601 return LDB_ERR_OPERATIONS_ERROR;
6603 la_entry->la = talloc(la_entry, struct drsuapi_DsReplicaLinkedAttribute);
6604 if (la_entry->la == NULL) {
6605 talloc_free(la_entry);
6607 return LDB_ERR_OPERATIONS_ERROR;
6609 *la_entry->la = ar->objs->linked_attributes[i];
6611 /* we need to steal the non-scalars so they stay
6612 around until the end of the transaction */
6613 talloc_steal(la_entry->la, la_entry->la->identifier);
6614 talloc_steal(la_entry->la, la_entry->la->value.blob);
6616 DLIST_ADD(replmd_private->la_list, la_entry);
6619 return replmd_replicated_apply_next(ar);
6623 process one linked attribute structure
6625 static int replmd_process_linked_attribute(struct ldb_module *module,
6626 struct replmd_private *replmd_private,
6627 struct la_entry *la_entry,
6628 struct ldb_request *parent)
6630 struct drsuapi_DsReplicaLinkedAttribute *la = la_entry->la;
6631 struct ldb_context *ldb = ldb_module_get_ctx(module);
6632 struct ldb_message *msg;
6633 struct ldb_message *target_msg = NULL;
6634 TALLOC_CTX *tmp_ctx = talloc_new(la_entry);
6635 const struct dsdb_schema *schema = dsdb_get_schema(ldb, tmp_ctx);
6637 const struct dsdb_attribute *attr;
6638 struct dsdb_dn *dsdb_dn;
6639 uint64_t seq_num = 0;
6640 struct ldb_message_element *old_el;
6642 time_t t = time(NULL);
6643 struct ldb_result *res;
6644 struct ldb_result *target_res;
6645 const char *attrs[4];
6646 const char *attrs2[] = { "isDeleted", "isRecycled", NULL };
6647 struct parsed_dn *pdn_list, *pdn, *next;
6648 struct GUID guid = GUID_zero();
6650 bool active = (la->flags & DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE)?true:false;
6652 enum deletion_state deletion_state = OBJECT_NOT_DELETED;
6653 enum deletion_state target_deletion_state = OBJECT_NOT_DELETED;
6656 linked_attributes[0]:
6657 &objs->linked_attributes[i]: struct drsuapi_DsReplicaLinkedAttribute
6659 identifier: struct drsuapi_DsReplicaObjectIdentifier
6660 __ndr_size : 0x0000003a (58)
6661 __ndr_size_sid : 0x00000000 (0)
6662 guid : 8e95b6a9-13dd-4158-89db-3220a5be5cc7
6664 __ndr_size_dn : 0x00000000 (0)
6666 attid : DRSUAPI_ATTID_member (0x1F)
6667 value: struct drsuapi_DsAttributeValue
6668 __ndr_size : 0x0000007e (126)
6670 blob : DATA_BLOB length=126
6671 flags : 0x00000001 (1)
6672 1: DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE
6673 originating_add_time : Wed Sep 2 22:20:01 2009 EST
6674 meta_data: struct drsuapi_DsReplicaMetaData
6675 version : 0x00000015 (21)
6676 originating_change_time : Wed Sep 2 23:39:07 2009 EST
6677 originating_invocation_id: 794640f3-18cf-40ee-a211-a93992b67a64
6678 originating_usn : 0x000000000001e19c (123292)
6680 (for cases where the link is to a normal DN)
6681 &target: struct drsuapi_DsReplicaObjectIdentifier3
6682 __ndr_size : 0x0000007e (126)
6683 __ndr_size_sid : 0x0000001c (28)
6684 guid : 7639e594-db75-4086-b0d4-67890ae46031
6685 sid : S-1-5-21-2848215498-2472035911-1947525656-19924
6686 __ndr_size_dn : 0x00000022 (34)
6687 dn : 'CN=UOne,OU=TestOU,DC=vsofs8,DC=com'
6690 /* find the attribute being modified */
6691 attr = dsdb_attribute_by_attributeID_id(schema, la->attid);
6693 struct GUID_txt_buf guid_str;
6694 ldb_asprintf_errstring(ldb, "Unable to find attributeID 0x%x for link on <GUID=%s>",
6696 GUID_buf_string(&la->identifier->guid,
6698 talloc_free(tmp_ctx);
6699 return LDB_ERR_OPERATIONS_ERROR;
6702 attrs[0] = attr->lDAPDisplayName;
6703 attrs[1] = "isDeleted";
6704 attrs[2] = "isRecycled";
6707 /* get the existing message from the db for the object with
6708 this GUID, returning attribute being modified. We will then
6709 use this msg as the basis for a modify call */
6710 ret = dsdb_module_search(module, tmp_ctx, &res, NULL, LDB_SCOPE_SUBTREE, attrs,
6711 DSDB_FLAG_NEXT_MODULE |
6712 DSDB_SEARCH_SEARCH_ALL_PARTITIONS |
6713 DSDB_SEARCH_SHOW_RECYCLED |
6714 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT |
6715 DSDB_SEARCH_REVEAL_INTERNALS,
6717 "objectGUID=%s", GUID_string(tmp_ctx, &la->identifier->guid));
6718 if (ret != LDB_SUCCESS) {
6719 talloc_free(tmp_ctx);
6722 if (res->count != 1) {
6723 ldb_asprintf_errstring(ldb, "DRS linked attribute for GUID %s - DN not found",
6724 GUID_string(tmp_ctx, &la->identifier->guid));
6725 talloc_free(tmp_ctx);
6726 return LDB_ERR_NO_SUCH_OBJECT;
6731 * Check for deleted objects per MS-DRSR 4.1.10.6.13
6732 * ProcessLinkValue, because link updates are not applied to
6733 * recycled and tombstone objects. We don't have to delete
6734 * any existing link, that should have happened when the
6735 * object deletion was replicated or initiated.
6738 replmd_deletion_state(module, msg, &deletion_state, NULL);
6740 if (deletion_state >= OBJECT_RECYCLED) {
6741 talloc_free(tmp_ctx);
6745 old_el = ldb_msg_find_element(msg, attr->lDAPDisplayName);
6746 if (old_el == NULL) {
6747 ret = ldb_msg_add_empty(msg, attr->lDAPDisplayName, LDB_FLAG_MOD_REPLACE, &old_el);
6748 if (ret != LDB_SUCCESS) {
6749 ldb_module_oom(module);
6750 talloc_free(tmp_ctx);
6751 return LDB_ERR_OPERATIONS_ERROR;
6754 old_el->flags = LDB_FLAG_MOD_REPLACE;
6757 /* parse the existing links */
6758 ret = get_parsed_dns_trusted(module, replmd_private, tmp_ctx, old_el, &pdn_list,
6759 attr->syntax->ldap_oid, parent);
6761 if (ret != LDB_SUCCESS) {
6762 talloc_free(tmp_ctx);
6766 status = dsdb_dn_la_from_blob(ldb, attr, schema, tmp_ctx, la->value.blob, &dsdb_dn);
6767 if (!W_ERROR_IS_OK(status)) {
6768 ldb_asprintf_errstring(ldb, "Failed to parsed linked attribute blob for %s on %s - %s\n",
6769 old_el->name, ldb_dn_get_linearized(msg->dn), win_errstr(status));
6770 talloc_free(tmp_ctx);
6771 return LDB_ERR_OPERATIONS_ERROR;
6774 ntstatus = dsdb_get_extended_dn_guid(dsdb_dn->dn, &guid, "GUID");
6775 if (!NT_STATUS_IS_OK(ntstatus) && !active) {
6777 * This strange behaviour (allowing a NULL/missing
6778 * GUID) originally comes from:
6780 * commit e3054ce0fe0f8f62d2f5b2a77893e7a1479128bd
6781 * Author: Andrew Tridgell <tridge@samba.org>
6782 * Date: Mon Dec 21 21:21:55 2009 +1100
6784 * s4-drs: cope better with NULL GUIDS from DRS
6786 * It is valid to get a NULL GUID over DRS for a deleted forward link. We
6787 * need to match by DN if possible when seeing if we should update an
6790 * Pair-Programmed-With: Andrew Bartlett <abartlet@samba.org>
6793 ret = dsdb_module_search_dn(module, tmp_ctx, &target_res,
6794 dsdb_dn->dn, attrs2,
6795 DSDB_FLAG_NEXT_MODULE |
6796 DSDB_SEARCH_SHOW_RECYCLED |
6797 DSDB_SEARCH_SEARCH_ALL_PARTITIONS |
6798 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT,
6800 } else if (!NT_STATUS_IS_OK(ntstatus)) {
6801 ldb_asprintf_errstring(ldb, "Failed to find GUID in linked attribute blob for %s on %s from %s",
6803 ldb_dn_get_linearized(dsdb_dn->dn),
6804 ldb_dn_get_linearized(msg->dn));
6805 talloc_free(tmp_ctx);
6806 return LDB_ERR_OPERATIONS_ERROR;
6808 ret = dsdb_module_search(module, tmp_ctx, &target_res,
6809 NULL, LDB_SCOPE_SUBTREE,
6811 DSDB_FLAG_NEXT_MODULE |
6812 DSDB_SEARCH_SHOW_RECYCLED |
6813 DSDB_SEARCH_SEARCH_ALL_PARTITIONS |
6814 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT,
6817 GUID_string(tmp_ctx, &guid));
6820 if (ret != LDB_SUCCESS) {
6821 ldb_asprintf_errstring(ldb_module_get_ctx(module), "Failed to re-resolve GUID %s: %s\n",
6822 GUID_string(tmp_ctx, &guid),
6823 ldb_errstring(ldb_module_get_ctx(module)));
6824 talloc_free(tmp_ctx);
6828 if (target_res->count == 0) {
6829 DEBUG(2,(__location__ ": WARNING: Failed to re-resolve GUID %s - using %s\n",
6830 GUID_string(tmp_ctx, &guid),
6831 ldb_dn_get_linearized(dsdb_dn->dn)));
6832 } else if (target_res->count != 1) {
6833 ldb_asprintf_errstring(ldb_module_get_ctx(module), "More than one object found matching objectGUID %s\n",
6834 GUID_string(tmp_ctx, &guid));
6835 talloc_free(tmp_ctx);
6836 return LDB_ERR_OPERATIONS_ERROR;
6838 target_msg = target_res->msgs[0];
6839 dsdb_dn->dn = talloc_steal(dsdb_dn, target_msg->dn);
6843 * Check for deleted objects per MS-DRSR 4.1.10.6.13
6844 * ProcessLinkValue, because link updates are not applied to
6845 * recycled and tombstone objects. We don't have to delete
6846 * any existing link, that should have happened when the
6847 * object deletion was replicated or initiated.
6849 replmd_deletion_state(module, target_msg,
6850 &target_deletion_state, NULL);
6852 if (target_deletion_state >= OBJECT_RECYCLED) {
6853 talloc_free(tmp_ctx);
6857 /* see if this link already exists */
6858 ret = parsed_dn_find(ldb, pdn_list, old_el->num_values,
6861 dsdb_dn->extra_part, 0,
6863 attr->syntax->ldap_oid,
6865 if (ret != LDB_SUCCESS) {
6866 talloc_free(tmp_ctx);
6872 /* see if this update is newer than what we have already */
6873 struct GUID invocation_id = GUID_zero();
6874 uint32_t version = 0;
6875 uint32_t originating_usn = 0;
6876 NTTIME change_time = 0;
6877 uint32_t rmd_flags = dsdb_dn_rmd_flags(pdn->dsdb_dn->dn);
6879 dsdb_get_extended_dn_guid(pdn->dsdb_dn->dn, &invocation_id, "RMD_INVOCID");
6880 dsdb_get_extended_dn_uint32(pdn->dsdb_dn->dn, &version, "RMD_VERSION");
6881 dsdb_get_extended_dn_uint32(pdn->dsdb_dn->dn, &originating_usn, "RMD_ORIGINATING_USN");
6882 dsdb_get_extended_dn_nttime(pdn->dsdb_dn->dn, &change_time, "RMD_CHANGETIME");
6884 if (!replmd_update_is_newer(&invocation_id,
6885 &la->meta_data.originating_invocation_id,
6887 la->meta_data.version,
6889 la->meta_data.originating_change_time)) {
6890 DEBUG(3,("Discarding older DRS linked attribute update to %s on %s from %s\n",
6891 old_el->name, ldb_dn_get_linearized(msg->dn),
6892 GUID_string(tmp_ctx, &la->meta_data.originating_invocation_id)));
6893 talloc_free(tmp_ctx);
6897 /* get a seq_num for this change */
6898 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &seq_num);
6899 if (ret != LDB_SUCCESS) {
6900 talloc_free(tmp_ctx);
6904 if (!(rmd_flags & DSDB_RMD_FLAG_DELETED)) {
6905 /* remove the existing backlink */
6906 ret = replmd_add_backlink(module, replmd_private,
6911 if (ret != LDB_SUCCESS) {
6912 talloc_free(tmp_ctx);
6917 ret = replmd_update_la_val(tmp_ctx, pdn->v, dsdb_dn, pdn->dsdb_dn,
6918 &la->meta_data.originating_invocation_id,
6919 la->meta_data.originating_usn, seq_num,
6920 la->meta_data.originating_change_time,
6921 la->meta_data.version,
6923 if (ret != LDB_SUCCESS) {
6924 talloc_free(tmp_ctx);
6929 /* add the new backlink */
6930 ret = replmd_add_backlink(module, replmd_private,
6935 if (ret != LDB_SUCCESS) {
6936 talloc_free(tmp_ctx);
6942 /* get a seq_num for this change */
6943 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &seq_num);
6944 if (ret != LDB_SUCCESS) {
6945 talloc_free(tmp_ctx);
6949 * We know where the new one needs to be, from the *next
6950 * pointer into pdn_list.
6953 offset = old_el->num_values;
6955 if (next->dsdb_dn == NULL) {
6956 ret = really_parse_trusted_dn(tmp_ctx, ldb, next,
6957 attr->syntax->ldap_oid);
6958 if (ret != LDB_SUCCESS) {
6962 offset = next - pdn_list;
6963 if (offset > old_el->num_values) {
6964 talloc_free(tmp_ctx);
6965 return LDB_ERR_OPERATIONS_ERROR;
6969 old_el->values = talloc_realloc(msg->elements, old_el->values,
6970 struct ldb_val, old_el->num_values+1);
6971 if (!old_el->values) {
6972 ldb_module_oom(module);
6973 return LDB_ERR_OPERATIONS_ERROR;
6976 if (offset != old_el->num_values) {
6977 memmove(&old_el->values[offset + 1], &old_el->values[offset],
6978 (old_el->num_values - offset) * sizeof(old_el->values[0]));
6981 old_el->num_values++;
6983 ret = replmd_build_la_val(tmp_ctx, &old_el->values[offset], dsdb_dn,
6984 &la->meta_data.originating_invocation_id,
6985 la->meta_data.originating_usn, seq_num,
6986 la->meta_data.originating_change_time,
6987 la->meta_data.version,
6989 if (ret != LDB_SUCCESS) {
6990 talloc_free(tmp_ctx);
6995 ret = replmd_add_backlink(module, replmd_private,
7000 if (ret != LDB_SUCCESS) {
7001 talloc_free(tmp_ctx);
7007 /* we only change whenChanged and uSNChanged if the seq_num
7009 ret = add_time_element(msg, "whenChanged", t);
7010 if (ret != LDB_SUCCESS) {
7011 talloc_free(tmp_ctx);
7016 ret = add_uint64_element(ldb, msg, "uSNChanged", seq_num);
7017 if (ret != LDB_SUCCESS) {
7018 talloc_free(tmp_ctx);
7023 old_el = ldb_msg_find_element(msg, attr->lDAPDisplayName);
7024 if (old_el == NULL) {
7025 talloc_free(tmp_ctx);
7026 return ldb_operr(ldb);
7029 ret = dsdb_check_single_valued_link(attr, old_el);
7030 if (ret != LDB_SUCCESS) {
7031 talloc_free(tmp_ctx);
7035 old_el->flags |= LDB_FLAG_INTERNAL_DISABLE_SINGLE_VALUE_CHECK;
7037 ret = linked_attr_modify(module, msg, parent);
7038 if (ret != LDB_SUCCESS) {
7039 ldb_debug(ldb, LDB_DEBUG_WARNING, "Failed to apply linked attribute change '%s'\n%s\n",
7041 ldb_ldif_message_string(ldb, tmp_ctx, LDB_CHANGETYPE_MODIFY, msg));
7042 talloc_free(tmp_ctx);
7046 talloc_free(tmp_ctx);
7051 static int replmd_extended(struct ldb_module *module, struct ldb_request *req)
7053 if (strcmp(req->op.extended.oid, DSDB_EXTENDED_REPLICATED_OBJECTS_OID) == 0) {
7054 return replmd_extended_replicated_objects(module, req);
7057 return ldb_next_request(module, req);
7062 we hook into the transaction operations to allow us to
7063 perform the linked attribute updates at the end of the whole
7064 transaction. This allows a forward linked attribute to be created
7065 before the object is created. During a vampire, w2k8 sends us linked
7066 attributes before the objects they are part of.
7068 static int replmd_start_transaction(struct ldb_module *module)
7070 /* create our private structure for this transaction */
7071 struct replmd_private *replmd_private = talloc_get_type(ldb_module_get_private(module),
7072 struct replmd_private);
7073 replmd_txn_cleanup(replmd_private);
7075 /* free any leftover mod_usn records from cancelled
7077 while (replmd_private->ncs) {
7078 struct nc_entry *e = replmd_private->ncs;
7079 DLIST_REMOVE(replmd_private->ncs, e);
7083 replmd_private->originating_updates = false;
7085 return ldb_next_start_trans(module);
7089 on prepare commit we loop over our queued la_context structures and
7092 static int replmd_prepare_commit(struct ldb_module *module)
7094 struct replmd_private *replmd_private =
7095 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
7096 struct la_entry *la, *prev;
7100 * Walk the list of linked attributes from DRS replication.
7102 * We walk backwards, to do the first entry first, as we
7103 * added the entries with DLIST_ADD() which puts them at the
7106 for (la = DLIST_TAIL(replmd_private->la_list); la; la=prev) {
7107 prev = DLIST_PREV(la);
7108 DLIST_REMOVE(replmd_private->la_list, la);
7109 ret = replmd_process_linked_attribute(module, replmd_private,
7111 if (ret != LDB_SUCCESS) {
7112 replmd_txn_cleanup(replmd_private);
7117 replmd_txn_cleanup(replmd_private);
7119 /* possibly change @REPLCHANGED */
7120 ret = replmd_notify_store(module, NULL);
7121 if (ret != LDB_SUCCESS) {
7125 return ldb_next_prepare_commit(module);
7128 static int replmd_del_transaction(struct ldb_module *module)
7130 struct replmd_private *replmd_private =
7131 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
7132 replmd_txn_cleanup(replmd_private);
7134 return ldb_next_del_trans(module);
7138 static const struct ldb_module_ops ldb_repl_meta_data_module_ops = {
7139 .name = "repl_meta_data",
7140 .init_context = replmd_init,
7142 .modify = replmd_modify,
7143 .rename = replmd_rename,
7144 .del = replmd_delete,
7145 .extended = replmd_extended,
7146 .start_transaction = replmd_start_transaction,
7147 .prepare_commit = replmd_prepare_commit,
7148 .del_transaction = replmd_del_transaction,
7151 int ldb_repl_meta_data_module_init(const char *version)
7153 LDB_MODULE_CHECK_VERSION(version);
7154 return ldb_register_module(&ldb_repl_meta_data_module_ops);