4 Copyright (C) Simo Sorce 2004-2008
5 Copyright (C) Andrew Bartlett <abartlet@samba.org> 2005-2013
6 Copyright (C) Andrew Tridgell 2005-2009
7 Copyright (C) Stefan Metzmacher <metze@samba.org> 2007
8 Copyright (C) Matthieu Patou <mat@samba.org> 2010-2011
10 This program is free software; you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation; either version 3 of the License, or
13 (at your option) any later version.
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
20 You should have received a copy of the GNU General Public License
21 along with this program. If not, see <http://www.gnu.org/licenses/>.
27 * Component: ldb repl_meta_data module
29 * Description: - add a unique objectGUID onto every new record,
30 * - handle whenCreated, whenChanged timestamps
31 * - handle uSNCreated, uSNChanged numbers
32 * - handle replPropertyMetaData attribute
35 * Author: Stefan Metzmacher
39 #include "ldb_module.h"
40 #include "dsdb/samdb/samdb.h"
41 #include "dsdb/common/proto.h"
42 #include "dsdb/common/util.h"
43 #include "../libds/common/flags.h"
44 #include "librpc/gen_ndr/irpc.h"
45 #include "librpc/gen_ndr/ndr_misc.h"
46 #include "librpc/gen_ndr/ndr_drsuapi.h"
47 #include "librpc/gen_ndr/ndr_drsblobs.h"
48 #include "param/param.h"
49 #include "libcli/security/security.h"
50 #include "lib/util/dlinklist.h"
51 #include "dsdb/samdb/ldb_modules/util.h"
52 #include "lib/util/tsort.h"
55 * It's 29/12/9999 at 23:59:59 UTC as specified in MS-ADTS 7.1.1.4.2
56 * Deleted Objects Container
58 static const NTTIME DELETED_OBJECT_CONTAINER_CHANGE_TIME = 2650466015990000000ULL;
60 struct replmd_private {
62 struct la_entry *la_list;
64 struct nc_entry *prev, *next;
67 uint64_t mod_usn_urgent;
69 struct ldb_dn *schema_dn;
70 bool originating_updates;
75 struct la_entry *next, *prev;
76 struct drsuapi_DsReplicaLinkedAttribute *la;
79 struct replmd_replicated_request {
80 struct ldb_module *module;
81 struct ldb_request *req;
83 const struct dsdb_schema *schema;
84 struct GUID our_invocation_id;
86 /* the controls we pass down */
87 struct ldb_control **controls;
90 * Backlinks for the replmd_add() case (we want to create
91 * backlinks after creating the user, but before the end of
94 struct la_backlink *la_backlinks;
96 /* details for the mode where we apply a bunch of inbound replication meessages */
98 uint32_t index_current;
99 struct dsdb_extended_replicated_objects *objs;
101 struct ldb_message *search_msg;
102 struct GUID local_parent_guid;
110 static int replmd_replicated_apply_merge(struct replmd_replicated_request *ar);
111 static int replmd_delete_internals(struct ldb_module *module, struct ldb_request *req, bool re_delete);
112 static int replmd_check_upgrade_links(struct ldb_context *ldb,
113 struct parsed_dn *dns, uint32_t count,
114 struct ldb_message_element *el,
115 const char *ldap_oid);
117 enum urgent_situation {
118 REPL_URGENT_ON_CREATE = 1,
119 REPL_URGENT_ON_UPDATE = 2,
120 REPL_URGENT_ON_DELETE = 4
123 enum deletion_state {
124 OBJECT_NOT_DELETED=1,
131 static void replmd_deletion_state(struct ldb_module *module,
132 const struct ldb_message *msg,
133 enum deletion_state *current_state,
134 enum deletion_state *next_state)
137 bool enabled = false;
140 *current_state = OBJECT_REMOVED;
141 if (next_state != NULL) {
142 *next_state = OBJECT_REMOVED;
147 ret = dsdb_recyclebin_enabled(module, &enabled);
148 if (ret != LDB_SUCCESS) {
152 if (ldb_msg_check_string_attribute(msg, "isDeleted", "TRUE")) {
154 *current_state = OBJECT_TOMBSTONE;
155 if (next_state != NULL) {
156 *next_state = OBJECT_REMOVED;
161 if (ldb_msg_check_string_attribute(msg, "isRecycled", "TRUE")) {
162 *current_state = OBJECT_RECYCLED;
163 if (next_state != NULL) {
164 *next_state = OBJECT_REMOVED;
169 *current_state = OBJECT_DELETED;
170 if (next_state != NULL) {
171 *next_state = OBJECT_RECYCLED;
176 *current_state = OBJECT_NOT_DELETED;
177 if (next_state == NULL) {
182 *next_state = OBJECT_DELETED;
184 *next_state = OBJECT_TOMBSTONE;
188 static const struct {
189 const char *update_name;
190 enum urgent_situation repl_situation;
191 } urgent_objects[] = {
192 {"nTDSDSA", (REPL_URGENT_ON_CREATE | REPL_URGENT_ON_DELETE)},
193 {"crossRef", (REPL_URGENT_ON_CREATE | REPL_URGENT_ON_DELETE)},
194 {"attributeSchema", (REPL_URGENT_ON_CREATE | REPL_URGENT_ON_UPDATE)},
195 {"classSchema", (REPL_URGENT_ON_CREATE | REPL_URGENT_ON_UPDATE)},
196 {"secret", (REPL_URGENT_ON_CREATE | REPL_URGENT_ON_UPDATE)},
197 {"rIDManager", (REPL_URGENT_ON_CREATE | REPL_URGENT_ON_UPDATE)},
201 /* Attributes looked for when updating or deleting, to check for a urgent replication needed */
202 static const char *urgent_attrs[] = {
205 "userAccountControl",
210 static bool replmd_check_urgent_objectclass(const struct ldb_message_element *objectclass_el,
211 enum urgent_situation situation)
214 for (i=0; urgent_objects[i].update_name; i++) {
216 if ((situation & urgent_objects[i].repl_situation) == 0) {
220 for (j=0; j<objectclass_el->num_values; j++) {
221 const struct ldb_val *v = &objectclass_el->values[j];
222 if (ldb_attr_cmp((const char *)v->data, urgent_objects[i].update_name) == 0) {
230 static bool replmd_check_urgent_attribute(const struct ldb_message_element *el)
232 if (ldb_attr_in_list(urgent_attrs, el->name)) {
238 static int replmd_replicated_apply_isDeleted(struct replmd_replicated_request *ar);
241 initialise the module
242 allocate the private structure and build the list
243 of partition DNs for use by replmd_notify()
245 static int replmd_init(struct ldb_module *module)
247 struct replmd_private *replmd_private;
248 struct ldb_context *ldb = ldb_module_get_ctx(module);
249 static const char *samba_dsdb_attrs[] = { SAMBA_COMPATIBLE_FEATURES_ATTR, NULL };
250 struct ldb_dn *samba_dsdb_dn;
251 struct ldb_result *res;
253 TALLOC_CTX *frame = talloc_stackframe();
254 replmd_private = talloc_zero(module, struct replmd_private);
255 if (replmd_private == NULL) {
258 return LDB_ERR_OPERATIONS_ERROR;
260 ldb_module_set_private(module, replmd_private);
262 replmd_private->schema_dn = ldb_get_schema_basedn(ldb);
264 samba_dsdb_dn = ldb_dn_new(frame, ldb, "@SAMBA_DSDB");
265 if (!samba_dsdb_dn) {
270 ret = dsdb_module_search_dn(module, frame, &res, samba_dsdb_dn,
271 samba_dsdb_attrs, DSDB_FLAG_NEXT_MODULE, NULL);
272 if (ret == LDB_SUCCESS) {
273 replmd_private->sorted_links
274 = ldb_msg_check_string_attribute(res->msgs[0],
275 SAMBA_COMPATIBLE_FEATURES_ATTR,
276 SAMBA_SORTED_LINKS_FEATURE);
280 return ldb_next_init(module);
284 cleanup our per-transaction contexts
286 static void replmd_txn_cleanup(struct replmd_private *replmd_private)
288 talloc_free(replmd_private->la_ctx);
289 replmd_private->la_list = NULL;
290 replmd_private->la_ctx = NULL;
296 struct la_backlink *next, *prev;
297 const char *attr_name;
298 struct ldb_dn *forward_dn;
299 struct GUID target_guid;
304 a ldb_modify request operating on modules below the
307 static int linked_attr_modify(struct ldb_module *module,
308 const struct ldb_message *message,
309 struct ldb_request *parent)
311 struct ldb_request *mod_req;
313 struct ldb_context *ldb = ldb_module_get_ctx(module);
314 TALLOC_CTX *tmp_ctx = talloc_new(module);
315 struct ldb_result *res;
317 res = talloc_zero(tmp_ctx, struct ldb_result);
319 talloc_free(tmp_ctx);
320 return ldb_oom(ldb_module_get_ctx(module));
323 ret = ldb_build_mod_req(&mod_req, ldb, tmp_ctx,
327 ldb_modify_default_callback,
329 LDB_REQ_SET_LOCATION(mod_req);
330 if (ret != LDB_SUCCESS) {
331 talloc_free(tmp_ctx);
335 ret = ldb_request_add_control(mod_req, DSDB_CONTROL_REPLICATED_UPDATE_OID,
337 if (ret != LDB_SUCCESS) {
341 /* Run the new request */
342 ret = ldb_next_request(module, mod_req);
344 if (ret == LDB_SUCCESS) {
345 ret = ldb_wait(mod_req->handle, LDB_WAIT_ALL);
348 talloc_free(tmp_ctx);
353 process a backlinks we accumulated during a transaction, adding and
354 deleting the backlinks from the target objects
356 static int replmd_process_backlink(struct ldb_module *module, struct la_backlink *bl, struct ldb_request *parent)
358 struct ldb_dn *target_dn, *source_dn;
360 struct ldb_context *ldb = ldb_module_get_ctx(module);
361 struct ldb_message *msg;
362 TALLOC_CTX *frame = talloc_stackframe();
368 - construct ldb_message
369 - either an add or a delete
371 ret = dsdb_module_dn_by_guid(module, frame, &bl->target_guid, &target_dn, parent);
372 if (ret != LDB_SUCCESS) {
373 struct GUID_txt_buf guid_str;
374 DEBUG(2,(__location__ ": WARNING: Failed to find target DN for linked attribute with GUID %s\n",
375 GUID_buf_string(&bl->target_guid, &guid_str)));
380 msg = ldb_msg_new(frame);
382 ldb_module_oom(module);
384 return LDB_ERR_OPERATIONS_ERROR;
387 source_dn = ldb_dn_copy(frame, bl->forward_dn);
389 ldb_module_oom(module);
391 return LDB_ERR_OPERATIONS_ERROR;
393 /* Filter down to the attributes we want in the backlink */
394 const char *accept[] = { "GUID", "SID", NULL };
395 ldb_dn_extended_filter(source_dn, accept);
398 /* construct a ldb_message for adding/deleting the backlink */
400 dn_string = ldb_dn_get_extended_linearized(frame, bl->forward_dn, 1);
402 ldb_module_oom(module);
404 return LDB_ERR_OPERATIONS_ERROR;
406 ret = ldb_msg_add_steal_string(msg, bl->attr_name, dn_string);
407 if (ret != LDB_SUCCESS) {
411 msg->elements[0].flags = bl->active?LDB_FLAG_MOD_ADD:LDB_FLAG_MOD_DELETE;
413 /* a backlink should never be single valued. Unfortunately the
414 exchange schema has a attribute
415 msExchBridgeheadedLocalConnectorsDNBL which is single
416 valued and a backlink. We need to cope with that by
417 ignoring the single value flag */
418 msg->elements[0].flags |= LDB_FLAG_INTERNAL_DISABLE_SINGLE_VALUE_CHECK;
420 ret = dsdb_module_modify(module, msg, DSDB_FLAG_NEXT_MODULE, parent);
421 if (ret == LDB_ERR_NO_SUCH_ATTRIBUTE && !bl->active) {
422 /* we allow LDB_ERR_NO_SUCH_ATTRIBUTE as success to
423 cope with possible corruption where the backlink has
424 already been removed */
425 DEBUG(3,("WARNING: backlink from %s already removed from %s - %s\n",
426 ldb_dn_get_linearized(target_dn),
427 ldb_dn_get_linearized(source_dn),
428 ldb_errstring(ldb)));
430 } else if (ret != LDB_SUCCESS) {
431 ldb_asprintf_errstring(ldb, "Failed to %s backlink from %s to %s - %s",
432 bl->active?"add":"remove",
433 ldb_dn_get_linearized(source_dn),
434 ldb_dn_get_linearized(target_dn),
444 add a backlink to the list of backlinks to add/delete in the prepare
447 forward_dn is stolen onto the defereed context
449 static int replmd_defer_add_backlink(struct ldb_module *module,
450 struct replmd_private *replmd_private,
451 const struct dsdb_schema *schema,
452 struct replmd_replicated_request *ac,
453 struct ldb_dn *forward_dn,
454 struct GUID *target_guid, bool active,
455 const struct dsdb_attribute *schema_attr,
456 struct ldb_request *parent)
458 const struct dsdb_attribute *target_attr;
459 struct la_backlink *bl;
461 bl = talloc(ac, struct la_backlink);
463 ldb_module_oom(module);
464 return LDB_ERR_OPERATIONS_ERROR;
467 target_attr = dsdb_attribute_by_linkID(schema, schema_attr->linkID ^ 1);
470 * windows 2003 has a broken schema where the
471 * definition of msDS-IsDomainFor is missing (which is
472 * supposed to be the backlink of the
473 * msDS-HasDomainNCs attribute
478 bl->attr_name = target_attr->lDAPDisplayName;
479 bl->forward_dn = talloc_steal(bl, forward_dn);
480 bl->target_guid = *target_guid;
483 DLIST_ADD(ac->la_backlinks, bl);
489 add a backlink to the list of backlinks to add/delete in the prepare
492 static int replmd_add_backlink(struct ldb_module *module,
493 struct replmd_private *replmd_private,
494 const struct dsdb_schema *schema,
495 struct ldb_dn *forward_dn,
496 struct GUID *target_guid, bool active,
497 const struct dsdb_attribute *schema_attr,
498 struct ldb_request *parent)
500 const struct dsdb_attribute *target_attr;
501 struct la_backlink bl;
504 target_attr = dsdb_attribute_by_linkID(schema, schema_attr->linkID ^ 1);
507 * windows 2003 has a broken schema where the
508 * definition of msDS-IsDomainFor is missing (which is
509 * supposed to be the backlink of the
510 * msDS-HasDomainNCs attribute
515 bl.attr_name = target_attr->lDAPDisplayName;
516 bl.forward_dn = forward_dn;
517 bl.target_guid = *target_guid;
520 ret = replmd_process_backlink(module, &bl, parent);
526 * Callback for most write operations in this module:
528 * notify the repl task that a object has changed. The notifies are
529 * gathered up in the replmd_private structure then written to the
530 * @REPLCHANGED object in each partition during the prepare_commit
532 static int replmd_op_callback(struct ldb_request *req, struct ldb_reply *ares)
535 struct replmd_replicated_request *ac =
536 talloc_get_type_abort(req->context, struct replmd_replicated_request);
537 struct replmd_private *replmd_private =
538 talloc_get_type_abort(ldb_module_get_private(ac->module), struct replmd_private);
539 struct nc_entry *modified_partition;
540 struct ldb_control *partition_ctrl;
541 const struct dsdb_control_current_partition *partition;
543 struct ldb_control **controls;
545 partition_ctrl = ldb_reply_get_control(ares, DSDB_CONTROL_CURRENT_PARTITION_OID);
547 controls = ares->controls;
548 if (ldb_request_get_control(ac->req,
549 DSDB_CONTROL_CURRENT_PARTITION_OID) == NULL) {
551 * Remove the current partition control from what we pass up
552 * the chain if it hasn't been requested manually.
554 controls = ldb_controls_except_specified(ares->controls, ares,
558 if (ares->error != LDB_SUCCESS) {
559 DEBUG(5,("%s failure. Error is: %s\n", __FUNCTION__, ldb_strerror(ares->error)));
560 return ldb_module_done(ac->req, controls,
561 ares->response, ares->error);
564 if (ares->type != LDB_REPLY_DONE) {
565 ldb_set_errstring(ldb_module_get_ctx(ac->module), "Invalid reply type for notify\n!");
566 return ldb_module_done(ac->req, NULL,
567 NULL, LDB_ERR_OPERATIONS_ERROR);
570 if (ac->apply_mode == false) {
571 struct la_backlink *bl;
573 * process our backlink list after an replmd_add(),
574 * creating and deleting backlinks as necessary (this
575 * code is sync). The other cases are handled inline
578 for (bl=ac->la_backlinks; bl; bl=bl->next) {
579 ret = replmd_process_backlink(ac->module, bl, ac->req);
580 if (ret != LDB_SUCCESS) {
581 return ldb_module_done(ac->req, NULL,
587 if (!partition_ctrl) {
588 ldb_set_errstring(ldb_module_get_ctx(ac->module),"No partition control on reply");
589 return ldb_module_done(ac->req, NULL,
590 NULL, LDB_ERR_OPERATIONS_ERROR);
593 partition = talloc_get_type_abort(partition_ctrl->data,
594 struct dsdb_control_current_partition);
596 if (ac->seq_num > 0) {
597 for (modified_partition = replmd_private->ncs; modified_partition;
598 modified_partition = modified_partition->next) {
599 if (ldb_dn_compare(modified_partition->dn, partition->dn) == 0) {
604 if (modified_partition == NULL) {
605 modified_partition = talloc_zero(replmd_private, struct nc_entry);
606 if (!modified_partition) {
607 ldb_oom(ldb_module_get_ctx(ac->module));
608 return ldb_module_done(ac->req, NULL,
609 NULL, LDB_ERR_OPERATIONS_ERROR);
611 modified_partition->dn = ldb_dn_copy(modified_partition, partition->dn);
612 if (!modified_partition->dn) {
613 ldb_oom(ldb_module_get_ctx(ac->module));
614 return ldb_module_done(ac->req, NULL,
615 NULL, LDB_ERR_OPERATIONS_ERROR);
617 DLIST_ADD(replmd_private->ncs, modified_partition);
620 if (ac->seq_num > modified_partition->mod_usn) {
621 modified_partition->mod_usn = ac->seq_num;
623 modified_partition->mod_usn_urgent = ac->seq_num;
626 if (!ac->apply_mode) {
627 replmd_private->originating_updates = true;
631 if (ac->apply_mode) {
632 ret = replmd_replicated_apply_isDeleted(ac);
633 if (ret != LDB_SUCCESS) {
634 return ldb_module_done(ac->req, NULL, NULL, ret);
638 /* free the partition control container here, for the
639 * common path. Other cases will have it cleaned up
640 * eventually with the ares */
641 talloc_free(partition_ctrl);
642 return ldb_module_done(ac->req, controls,
643 ares->response, LDB_SUCCESS);
649 * update a @REPLCHANGED record in each partition if there have been
650 * any writes of replicated data in the partition
652 static int replmd_notify_store(struct ldb_module *module, struct ldb_request *parent)
654 struct replmd_private *replmd_private =
655 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
657 while (replmd_private->ncs) {
659 struct nc_entry *modified_partition = replmd_private->ncs;
661 ret = dsdb_module_save_partition_usn(module, modified_partition->dn,
662 modified_partition->mod_usn,
663 modified_partition->mod_usn_urgent, parent);
664 if (ret != LDB_SUCCESS) {
665 DEBUG(0,(__location__ ": Failed to save partition uSN for %s\n",
666 ldb_dn_get_linearized(modified_partition->dn)));
670 if (ldb_dn_compare(modified_partition->dn,
671 replmd_private->schema_dn) == 0) {
672 struct ldb_result *ext_res;
673 ret = dsdb_module_extended(module,
674 replmd_private->schema_dn,
676 DSDB_EXTENDED_SCHEMA_UPDATE_NOW_OID,
678 DSDB_FLAG_NEXT_MODULE,
680 if (ret != LDB_SUCCESS) {
683 talloc_free(ext_res);
686 DLIST_REMOVE(replmd_private->ncs, modified_partition);
687 talloc_free(modified_partition);
695 created a replmd_replicated_request context
697 static struct replmd_replicated_request *replmd_ctx_init(struct ldb_module *module,
698 struct ldb_request *req)
700 struct ldb_context *ldb;
701 struct replmd_replicated_request *ac;
702 const struct GUID *our_invocation_id;
704 ldb = ldb_module_get_ctx(module);
706 ac = talloc_zero(req, struct replmd_replicated_request);
715 ac->schema = dsdb_get_schema(ldb, ac);
717 ldb_debug_set(ldb, LDB_DEBUG_FATAL,
718 "replmd_modify: no dsdb_schema loaded");
719 DEBUG(0,(__location__ ": %s\n", ldb_errstring(ldb)));
724 /* get our invocationId */
725 our_invocation_id = samdb_ntds_invocation_id(ldb);
726 if (!our_invocation_id) {
727 ldb_debug_set(ldb, LDB_DEBUG_FATAL,
728 "replmd_add: unable to find invocationId\n");
732 ac->our_invocation_id = *our_invocation_id;
738 add a time element to a record
740 static int add_time_element(struct ldb_message *msg, const char *attr, time_t t)
742 struct ldb_message_element *el;
746 if (ldb_msg_find_element(msg, attr) != NULL) {
750 s = ldb_timestring(msg, t);
752 return LDB_ERR_OPERATIONS_ERROR;
755 ret = ldb_msg_add_string(msg, attr, s);
756 if (ret != LDB_SUCCESS) {
760 el = ldb_msg_find_element(msg, attr);
761 /* always set as replace. This works because on add ops, the flag
763 el->flags = LDB_FLAG_MOD_REPLACE;
769 add a uint64_t element to a record
771 static int add_uint64_element(struct ldb_context *ldb, struct ldb_message *msg,
772 const char *attr, uint64_t v)
774 struct ldb_message_element *el;
777 if (ldb_msg_find_element(msg, attr) != NULL) {
781 ret = samdb_msg_add_uint64(ldb, msg, msg, attr, v);
782 if (ret != LDB_SUCCESS) {
786 el = ldb_msg_find_element(msg, attr);
787 /* always set as replace. This works because on add ops, the flag
789 el->flags = LDB_FLAG_MOD_REPLACE;
794 static int replmd_replPropertyMetaData1_attid_sort(const struct replPropertyMetaData1 *m1,
795 const struct replPropertyMetaData1 *m2,
796 const uint32_t *rdn_attid)
799 * This assignment seems inoccous, but it is critical for the
800 * system, as we need to do the comparisons as a unsigned
801 * quantity, not signed (enums are signed integers)
803 uint32_t attid_1 = m1->attid;
804 uint32_t attid_2 = m2->attid;
806 if (attid_1 == attid_2) {
811 * See above regarding this being an unsigned comparison.
812 * Otherwise when the high bit is set on non-standard
813 * attributes, they would end up first, before objectClass
816 return attid_1 > attid_2 ? 1 : -1;
819 static int replmd_replPropertyMetaDataCtr1_verify(struct ldb_context *ldb,
820 struct replPropertyMetaDataCtr1 *ctr1,
823 if (ctr1->count == 0) {
824 ldb_debug_set(ldb, LDB_DEBUG_FATAL,
825 "No elements found in replPropertyMetaData for %s!\n",
826 ldb_dn_get_linearized(dn));
827 return LDB_ERR_CONSTRAINT_VIOLATION;
830 /* the objectClass attribute is value 0x00000000, so must be first */
831 if (ctr1->array[0].attid != DRSUAPI_ATTID_objectClass) {
832 ldb_debug_set(ldb, LDB_DEBUG_FATAL,
833 "No objectClass found in replPropertyMetaData for %s!\n",
834 ldb_dn_get_linearized(dn));
835 return LDB_ERR_OBJECT_CLASS_VIOLATION;
841 static int replmd_replPropertyMetaDataCtr1_sort_and_verify(struct ldb_context *ldb,
842 struct replPropertyMetaDataCtr1 *ctr1,
845 /* Note this is O(n^2) for the almost-sorted case, which this is */
846 LDB_TYPESAFE_QSORT(ctr1->array, ctr1->count, NULL,
847 replmd_replPropertyMetaData1_attid_sort);
848 return replmd_replPropertyMetaDataCtr1_verify(ldb, ctr1, dn);
851 static int replmd_ldb_message_element_attid_sort(const struct ldb_message_element *e1,
852 const struct ldb_message_element *e2,
853 const struct dsdb_schema *schema)
855 const struct dsdb_attribute *a1;
856 const struct dsdb_attribute *a2;
859 * TODO: make this faster by caching the dsdb_attribute pointer
860 * on the ldb_messag_element
863 a1 = dsdb_attribute_by_lDAPDisplayName(schema, e1->name);
864 a2 = dsdb_attribute_by_lDAPDisplayName(schema, e2->name);
867 * TODO: remove this check, we should rely on e1 and e2 having valid attribute names
871 return strcasecmp(e1->name, e2->name);
873 if (a1->attributeID_id == a2->attributeID_id) {
876 return a1->attributeID_id > a2->attributeID_id ? 1 : -1;
879 static void replmd_ldb_message_sort(struct ldb_message *msg,
880 const struct dsdb_schema *schema)
882 LDB_TYPESAFE_QSORT(msg->elements, msg->num_elements, schema, replmd_ldb_message_element_attid_sort);
885 static int replmd_build_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct dsdb_dn *dsdb_dn,
886 const struct GUID *invocation_id, uint64_t seq_num,
887 uint64_t local_usn, NTTIME nttime, uint32_t version, bool deleted);
889 static int get_parsed_dns(struct ldb_module *module, TALLOC_CTX *mem_ctx,
890 struct ldb_message_element *el, struct parsed_dn **pdn,
891 const char *ldap_oid, struct ldb_request *parent);
894 fix up linked attributes in replmd_add.
895 This involves setting up the right meta-data in extended DN
896 components, and creating backlinks to the object
898 static int replmd_add_fix_la(struct ldb_module *module, TALLOC_CTX *mem_ctx,
899 struct replmd_private *replmd_private,
900 struct ldb_message_element *el,
901 struct replmd_replicated_request *ac,
903 struct ldb_dn *forward_dn,
904 const struct dsdb_attribute *sa,
905 struct ldb_request *parent)
908 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
909 struct ldb_context *ldb = ldb_module_get_ctx(module);
910 struct parsed_dn *pdn;
911 /* We will take a reference to the schema in replmd_add_backlink */
912 const struct dsdb_schema *schema = dsdb_get_schema(ldb, NULL);
913 struct ldb_val *new_values = NULL;
916 if (dsdb_check_single_valued_link(sa, el) == LDB_SUCCESS) {
917 el->flags |= LDB_FLAG_INTERNAL_DISABLE_SINGLE_VALUE_CHECK;
919 ldb_asprintf_errstring(ldb,
920 "Attribute %s is single valued but "
921 "more than one value has been supplied",
923 talloc_free(tmp_ctx);
924 return LDB_ERR_CONSTRAINT_VIOLATION;
927 ret = get_parsed_dns(module, tmp_ctx, el, &pdn,
928 sa->syntax->ldap_oid, parent);
929 if (ret != LDB_SUCCESS) {
930 talloc_free(tmp_ctx);
934 new_values = talloc_array(tmp_ctx, struct ldb_val, el->num_values);
935 if (new_values == NULL) {
936 ldb_module_oom(module);
937 talloc_free(tmp_ctx);
938 return LDB_ERR_OPERATIONS_ERROR;
941 for (i = 0; i < el->num_values; i++) {
942 struct parsed_dn *p = &pdn[i];
943 ret = replmd_build_la_val(el->values, p->v, p->dsdb_dn,
944 &ac->our_invocation_id,
945 ac->seq_num, ac->seq_num, now, 0, false);
946 if (ret != LDB_SUCCESS) {
947 talloc_free(tmp_ctx);
951 ret = replmd_defer_add_backlink(module, replmd_private,
953 forward_dn, &p->guid, true, sa,
955 if (ret != LDB_SUCCESS) {
956 talloc_free(tmp_ctx);
960 new_values[i] = *p->v;
962 el->values = talloc_steal(mem_ctx, new_values);
964 talloc_free(tmp_ctx);
968 static int replmd_add_make_extended_dn(struct ldb_request *req,
969 const DATA_BLOB *guid_blob,
970 struct ldb_dn **_extended_dn)
973 const DATA_BLOB *sid_blob;
974 /* Calculate an extended DN for any linked attributes */
975 struct ldb_dn *extended_dn = ldb_dn_copy(req, req->op.add.message->dn);
977 return LDB_ERR_OPERATIONS_ERROR;
979 ret = ldb_dn_set_extended_component(extended_dn, "GUID", guid_blob);
980 if (ret != LDB_SUCCESS) {
984 sid_blob = ldb_msg_find_ldb_val(req->op.add.message, "objectSID");
985 if (sid_blob != NULL) {
986 ret = ldb_dn_set_extended_component(extended_dn, "SID", sid_blob);
987 if (ret != LDB_SUCCESS) {
991 *_extended_dn = extended_dn;
996 intercept add requests
998 static int replmd_add(struct ldb_module *module, struct ldb_request *req)
1000 struct ldb_context *ldb;
1001 struct ldb_control *control;
1002 struct replmd_replicated_request *ac;
1003 enum ndr_err_code ndr_err;
1004 struct ldb_request *down_req;
1005 struct ldb_message *msg;
1006 const DATA_BLOB *guid_blob;
1007 DATA_BLOB guid_blob_stack;
1009 uint8_t guid_data[16];
1010 struct replPropertyMetaDataBlob nmd;
1011 struct ldb_val nmd_value;
1012 struct ldb_dn *extended_dn = NULL;
1015 * The use of a time_t here seems odd, but as the NTTIME
1016 * elements are actually declared as NTTIME_1sec in the IDL,
1017 * getting a higher resolution timestamp is not required.
1019 time_t t = time(NULL);
1024 unsigned int functional_level;
1026 bool allow_add_guid = false;
1027 bool remove_current_guid = false;
1028 bool is_urgent = false;
1029 bool is_schema_nc = false;
1030 struct ldb_message_element *objectclass_el;
1031 struct replmd_private *replmd_private =
1032 talloc_get_type_abort(ldb_module_get_private(module), struct replmd_private);
1034 /* check if there's a show relax control (used by provision to say 'I know what I'm doing') */
1035 control = ldb_request_get_control(req, LDB_CONTROL_RELAX_OID);
1037 allow_add_guid = true;
1040 /* do not manipulate our control entries */
1041 if (ldb_dn_is_special(req->op.add.message->dn)) {
1042 return ldb_next_request(module, req);
1045 ldb = ldb_module_get_ctx(module);
1047 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_add\n");
1049 guid_blob = ldb_msg_find_ldb_val(req->op.add.message, "objectGUID");
1050 if (guid_blob != NULL) {
1051 if (!allow_add_guid) {
1052 ldb_set_errstring(ldb,
1053 "replmd_add: it's not allowed to add an object with objectGUID!");
1054 return LDB_ERR_UNWILLING_TO_PERFORM;
1056 NTSTATUS status = GUID_from_data_blob(guid_blob,&guid);
1057 if (!NT_STATUS_IS_OK(status)) {
1058 ldb_set_errstring(ldb,
1059 "replmd_add: Unable to parse the 'objectGUID' as a GUID!");
1060 return LDB_ERR_UNWILLING_TO_PERFORM;
1062 /* we remove this attribute as it can be a string and
1063 * will not be treated correctly and then we will re-add
1064 * it later on in the good format */
1065 remove_current_guid = true;
1069 guid = GUID_random();
1071 guid_blob_stack = data_blob_const(guid_data, sizeof(guid_data));
1073 /* This can't fail */
1074 ndr_push_struct_into_fixed_blob(&guid_blob_stack, &guid,
1075 (ndr_push_flags_fn_t)ndr_push_GUID);
1076 guid_blob = &guid_blob_stack;
1079 ac = replmd_ctx_init(module, req);
1081 return ldb_module_oom(module);
1084 functional_level = dsdb_functional_level(ldb);
1086 /* Get a sequence number from the backend */
1087 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &ac->seq_num);
1088 if (ret != LDB_SUCCESS) {
1093 /* we have to copy the message as the caller might have it as a const */
1094 msg = ldb_msg_copy_shallow(ac, req->op.add.message);
1098 return LDB_ERR_OPERATIONS_ERROR;
1101 /* generated times */
1102 unix_to_nt_time(&now, t);
1103 time_str = ldb_timestring(msg, t);
1107 return LDB_ERR_OPERATIONS_ERROR;
1109 if (remove_current_guid) {
1110 ldb_msg_remove_attr(msg,"objectGUID");
1114 * remove autogenerated attributes
1116 ldb_msg_remove_attr(msg, "whenCreated");
1117 ldb_msg_remove_attr(msg, "whenChanged");
1118 ldb_msg_remove_attr(msg, "uSNCreated");
1119 ldb_msg_remove_attr(msg, "uSNChanged");
1120 ldb_msg_remove_attr(msg, "replPropertyMetaData");
1123 * readd replicated attributes
1125 ret = ldb_msg_add_string(msg, "whenCreated", time_str);
1126 if (ret != LDB_SUCCESS) {
1132 /* build the replication meta_data */
1135 nmd.ctr.ctr1.count = msg->num_elements;
1136 nmd.ctr.ctr1.array = talloc_array(msg,
1137 struct replPropertyMetaData1,
1138 nmd.ctr.ctr1.count);
1139 if (!nmd.ctr.ctr1.array) {
1142 return LDB_ERR_OPERATIONS_ERROR;
1145 is_schema_nc = ldb_dn_compare_base(replmd_private->schema_dn, msg->dn) == 0;
1147 for (i=0; i < msg->num_elements;) {
1148 struct ldb_message_element *e = &msg->elements[i];
1149 struct replPropertyMetaData1 *m = &nmd.ctr.ctr1.array[ni];
1150 const struct dsdb_attribute *sa;
1152 if (e->name[0] == '@') {
1157 sa = dsdb_attribute_by_lDAPDisplayName(ac->schema, e->name);
1159 ldb_debug_set(ldb, LDB_DEBUG_ERROR,
1160 "replmd_add: attribute '%s' not defined in schema\n",
1163 return LDB_ERR_NO_SUCH_ATTRIBUTE;
1166 if ((sa->systemFlags & DS_FLAG_ATTR_NOT_REPLICATED) || (sa->systemFlags & DS_FLAG_ATTR_IS_CONSTRUCTED)) {
1167 /* if the attribute is not replicated (0x00000001)
1168 * or constructed (0x00000004) it has no metadata
1174 if (sa->linkID != 0 && functional_level > DS_DOMAIN_FUNCTION_2000) {
1175 if (extended_dn == NULL) {
1176 ret = replmd_add_make_extended_dn(req,
1179 if (ret != LDB_SUCCESS) {
1186 * Prepare the context for the backlinks and
1187 * create metadata for the forward links. The
1188 * backlinks are created in
1189 * replmd_op_callback() after the successful
1190 * ADD of the object.
1192 ret = replmd_add_fix_la(module, msg->elements,
1197 if (ret != LDB_SUCCESS) {
1201 /* linked attributes are not stored in
1202 replPropertyMetaData in FL above w2k */
1207 m->attid = dsdb_attribute_get_attid(sa, is_schema_nc);
1209 if (m->attid == DRSUAPI_ATTID_isDeleted) {
1210 const struct ldb_val *rdn_val = ldb_dn_get_rdn_val(msg->dn);
1213 if (rdn_val == NULL) {
1216 return LDB_ERR_OPERATIONS_ERROR;
1219 rdn = (const char*)rdn_val->data;
1220 if (strcmp(rdn, "Deleted Objects") == 0) {
1222 * Set the originating_change_time to 29/12/9999 at 23:59:59
1223 * as specified in MS-ADTS 7.1.1.4.2 Deleted Objects Container
1225 m->originating_change_time = DELETED_OBJECT_CONTAINER_CHANGE_TIME;
1227 m->originating_change_time = now;
1230 m->originating_change_time = now;
1232 m->originating_invocation_id = ac->our_invocation_id;
1233 m->originating_usn = ac->seq_num;
1234 m->local_usn = ac->seq_num;
1237 if (!(e->flags & DSDB_FLAG_INTERNAL_FORCE_META_DATA)) {
1242 e->flags &= ~DSDB_FLAG_INTERNAL_FORCE_META_DATA;
1244 if (e->num_values != 0) {
1249 ldb_msg_remove_element(msg, e);
1252 /* fix meta data count */
1253 nmd.ctr.ctr1.count = ni;
1256 * sort meta data array
1258 ret = replmd_replPropertyMetaDataCtr1_sort_and_verify(ldb, &nmd.ctr.ctr1, msg->dn);
1259 if (ret != LDB_SUCCESS) {
1260 ldb_asprintf_errstring(ldb, "%s: error during direct ADD: %s", __func__, ldb_errstring(ldb));
1265 /* generated NDR encoded values */
1266 ndr_err = ndr_push_struct_blob(&nmd_value, msg,
1268 (ndr_push_flags_fn_t)ndr_push_replPropertyMetaDataBlob);
1269 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1272 return LDB_ERR_OPERATIONS_ERROR;
1276 * add the autogenerated values
1278 ret = dsdb_msg_add_guid(msg, &guid, "objectGUID");
1279 if (ret != LDB_SUCCESS) {
1284 ret = ldb_msg_add_string(msg, "whenChanged", time_str);
1285 if (ret != LDB_SUCCESS) {
1290 ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNCreated", ac->seq_num);
1291 if (ret != LDB_SUCCESS) {
1296 ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNChanged", ac->seq_num);
1297 if (ret != LDB_SUCCESS) {
1302 ret = ldb_msg_add_value(msg, "replPropertyMetaData", &nmd_value, NULL);
1303 if (ret != LDB_SUCCESS) {
1310 * sort the attributes by attid before storing the object
1312 replmd_ldb_message_sort(msg, ac->schema);
1315 * Assert that we do have an objectClass
1317 objectclass_el = ldb_msg_find_element(msg, "objectClass");
1318 if (objectclass_el == NULL) {
1319 ldb_asprintf_errstring(ldb, __location__
1320 ": objectClass missing on %s\n",
1321 ldb_dn_get_linearized(msg->dn));
1323 return LDB_ERR_OBJECT_CLASS_VIOLATION;
1325 is_urgent = replmd_check_urgent_objectclass(objectclass_el,
1326 REPL_URGENT_ON_CREATE);
1328 ac->is_urgent = is_urgent;
1329 ret = ldb_build_add_req(&down_req, ldb, ac,
1332 ac, replmd_op_callback,
1335 LDB_REQ_SET_LOCATION(down_req);
1336 if (ret != LDB_SUCCESS) {
1341 /* current partition control is needed by "replmd_op_callback" */
1342 if (ldb_request_get_control(req, DSDB_CONTROL_CURRENT_PARTITION_OID) == NULL) {
1343 ret = ldb_request_add_control(down_req,
1344 DSDB_CONTROL_CURRENT_PARTITION_OID,
1346 if (ret != LDB_SUCCESS) {
1352 if (functional_level == DS_DOMAIN_FUNCTION_2000) {
1353 ret = ldb_request_add_control(down_req, DSDB_CONTROL_APPLY_LINKS, false, NULL);
1354 if (ret != LDB_SUCCESS) {
1360 /* mark the control done */
1362 control->critical = 0;
1364 /* go on with the call chain */
1365 return ldb_next_request(module, down_req);
1370 * update the replPropertyMetaData for one element
1372 static int replmd_update_rpmd_element(struct ldb_context *ldb,
1373 struct ldb_message *msg,
1374 struct ldb_message_element *el,
1375 struct ldb_message_element *old_el,
1376 struct replPropertyMetaDataBlob *omd,
1377 const struct dsdb_schema *schema,
1379 const struct GUID *our_invocation_id,
1382 bool is_forced_rodc,
1383 struct ldb_request *req)
1386 const struct dsdb_attribute *a;
1387 struct replPropertyMetaData1 *md1;
1388 bool may_skip = false;
1391 a = dsdb_attribute_by_lDAPDisplayName(schema, el->name);
1393 if (ldb_request_get_control(req, LDB_CONTROL_RELAX_OID)) {
1394 /* allow this to make it possible for dbcheck
1395 to remove bad attributes */
1399 DEBUG(0,(__location__ ": Unable to find attribute %s in schema\n",
1401 return LDB_ERR_OPERATIONS_ERROR;
1404 attid = dsdb_attribute_get_attid(a, is_schema_nc);
1406 if ((a->systemFlags & DS_FLAG_ATTR_NOT_REPLICATED) || (a->systemFlags & DS_FLAG_ATTR_IS_CONSTRUCTED)) {
1411 * if the attribute's value haven't changed, and this isn't
1412 * just a delete of everything then return LDB_SUCCESS Unless
1413 * we have the provision control or if the attribute is
1414 * interSiteTopologyGenerator as this page explain:
1415 * http://support.microsoft.com/kb/224815 this attribute is
1416 * periodicaly written by the DC responsible for the intersite
1417 * generation in a given site
1419 * Unchanged could be deleting or replacing an already-gone
1420 * thing with an unconstrained delete/empty replace or a
1421 * replace with the same value, but not an add with the same
1422 * value because that could be about adding a duplicate (which
1423 * is for someone else to error out on).
1425 if (old_el != NULL && ldb_msg_element_equal_ordered(el, old_el)) {
1426 if (LDB_FLAG_MOD_TYPE(el->flags) == LDB_FLAG_MOD_REPLACE) {
1429 } else if (old_el == NULL && el->num_values == 0) {
1430 if (LDB_FLAG_MOD_TYPE(el->flags) == LDB_FLAG_MOD_REPLACE) {
1432 } else if (LDB_FLAG_MOD_TYPE(el->flags) == LDB_FLAG_MOD_DELETE) {
1435 } else if (a->linkID != 0 && LDB_FLAG_MOD_TYPE(el->flags) == LDB_FLAG_MOD_DELETE &&
1436 ldb_request_get_control(req, DSDB_CONTROL_REPLMD_VANISH_LINKS) != NULL) {
1438 * We intentionally skip the version bump when attempting to
1441 * The control is set by dbcheck and expunge-tombstones which
1442 * both attempt to be non-replicating. Otherwise, making an
1443 * alteration to the replication state would trigger a
1444 * broadcast of all expunged objects.
1449 if (el->flags & DSDB_FLAG_INTERNAL_FORCE_META_DATA) {
1451 el->flags &= ~DSDB_FLAG_INTERNAL_FORCE_META_DATA;
1455 if (strcmp(el->name, "interSiteTopologyGenerator") != 0 &&
1456 !ldb_request_get_control(req, LDB_CONTROL_PROVISION_OID)) {
1458 * allow this to make it possible for dbcheck
1459 * to rebuild broken metadata
1465 for (i=0; i<omd->ctr.ctr1.count; i++) {
1467 * First check if we find it under the msDS-IntID,
1468 * then check if we find it under the OID and
1471 * This allows the administrator to simply re-write
1472 * the attributes and so restore replication, which is
1473 * likely what they will try to do.
1475 if (attid == omd->ctr.ctr1.array[i].attid) {
1479 if (a->attributeID_id == omd->ctr.ctr1.array[i].attid) {
1484 if (a->linkID != 0 && dsdb_functional_level(ldb) > DS_DOMAIN_FUNCTION_2000) {
1485 /* linked attributes are not stored in
1486 replPropertyMetaData in FL above w2k, but we do
1487 raise the seqnum for the object */
1488 if (*seq_num == 0 &&
1489 ldb_sequence_number(ldb, LDB_SEQ_NEXT, seq_num) != LDB_SUCCESS) {
1490 return LDB_ERR_OPERATIONS_ERROR;
1495 if (i == omd->ctr.ctr1.count) {
1496 /* we need to add a new one */
1497 omd->ctr.ctr1.array = talloc_realloc(msg, omd->ctr.ctr1.array,
1498 struct replPropertyMetaData1, omd->ctr.ctr1.count+1);
1499 if (omd->ctr.ctr1.array == NULL) {
1501 return LDB_ERR_OPERATIONS_ERROR;
1503 omd->ctr.ctr1.count++;
1504 ZERO_STRUCT(omd->ctr.ctr1.array[i]);
1507 /* Get a new sequence number from the backend. We only do this
1508 * if we have a change that requires a new
1509 * replPropertyMetaData element
1511 if (*seq_num == 0) {
1512 int ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, seq_num);
1513 if (ret != LDB_SUCCESS) {
1514 return LDB_ERR_OPERATIONS_ERROR;
1518 md1 = &omd->ctr.ctr1.array[i];
1522 if (md1->attid == DRSUAPI_ATTID_isDeleted) {
1523 const struct ldb_val *rdn_val = ldb_dn_get_rdn_val(msg->dn);
1526 if (rdn_val == NULL) {
1528 return LDB_ERR_OPERATIONS_ERROR;
1531 rdn = (const char*)rdn_val->data;
1532 if (strcmp(rdn, "Deleted Objects") == 0) {
1534 * Set the originating_change_time to 29/12/9999 at 23:59:59
1535 * as specified in MS-ADTS 7.1.1.4.2 Deleted Objects Container
1537 md1->originating_change_time = DELETED_OBJECT_CONTAINER_CHANGE_TIME;
1539 md1->originating_change_time = now;
1542 md1->originating_change_time = now;
1544 md1->originating_invocation_id = *our_invocation_id;
1545 md1->originating_usn = *seq_num;
1546 md1->local_usn = *seq_num;
1548 if (is_forced_rodc) {
1549 /* Force version to 0 to be overriden later via replication */
1557 * Bump the replPropertyMetaData version on an attribute, and if it
1558 * has changed (or forced by leaving rdn_old NULL), update the value
1561 * This is important, as calling a modify operation may not change the
1562 * version number if the values appear unchanged, but a rename between
1563 * parents bumps this value.
1566 static int replmd_update_rpmd_rdn_attr(struct ldb_context *ldb,
1567 struct ldb_message *msg,
1568 const struct ldb_val *rdn_new,
1569 const struct ldb_val *rdn_old,
1570 struct replPropertyMetaDataBlob *omd,
1571 struct replmd_replicated_request *ar,
1574 bool is_forced_rodc)
1576 const char *rdn_name = ldb_dn_get_rdn_name(msg->dn);
1577 const struct dsdb_attribute *rdn_attr =
1578 dsdb_attribute_by_lDAPDisplayName(ar->schema, rdn_name);
1579 const char *attr_name = rdn_attr != NULL ?
1580 rdn_attr->lDAPDisplayName :
1582 struct ldb_message_element new_el = {
1583 .flags = LDB_FLAG_MOD_REPLACE,
1586 .values = discard_const_p(struct ldb_val, rdn_new)
1588 struct ldb_message_element old_el = {
1589 .flags = LDB_FLAG_MOD_REPLACE,
1591 .num_values = rdn_old ? 1 : 0,
1592 .values = discard_const_p(struct ldb_val, rdn_old)
1595 if (ldb_msg_element_equal_ordered(&new_el, &old_el) == false) {
1596 int ret = ldb_msg_add(msg, &new_el, LDB_FLAG_MOD_REPLACE);
1597 if (ret != LDB_SUCCESS) {
1598 return ldb_oom(ldb);
1602 return replmd_update_rpmd_element(ldb, msg, &new_el, NULL,
1603 omd, ar->schema, &ar->seq_num,
1604 &ar->our_invocation_id,
1605 now, is_schema_nc, is_forced_rodc,
1610 static uint64_t find_max_local_usn(struct replPropertyMetaDataBlob omd)
1612 uint32_t count = omd.ctr.ctr1.count;
1615 for (i=0; i < count; i++) {
1616 struct replPropertyMetaData1 m = omd.ctr.ctr1.array[i];
1617 if (max < m.local_usn) {
1625 * update the replPropertyMetaData object each time we modify an
1626 * object. This is needed for DRS replication, as the merge on the
1627 * client is based on this object
1629 static int replmd_update_rpmd(struct ldb_module *module,
1630 const struct dsdb_schema *schema,
1631 struct ldb_request *req,
1632 const char * const *rename_attrs,
1633 struct ldb_message *msg, uint64_t *seq_num,
1634 time_t t, bool is_schema_nc,
1635 bool *is_urgent, bool *rodc)
1637 const struct ldb_val *omd_value;
1638 enum ndr_err_code ndr_err;
1639 struct replPropertyMetaDataBlob omd;
1642 const struct GUID *our_invocation_id;
1644 const char * const *attrs = NULL;
1645 const char * const attrs2[] = { "uSNChanged", "objectClass", "instanceType", NULL };
1646 struct ldb_result *res;
1647 struct ldb_context *ldb;
1648 struct ldb_message_element *objectclass_el;
1649 enum urgent_situation situation;
1650 bool rmd_is_provided;
1651 bool rmd_is_just_resorted = false;
1652 const char *not_rename_attrs[4 + msg->num_elements];
1653 bool is_forced_rodc = false;
1656 attrs = rename_attrs;
1658 for (i = 0; i < msg->num_elements; i++) {
1659 not_rename_attrs[i] = msg->elements[i].name;
1661 not_rename_attrs[i] = "replPropertyMetaData";
1662 not_rename_attrs[i+1] = "objectClass";
1663 not_rename_attrs[i+2] = "instanceType";
1664 not_rename_attrs[i+3] = NULL;
1665 attrs = not_rename_attrs;
1668 ldb = ldb_module_get_ctx(module);
1670 ret = samdb_rodc(ldb, rodc);
1671 if (ret != LDB_SUCCESS) {
1672 DEBUG(4, (__location__ ": unable to tell if we are an RODC\n"));
1677 ldb_request_get_control(req, DSDB_CONTROL_FORCE_RODC_LOCAL_CHANGE)) {
1678 is_forced_rodc = true;
1681 our_invocation_id = samdb_ntds_invocation_id(ldb);
1682 if (!our_invocation_id) {
1683 /* this happens during an initial vampire while
1684 updating the schema */
1685 DEBUG(5,("No invocationID - skipping replPropertyMetaData update\n"));
1689 unix_to_nt_time(&now, t);
1691 if (ldb_request_get_control(req, DSDB_CONTROL_CHANGEREPLMETADATA_OID)) {
1692 rmd_is_provided = true;
1693 if (ldb_request_get_control(req, DSDB_CONTROL_CHANGEREPLMETADATA_RESORT_OID)) {
1694 rmd_is_just_resorted = true;
1697 rmd_is_provided = false;
1700 /* if isDeleted is present and is TRUE, then we consider we are deleting,
1701 * otherwise we consider we are updating */
1702 if (ldb_msg_check_string_attribute(msg, "isDeleted", "TRUE")) {
1703 situation = REPL_URGENT_ON_DELETE;
1704 } else if (rename_attrs) {
1705 situation = REPL_URGENT_ON_CREATE | REPL_URGENT_ON_DELETE;
1707 situation = REPL_URGENT_ON_UPDATE;
1710 if (rmd_is_provided) {
1711 /* In this case the change_replmetadata control was supplied */
1712 /* We check that it's the only attribute that is provided
1713 * (it's a rare case so it's better to keep the code simplier)
1714 * We also check that the highest local_usn is bigger or the same as
1717 if( msg->num_elements != 1 ||
1718 strncmp(msg->elements[0].name,
1719 "replPropertyMetaData", 20) ) {
1720 DEBUG(0,(__location__ ": changereplmetada control called without "\
1721 "a specified replPropertyMetaData attribute or with others\n"));
1722 return LDB_ERR_OPERATIONS_ERROR;
1724 if (situation != REPL_URGENT_ON_UPDATE) {
1725 DEBUG(0,(__location__ ": changereplmetada control can't be called when deleting an object\n"));
1726 return LDB_ERR_OPERATIONS_ERROR;
1728 omd_value = ldb_msg_find_ldb_val(msg, "replPropertyMetaData");
1730 DEBUG(0,(__location__ ": replPropertyMetaData was not specified for Object %s\n",
1731 ldb_dn_get_linearized(msg->dn)));
1732 return LDB_ERR_OPERATIONS_ERROR;
1734 ndr_err = ndr_pull_struct_blob(omd_value, msg, &omd,
1735 (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
1736 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1737 DEBUG(0,(__location__ ": Failed to parse replPropertyMetaData for %s\n",
1738 ldb_dn_get_linearized(msg->dn)));
1739 return LDB_ERR_OPERATIONS_ERROR;
1742 ret = dsdb_module_search_dn(module, msg, &res, msg->dn, attrs2,
1743 DSDB_FLAG_NEXT_MODULE |
1744 DSDB_SEARCH_SHOW_RECYCLED |
1745 DSDB_SEARCH_SHOW_EXTENDED_DN |
1746 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT |
1747 DSDB_SEARCH_REVEAL_INTERNALS, req);
1749 if (ret != LDB_SUCCESS) {
1753 if (rmd_is_just_resorted == false) {
1754 *seq_num = find_max_local_usn(omd);
1756 db_seq = ldb_msg_find_attr_as_uint64(res->msgs[0], "uSNChanged", 0);
1759 * The test here now allows for a new
1760 * replPropertyMetaData with no change, if was
1761 * just dbcheck re-sorting the values.
1763 if (*seq_num <= db_seq) {
1764 DEBUG(0,(__location__ ": changereplmetada control provided but max(local_usn)" \
1765 " is less than uSNChanged (max = %lld uSNChanged = %lld)\n",
1766 (long long)*seq_num, (long long)db_seq));
1767 return LDB_ERR_OPERATIONS_ERROR;
1772 /* search for the existing replPropertyMetaDataBlob. We need
1773 * to use REVEAL and ask for DNs in storage format to support
1774 * the check for values being the same in
1775 * replmd_update_rpmd_element()
1777 ret = dsdb_module_search_dn(module, msg, &res, msg->dn, attrs,
1778 DSDB_FLAG_NEXT_MODULE |
1779 DSDB_SEARCH_SHOW_RECYCLED |
1780 DSDB_SEARCH_SHOW_EXTENDED_DN |
1781 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT |
1782 DSDB_SEARCH_REVEAL_INTERNALS, req);
1783 if (ret != LDB_SUCCESS) {
1787 omd_value = ldb_msg_find_ldb_val(res->msgs[0], "replPropertyMetaData");
1789 DEBUG(0,(__location__ ": Object %s does not have a replPropertyMetaData attribute\n",
1790 ldb_dn_get_linearized(msg->dn)));
1791 return LDB_ERR_OPERATIONS_ERROR;
1794 ndr_err = ndr_pull_struct_blob(omd_value, msg, &omd,
1795 (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
1796 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1797 DEBUG(0,(__location__ ": Failed to parse replPropertyMetaData for %s\n",
1798 ldb_dn_get_linearized(msg->dn)));
1799 return LDB_ERR_OPERATIONS_ERROR;
1802 if (omd.version != 1) {
1803 DEBUG(0,(__location__ ": bad version %u in replPropertyMetaData for %s\n",
1804 omd.version, ldb_dn_get_linearized(msg->dn)));
1805 return LDB_ERR_OPERATIONS_ERROR;
1808 for (i=0; i<msg->num_elements;) {
1809 struct ldb_message_element *el = &msg->elements[i];
1810 struct ldb_message_element *old_el;
1812 old_el = ldb_msg_find_element(res->msgs[0], el->name);
1813 ret = replmd_update_rpmd_element(ldb, msg, el, old_el,
1814 &omd, schema, seq_num,
1819 if (ret != LDB_SUCCESS) {
1823 if (!*is_urgent && (situation == REPL_URGENT_ON_UPDATE)) {
1824 *is_urgent = replmd_check_urgent_attribute(el);
1827 if (!(el->flags & DSDB_FLAG_INTERNAL_FORCE_META_DATA)) {
1832 el->flags &= ~DSDB_FLAG_INTERNAL_FORCE_META_DATA;
1834 if (el->num_values != 0) {
1839 ldb_msg_remove_element(msg, el);
1844 * Assert that we have an objectClass attribute - this is major
1845 * corruption if we don't have this!
1847 objectclass_el = ldb_msg_find_element(res->msgs[0], "objectClass");
1848 if (objectclass_el != NULL) {
1850 * Now check if this objectClass means we need to do urgent replication
1852 if (!*is_urgent && replmd_check_urgent_objectclass(objectclass_el,
1856 } else if (!ldb_request_get_control(req, DSDB_CONTROL_DBCHECK)) {
1857 ldb_asprintf_errstring(ldb, __location__
1858 ": objectClass missing on %s\n",
1859 ldb_dn_get_linearized(msg->dn));
1860 return LDB_ERR_OBJECT_CLASS_VIOLATION;
1864 * replmd_update_rpmd_element has done an update if the
1867 if (*seq_num != 0 || rmd_is_just_resorted == true) {
1868 struct ldb_val *md_value;
1869 struct ldb_message_element *el;
1871 /*if we are RODC and this is a DRSR update then its ok*/
1872 if (!ldb_request_get_control(req, DSDB_CONTROL_REPLICATED_UPDATE_OID)
1873 && !ldb_request_get_control(req, DSDB_CONTROL_DBCHECK_MODIFY_RO_REPLICA)
1874 && !is_forced_rodc) {
1875 unsigned instanceType;
1878 ldb_set_errstring(ldb, "RODC modify is forbidden!");
1879 return LDB_ERR_REFERRAL;
1882 instanceType = ldb_msg_find_attr_as_uint(res->msgs[0], "instanceType", INSTANCE_TYPE_WRITE);
1883 if (!(instanceType & INSTANCE_TYPE_WRITE)) {
1884 return ldb_error(ldb, LDB_ERR_UNWILLING_TO_PERFORM,
1885 "cannot change replicated attribute on partial replica");
1889 md_value = talloc(msg, struct ldb_val);
1890 if (md_value == NULL) {
1892 return LDB_ERR_OPERATIONS_ERROR;
1895 ret = replmd_replPropertyMetaDataCtr1_sort_and_verify(ldb, &omd.ctr.ctr1, msg->dn);
1896 if (ret != LDB_SUCCESS) {
1897 ldb_asprintf_errstring(ldb, "%s: %s", __func__, ldb_errstring(ldb));
1901 ndr_err = ndr_push_struct_blob(md_value, msg, &omd,
1902 (ndr_push_flags_fn_t)ndr_push_replPropertyMetaDataBlob);
1903 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1904 DEBUG(0,(__location__ ": Failed to marshall replPropertyMetaData for %s\n",
1905 ldb_dn_get_linearized(msg->dn)));
1906 return LDB_ERR_OPERATIONS_ERROR;
1909 ret = ldb_msg_add_empty(msg, "replPropertyMetaData", LDB_FLAG_MOD_REPLACE, &el);
1910 if (ret != LDB_SUCCESS) {
1911 DEBUG(0,(__location__ ": Failed to add updated replPropertyMetaData %s\n",
1912 ldb_dn_get_linearized(msg->dn)));
1917 el->values = md_value;
1923 static int parsed_dn_compare(struct parsed_dn *pdn1, struct parsed_dn *pdn2)
1925 int ret = ndr_guid_compare(&pdn1->guid, &pdn2->guid);
1927 return data_blob_cmp(&pdn1->dsdb_dn->extra_part,
1928 &pdn2->dsdb_dn->extra_part);
1934 get a series of message element values as an array of DNs and GUIDs
1935 the result is sorted by GUID
1937 static int get_parsed_dns(struct ldb_module *module, TALLOC_CTX *mem_ctx,
1938 struct ldb_message_element *el, struct parsed_dn **pdn,
1939 const char *ldap_oid, struct ldb_request *parent)
1942 bool values_are_sorted = true;
1943 struct ldb_context *ldb = ldb_module_get_ctx(module);
1950 (*pdn) = talloc_array(mem_ctx, struct parsed_dn, el->num_values);
1952 ldb_module_oom(module);
1953 return LDB_ERR_OPERATIONS_ERROR;
1956 for (i=0; i<el->num_values; i++) {
1957 struct ldb_val *v = &el->values[i];
1960 struct parsed_dn *p;
1964 p->dsdb_dn = dsdb_dn_parse(*pdn, ldb, v, ldap_oid);
1965 if (p->dsdb_dn == NULL) {
1966 return LDB_ERR_INVALID_DN_SYNTAX;
1969 dn = p->dsdb_dn->dn;
1971 status = dsdb_get_extended_dn_guid(dn, &p->guid, "GUID");
1972 if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND) ||
1973 unlikely(GUID_all_zero(&p->guid))) {
1974 /* we got a DN without a GUID - go find the GUID */
1975 int ret = dsdb_module_guid_by_dn(module, dn, &p->guid, parent);
1976 if (ret != LDB_SUCCESS) {
1977 ldb_asprintf_errstring(ldb, "Unable to find GUID for DN %s\n",
1978 ldb_dn_get_linearized(dn));
1979 if (ret == LDB_ERR_NO_SUCH_OBJECT &&
1980 LDB_FLAG_MOD_TYPE(el->flags) == LDB_FLAG_MOD_DELETE &&
1981 ldb_attr_cmp(el->name, "member") == 0) {
1982 return LDB_ERR_UNWILLING_TO_PERFORM;
1986 ret = dsdb_set_extended_dn_guid(dn, &p->guid, "GUID");
1987 if (ret != LDB_SUCCESS) {
1990 } else if (!NT_STATUS_IS_OK(status)) {
1991 return LDB_ERR_OPERATIONS_ERROR;
1993 if (i > 0 && values_are_sorted) {
1994 int cmp = parsed_dn_compare(p, &(*pdn)[i - 1]);
1996 values_are_sorted = false;
1999 /* keep a pointer to the original ldb_val */
2002 if (! values_are_sorted) {
2003 TYPESAFE_QSORT(*pdn, el->num_values, parsed_dn_compare);
2009 * Get a series of trusted message element values. The result is sorted by
2010 * GUID, even though the GUIDs might not be known. That works because we trust
2011 * the database to give us the elements like that if the
2012 * replmd_private->sorted_links flag is set.
2014 * We also ensure that the links are in the Functional Level 2003
2015 * linked attributes format.
2017 static int get_parsed_dns_trusted(struct ldb_module *module,
2018 struct replmd_private *replmd_private,
2019 TALLOC_CTX *mem_ctx,
2020 struct ldb_message_element *el,
2021 struct parsed_dn **pdn,
2022 const char *ldap_oid,
2023 struct ldb_request *parent)
2032 if (!replmd_private->sorted_links) {
2033 /* We need to sort the list. This is the slow old path we want
2036 ret = get_parsed_dns(module, mem_ctx, el, pdn, ldap_oid,
2038 if (ret != LDB_SUCCESS) {
2042 /* Here we get a list of 'struct parsed_dns' without the parsing */
2043 *pdn = talloc_zero_array(mem_ctx, struct parsed_dn,
2046 ldb_module_oom(module);
2047 return LDB_ERR_OPERATIONS_ERROR;
2050 for (i = 0; i < el->num_values; i++) {
2051 (*pdn)[i].v = &el->values[i];
2056 * This upgrades links to FL2003 style, and sorts the result
2057 * if that was needed.
2059 * TODO: Add a database feature that asserts we have no FL2000
2060 * style links to avoid this check or add a feature that
2061 * uses a similar check to find sorted/unsorted links
2062 * for an on-the-fly upgrade.
2065 ret = replmd_check_upgrade_links(ldb_module_get_ctx(module),
2066 *pdn, el->num_values,
2069 if (ret != LDB_SUCCESS) {
2077 build a new extended DN, including all meta data fields
2079 RMD_FLAGS = DSDB_RMD_FLAG_* bits
2080 RMD_ADDTIME = originating_add_time
2081 RMD_INVOCID = originating_invocation_id
2082 RMD_CHANGETIME = originating_change_time
2083 RMD_ORIGINATING_USN = originating_usn
2084 RMD_LOCAL_USN = local_usn
2085 RMD_VERSION = version
2087 static int replmd_build_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct dsdb_dn *dsdb_dn,
2088 const struct GUID *invocation_id, uint64_t seq_num,
2089 uint64_t local_usn, NTTIME nttime, uint32_t version, bool deleted)
2091 struct ldb_dn *dn = dsdb_dn->dn;
2092 const char *tstring, *usn_string, *flags_string;
2093 struct ldb_val tval;
2095 struct ldb_val usnv, local_usnv;
2096 struct ldb_val vers, flagsv;
2099 const char *dnstring;
2101 uint32_t rmd_flags = deleted?DSDB_RMD_FLAG_DELETED:0;
2103 tstring = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)nttime);
2105 return LDB_ERR_OPERATIONS_ERROR;
2107 tval = data_blob_string_const(tstring);
2109 usn_string = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)seq_num);
2111 return LDB_ERR_OPERATIONS_ERROR;
2113 usnv = data_blob_string_const(usn_string);
2115 usn_string = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)local_usn);
2117 return LDB_ERR_OPERATIONS_ERROR;
2119 local_usnv = data_blob_string_const(usn_string);
2121 vstring = talloc_asprintf(mem_ctx, "%lu", (unsigned long)version);
2123 return LDB_ERR_OPERATIONS_ERROR;
2125 vers = data_blob_string_const(vstring);
2127 status = GUID_to_ndr_blob(invocation_id, dn, &iid);
2128 if (!NT_STATUS_IS_OK(status)) {
2129 return LDB_ERR_OPERATIONS_ERROR;
2132 flags_string = talloc_asprintf(mem_ctx, "%u", rmd_flags);
2133 if (!flags_string) {
2134 return LDB_ERR_OPERATIONS_ERROR;
2136 flagsv = data_blob_string_const(flags_string);
2138 ret = ldb_dn_set_extended_component(dn, "RMD_FLAGS", &flagsv);
2139 if (ret != LDB_SUCCESS) return ret;
2140 ret = ldb_dn_set_extended_component(dn, "RMD_ADDTIME", &tval);
2141 if (ret != LDB_SUCCESS) return ret;
2142 ret = ldb_dn_set_extended_component(dn, "RMD_INVOCID", &iid);
2143 if (ret != LDB_SUCCESS) return ret;
2144 ret = ldb_dn_set_extended_component(dn, "RMD_CHANGETIME", &tval);
2145 if (ret != LDB_SUCCESS) return ret;
2146 ret = ldb_dn_set_extended_component(dn, "RMD_LOCAL_USN", &local_usnv);
2147 if (ret != LDB_SUCCESS) return ret;
2148 ret = ldb_dn_set_extended_component(dn, "RMD_ORIGINATING_USN", &usnv);
2149 if (ret != LDB_SUCCESS) return ret;
2150 ret = ldb_dn_set_extended_component(dn, "RMD_VERSION", &vers);
2151 if (ret != LDB_SUCCESS) return ret;
2153 dnstring = dsdb_dn_get_extended_linearized(mem_ctx, dsdb_dn, 1);
2154 if (dnstring == NULL) {
2155 return LDB_ERR_OPERATIONS_ERROR;
2157 *v = data_blob_string_const(dnstring);
2162 static int replmd_update_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct dsdb_dn *dsdb_dn,
2163 struct dsdb_dn *old_dsdb_dn, const struct GUID *invocation_id,
2164 uint64_t seq_num, uint64_t local_usn, NTTIME nttime,
2165 uint32_t version, bool deleted);
2168 check if any links need upgrading from w2k format
2170 static int replmd_check_upgrade_links(struct ldb_context *ldb,
2171 struct parsed_dn *dns, uint32_t count,
2172 struct ldb_message_element *el,
2173 const char *ldap_oid)
2176 const struct GUID *invocation_id = NULL;
2177 for (i=0; i<count; i++) {
2181 if (dns[i].dsdb_dn == NULL) {
2182 ret = really_parse_trusted_dn(dns, ldb, &dns[i],
2184 if (ret != LDB_SUCCESS) {
2185 return LDB_ERR_INVALID_DN_SYNTAX;
2189 status = dsdb_get_extended_dn_uint32(dns[i].dsdb_dn->dn,
2190 &version, "RMD_VERSION");
2191 if (!NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
2193 * We optimistically assume they are all the same; if
2194 * the first one is fixed, they are all fixed.
2196 * If the first one was *not* fixed and we find a
2197 * later one that is, that is an occasion to shout
2203 DEBUG(0, ("Mixed w2k and fixed format "
2204 "linked attributes\n"));
2208 if (invocation_id == NULL) {
2209 invocation_id = samdb_ntds_invocation_id(ldb);
2210 if (invocation_id == NULL) {
2211 return LDB_ERR_OPERATIONS_ERROR;
2216 /* it's an old one that needs upgrading */
2217 ret = replmd_update_la_val(el->values, dns[i].v,
2218 dns[i].dsdb_dn, dns[i].dsdb_dn,
2219 invocation_id, 1, 1, 0, 0, false);
2220 if (ret != LDB_SUCCESS) {
2226 * This sort() is critical for the operation of
2227 * get_parsed_dns_trusted() because callers of this function
2228 * expect a sorted list, and FL2000 style links are not
2229 * sorted. In particular, as well as the upgrade case,
2230 * get_parsed_dns_trusted() is called from
2231 * replmd_delete_remove_link() even in FL2000 mode
2233 * We do not normally pay the cost of the qsort() due to the
2234 * early return in the RMD_VERSION found case.
2236 TYPESAFE_QSORT(dns, count, parsed_dn_compare);
2241 update an extended DN, including all meta data fields
2243 see replmd_build_la_val for value names
2245 static int replmd_update_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct dsdb_dn *dsdb_dn,
2246 struct dsdb_dn *old_dsdb_dn, const struct GUID *invocation_id,
2247 uint64_t usn, uint64_t local_usn, NTTIME nttime,
2248 uint32_t version, bool deleted)
2250 struct ldb_dn *dn = dsdb_dn->dn;
2251 const char *tstring, *usn_string, *flags_string;
2252 struct ldb_val tval;
2254 struct ldb_val usnv, local_usnv;
2255 struct ldb_val vers, flagsv;
2256 const struct ldb_val *old_addtime;
2257 uint32_t old_version;
2260 const char *dnstring;
2262 uint32_t rmd_flags = deleted?DSDB_RMD_FLAG_DELETED:0;
2264 tstring = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)nttime);
2266 return LDB_ERR_OPERATIONS_ERROR;
2268 tval = data_blob_string_const(tstring);
2270 usn_string = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)usn);
2272 return LDB_ERR_OPERATIONS_ERROR;
2274 usnv = data_blob_string_const(usn_string);
2276 usn_string = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)local_usn);
2278 return LDB_ERR_OPERATIONS_ERROR;
2280 local_usnv = data_blob_string_const(usn_string);
2282 status = GUID_to_ndr_blob(invocation_id, dn, &iid);
2283 if (!NT_STATUS_IS_OK(status)) {
2284 return LDB_ERR_OPERATIONS_ERROR;
2287 flags_string = talloc_asprintf(mem_ctx, "%u", rmd_flags);
2288 if (!flags_string) {
2289 return LDB_ERR_OPERATIONS_ERROR;
2291 flagsv = data_blob_string_const(flags_string);
2293 ret = ldb_dn_set_extended_component(dn, "RMD_FLAGS", &flagsv);
2294 if (ret != LDB_SUCCESS) return ret;
2296 /* get the ADDTIME from the original */
2297 old_addtime = ldb_dn_get_extended_component(old_dsdb_dn->dn, "RMD_ADDTIME");
2298 if (old_addtime == NULL) {
2299 old_addtime = &tval;
2301 if (dsdb_dn != old_dsdb_dn ||
2302 ldb_dn_get_extended_component(dn, "RMD_ADDTIME") == NULL) {
2303 ret = ldb_dn_set_extended_component(dn, "RMD_ADDTIME", old_addtime);
2304 if (ret != LDB_SUCCESS) return ret;
2307 /* use our invocation id */
2308 ret = ldb_dn_set_extended_component(dn, "RMD_INVOCID", &iid);
2309 if (ret != LDB_SUCCESS) return ret;
2311 /* changetime is the current time */
2312 ret = ldb_dn_set_extended_component(dn, "RMD_CHANGETIME", &tval);
2313 if (ret != LDB_SUCCESS) return ret;
2315 /* update the USN */
2316 ret = ldb_dn_set_extended_component(dn, "RMD_ORIGINATING_USN", &usnv);
2317 if (ret != LDB_SUCCESS) return ret;
2319 ret = ldb_dn_set_extended_component(dn, "RMD_LOCAL_USN", &local_usnv);
2320 if (ret != LDB_SUCCESS) return ret;
2322 /* increase the version by 1 */
2323 status = dsdb_get_extended_dn_uint32(old_dsdb_dn->dn, &old_version, "RMD_VERSION");
2324 if (NT_STATUS_IS_OK(status) && old_version >= version) {
2325 version = old_version+1;
2327 vstring = talloc_asprintf(dn, "%lu", (unsigned long)version);
2328 vers = data_blob_string_const(vstring);
2329 ret = ldb_dn_set_extended_component(dn, "RMD_VERSION", &vers);
2330 if (ret != LDB_SUCCESS) return ret;
2332 dnstring = dsdb_dn_get_extended_linearized(mem_ctx, dsdb_dn, 1);
2333 if (dnstring == NULL) {
2334 return LDB_ERR_OPERATIONS_ERROR;
2336 *v = data_blob_string_const(dnstring);
2342 handle adding a linked attribute
2344 static int replmd_modify_la_add(struct ldb_module *module,
2345 struct replmd_private *replmd_private,
2346 const struct dsdb_schema *schema,
2347 struct ldb_message *msg,
2348 struct ldb_message_element *el,
2349 struct ldb_message_element *old_el,
2350 const struct dsdb_attribute *schema_attr,
2353 struct ldb_dn *msg_dn,
2354 struct ldb_request *parent)
2357 struct parsed_dn *dns, *old_dns;
2358 TALLOC_CTX *tmp_ctx = talloc_new(msg);
2360 struct ldb_val *new_values = NULL;
2361 unsigned old_num_values = old_el ? old_el->num_values : 0;
2362 unsigned num_values = 0;
2363 unsigned max_num_values;
2364 const struct GUID *invocation_id;
2365 struct ldb_context *ldb = ldb_module_get_ctx(module);
2367 unix_to_nt_time(&now, t);
2369 invocation_id = samdb_ntds_invocation_id(ldb);
2370 if (!invocation_id) {
2371 talloc_free(tmp_ctx);
2372 return LDB_ERR_OPERATIONS_ERROR;
2375 /* get the DNs to be added, fully parsed.
2377 * We need full parsing because they came off the wire and we don't
2378 * trust them, besides which we need their details to know where to put
2381 ret = get_parsed_dns(module, tmp_ctx, el, &dns,
2382 schema_attr->syntax->ldap_oid, parent);
2383 if (ret != LDB_SUCCESS) {
2384 talloc_free(tmp_ctx);
2388 /* get the existing DNs, lazily parsed */
2389 ret = get_parsed_dns_trusted(module, replmd_private,
2390 tmp_ctx, old_el, &old_dns,
2391 schema_attr->syntax->ldap_oid, parent);
2393 if (ret != LDB_SUCCESS) {
2394 talloc_free(tmp_ctx);
2398 max_num_values = old_num_values + el->num_values;
2399 if (max_num_values < old_num_values) {
2400 DEBUG(0, ("we seem to have overflow in replmd_modify_la_add. "
2401 "old values: %u, new values: %u, sum: %u",
2402 old_num_values, el->num_values, max_num_values));
2403 talloc_free(tmp_ctx);
2404 return LDB_ERR_OPERATIONS_ERROR;
2407 new_values = talloc_zero_array(tmp_ctx, struct ldb_val, max_num_values);
2409 if (new_values == NULL) {
2410 ldb_module_oom(module);
2411 talloc_free(tmp_ctx);
2412 return LDB_ERR_OPERATIONS_ERROR;
2416 * For each new value, find where it would go in the list. If there is
2417 * a matching GUID there, we update the existing value; otherwise we
2421 for (i = 0; i < el->num_values; i++) {
2422 struct parsed_dn *exact;
2423 struct parsed_dn *next;
2425 int err = parsed_dn_find(ldb, old_dns, old_num_values,
2428 dns[i].dsdb_dn->extra_part, 0,
2430 schema_attr->syntax->ldap_oid,
2432 if (err != LDB_SUCCESS) {
2433 talloc_free(tmp_ctx);
2437 if (exact != NULL) {
2439 * We are trying to add one that exists, which is only
2440 * allowed if it was previously deleted.
2442 * When we do undelete a link we change it in place.
2443 * It will be copied across into the right spot in due
2447 rmd_flags = dsdb_dn_rmd_flags(exact->dsdb_dn->dn);
2449 if (!(rmd_flags & DSDB_RMD_FLAG_DELETED)) {
2450 struct GUID_txt_buf guid_str;
2451 ldb_asprintf_errstring(ldb,
2452 "Attribute %s already "
2453 "exists for target GUID %s",
2455 GUID_buf_string(&exact->guid,
2457 talloc_free(tmp_ctx);
2458 /* error codes for 'member' need to be
2460 if (ldb_attr_cmp(el->name, "member") == 0) {
2461 return LDB_ERR_ENTRY_ALREADY_EXISTS;
2463 return LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS;
2467 ret = replmd_update_la_val(new_values, exact->v,
2470 invocation_id, seq_num,
2471 seq_num, now, 0, false);
2472 if (ret != LDB_SUCCESS) {
2473 talloc_free(tmp_ctx);
2477 ret = replmd_add_backlink(module, replmd_private,
2484 if (ret != LDB_SUCCESS) {
2485 talloc_free(tmp_ctx);
2491 * Here we don't have an exact match.
2493 * If next is NULL, this one goes beyond the end of the
2494 * existing list, so we need to add all of those ones first.
2496 * If next is not NULL, we need to add all the ones before
2500 offset = old_num_values;
2502 /* next should have been parsed, but let's make sure */
2503 if (next->dsdb_dn == NULL) {
2504 ret = really_parse_trusted_dn(tmp_ctx, ldb, next,
2505 schema_attr->syntax->ldap_oid);
2506 if (ret != LDB_SUCCESS) {
2510 offset = MIN(next - old_dns, old_num_values);
2513 /* put all the old ones before next on the list */
2514 for (; j < offset; j++) {
2515 new_values[num_values] = *old_dns[j].v;
2519 ret = replmd_add_backlink(module, replmd_private,
2524 /* Make the new linked attribute ldb_val. */
2525 ret = replmd_build_la_val(new_values, &new_values[num_values],
2526 dns[i].dsdb_dn, invocation_id,
2529 if (ret != LDB_SUCCESS) {
2530 talloc_free(tmp_ctx);
2534 if (ret != LDB_SUCCESS) {
2535 talloc_free(tmp_ctx);
2539 /* copy the rest of the old ones (if any) */
2540 for (; j < old_num_values; j++) {
2541 new_values[num_values] = *old_dns[j].v;
2545 talloc_steal(msg->elements, new_values);
2546 if (old_el != NULL) {
2547 talloc_steal(msg->elements, old_el->values);
2549 el->values = new_values;
2550 el->num_values = num_values;
2552 talloc_free(tmp_ctx);
2554 /* we now tell the backend to replace all existing values
2555 with the one we have constructed */
2556 el->flags = LDB_FLAG_MOD_REPLACE;
2563 handle deleting all active linked attributes
2565 static int replmd_modify_la_delete(struct ldb_module *module,
2566 struct replmd_private *replmd_private,
2567 const struct dsdb_schema *schema,
2568 struct ldb_message *msg,
2569 struct ldb_message_element *el,
2570 struct ldb_message_element *old_el,
2571 const struct dsdb_attribute *schema_attr,
2574 struct ldb_dn *msg_dn,
2575 struct ldb_request *parent)
2578 struct parsed_dn *dns, *old_dns;
2579 TALLOC_CTX *tmp_ctx = NULL;
2581 struct ldb_context *ldb = ldb_module_get_ctx(module);
2582 struct ldb_control *vanish_links_ctrl = NULL;
2583 bool vanish_links = false;
2584 unsigned int num_to_delete = el->num_values;
2586 const struct GUID *invocation_id;
2589 unix_to_nt_time(&now, t);
2591 invocation_id = samdb_ntds_invocation_id(ldb);
2592 if (!invocation_id) {
2593 return LDB_ERR_OPERATIONS_ERROR;
2596 if (old_el == NULL || old_el->num_values == 0) {
2597 /* there is nothing to delete... */
2598 if (num_to_delete == 0) {
2599 /* and we're deleting nothing, so that's OK */
2602 return LDB_ERR_NO_SUCH_ATTRIBUTE;
2605 tmp_ctx = talloc_new(msg);
2606 if (tmp_ctx == NULL) {
2607 return LDB_ERR_OPERATIONS_ERROR;
2610 ret = get_parsed_dns(module, tmp_ctx, el, &dns,
2611 schema_attr->syntax->ldap_oid, parent);
2612 if (ret != LDB_SUCCESS) {
2613 talloc_free(tmp_ctx);
2617 ret = get_parsed_dns_trusted(module, replmd_private,
2618 tmp_ctx, old_el, &old_dns,
2619 schema_attr->syntax->ldap_oid, parent);
2621 if (ret != LDB_SUCCESS) {
2622 talloc_free(tmp_ctx);
2627 vanish_links_ctrl = ldb_request_get_control(parent, DSDB_CONTROL_REPLMD_VANISH_LINKS);
2628 if (vanish_links_ctrl) {
2629 vanish_links = true;
2630 vanish_links_ctrl->critical = false;
2634 /* we empty out el->values here to avoid damage if we return early. */
2639 * If vanish links is set, we are actually removing members of
2640 * old_el->values; otherwise we are just marking them deleted.
2642 * There is a special case when no values are given: we remove them
2643 * all. When we have the vanish_links control we just have to remove
2644 * the backlinks and change our element to replace the existing values
2645 * with the empty list.
2648 if (num_to_delete == 0) {
2649 for (i = 0; i < old_el->num_values; i++) {
2650 struct parsed_dn *p = &old_dns[i];
2651 if (p->dsdb_dn == NULL) {
2652 ret = really_parse_trusted_dn(tmp_ctx, ldb, p,
2653 schema_attr->syntax->ldap_oid);
2654 if (ret != LDB_SUCCESS) {
2658 ret = replmd_add_backlink(module, replmd_private,
2659 schema, msg_dn, &p->guid,
2662 if (ret != LDB_SUCCESS) {
2663 talloc_free(tmp_ctx);
2670 rmd_flags = dsdb_dn_rmd_flags(p->dsdb_dn->dn);
2671 if (rmd_flags & DSDB_RMD_FLAG_DELETED) {
2675 ret = replmd_update_la_val(old_el->values, p->v,
2676 p->dsdb_dn, p->dsdb_dn,
2677 invocation_id, seq_num,
2678 seq_num, now, 0, true);
2679 if (ret != LDB_SUCCESS) {
2680 talloc_free(tmp_ctx);
2686 el->flags = LDB_FLAG_MOD_REPLACE;
2687 talloc_free(tmp_ctx);
2693 for (i = 0; i < num_to_delete; i++) {
2694 struct parsed_dn *p = &dns[i];
2695 struct parsed_dn *exact = NULL;
2696 struct parsed_dn *next = NULL;
2697 ret = parsed_dn_find(ldb, old_dns, old_el->num_values,
2700 p->dsdb_dn->extra_part, 0,
2702 schema_attr->syntax->ldap_oid,
2704 if (ret != LDB_SUCCESS) {
2705 talloc_free(tmp_ctx);
2708 if (exact == NULL) {
2709 struct GUID_txt_buf buf;
2710 ldb_asprintf_errstring(ldb, "Attribute %s doesn't "
2711 "exist for target GUID %s",
2713 GUID_buf_string(&p->guid, &buf));
2714 if (ldb_attr_cmp(el->name, "member") == 0) {
2715 talloc_free(tmp_ctx);
2716 return LDB_ERR_UNWILLING_TO_PERFORM;
2718 talloc_free(tmp_ctx);
2719 return LDB_ERR_NO_SUCH_ATTRIBUTE;
2724 if (CHECK_DEBUGLVL(5)) {
2725 rmd_flags = dsdb_dn_rmd_flags(exact->dsdb_dn->dn);
2726 if ((rmd_flags & DSDB_RMD_FLAG_DELETED)) {
2727 struct GUID_txt_buf buf;
2728 const char *guid_str = \
2729 GUID_buf_string(&p->guid, &buf);
2730 DEBUG(5, ("Deleting deleted linked "
2731 "attribute %s to %s, because "
2732 "vanish_links control is set\n",
2733 el->name, guid_str));
2737 /* remove the backlink */
2738 ret = replmd_add_backlink(module,
2745 if (ret != LDB_SUCCESS) {
2746 talloc_free(tmp_ctx);
2750 /* We flag the deletion and tidy it up later. */
2755 rmd_flags = dsdb_dn_rmd_flags(exact->dsdb_dn->dn);
2757 if (rmd_flags & DSDB_RMD_FLAG_DELETED) {
2758 struct GUID_txt_buf buf;
2759 const char *guid_str = GUID_buf_string(&p->guid, &buf);
2760 ldb_asprintf_errstring(ldb, "Attribute %s already "
2761 "deleted for target GUID %s",
2762 el->name, guid_str);
2763 if (ldb_attr_cmp(el->name, "member") == 0) {
2764 talloc_free(tmp_ctx);
2765 return LDB_ERR_UNWILLING_TO_PERFORM;
2767 talloc_free(tmp_ctx);
2768 return LDB_ERR_NO_SUCH_ATTRIBUTE;
2772 ret = replmd_update_la_val(old_el->values, exact->v,
2773 exact->dsdb_dn, exact->dsdb_dn,
2774 invocation_id, seq_num, seq_num,
2776 if (ret != LDB_SUCCESS) {
2777 talloc_free(tmp_ctx);
2780 ret = replmd_add_backlink(module, replmd_private,
2785 if (ret != LDB_SUCCESS) {
2786 talloc_free(tmp_ctx);
2793 for (i = 0; i < old_el->num_values; i++) {
2794 if (old_dns[i].v != NULL) {
2795 old_el->values[j] = *old_dns[i].v;
2799 old_el->num_values = j;
2802 el->values = talloc_steal(msg->elements, old_el->values);
2803 el->num_values = old_el->num_values;
2805 talloc_free(tmp_ctx);
2807 /* we now tell the backend to replace all existing values
2808 with the one we have constructed */
2809 el->flags = LDB_FLAG_MOD_REPLACE;
2815 handle replacing a linked attribute
2817 static int replmd_modify_la_replace(struct ldb_module *module,
2818 struct replmd_private *replmd_private,
2819 const struct dsdb_schema *schema,
2820 struct ldb_message *msg,
2821 struct ldb_message_element *el,
2822 struct ldb_message_element *old_el,
2823 const struct dsdb_attribute *schema_attr,
2826 struct ldb_dn *msg_dn,
2827 struct ldb_request *parent)
2829 unsigned int i, old_i, new_i;
2830 struct parsed_dn *dns, *old_dns;
2831 TALLOC_CTX *tmp_ctx = talloc_new(msg);
2833 const struct GUID *invocation_id;
2834 struct ldb_context *ldb = ldb_module_get_ctx(module);
2835 struct ldb_val *new_values = NULL;
2836 const char *ldap_oid = schema_attr->syntax->ldap_oid;
2837 unsigned int old_num_values;
2838 unsigned int repl_num_values;
2839 unsigned int max_num_values;
2842 unix_to_nt_time(&now, t);
2844 invocation_id = samdb_ntds_invocation_id(ldb);
2845 if (!invocation_id) {
2846 return LDB_ERR_OPERATIONS_ERROR;
2850 * The replace operation is unlike the replace and delete cases in that
2851 * we need to look at every existing link to see whether it is being
2852 * retained or deleted. In other words, we can't avoid parsing the GUIDs.
2854 * As we are trying to combine two sorted lists, the algorithm we use
2855 * is akin to the merge phase of a merge sort. We interleave the two
2856 * lists, doing different things depending on which side the current
2859 * There are three main cases, with some sub-cases.
2861 * - a DN is in the old list but not the new one. It needs to be
2862 * marked as deleted (but left in the list).
2863 * - maybe it is already deleted, and we have less to do.
2865 * - a DN is in both lists. The old data gets replaced by the new,
2866 * and the list doesn't grow. The old link may have been marked as
2867 * deleted, in which case we undelete it.
2869 * - a DN is in the new list only. We add it in the right place.
2872 old_num_values = old_el ? old_el->num_values : 0;
2873 repl_num_values = el->num_values;
2874 max_num_values = old_num_values + repl_num_values;
2876 if (max_num_values == 0) {
2877 /* There is nothing to do! */
2881 ret = get_parsed_dns(module, tmp_ctx, el, &dns, ldap_oid, parent);
2882 if (ret != LDB_SUCCESS) {
2883 talloc_free(tmp_ctx);
2887 ret = get_parsed_dns(module, tmp_ctx, old_el, &old_dns,
2889 if (ret != LDB_SUCCESS) {
2890 talloc_free(tmp_ctx);
2894 ret = replmd_check_upgrade_links(ldb, old_dns, old_num_values,
2896 if (ret != LDB_SUCCESS) {
2897 talloc_free(tmp_ctx);
2901 new_values = talloc_array(tmp_ctx, struct ldb_val, max_num_values);
2902 if (new_values == NULL) {
2903 ldb_module_oom(module);
2904 talloc_free(tmp_ctx);
2905 return LDB_ERR_OPERATIONS_ERROR;
2910 for (i = 0; i < max_num_values; i++) {
2912 struct parsed_dn *old_p, *new_p;
2913 if (old_i < old_num_values && new_i < repl_num_values) {
2914 old_p = &old_dns[old_i];
2915 new_p = &dns[new_i];
2916 cmp = parsed_dn_compare(old_p, new_p);
2917 } else if (old_i < old_num_values) {
2918 /* the new list is empty, read the old list */
2919 old_p = &old_dns[old_i];
2922 } else if (new_i < repl_num_values) {
2923 /* the old list is empty, read new list */
2925 new_p = &dns[new_i];
2933 * An old ones that come before the next replacement
2934 * (if any). We mark it as deleted and add it to the
2937 uint32_t rmd_flags = dsdb_dn_rmd_flags(old_p->dsdb_dn->dn);
2938 if ((rmd_flags & DSDB_RMD_FLAG_DELETED) == 0) {
2939 ret = replmd_update_la_val(new_values, old_p->v,
2945 if (ret != LDB_SUCCESS) {
2946 talloc_free(tmp_ctx);
2950 ret = replmd_add_backlink(module, replmd_private,
2953 &old_p->guid, false,
2956 if (ret != LDB_SUCCESS) {
2957 talloc_free(tmp_ctx);
2961 new_values[i] = *old_p->v;
2963 } else if (cmp == 0) {
2965 * We are overwriting one. If it was previously
2966 * deleted, we need to add a backlink.
2968 * Note that if any RMD_FLAGs in an extended new DN
2973 ret = replmd_update_la_val(new_values, old_p->v,
2979 if (ret != LDB_SUCCESS) {
2980 talloc_free(tmp_ctx);
2984 rmd_flags = dsdb_dn_rmd_flags(old_p->dsdb_dn->dn);
2985 if ((rmd_flags & DSDB_RMD_FLAG_DELETED) != 0) {
2986 ret = replmd_add_backlink(module, replmd_private,
2992 if (ret != LDB_SUCCESS) {
2993 talloc_free(tmp_ctx);
2998 new_values[i] = *old_p->v;
3003 * Replacements that don't match an existing one. We
3004 * just add them to the final list.
3006 ret = replmd_build_la_val(new_values,
3012 if (ret != LDB_SUCCESS) {
3013 talloc_free(tmp_ctx);
3016 ret = replmd_add_backlink(module, replmd_private,
3022 if (ret != LDB_SUCCESS) {
3023 talloc_free(tmp_ctx);
3026 new_values[i] = *new_p->v;
3030 if (old_el != NULL) {
3031 talloc_steal(msg->elements, old_el->values);
3033 el->values = talloc_steal(msg->elements, new_values);
3035 talloc_free(tmp_ctx);
3037 el->flags = LDB_FLAG_MOD_REPLACE;
3044 handle linked attributes in modify requests
3046 static int replmd_modify_handle_linked_attribs(struct ldb_module *module,
3047 struct replmd_private *replmd_private,
3048 struct ldb_message *msg,
3049 uint64_t seq_num, time_t t,
3050 struct ldb_request *parent)
3052 struct ldb_result *res;
3055 struct ldb_context *ldb = ldb_module_get_ctx(module);
3056 struct ldb_message *old_msg;
3058 const struct dsdb_schema *schema;
3060 if (dsdb_functional_level(ldb) == DS_DOMAIN_FUNCTION_2000) {
3062 * Nothing special is required for modifying or vanishing links
3063 * in fl2000 since they are just strings in a multi-valued
3066 struct ldb_control *ctrl = ldb_request_get_control(parent,
3067 DSDB_CONTROL_REPLMD_VANISH_LINKS);
3069 ctrl->critical = false;
3077 * We should restrict this to the intersection of the list of
3078 * linked attributes in the schema and the list of attributes
3081 * This will help performance a little, as otherwise we have
3082 * to allocate the entire object value-by-value.
3084 ret = dsdb_module_search_dn(module, msg, &res, msg->dn, NULL,
3085 DSDB_FLAG_NEXT_MODULE |
3086 DSDB_SEARCH_SHOW_RECYCLED |
3087 DSDB_SEARCH_REVEAL_INTERNALS |
3088 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT,
3090 if (ret != LDB_SUCCESS) {
3093 schema = dsdb_get_schema(ldb, res);
3095 return LDB_ERR_OPERATIONS_ERROR;
3098 old_msg = res->msgs[0];
3100 for (i=0; i<msg->num_elements; i++) {
3101 struct ldb_message_element *el = &msg->elements[i];
3102 struct ldb_message_element *old_el, *new_el;
3103 const struct dsdb_attribute *schema_attr
3104 = dsdb_attribute_by_lDAPDisplayName(schema, el->name);
3106 ldb_asprintf_errstring(ldb,
3107 "%s: attribute %s is not a valid attribute in schema",
3108 __FUNCTION__, el->name);
3109 return LDB_ERR_OBJECT_CLASS_VIOLATION;
3111 if (schema_attr->linkID == 0) {
3114 if ((schema_attr->linkID & 1) == 1) {
3115 if (parent && ldb_request_get_control(parent, DSDB_CONTROL_DBCHECK)) {
3118 /* Odd is for the target. Illegal to modify */
3119 ldb_asprintf_errstring(ldb,
3120 "attribute %s must not be modified directly, it is a linked attribute", el->name);
3121 return LDB_ERR_UNWILLING_TO_PERFORM;
3123 old_el = ldb_msg_find_element(old_msg, el->name);
3124 switch (el->flags & LDB_FLAG_MOD_MASK) {
3125 case LDB_FLAG_MOD_REPLACE:
3126 ret = replmd_modify_la_replace(module, replmd_private,
3127 schema, msg, el, old_el,
3128 schema_attr, seq_num, t,
3132 case LDB_FLAG_MOD_DELETE:
3133 ret = replmd_modify_la_delete(module, replmd_private,
3134 schema, msg, el, old_el,
3135 schema_attr, seq_num, t,
3139 case LDB_FLAG_MOD_ADD:
3140 ret = replmd_modify_la_add(module, replmd_private,
3141 schema, msg, el, old_el,
3142 schema_attr, seq_num, t,
3147 ldb_asprintf_errstring(ldb,
3148 "invalid flags 0x%x for %s linked attribute",
3149 el->flags, el->name);
3150 return LDB_ERR_UNWILLING_TO_PERFORM;
3152 if (dsdb_check_single_valued_link(schema_attr, el) != LDB_SUCCESS) {
3153 ldb_asprintf_errstring(ldb,
3154 "Attribute %s is single valued but more than one value has been supplied",
3156 return LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS;
3158 el->flags |= LDB_FLAG_INTERNAL_DISABLE_SINGLE_VALUE_CHECK;
3163 if (ret != LDB_SUCCESS) {
3167 ldb_msg_remove_attr(old_msg, el->name);
3169 ldb_msg_add_empty(old_msg, el->name, 0, &new_el);
3170 new_el->num_values = el->num_values;
3171 new_el->values = talloc_steal(msg->elements, el->values);
3173 /* TODO: this relises a bit too heavily on the exact
3174 behaviour of ldb_msg_find_element and
3175 ldb_msg_remove_element */
3176 old_el = ldb_msg_find_element(msg, el->name);
3178 ldb_msg_remove_element(msg, old_el);
3188 static int send_rodc_referral(struct ldb_request *req,
3189 struct ldb_context *ldb,
3192 char *referral = NULL;
3193 struct loadparm_context *lp_ctx = NULL;
3194 struct ldb_dn *fsmo_role_dn = NULL;
3195 struct ldb_dn *role_owner_dn = NULL;
3196 const char *domain = NULL;
3199 lp_ctx = talloc_get_type(ldb_get_opaque(ldb, "loadparm"),
3200 struct loadparm_context);
3202 werr = dsdb_get_fsmo_role_info(req, ldb, DREPL_PDC_MASTER,
3203 &fsmo_role_dn, &role_owner_dn);
3205 if (W_ERROR_IS_OK(werr)) {
3206 struct ldb_dn *server_dn = ldb_dn_copy(req, role_owner_dn);
3207 if (server_dn != NULL) {
3208 ldb_dn_remove_child_components(server_dn, 1);
3209 domain = samdb_dn_to_dnshostname(ldb, req,
3214 if (domain == NULL) {
3215 domain = lpcfg_dnsdomain(lp_ctx);
3218 referral = talloc_asprintf(req, "ldap://%s/%s",
3220 ldb_dn_get_linearized(dn));
3221 if (referral == NULL) {
3223 return LDB_ERR_OPERATIONS_ERROR;
3226 return ldb_module_send_referral(req, referral);
3230 static int replmd_modify(struct ldb_module *module, struct ldb_request *req)
3232 struct ldb_context *ldb;
3233 struct replmd_replicated_request *ac;
3234 struct ldb_request *down_req;
3235 struct ldb_message *msg;
3236 time_t t = time(NULL);
3238 bool is_urgent = false, rodc = false;
3239 bool is_schema_nc = false;
3240 unsigned int functional_level;
3241 const struct ldb_message_element *guid_el = NULL;
3242 struct ldb_control *sd_propagation_control;
3243 struct replmd_private *replmd_private =
3244 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
3246 /* do not manipulate our control entries */
3247 if (ldb_dn_is_special(req->op.mod.message->dn)) {
3248 return ldb_next_request(module, req);
3251 sd_propagation_control = ldb_request_get_control(req,
3252 DSDB_CONTROL_SEC_DESC_PROPAGATION_OID);
3253 if (sd_propagation_control != NULL) {
3254 if (req->op.mod.message->num_elements != 1) {
3255 return ldb_module_operr(module);
3257 ret = strcmp(req->op.mod.message->elements[0].name,
3258 "nTSecurityDescriptor");
3260 return ldb_module_operr(module);
3263 return ldb_next_request(module, req);
3266 ldb = ldb_module_get_ctx(module);
3268 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_modify\n");
3270 guid_el = ldb_msg_find_element(req->op.mod.message, "objectGUID");
3271 if (guid_el != NULL) {
3272 ldb_set_errstring(ldb,
3273 "replmd_modify: it's not allowed to change the objectGUID!");
3274 return LDB_ERR_CONSTRAINT_VIOLATION;
3277 ac = replmd_ctx_init(module, req);
3279 return ldb_module_oom(module);
3282 functional_level = dsdb_functional_level(ldb);
3284 /* we have to copy the message as the caller might have it as a const */
3285 msg = ldb_msg_copy_shallow(ac, req->op.mod.message);
3289 return LDB_ERR_OPERATIONS_ERROR;
3292 ldb_msg_remove_attr(msg, "whenChanged");
3293 ldb_msg_remove_attr(msg, "uSNChanged");
3295 is_schema_nc = ldb_dn_compare_base(replmd_private->schema_dn, msg->dn) == 0;
3297 ret = replmd_update_rpmd(module, ac->schema, req, NULL,
3298 msg, &ac->seq_num, t, is_schema_nc,
3300 if (rodc && (ret == LDB_ERR_REFERRAL)) {
3301 ret = send_rodc_referral(req, ldb, msg->dn);
3307 if (ret != LDB_SUCCESS) {
3312 ret = replmd_modify_handle_linked_attribs(module, replmd_private,
3313 msg, ac->seq_num, t, req);
3314 if (ret != LDB_SUCCESS) {
3320 * - replace the old object with the newly constructed one
3323 ac->is_urgent = is_urgent;
3325 ret = ldb_build_mod_req(&down_req, ldb, ac,
3328 ac, replmd_op_callback,
3330 LDB_REQ_SET_LOCATION(down_req);
3331 if (ret != LDB_SUCCESS) {
3336 /* current partition control is needed by "replmd_op_callback" */
3337 if (ldb_request_get_control(req, DSDB_CONTROL_CURRENT_PARTITION_OID) == NULL) {
3338 ret = ldb_request_add_control(down_req,
3339 DSDB_CONTROL_CURRENT_PARTITION_OID,
3341 if (ret != LDB_SUCCESS) {
3347 /* If we are in functional level 2000, then
3348 * replmd_modify_handle_linked_attribs will have done
3350 if (functional_level == DS_DOMAIN_FUNCTION_2000) {
3351 ret = ldb_request_add_control(down_req, DSDB_CONTROL_APPLY_LINKS, false, NULL);
3352 if (ret != LDB_SUCCESS) {
3358 talloc_steal(down_req, msg);
3360 /* we only change whenChanged and uSNChanged if the seq_num
3362 if (ac->seq_num != 0) {
3363 ret = add_time_element(msg, "whenChanged", t);
3364 if (ret != LDB_SUCCESS) {
3370 ret = add_uint64_element(ldb, msg, "uSNChanged", ac->seq_num);
3371 if (ret != LDB_SUCCESS) {
3378 /* go on with the call chain */
3379 return ldb_next_request(module, down_req);
3382 static int replmd_rename_callback(struct ldb_request *req, struct ldb_reply *ares);
3385 handle a rename request
3387 On a rename we need to do an extra ldb_modify which sets the
3388 whenChanged and uSNChanged attributes. We do this in a callback after the success.
3390 static int replmd_rename(struct ldb_module *module, struct ldb_request *req)
3392 struct ldb_context *ldb;
3393 struct replmd_replicated_request *ac;
3395 struct ldb_request *down_req;
3397 /* do not manipulate our control entries */
3398 if (ldb_dn_is_special(req->op.mod.message->dn)) {
3399 return ldb_next_request(module, req);
3402 ldb = ldb_module_get_ctx(module);
3404 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_rename\n");
3406 ac = replmd_ctx_init(module, req);
3408 return ldb_module_oom(module);
3411 ret = ldb_build_rename_req(&down_req, ldb, ac,
3412 ac->req->op.rename.olddn,
3413 ac->req->op.rename.newdn,
3415 ac, replmd_rename_callback,
3417 LDB_REQ_SET_LOCATION(down_req);
3418 if (ret != LDB_SUCCESS) {
3423 /* go on with the call chain */
3424 return ldb_next_request(module, down_req);
3427 /* After the rename is compleated, update the whenchanged etc */
3428 static int replmd_rename_callback(struct ldb_request *req, struct ldb_reply *ares)
3430 struct ldb_context *ldb;
3431 struct ldb_request *down_req;
3432 struct ldb_message *msg;
3433 const struct dsdb_attribute *rdn_attr;
3434 const char *rdn_name;
3435 const struct ldb_val *rdn_val;
3436 const char *attrs[5] = { NULL, };
3437 time_t t = time(NULL);
3439 bool is_urgent = false, rodc = false;
3441 struct replmd_replicated_request *ac =
3442 talloc_get_type(req->context, struct replmd_replicated_request);
3443 struct replmd_private *replmd_private =
3444 talloc_get_type(ldb_module_get_private(ac->module),
3445 struct replmd_private);
3447 ldb = ldb_module_get_ctx(ac->module);
3449 if (ares->error != LDB_SUCCESS) {
3450 return ldb_module_done(ac->req, ares->controls,
3451 ares->response, ares->error);
3454 if (ares->type != LDB_REPLY_DONE) {
3455 ldb_set_errstring(ldb,
3456 "invalid ldb_reply_type in callback");
3458 return ldb_module_done(ac->req, NULL, NULL,
3459 LDB_ERR_OPERATIONS_ERROR);
3463 * - replace the old object with the newly constructed one
3466 msg = ldb_msg_new(ac);
3469 return LDB_ERR_OPERATIONS_ERROR;
3472 msg->dn = ac->req->op.rename.newdn;
3474 is_schema_nc = ldb_dn_compare_base(replmd_private->schema_dn, msg->dn) == 0;
3476 rdn_name = ldb_dn_get_rdn_name(msg->dn);
3477 if (rdn_name == NULL) {
3479 return ldb_module_done(ac->req, NULL, NULL,
3483 /* normalize the rdn attribute name */
3484 rdn_attr = dsdb_attribute_by_lDAPDisplayName(ac->schema, rdn_name);
3485 if (rdn_attr == NULL) {
3487 return ldb_module_done(ac->req, NULL, NULL,
3490 rdn_name = rdn_attr->lDAPDisplayName;
3492 rdn_val = ldb_dn_get_rdn_val(msg->dn);
3493 if (rdn_val == NULL) {
3495 return ldb_module_done(ac->req, NULL, NULL,
3499 if (ldb_msg_add_empty(msg, rdn_name, LDB_FLAG_MOD_REPLACE, NULL) != 0) {
3501 return ldb_module_done(ac->req, NULL, NULL,
3504 if (ldb_msg_add_value(msg, rdn_name, rdn_val, NULL) != 0) {
3506 return ldb_module_done(ac->req, NULL, NULL,
3509 if (ldb_msg_add_empty(msg, "name", LDB_FLAG_MOD_REPLACE, NULL) != 0) {
3511 return ldb_module_done(ac->req, NULL, NULL,
3514 if (ldb_msg_add_value(msg, "name", rdn_val, NULL) != 0) {
3516 return ldb_module_done(ac->req, NULL, NULL,
3521 * here we let replmd_update_rpmd() only search for
3522 * the existing "replPropertyMetaData" and rdn_name attributes.
3524 * We do not want the existing "name" attribute as
3525 * the "name" attribute needs to get the version
3526 * updated on rename even if the rdn value hasn't changed.
3528 * This is the diff of the meta data, for a moved user
3529 * on a w2k8r2 server:
3532 * -dn: CN=sdf df,CN=Users,DC=bla,DC=base
3533 * +dn: CN=sdf df,OU=TestOU,DC=bla,DC=base
3534 * replPropertyMetaData: NDR: struct replPropertyMetaDataBlob
3535 * version : 0x00000001 (1)
3536 * reserved : 0x00000000 (0)
3537 * @@ -66,11 +66,11 @@ replPropertyMetaData: NDR: struct re
3538 * local_usn : 0x00000000000037a5 (14245)
3539 * array: struct replPropertyMetaData1
3540 * attid : DRSUAPI_ATTID_name (0x90001)
3541 * - version : 0x00000001 (1)
3542 * - originating_change_time : Wed Feb 9 17:20:49 2011 CET
3543 * + version : 0x00000002 (2)
3544 * + originating_change_time : Wed Apr 6 15:21:01 2011 CEST
3545 * originating_invocation_id: 0d36ca05-5507-4e62-aca3-354bab0d39e1
3546 * - originating_usn : 0x00000000000037a5 (14245)
3547 * - local_usn : 0x00000000000037a5 (14245)
3548 * + originating_usn : 0x0000000000003834 (14388)
3549 * + local_usn : 0x0000000000003834 (14388)
3550 * array: struct replPropertyMetaData1
3551 * attid : DRSUAPI_ATTID_userAccountControl (0x90008)
3552 * version : 0x00000004 (4)
3554 attrs[0] = "replPropertyMetaData";
3555 attrs[1] = "objectClass";
3556 attrs[2] = "instanceType";
3557 attrs[3] = rdn_name;
3560 ret = replmd_update_rpmd(ac->module, ac->schema, req, attrs,
3561 msg, &ac->seq_num, t,
3562 is_schema_nc, &is_urgent, &rodc);
3563 if (rodc && (ret == LDB_ERR_REFERRAL)) {
3564 ret = send_rodc_referral(req, ldb, ac->req->op.rename.olddn);
3566 return ldb_module_done(req, NULL, NULL, ret);
3569 if (ret != LDB_SUCCESS) {
3571 return ldb_module_done(ac->req, NULL, NULL, ret);
3574 if (ac->seq_num == 0) {
3576 return ldb_module_done(ac->req, NULL, NULL,
3578 "internal error seq_num == 0"));
3580 ac->is_urgent = is_urgent;
3582 ret = ldb_build_mod_req(&down_req, ldb, ac,
3585 ac, replmd_op_callback,
3587 LDB_REQ_SET_LOCATION(down_req);
3588 if (ret != LDB_SUCCESS) {
3593 /* current partition control is needed by "replmd_op_callback" */
3594 if (ldb_request_get_control(req, DSDB_CONTROL_CURRENT_PARTITION_OID) == NULL) {
3595 ret = ldb_request_add_control(down_req,
3596 DSDB_CONTROL_CURRENT_PARTITION_OID,
3598 if (ret != LDB_SUCCESS) {
3604 talloc_steal(down_req, msg);
3606 ret = add_time_element(msg, "whenChanged", t);
3607 if (ret != LDB_SUCCESS) {
3613 ret = add_uint64_element(ldb, msg, "uSNChanged", ac->seq_num);
3614 if (ret != LDB_SUCCESS) {
3620 /* go on with the call chain - do the modify after the rename */
3621 return ldb_next_request(ac->module, down_req);
3625 * remove links from objects that point at this object when an object
3626 * is deleted. We remove it from the NEXT module per MS-DRSR 5.160
3627 * RemoveObj which states that link removal due to the object being
3628 * deleted is NOT an originating update - they just go away!
3631 static int replmd_delete_remove_link(struct ldb_module *module,
3632 const struct dsdb_schema *schema,
3633 struct replmd_private *replmd_private,
3636 struct ldb_message_element *el,
3637 const struct dsdb_attribute *sa,
3638 struct ldb_request *parent)
3641 TALLOC_CTX *tmp_ctx = talloc_new(module);
3642 struct ldb_context *ldb = ldb_module_get_ctx(module);
3644 for (i=0; i<el->num_values; i++) {
3645 struct dsdb_dn *dsdb_dn;
3647 struct ldb_message *msg;
3648 const struct dsdb_attribute *target_attr;
3649 struct ldb_message_element *el2;
3651 struct ldb_val dn_val;
3652 uint32_t dsdb_flags = 0;
3653 const char *attrs[] = { NULL, NULL };
3654 struct ldb_result *link_res;
3655 struct ldb_message *link_msg;
3656 struct ldb_message_element *link_el;
3657 struct parsed_dn *link_dns;
3658 struct parsed_dn *p = NULL, *unused = NULL;
3660 if (dsdb_dn_is_deleted_val(&el->values[i])) {
3664 dsdb_dn = dsdb_dn_parse(tmp_ctx, ldb, &el->values[i], sa->syntax->ldap_oid);
3666 talloc_free(tmp_ctx);
3667 return LDB_ERR_OPERATIONS_ERROR;
3670 /* remove the link */
3671 msg = ldb_msg_new(tmp_ctx);
3673 ldb_module_oom(module);
3674 talloc_free(tmp_ctx);
3675 return LDB_ERR_OPERATIONS_ERROR;
3679 msg->dn = dsdb_dn->dn;
3681 target_attr = dsdb_attribute_by_linkID(schema, sa->linkID ^ 1);
3682 if (target_attr == NULL) {
3685 attrs[0] = target_attr->lDAPDisplayName;
3687 ret = ldb_msg_add_empty(msg, target_attr->lDAPDisplayName,
3688 LDB_FLAG_MOD_DELETE, &el2);
3689 if (ret != LDB_SUCCESS) {
3690 ldb_module_oom(module);
3691 talloc_free(tmp_ctx);
3692 return LDB_ERR_OPERATIONS_ERROR;
3695 ret = dsdb_module_search_dn(module, tmp_ctx, &link_res,
3697 DSDB_FLAG_NEXT_MODULE |
3698 DSDB_SEARCH_SHOW_EXTENDED_DN,
3701 if (ret != LDB_SUCCESS) {
3702 talloc_free(tmp_ctx);
3706 link_msg = link_res->msgs[0];
3707 link_el = ldb_msg_find_element(link_msg,
3708 target_attr->lDAPDisplayName);
3709 if (link_el == NULL) {
3710 talloc_free(tmp_ctx);
3711 return LDB_ERR_NO_SUCH_ATTRIBUTE;
3715 * This call 'upgrades' the links in link_dns, but we
3716 * do not commit the result back into the database, so
3717 * this is safe to call in FL2000 or on databases that
3718 * have been run at that level in the past.
3720 ret = get_parsed_dns_trusted(module, replmd_private, tmp_ctx,
3722 target_attr->syntax->ldap_oid, parent);
3723 if (ret != LDB_SUCCESS) {
3724 talloc_free(tmp_ctx);
3728 ret = parsed_dn_find(ldb, link_dns, link_el->num_values,
3732 target_attr->syntax->ldap_oid, false);
3733 if (ret != LDB_SUCCESS) {
3734 talloc_free(tmp_ctx);
3739 ldb_asprintf_errstring(ldb_module_get_ctx(module),
3740 "Failed to find forward link on %s "
3741 "as %s to remove backlink %s on %s",
3742 ldb_dn_get_linearized(msg->dn),
3743 target_attr->lDAPDisplayName,
3744 sa->lDAPDisplayName,
3745 ldb_dn_get_linearized(dn));
3746 talloc_free(tmp_ctx);
3747 return LDB_ERR_NO_SUCH_ATTRIBUTE;
3751 /* This needs to get the Binary DN, by first searching */
3752 dn_str = dsdb_dn_get_linearized(tmp_ctx,
3755 dn_val = data_blob_string_const(dn_str);
3756 el2->values = &dn_val;
3757 el2->num_values = 1;
3760 * Ensure that we tell the modification to vanish any linked
3761 * attributes (not simply mark them as isDeleted = TRUE)
3763 dsdb_flags |= DSDB_REPLMD_VANISH_LINKS;
3765 ret = dsdb_module_modify(module, msg, dsdb_flags|DSDB_FLAG_OWN_MODULE, parent);
3766 if (ret != LDB_SUCCESS) {
3767 talloc_free(tmp_ctx);
3771 talloc_free(tmp_ctx);
3777 handle update of replication meta data for deletion of objects
3779 This also handles the mapping of delete to a rename operation
3780 to allow deletes to be replicated.
3782 It also handles the incoming deleted objects, to ensure they are
3783 fully deleted here. In that case re_delete is true, and we do not
3784 use this as a signal to change the deleted state, just reinforce it.
3787 static int replmd_delete_internals(struct ldb_module *module, struct ldb_request *req, bool re_delete)
3789 int ret = LDB_ERR_OTHER;
3790 bool retb, disallow_move_on_delete;
3791 struct ldb_dn *old_dn, *new_dn;
3792 const char *rdn_name;
3793 const struct ldb_val *rdn_value, *new_rdn_value;
3795 struct ldb_context *ldb = ldb_module_get_ctx(module);
3796 const struct dsdb_schema *schema;
3797 struct ldb_message *msg, *old_msg;
3798 struct ldb_message_element *el;
3799 TALLOC_CTX *tmp_ctx;
3800 struct ldb_result *res, *parent_res;
3801 static const char * const preserved_attrs[] = {
3802 /* yes, this really is a hard coded list. See MS-ADTS
3803 section 3.1.1.5.5.1.1 */
3806 "dNReferenceUpdate",
3817 "msDS-LastKnownRDN",
3823 "distinguishedName",
3827 "proxiedObjectName",
3829 "nTSecurityDescriptor",
3830 "replPropertyMetaData",
3832 "securityIdentifier",
3840 "userAccountControl",
3847 static const char * const all_attrs[] = {
3848 DSDB_SECRET_ATTRIBUTES,
3852 unsigned int i, el_count = 0;
3853 uint32_t dsdb_flags = 0;
3854 struct replmd_private *replmd_private;
3855 enum deletion_state deletion_state, next_deletion_state;
3857 if (ldb_dn_is_special(req->op.del.dn)) {
3858 return ldb_next_request(module, req);
3862 * We have to allow dbcheck to remove an object that
3863 * is beyond repair, and to do so totally. This could
3864 * mean we we can get a partial object from the other
3865 * DC, causing havoc, so dbcheck suggests
3866 * re-replication first. dbcheck sets both DBCHECK
3867 * and RELAX in this situation.
3869 if (ldb_request_get_control(req, LDB_CONTROL_RELAX_OID)
3870 && ldb_request_get_control(req, DSDB_CONTROL_DBCHECK)) {
3871 /* really, really remove it */
3872 return ldb_next_request(module, req);
3875 tmp_ctx = talloc_new(ldb);
3878 return LDB_ERR_OPERATIONS_ERROR;
3881 schema = dsdb_get_schema(ldb, tmp_ctx);
3883 talloc_free(tmp_ctx);
3884 return LDB_ERR_OPERATIONS_ERROR;
3887 old_dn = ldb_dn_copy(tmp_ctx, req->op.del.dn);
3889 /* we need the complete msg off disk, so we can work out which
3890 attributes need to be removed */
3891 ret = dsdb_module_search_dn(module, tmp_ctx, &res, old_dn, all_attrs,
3892 DSDB_FLAG_NEXT_MODULE |
3893 DSDB_SEARCH_SHOW_RECYCLED |
3894 DSDB_SEARCH_REVEAL_INTERNALS |
3895 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT, req);
3896 if (ret != LDB_SUCCESS) {
3897 ldb_asprintf_errstring(ldb_module_get_ctx(module),
3898 "repmd_delete: Failed to %s %s, because we failed to find it: %s",
3899 re_delete ? "re-delete" : "delete",
3900 ldb_dn_get_linearized(old_dn),
3901 ldb_errstring(ldb_module_get_ctx(module)));
3902 talloc_free(tmp_ctx);
3905 old_msg = res->msgs[0];
3907 replmd_deletion_state(module, old_msg,
3909 &next_deletion_state);
3911 /* This supports us noticing an incoming isDeleted and acting on it */
3913 SMB_ASSERT(deletion_state > OBJECT_NOT_DELETED);
3914 next_deletion_state = deletion_state;
3917 if (next_deletion_state == OBJECT_REMOVED) {
3919 * We have to prevent objects being deleted, even if
3920 * the administrator really wants them gone, as
3921 * without the tombstone, we can get a partial object
3922 * from the other DC, causing havoc.
3924 * The only other valid case is when the 180 day
3925 * timeout has expired, when relax is specified.
3927 if (ldb_request_get_control(req, LDB_CONTROL_RELAX_OID)) {
3928 /* it is already deleted - really remove it this time */
3929 talloc_free(tmp_ctx);
3930 return ldb_next_request(module, req);
3933 ldb_asprintf_errstring(ldb, "Refusing to delete tombstone object %s. "
3934 "This check is to prevent corruption of the replicated state.",
3935 ldb_dn_get_linearized(old_msg->dn));
3936 return LDB_ERR_UNWILLING_TO_PERFORM;
3939 rdn_name = ldb_dn_get_rdn_name(old_dn);
3940 rdn_value = ldb_dn_get_rdn_val(old_dn);
3941 if ((rdn_name == NULL) || (rdn_value == NULL)) {
3942 talloc_free(tmp_ctx);
3943 return ldb_operr(ldb);
3946 msg = ldb_msg_new(tmp_ctx);
3948 ldb_module_oom(module);
3949 talloc_free(tmp_ctx);
3950 return LDB_ERR_OPERATIONS_ERROR;
3955 /* consider the SYSTEM_FLAG_DISALLOW_MOVE_ON_DELETE flag */
3956 disallow_move_on_delete =
3957 (ldb_msg_find_attr_as_int(old_msg, "systemFlags", 0)
3958 & SYSTEM_FLAG_DISALLOW_MOVE_ON_DELETE);
3960 /* work out where we will be renaming this object to */
3961 if (!disallow_move_on_delete) {
3962 struct ldb_dn *deleted_objects_dn;
3963 ret = dsdb_get_deleted_objects_dn(ldb, tmp_ctx, old_dn,
3964 &deleted_objects_dn);
3967 * We should not move objects if we can't find the
3968 * deleted objects DN. Not moving (or otherwise
3969 * harming) the Deleted Objects DN itself is handled
3972 if (re_delete && (ret != LDB_SUCCESS)) {
3973 new_dn = ldb_dn_get_parent(tmp_ctx, old_dn);
3974 if (new_dn == NULL) {
3975 ldb_module_oom(module);
3976 talloc_free(tmp_ctx);
3977 return LDB_ERR_OPERATIONS_ERROR;
3979 } else if (ret != LDB_SUCCESS) {
3980 /* this is probably an attempted delete on a partition
3981 * that doesn't allow delete operations, such as the
3982 * schema partition */
3983 ldb_asprintf_errstring(ldb, "No Deleted Objects container for DN %s",
3984 ldb_dn_get_linearized(old_dn));
3985 talloc_free(tmp_ctx);
3986 return LDB_ERR_UNWILLING_TO_PERFORM;
3988 new_dn = deleted_objects_dn;
3991 new_dn = ldb_dn_get_parent(tmp_ctx, old_dn);
3992 if (new_dn == NULL) {
3993 ldb_module_oom(module);
3994 talloc_free(tmp_ctx);
3995 return LDB_ERR_OPERATIONS_ERROR;
3999 /* get the objects GUID from the search we just did */
4000 guid = samdb_result_guid(old_msg, "objectGUID");
4002 if (deletion_state == OBJECT_NOT_DELETED) {
4003 /* Add a formatted child */
4004 retb = ldb_dn_add_child_fmt(new_dn, "%s=%s\\0ADEL:%s",
4006 ldb_dn_escape_value(tmp_ctx, *rdn_value),
4007 GUID_string(tmp_ctx, &guid));
4009 ldb_asprintf_errstring(ldb, __location__
4010 ": Unable to add a formatted child to dn: %s",
4011 ldb_dn_get_linearized(new_dn));
4012 talloc_free(tmp_ctx);
4013 return LDB_ERR_OPERATIONS_ERROR;
4016 ret = ldb_msg_add_string(msg, "isDeleted", "TRUE");
4017 if (ret != LDB_SUCCESS) {
4018 ldb_asprintf_errstring(ldb, __location__
4019 ": Failed to add isDeleted string to the msg");
4020 talloc_free(tmp_ctx);
4023 msg->elements[el_count++].flags = LDB_FLAG_MOD_REPLACE;
4026 * No matter what has happened with other renames etc, try again to
4027 * get this to be under the deleted DN. See MS-DRSR 5.160 RemoveObj
4030 struct ldb_dn *rdn = ldb_dn_copy(tmp_ctx, old_dn);
4031 retb = ldb_dn_remove_base_components(rdn, ldb_dn_get_comp_num(rdn) - 1);
4033 ldb_asprintf_errstring(ldb, __location__
4034 ": Unable to add a prepare rdn of %s",
4035 ldb_dn_get_linearized(rdn));
4036 talloc_free(tmp_ctx);
4037 return LDB_ERR_OPERATIONS_ERROR;
4039 SMB_ASSERT(ldb_dn_get_comp_num(rdn) == 1);
4041 retb = ldb_dn_add_child(new_dn, rdn);
4043 ldb_asprintf_errstring(ldb, __location__
4044 ": Unable to add rdn %s to base dn: %s",
4045 ldb_dn_get_linearized(rdn),
4046 ldb_dn_get_linearized(new_dn));
4047 talloc_free(tmp_ctx);
4048 return LDB_ERR_OPERATIONS_ERROR;
4053 now we need to modify the object in the following ways:
4055 - add isDeleted=TRUE
4056 - update rDN and name, with new rDN
4057 - remove linked attributes
4058 - remove objectCategory and sAMAccountType
4059 - remove attribs not on the preserved list
4060 - preserved if in above list, or is rDN
4061 - remove all linked attribs from this object
4062 - remove all links from other objects to this object
4063 - add lastKnownParent
4064 - update replPropertyMetaData?
4066 see MS-ADTS "Tombstone Requirements" section 3.1.1.5.5.1.1
4069 if (deletion_state == OBJECT_NOT_DELETED) {
4070 struct ldb_dn *parent_dn = ldb_dn_get_parent(tmp_ctx, old_dn);
4071 char *parent_dn_str = NULL;
4073 /* we need the storage form of the parent GUID */
4074 ret = dsdb_module_search_dn(module, tmp_ctx, &parent_res,
4076 DSDB_FLAG_NEXT_MODULE |
4077 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT |
4078 DSDB_SEARCH_REVEAL_INTERNALS|
4079 DSDB_SEARCH_SHOW_RECYCLED, req);
4080 if (ret != LDB_SUCCESS) {
4081 ldb_asprintf_errstring(ldb_module_get_ctx(module),
4082 "repmd_delete: Failed to %s %s, "
4083 "because we failed to find it's parent (%s): %s",
4084 re_delete ? "re-delete" : "delete",
4085 ldb_dn_get_linearized(old_dn),
4086 ldb_dn_get_linearized(parent_dn),
4087 ldb_errstring(ldb_module_get_ctx(module)));
4088 talloc_free(tmp_ctx);
4093 * Now we can use the DB version,
4094 * it will have the extended DN info in it
4096 parent_dn = parent_res->msgs[0]->dn;
4097 parent_dn_str = ldb_dn_get_extended_linearized(tmp_ctx,
4100 if (parent_dn_str == NULL) {
4101 talloc_free(tmp_ctx);
4102 return ldb_module_oom(module);
4105 ret = ldb_msg_add_steal_string(msg, "lastKnownParent",
4107 if (ret != LDB_SUCCESS) {
4108 ldb_asprintf_errstring(ldb, __location__
4109 ": Failed to add lastKnownParent "
4110 "string when deleting %s",
4111 ldb_dn_get_linearized(old_dn));
4112 talloc_free(tmp_ctx);
4115 msg->elements[el_count++].flags = LDB_FLAG_MOD_REPLACE;
4117 if (next_deletion_state == OBJECT_DELETED) {
4118 ret = ldb_msg_add_value(msg, "msDS-LastKnownRDN", rdn_value, NULL);
4119 if (ret != LDB_SUCCESS) {
4120 ldb_asprintf_errstring(ldb, __location__
4121 ": Failed to add msDS-LastKnownRDN "
4122 "string when deleting %s",
4123 ldb_dn_get_linearized(old_dn));
4124 talloc_free(tmp_ctx);
4127 msg->elements[el_count++].flags = LDB_FLAG_MOD_ADD;
4131 switch (next_deletion_state) {
4133 case OBJECT_RECYCLED:
4134 case OBJECT_TOMBSTONE:
4137 * MS-ADTS 3.1.1.5.5.1.1 Tombstone Requirements
4138 * describes what must be removed from a tombstone
4141 * MS-ADTS 3.1.1.5.5.1.3 Recycled-Object Requirements
4142 * describes what must be removed from a recycled
4148 * we also mark it as recycled, meaning this object can't be
4149 * recovered (we are stripping its attributes).
4150 * This is done only if we have this schema object of course ...
4151 * This behavior is identical to the one of Windows 2008R2 which
4152 * always set the isRecycled attribute, even if the recycle-bin is
4153 * not activated and what ever the forest level is.
4155 if (dsdb_attribute_by_lDAPDisplayName(schema, "isRecycled") != NULL) {
4156 ret = ldb_msg_add_string(msg, "isRecycled", "TRUE");
4157 if (ret != LDB_SUCCESS) {
4158 DEBUG(0,(__location__ ": Failed to add isRecycled string to the msg\n"));
4159 ldb_module_oom(module);
4160 talloc_free(tmp_ctx);
4163 msg->elements[el_count++].flags = LDB_FLAG_MOD_REPLACE;
4166 replmd_private = talloc_get_type(ldb_module_get_private(module),
4167 struct replmd_private);
4168 /* work out which of the old attributes we will be removing */
4169 for (i=0; i<old_msg->num_elements; i++) {
4170 const struct dsdb_attribute *sa;
4171 el = &old_msg->elements[i];
4172 sa = dsdb_attribute_by_lDAPDisplayName(schema, el->name);
4174 talloc_free(tmp_ctx);
4175 return LDB_ERR_OPERATIONS_ERROR;
4177 if (ldb_attr_cmp(el->name, rdn_name) == 0) {
4178 /* don't remove the rDN */
4181 if (sa->linkID & 1) {
4183 we have a backlink in this object
4184 that needs to be removed. We're not
4185 allowed to remove it directly
4186 however, so we instead setup a
4187 modify to delete the corresponding
4190 ret = replmd_delete_remove_link(module, schema,
4194 if (ret != LDB_SUCCESS) {
4195 const char *old_dn_str
4196 = ldb_dn_get_linearized(old_dn);
4197 ldb_asprintf_errstring(ldb,
4199 ": Failed to remove backlink of "
4200 "%s when deleting %s: %s",
4203 ldb_errstring(ldb));
4204 talloc_free(tmp_ctx);
4205 return LDB_ERR_OPERATIONS_ERROR;
4207 /* now we continue, which means we
4208 won't remove this backlink
4212 } else if (sa->linkID == 0) {
4213 if (ldb_attr_in_list(preserved_attrs, el->name)) {
4216 if (sa->searchFlags & SEARCH_FLAG_PRESERVEONDELETE) {
4221 * Ensure that we tell the modification to vanish any linked
4222 * attributes (not simply mark them as isDeleted = TRUE)
4224 dsdb_flags |= DSDB_REPLMD_VANISH_LINKS;
4226 ret = ldb_msg_add_empty(msg, el->name, LDB_FLAG_MOD_DELETE, &el);
4227 if (ret != LDB_SUCCESS) {
4228 talloc_free(tmp_ctx);
4229 ldb_module_oom(module);
4236 case OBJECT_DELETED:
4238 * MS-ADTS 3.1.1.5.5.1.2 Deleted-Object Requirements
4239 * describes what must be removed from a deleted
4243 ret = ldb_msg_add_empty(msg, "objectCategory", LDB_FLAG_MOD_REPLACE, NULL);
4244 if (ret != LDB_SUCCESS) {
4245 talloc_free(tmp_ctx);
4246 ldb_module_oom(module);
4250 ret = ldb_msg_add_empty(msg, "sAMAccountType", LDB_FLAG_MOD_REPLACE, NULL);
4251 if (ret != LDB_SUCCESS) {
4252 talloc_free(tmp_ctx);
4253 ldb_module_oom(module);
4263 if (deletion_state == OBJECT_NOT_DELETED) {
4264 const struct dsdb_attribute *sa;
4266 /* work out what the new rdn value is, for updating the
4267 rDN and name fields */
4268 new_rdn_value = ldb_dn_get_rdn_val(new_dn);
4269 if (new_rdn_value == NULL) {
4270 talloc_free(tmp_ctx);
4271 return ldb_operr(ldb);
4274 sa = dsdb_attribute_by_lDAPDisplayName(schema, rdn_name);
4276 talloc_free(tmp_ctx);
4277 return LDB_ERR_OPERATIONS_ERROR;
4280 ret = ldb_msg_add_value(msg, sa->lDAPDisplayName, new_rdn_value,
4282 if (ret != LDB_SUCCESS) {
4283 talloc_free(tmp_ctx);
4286 el->flags = LDB_FLAG_MOD_REPLACE;
4288 el = ldb_msg_find_element(old_msg, "name");
4290 ret = ldb_msg_add_value(msg, "name", new_rdn_value, &el);
4291 if (ret != LDB_SUCCESS) {
4292 talloc_free(tmp_ctx);
4295 el->flags = LDB_FLAG_MOD_REPLACE;
4300 * TODO: Per MS-DRSR 5.160 RemoveObj we should remove links directly, not as an originating update!
4305 * No matter what has happned with other renames, try again to
4306 * get this to be under the deleted DN.
4308 if (strcmp(ldb_dn_get_linearized(old_dn), ldb_dn_get_linearized(new_dn)) != 0) {
4309 /* now rename onto the new DN */
4310 ret = dsdb_module_rename(module, old_dn, new_dn, DSDB_FLAG_NEXT_MODULE, req);
4311 if (ret != LDB_SUCCESS){
4312 DEBUG(0,(__location__ ": Failed to rename object from '%s' to '%s' - %s\n",
4313 ldb_dn_get_linearized(old_dn),
4314 ldb_dn_get_linearized(new_dn),
4315 ldb_errstring(ldb)));
4316 talloc_free(tmp_ctx);
4322 ret = dsdb_module_modify(module, msg, dsdb_flags|DSDB_FLAG_OWN_MODULE, req);
4323 if (ret != LDB_SUCCESS) {
4324 ldb_asprintf_errstring(ldb, "replmd_delete: Failed to modify object %s in delete - %s",
4325 ldb_dn_get_linearized(old_dn), ldb_errstring(ldb));
4326 talloc_free(tmp_ctx);
4330 talloc_free(tmp_ctx);
4332 return ldb_module_done(req, NULL, NULL, LDB_SUCCESS);
4335 static int replmd_delete(struct ldb_module *module, struct ldb_request *req)
4337 return replmd_delete_internals(module, req, false);
4341 static int replmd_replicated_request_error(struct replmd_replicated_request *ar, int ret)
4346 static int replmd_replicated_request_werror(struct replmd_replicated_request *ar, WERROR status)
4348 int ret = LDB_ERR_OTHER;
4349 /* TODO: do some error mapping */
4351 /* Let the caller know the full WERROR */
4352 ar->objs->error = status;
4358 static struct replPropertyMetaData1 *
4359 replmd_replPropertyMetaData1_find_attid(struct replPropertyMetaDataBlob *md_blob,
4360 enum drsuapi_DsAttributeId attid)
4363 struct replPropertyMetaDataCtr1 *rpmd_ctr = &md_blob->ctr.ctr1;
4365 for (i = 0; i < rpmd_ctr->count; i++) {
4366 if (rpmd_ctr->array[i].attid == attid) {
4367 return &rpmd_ctr->array[i];
4375 return true if an update is newer than an existing entry
4376 see section 5.11 of MS-ADTS
4378 static bool replmd_update_is_newer(const struct GUID *current_invocation_id,
4379 const struct GUID *update_invocation_id,
4380 uint32_t current_version,
4381 uint32_t update_version,
4382 NTTIME current_change_time,
4383 NTTIME update_change_time)
4385 if (update_version != current_version) {
4386 return update_version > current_version;
4388 if (update_change_time != current_change_time) {
4389 return update_change_time > current_change_time;
4391 return GUID_compare(update_invocation_id, current_invocation_id) > 0;
4394 static bool replmd_replPropertyMetaData1_is_newer(struct replPropertyMetaData1 *cur_m,
4395 struct replPropertyMetaData1 *new_m)
4397 return replmd_update_is_newer(&cur_m->originating_invocation_id,
4398 &new_m->originating_invocation_id,
4401 cur_m->originating_change_time,
4402 new_m->originating_change_time);
4405 static bool replmd_replPropertyMetaData1_new_should_be_taken(uint32_t dsdb_repl_flags,
4406 struct replPropertyMetaData1 *cur_m,
4407 struct replPropertyMetaData1 *new_m)
4412 * If the new replPropertyMetaData entry for this attribute is
4413 * not provided (this happens in the case where we look for
4414 * ATTID_name, but the name was not changed), then the local
4415 * state is clearly still current, as the remote
4416 * server didn't send it due to being older the high watermark
4419 if (new_m == NULL) {
4423 if (dsdb_repl_flags & DSDB_REPL_FLAG_PRIORITISE_INCOMING) {
4425 * if we compare equal then do an
4426 * update. This is used when a client
4427 * asks for a FULL_SYNC, and can be
4428 * used to recover a corrupt
4431 * This call is a bit tricky, what we
4432 * are doing it turning the 'is_newer'
4433 * call into a 'not is older' by
4434 * swapping cur_m and new_m, and negating the
4437 cmp = !replmd_replPropertyMetaData1_is_newer(new_m,
4440 cmp = replmd_replPropertyMetaData1_is_newer(cur_m,
4450 static struct ldb_dn *replmd_conflict_dn(TALLOC_CTX *mem_ctx, struct ldb_dn *dn, struct GUID *guid)
4452 const struct ldb_val *rdn_val;
4453 const char *rdn_name;
4454 struct ldb_dn *new_dn;
4456 rdn_val = ldb_dn_get_rdn_val(dn);
4457 rdn_name = ldb_dn_get_rdn_name(dn);
4458 if (!rdn_val || !rdn_name) {
4462 new_dn = ldb_dn_copy(mem_ctx, dn);
4467 if (!ldb_dn_remove_child_components(new_dn, 1)) {
4471 if (!ldb_dn_add_child_fmt(new_dn, "%s=%s\\0ACNF:%s",
4473 ldb_dn_escape_value(new_dn, *rdn_val),
4474 GUID_string(new_dn, guid))) {
4483 perform a modify operation which sets the rDN and name attributes to
4484 their current values. This has the effect of changing these
4485 attributes to have been last updated by the current DC. This is
4486 needed to ensure that renames performed as part of conflict
4487 resolution are propogated to other DCs
4489 static int replmd_name_modify(struct replmd_replicated_request *ar,
4490 struct ldb_request *req, struct ldb_dn *dn)
4492 struct ldb_message *msg;
4493 const char *rdn_name;
4494 const struct ldb_val *rdn_val;
4495 const struct dsdb_attribute *rdn_attr;
4498 msg = ldb_msg_new(req);
4504 rdn_name = ldb_dn_get_rdn_name(dn);
4505 if (rdn_name == NULL) {
4509 /* normalize the rdn attribute name */
4510 rdn_attr = dsdb_attribute_by_lDAPDisplayName(ar->schema, rdn_name);
4511 if (rdn_attr == NULL) {
4514 rdn_name = rdn_attr->lDAPDisplayName;
4516 rdn_val = ldb_dn_get_rdn_val(dn);
4517 if (rdn_val == NULL) {
4521 if (ldb_msg_add_empty(msg, rdn_name, LDB_FLAG_MOD_REPLACE, NULL) != 0) {
4524 if (ldb_msg_add_value(msg, rdn_name, rdn_val, NULL) != 0) {
4527 if (ldb_msg_add_empty(msg, "name", LDB_FLAG_MOD_REPLACE, NULL) != 0) {
4530 if (ldb_msg_add_value(msg, "name", rdn_val, NULL) != 0) {
4535 * We have to mark this as a replicated update otherwise
4536 * schema_data may reject a rename in the schema partition
4539 ret = dsdb_module_modify(ar->module, msg,
4540 DSDB_FLAG_OWN_MODULE|DSDB_FLAG_REPLICATED_UPDATE,
4542 if (ret != LDB_SUCCESS) {
4543 DEBUG(0,(__location__ ": Failed to modify rDN/name of DN being DRS renamed '%s' - %s",
4544 ldb_dn_get_linearized(dn),
4545 ldb_errstring(ldb_module_get_ctx(ar->module))));
4555 DEBUG(0,(__location__ ": Failed to setup modify rDN/name of DN being DRS renamed '%s'",
4556 ldb_dn_get_linearized(dn)));
4557 return LDB_ERR_OPERATIONS_ERROR;
4562 callback for conflict DN handling where we have renamed the incoming
4563 record. After renaming it, we need to ensure the change of name and
4564 rDN for the incoming record is seen as an originating update by this DC.
4566 This also handles updating lastKnownParent for entries sent to lostAndFound
4568 static int replmd_op_name_modify_callback(struct ldb_request *req, struct ldb_reply *ares)
4570 struct replmd_replicated_request *ar =
4571 talloc_get_type_abort(req->context, struct replmd_replicated_request);
4572 struct ldb_dn *conflict_dn = NULL;
4575 if (ares->error != LDB_SUCCESS) {
4576 /* call the normal callback for everything except success */
4577 return replmd_op_callback(req, ares);
4580 switch (req->operation) {
4582 conflict_dn = req->op.add.message->dn;
4585 conflict_dn = req->op.mod.message->dn;
4588 smb_panic("replmd_op_name_modify_callback called in unknown circumstances");
4591 /* perform a modify of the rDN and name of the record */
4592 ret = replmd_name_modify(ar, req, conflict_dn);
4593 if (ret != LDB_SUCCESS) {
4595 return replmd_op_callback(req, ares);
4598 if (ar->objs->objects[ar->index_current].last_known_parent) {
4599 struct ldb_message *msg = ldb_msg_new(req);
4601 ldb_module_oom(ar->module);
4602 return LDB_ERR_OPERATIONS_ERROR;
4605 msg->dn = req->op.add.message->dn;
4607 ret = ldb_msg_add_steal_string(msg, "lastKnownParent",
4608 ldb_dn_get_extended_linearized(msg, ar->objs->objects[ar->index_current].last_known_parent, 1));
4609 if (ret != LDB_SUCCESS) {
4610 DEBUG(0,(__location__ ": Failed to add lastKnownParent string to the msg\n"));
4611 ldb_module_oom(ar->module);
4614 msg->elements[0].flags = LDB_FLAG_MOD_REPLACE;
4616 ret = dsdb_module_modify(ar->module, msg, DSDB_FLAG_OWN_MODULE, req);
4617 if (ret != LDB_SUCCESS) {
4618 DEBUG(0,(__location__ ": Failed to modify lastKnownParent of lostAndFound DN '%s' - %s",
4619 ldb_dn_get_linearized(msg->dn),
4620 ldb_errstring(ldb_module_get_ctx(ar->module))));
4626 return replmd_op_callback(req, ares);
4630 callback for replmd_replicated_apply_add()
4631 This copes with the creation of conflict records in the case where
4632 the DN exists, but with a different objectGUID
4634 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))
4636 struct ldb_dn *conflict_dn;
4637 struct replmd_replicated_request *ar =
4638 talloc_get_type_abort(req->context, struct replmd_replicated_request);
4639 struct ldb_result *res;
4640 const char *attrs[] = { "replPropertyMetaData", "objectGUID", NULL };
4642 const struct ldb_val *omd_value;
4643 struct replPropertyMetaDataBlob omd, *rmd;
4644 enum ndr_err_code ndr_err;
4645 bool rename_incoming_record, rodc;
4646 struct replPropertyMetaData1 *rmd_name, *omd_name;
4647 struct ldb_message *msg;
4648 struct ldb_request *down_req = NULL;
4650 /* call the normal callback for success */
4651 if (ares->error == LDB_SUCCESS) {
4652 return callback(req, ares);
4656 * we have a conflict, and need to decide if we will keep the
4657 * new record or the old record
4660 msg = ar->objs->objects[ar->index_current].msg;
4661 conflict_dn = msg->dn;
4663 /* For failures other than conflicts, fail the whole operation here */
4664 if (ares->error != LDB_ERR_ENTRY_ALREADY_EXISTS) {
4665 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module), "Failed to locally apply remote add of %s: %s",
4666 ldb_dn_get_linearized(conflict_dn),
4667 ldb_errstring(ldb_module_get_ctx(ar->module)));
4669 return ldb_module_done(ar->req, NULL, NULL,
4670 LDB_ERR_OPERATIONS_ERROR);
4673 ret = samdb_rodc(ldb_module_get_ctx(ar->module), &rodc);
4674 if (ret != LDB_SUCCESS) {
4675 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)));
4676 return ldb_module_done(ar->req, NULL, NULL,
4677 LDB_ERR_OPERATIONS_ERROR);
4683 * We are on an RODC, or were a GC for this
4684 * partition, so we have to fail this until
4685 * someone who owns the partition sorts it
4688 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
4689 "Conflict adding object '%s' from incoming replication as we are read only for the partition. \n"
4690 " - We must fail the operation until a master for this partition resolves the conflict",
4691 ldb_dn_get_linearized(conflict_dn));
4696 * first we need the replPropertyMetaData attribute from the
4697 * local, conflicting record
4699 ret = dsdb_module_search_dn(ar->module, req, &res, conflict_dn,
4701 DSDB_FLAG_NEXT_MODULE |
4702 DSDB_SEARCH_SHOW_DELETED |
4703 DSDB_SEARCH_SHOW_RECYCLED, req);
4704 if (ret != LDB_SUCCESS) {
4705 DEBUG(0,(__location__ ": Unable to find object for conflicting record '%s'\n",
4706 ldb_dn_get_linearized(conflict_dn)));
4710 omd_value = ldb_msg_find_ldb_val(res->msgs[0], "replPropertyMetaData");
4711 if (omd_value == NULL) {
4712 DEBUG(0,(__location__ ": Unable to find replPropertyMetaData for conflicting record '%s'\n",
4713 ldb_dn_get_linearized(conflict_dn)));
4717 ndr_err = ndr_pull_struct_blob(omd_value, res->msgs[0], &omd,
4718 (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
4719 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
4720 DEBUG(0,(__location__ ": Failed to parse old replPropertyMetaData for %s\n",
4721 ldb_dn_get_linearized(conflict_dn)));
4725 rmd = ar->objs->objects[ar->index_current].meta_data;
4728 * we decide which is newer based on the RPMD on the name
4729 * attribute. See [MS-DRSR] ResolveNameConflict.
4731 * We expect omd_name to be present, as this is from a local
4732 * search, but while rmd_name should have been given to us by
4733 * the remote server, if it is missing we just prefer the
4735 * replmd_replPropertyMetaData1_new_should_be_taken()
4737 rmd_name = replmd_replPropertyMetaData1_find_attid(rmd, DRSUAPI_ATTID_name);
4738 omd_name = replmd_replPropertyMetaData1_find_attid(&omd, DRSUAPI_ATTID_name);
4740 DEBUG(0,(__location__ ": Failed to find name attribute in local LDB replPropertyMetaData for %s\n",
4741 ldb_dn_get_linearized(conflict_dn)));
4746 * Should we preserve the current record, and so rename the
4747 * incoming record to be a conflict?
4749 rename_incoming_record
4750 = !replmd_replPropertyMetaData1_new_should_be_taken(ar->objs->dsdb_repl_flags & DSDB_REPL_FLAG_PRIORITISE_INCOMING,
4751 omd_name, rmd_name);
4753 if (rename_incoming_record) {
4755 struct ldb_dn *new_dn;
4757 guid = samdb_result_guid(msg, "objectGUID");
4758 if (GUID_all_zero(&guid)) {
4759 DEBUG(0,(__location__ ": Failed to find objectGUID for conflicting incoming record %s\n",
4760 ldb_dn_get_linearized(conflict_dn)));
4763 new_dn = replmd_conflict_dn(req, conflict_dn, &guid);
4764 if (new_dn == NULL) {
4765 DEBUG(0,(__location__ ": Failed to form conflict DN for %s\n",
4766 ldb_dn_get_linearized(conflict_dn)));
4770 DEBUG(2,(__location__ ": Resolving conflict record via incoming rename '%s' -> '%s'\n",
4771 ldb_dn_get_linearized(conflict_dn), ldb_dn_get_linearized(new_dn)));
4773 /* re-submit the request, but with the new DN */
4774 callback = replmd_op_name_modify_callback;
4777 /* we are renaming the existing record */
4779 struct ldb_dn *new_dn;
4781 guid = samdb_result_guid(res->msgs[0], "objectGUID");
4782 if (GUID_all_zero(&guid)) {
4783 DEBUG(0,(__location__ ": Failed to find objectGUID for existing conflict record %s\n",
4784 ldb_dn_get_linearized(conflict_dn)));
4788 new_dn = replmd_conflict_dn(req, conflict_dn, &guid);
4789 if (new_dn == NULL) {
4790 DEBUG(0,(__location__ ": Failed to form conflict DN for %s\n",
4791 ldb_dn_get_linearized(conflict_dn)));
4795 DEBUG(2,(__location__ ": Resolving conflict record via existing-record rename '%s' -> '%s'\n",
4796 ldb_dn_get_linearized(conflict_dn), ldb_dn_get_linearized(new_dn)));
4798 ret = dsdb_module_rename(ar->module, conflict_dn, new_dn,
4799 DSDB_FLAG_OWN_MODULE, req);
4800 if (ret != LDB_SUCCESS) {
4801 DEBUG(0,(__location__ ": Failed to rename conflict dn '%s' to '%s' - %s\n",
4802 ldb_dn_get_linearized(conflict_dn),
4803 ldb_dn_get_linearized(new_dn),
4804 ldb_errstring(ldb_module_get_ctx(ar->module))));
4809 * now we need to ensure that the rename is seen as an
4810 * originating update. We do that with a modify.
4812 ret = replmd_name_modify(ar, req, new_dn);
4813 if (ret != LDB_SUCCESS) {
4817 DEBUG(2,(__location__ ": With conflicting record renamed, re-apply replicated creation of '%s'\n",
4818 ldb_dn_get_linearized(req->op.add.message->dn)));
4821 ret = ldb_build_add_req(&down_req,
4822 ldb_module_get_ctx(ar->module),
4829 if (ret != LDB_SUCCESS) {
4832 LDB_REQ_SET_LOCATION(down_req);
4834 /* current partition control needed by "repmd_op_callback" */
4835 ret = ldb_request_add_control(down_req,
4836 DSDB_CONTROL_CURRENT_PARTITION_OID,
4838 if (ret != LDB_SUCCESS) {
4839 return replmd_replicated_request_error(ar, ret);
4842 if (ar->objs->dsdb_repl_flags & DSDB_REPL_FLAG_PARTIAL_REPLICA) {
4843 /* this tells the partition module to make it a
4844 partial replica if creating an NC */
4845 ret = ldb_request_add_control(down_req,
4846 DSDB_CONTROL_PARTIAL_REPLICA,
4848 if (ret != LDB_SUCCESS) {
4849 return replmd_replicated_request_error(ar, ret);
4854 * Finally we re-run the add, otherwise the new record won't
4855 * exist, as we are here because of that exact failure!
4857 return ldb_next_request(ar->module, down_req);
4860 /* on failure make the caller get the error. This means
4861 * replication will stop with an error, but there is not much
4864 return ldb_module_done(ar->req, NULL, NULL,
4869 callback for replmd_replicated_apply_add()
4870 This copes with the creation of conflict records in the case where
4871 the DN exists, but with a different objectGUID
4873 static int replmd_op_add_callback(struct ldb_request *req, struct ldb_reply *ares)
4875 struct replmd_replicated_request *ar =
4876 talloc_get_type_abort(req->context, struct replmd_replicated_request);
4878 if (ar->objs->objects[ar->index_current].last_known_parent) {
4879 /* This is like a conflict DN, where we put the object in LostAndFound
4880 see MS-DRSR 4.1.10.6.10 FindBestParentObject */
4881 return replmd_op_possible_conflict_callback(req, ares, replmd_op_name_modify_callback);
4884 return replmd_op_possible_conflict_callback(req, ares, replmd_op_callback);
4888 this is called when a new object comes in over DRS
4890 static int replmd_replicated_apply_add(struct replmd_replicated_request *ar)
4892 struct ldb_context *ldb;
4893 struct ldb_request *change_req;
4894 enum ndr_err_code ndr_err;
4895 struct ldb_message *msg;
4896 struct replPropertyMetaDataBlob *md;
4897 struct ldb_val md_value;
4900 bool remote_isDeleted = false;
4903 time_t t = time(NULL);
4904 const struct ldb_val *rdn_val;
4905 struct replmd_private *replmd_private =
4906 talloc_get_type(ldb_module_get_private(ar->module),
4907 struct replmd_private);
4908 unix_to_nt_time(&now, t);
4910 ldb = ldb_module_get_ctx(ar->module);
4911 msg = ar->objs->objects[ar->index_current].msg;
4912 md = ar->objs->objects[ar->index_current].meta_data;
4913 is_schema_nc = ldb_dn_compare_base(replmd_private->schema_dn, msg->dn) == 0;
4915 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &ar->seq_num);
4916 if (ret != LDB_SUCCESS) {
4917 return replmd_replicated_request_error(ar, ret);
4920 ret = dsdb_msg_add_guid(msg,
4921 &ar->objs->objects[ar->index_current].object_guid,
4923 if (ret != LDB_SUCCESS) {
4924 return replmd_replicated_request_error(ar, ret);
4927 ret = ldb_msg_add_string(msg, "whenChanged", ar->objs->objects[ar->index_current].when_changed);
4928 if (ret != LDB_SUCCESS) {
4929 return replmd_replicated_request_error(ar, ret);
4932 ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNCreated", ar->seq_num);
4933 if (ret != LDB_SUCCESS) {
4934 return replmd_replicated_request_error(ar, ret);
4937 ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNChanged", ar->seq_num);
4938 if (ret != LDB_SUCCESS) {
4939 return replmd_replicated_request_error(ar, ret);
4942 /* remove any message elements that have zero values */
4943 for (i=0; i<msg->num_elements; i++) {
4944 struct ldb_message_element *el = &msg->elements[i];
4946 if (el->num_values == 0) {
4947 if (ldb_attr_cmp(msg->elements[i].name, "objectClass") == 0) {
4948 ldb_asprintf_errstring(ldb, __location__
4949 ": empty objectClass sent on %s, aborting replication\n",
4950 ldb_dn_get_linearized(msg->dn));
4951 return replmd_replicated_request_error(ar, LDB_ERR_OBJECT_CLASS_VIOLATION);
4954 DEBUG(4,(__location__ ": Removing attribute %s with num_values==0\n",
4956 memmove(el, el+1, sizeof(*el)*(msg->num_elements - (i+1)));
4957 msg->num_elements--;
4964 struct GUID_txt_buf guid_txt;
4966 char *s = ldb_ldif_message_string(ldb, ar, LDB_CHANGETYPE_ADD, msg);
4967 DEBUG(4, ("DRS replication add message of %s:\n%s\n",
4968 GUID_buf_string(&ar->objs->objects[ar->index_current].object_guid, &guid_txt),
4973 remote_isDeleted = ldb_msg_find_attr_as_bool(msg,
4974 "isDeleted", false);
4977 * the meta data array is already sorted by the caller, except
4978 * for the RDN, which needs to be added.
4982 rdn_val = ldb_dn_get_rdn_val(msg->dn);
4983 ret = replmd_update_rpmd_rdn_attr(ldb, msg, rdn_val, NULL,
4984 md, ar, now, is_schema_nc,
4986 if (ret != LDB_SUCCESS) {
4987 ldb_asprintf_errstring(ldb, "%s: error during DRS repl ADD: %s", __func__, ldb_errstring(ldb));
4988 return replmd_replicated_request_error(ar, ret);
4991 ret = replmd_replPropertyMetaDataCtr1_sort_and_verify(ldb, &md->ctr.ctr1, msg->dn);
4992 if (ret != LDB_SUCCESS) {
4993 ldb_asprintf_errstring(ldb, "%s: error during DRS repl ADD: %s", __func__, ldb_errstring(ldb));
4994 return replmd_replicated_request_error(ar, ret);
4997 for (i=0; i < md->ctr.ctr1.count; i++) {
4998 md->ctr.ctr1.array[i].local_usn = ar->seq_num;
5000 ndr_err = ndr_push_struct_blob(&md_value, msg, md,
5001 (ndr_push_flags_fn_t)ndr_push_replPropertyMetaDataBlob);
5002 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
5003 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
5004 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
5006 ret = ldb_msg_add_value(msg, "replPropertyMetaData", &md_value, NULL);
5007 if (ret != LDB_SUCCESS) {
5008 return replmd_replicated_request_error(ar, ret);
5011 replmd_ldb_message_sort(msg, ar->schema);
5013 if (!remote_isDeleted) {
5014 ret = dsdb_module_schedule_sd_propagation(ar->module,
5015 ar->objs->partition_dn,
5017 if (ret != LDB_SUCCESS) {
5018 return replmd_replicated_request_error(ar, ret);
5022 ar->isDeleted = remote_isDeleted;
5024 ret = ldb_build_add_req(&change_req,
5030 replmd_op_add_callback,
5032 LDB_REQ_SET_LOCATION(change_req);
5033 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
5035 /* current partition control needed by "repmd_op_callback" */
5036 ret = ldb_request_add_control(change_req,
5037 DSDB_CONTROL_CURRENT_PARTITION_OID,
5039 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
5041 if (ar->objs->dsdb_repl_flags & DSDB_REPL_FLAG_PARTIAL_REPLICA) {
5042 /* this tells the partition module to make it a
5043 partial replica if creating an NC */
5044 ret = ldb_request_add_control(change_req,
5045 DSDB_CONTROL_PARTIAL_REPLICA,
5047 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
5050 return ldb_next_request(ar->module, change_req);
5053 static int replmd_replicated_apply_search_for_parent_callback(struct ldb_request *req,
5054 struct ldb_reply *ares)
5056 struct replmd_replicated_request *ar = talloc_get_type(req->context,
5057 struct replmd_replicated_request);
5061 return ldb_module_done(ar->req, NULL, NULL,
5062 LDB_ERR_OPERATIONS_ERROR);
5066 * The error NO_SUCH_OBJECT is not expected, unless the search
5067 * base is the partition DN, and that case doesn't happen here
5068 * because then we wouldn't get a parent_guid_value in any
5071 if (ares->error != LDB_SUCCESS) {
5072 return ldb_module_done(ar->req, ares->controls,
5073 ares->response, ares->error);
5076 switch (ares->type) {
5077 case LDB_REPLY_ENTRY:
5079 struct ldb_message *parent_msg = ares->message;
5080 struct ldb_message *msg = ar->objs->objects[ar->index_current].msg;
5081 struct ldb_dn *parent_dn;
5084 if (!ldb_msg_check_string_attribute(msg, "isDeleted", "TRUE")
5085 && ldb_msg_check_string_attribute(parent_msg, "isDeleted", "TRUE")) {
5086 /* Per MS-DRSR 4.1.10.6.10
5087 * FindBestParentObject we need to move this
5088 * new object under a deleted object to
5090 struct ldb_dn *nc_root;
5092 ret = dsdb_find_nc_root(ldb_module_get_ctx(ar->module), msg, msg->dn, &nc_root);
5093 if (ret == LDB_ERR_NO_SUCH_OBJECT) {
5094 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
5095 "No suitable NC root found for %s. "
5096 "We need to move this object because parent object %s "
5097 "is deleted, but this object is not.",
5098 ldb_dn_get_linearized(msg->dn),
5099 ldb_dn_get_linearized(parent_msg->dn));
5100 return ldb_module_done(ar->req, NULL, NULL, LDB_ERR_OPERATIONS_ERROR);
5101 } else if (ret != LDB_SUCCESS) {
5102 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
5103 "Unable to find NC root for %s: %s. "
5104 "We need to move this object because parent object %s "
5105 "is deleted, but this object is not.",
5106 ldb_dn_get_linearized(msg->dn),
5107 ldb_errstring(ldb_module_get_ctx(ar->module)),
5108 ldb_dn_get_linearized(parent_msg->dn));
5109 return ldb_module_done(ar->req, NULL, NULL, LDB_ERR_OPERATIONS_ERROR);
5112 ret = dsdb_wellknown_dn(ldb_module_get_ctx(ar->module), msg,
5114 DS_GUID_LOSTANDFOUND_CONTAINER,
5116 if (ret != LDB_SUCCESS) {
5117 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
5118 "Unable to find LostAndFound Container for %s "
5119 "in partition %s: %s. "
5120 "We need to move this object because parent object %s "
5121 "is deleted, but this object is not.",
5122 ldb_dn_get_linearized(msg->dn), ldb_dn_get_linearized(nc_root),
5123 ldb_errstring(ldb_module_get_ctx(ar->module)),
5124 ldb_dn_get_linearized(parent_msg->dn));
5125 return ldb_module_done(ar->req, NULL, NULL, LDB_ERR_OPERATIONS_ERROR);
5127 ar->objs->objects[ar->index_current].last_known_parent
5128 = talloc_steal(ar->objs->objects[ar->index_current].msg, parent_msg->dn);
5132 = talloc_steal(ar->objs->objects[ar->index_current].msg, parent_msg->dn);
5135 ar->objs->objects[ar->index_current].local_parent_dn = parent_dn;
5137 comp_num = ldb_dn_get_comp_num(msg->dn);
5139 if (!ldb_dn_remove_base_components(msg->dn, comp_num - 1)) {
5141 return ldb_module_done(ar->req, NULL, NULL, ldb_module_operr(ar->module));
5144 if (!ldb_dn_add_base(msg->dn, parent_dn)) {
5146 return ldb_module_done(ar->req, NULL, NULL, ldb_module_operr(ar->module));
5150 case LDB_REPLY_REFERRAL:
5151 /* we ignore referrals */
5154 case LDB_REPLY_DONE:
5156 if (ar->objs->objects[ar->index_current].local_parent_dn == NULL) {
5157 struct GUID_txt_buf str_buf;
5158 if (ar->search_msg != NULL) {
5159 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
5160 "No parent with GUID %s found for object locally known as %s",
5161 GUID_buf_string(ar->objs->objects[ar->index_current].parent_guid, &str_buf),
5162 ldb_dn_get_linearized(ar->search_msg->dn));
5164 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
5165 "No parent with GUID %s found for object remotely known as %s",
5166 GUID_buf_string(ar->objs->objects[ar->index_current].parent_guid, &str_buf),
5167 ldb_dn_get_linearized(ar->objs->objects[ar->index_current].msg->dn));
5171 * This error code is really important, as it
5172 * is the flag back to the callers to retry
5173 * this with DRSUAPI_DRS_GET_ANC, and so get
5174 * the parent objects before the child
5177 return ldb_module_done(ar->req, NULL, NULL,
5178 replmd_replicated_request_werror(ar, WERR_DS_DRA_MISSING_PARENT));
5181 if (ar->search_msg != NULL) {
5182 ret = replmd_replicated_apply_merge(ar);
5184 ret = replmd_replicated_apply_add(ar);
5186 if (ret != LDB_SUCCESS) {
5187 return ldb_module_done(ar->req, NULL, NULL, ret);
5196 * Look for the parent object, so we put the new object in the right
5197 * place This is akin to NameObject in MS-DRSR - this routine and the
5198 * callbacks find the right parent name, and correct name for this
5202 static int replmd_replicated_apply_search_for_parent(struct replmd_replicated_request *ar)
5204 struct ldb_context *ldb;
5208 struct ldb_request *search_req;
5209 static const char *attrs[] = {"isDeleted", NULL};
5210 struct GUID_txt_buf guid_str_buf;
5212 ldb = ldb_module_get_ctx(ar->module);
5214 if (ar->objs->objects[ar->index_current].parent_guid == NULL) {
5215 if (ar->search_msg != NULL) {
5216 return replmd_replicated_apply_merge(ar);
5218 return replmd_replicated_apply_add(ar);
5222 tmp_str = GUID_buf_string(ar->objs->objects[ar->index_current].parent_guid,
5225 filter = talloc_asprintf(ar, "(objectGUID=%s)", tmp_str);
5226 if (!filter) return replmd_replicated_request_werror(ar, WERR_NOT_ENOUGH_MEMORY);
5228 ret = ldb_build_search_req(&search_req,
5231 ar->objs->partition_dn,
5237 replmd_replicated_apply_search_for_parent_callback,
5239 LDB_REQ_SET_LOCATION(search_req);
5241 ret = dsdb_request_add_controls(search_req,
5242 DSDB_SEARCH_SHOW_RECYCLED|
5243 DSDB_SEARCH_SHOW_DELETED|
5244 DSDB_SEARCH_SHOW_EXTENDED_DN);
5245 if (ret != LDB_SUCCESS) {
5249 return ldb_next_request(ar->module, search_req);
5253 handle renames that come in over DRS replication
5255 static int replmd_replicated_handle_rename(struct replmd_replicated_request *ar,
5256 struct ldb_message *msg,
5257 struct ldb_request *parent,
5261 TALLOC_CTX *tmp_ctx = talloc_new(msg);
5262 struct ldb_result *res;
5263 struct ldb_dn *conflict_dn;
5264 const char *attrs[] = { "replPropertyMetaData", "objectGUID", NULL };
5265 const struct ldb_val *omd_value;
5266 struct replPropertyMetaDataBlob omd, *rmd;
5267 enum ndr_err_code ndr_err;
5268 bool rename_incoming_record, rodc;
5269 struct replPropertyMetaData1 *rmd_name, *omd_name;
5270 struct ldb_dn *new_dn;
5273 DEBUG(4,("replmd_replicated_request rename %s => %s\n",
5274 ldb_dn_get_linearized(ar->search_msg->dn),
5275 ldb_dn_get_linearized(msg->dn)));
5278 ret = dsdb_module_rename(ar->module, ar->search_msg->dn, msg->dn,
5279 DSDB_FLAG_NEXT_MODULE, ar->req);
5280 if (ret == LDB_SUCCESS) {
5281 talloc_free(tmp_ctx);
5286 if (ret != LDB_ERR_ENTRY_ALREADY_EXISTS) {
5287 talloc_free(tmp_ctx);
5288 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module), "Failed to locally apply remote rename from %s to %s: %s",
5289 ldb_dn_get_linearized(ar->search_msg->dn),
5290 ldb_dn_get_linearized(msg->dn),
5291 ldb_errstring(ldb_module_get_ctx(ar->module)));
5295 ret = samdb_rodc(ldb_module_get_ctx(ar->module), &rodc);
5296 if (ret != LDB_SUCCESS) {
5297 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
5298 "Failed to determine if we are an RODC when attempting to form conflict DN: %s",
5299 ldb_errstring(ldb_module_get_ctx(ar->module)));
5300 return LDB_ERR_OPERATIONS_ERROR;
5303 * we have a conflict, and need to decide if we will keep the
5304 * new record or the old record
5307 conflict_dn = msg->dn;
5311 * We are on an RODC, or were a GC for this
5312 * partition, so we have to fail this until
5313 * someone who owns the partition sorts it
5316 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
5317 "Conflict adding object '%s' from incoming replication but we are read only for the partition. \n"
5318 " - We must fail the operation until a master for this partition resolves the conflict",
5319 ldb_dn_get_linearized(conflict_dn));
5324 * first we need the replPropertyMetaData attribute from the
5327 ret = dsdb_module_search_dn(ar->module, tmp_ctx, &res, conflict_dn,
5329 DSDB_FLAG_NEXT_MODULE |
5330 DSDB_SEARCH_SHOW_DELETED |
5331 DSDB_SEARCH_SHOW_RECYCLED, ar->req);
5332 if (ret != LDB_SUCCESS) {
5333 DEBUG(0,(__location__ ": Unable to find object for conflicting record '%s'\n",
5334 ldb_dn_get_linearized(conflict_dn)));
5338 omd_value = ldb_msg_find_ldb_val(res->msgs[0], "replPropertyMetaData");
5339 if (omd_value == NULL) {
5340 DEBUG(0,(__location__ ": Unable to find replPropertyMetaData for conflicting record '%s'\n",
5341 ldb_dn_get_linearized(conflict_dn)));
5345 ndr_err = ndr_pull_struct_blob(omd_value, res->msgs[0], &omd,
5346 (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
5347 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
5348 DEBUG(0,(__location__ ": Failed to parse old replPropertyMetaData for %s\n",
5349 ldb_dn_get_linearized(conflict_dn)));
5353 rmd = ar->objs->objects[ar->index_current].meta_data;
5356 * we decide which is newer based on the RPMD on the name
5357 * attribute. See [MS-DRSR] ResolveNameConflict.
5359 * We expect omd_name to be present, as this is from a local
5360 * search, but while rmd_name should have been given to us by
5361 * the remote server, if it is missing we just prefer the
5363 * replmd_replPropertyMetaData1_new_should_be_taken()
5365 rmd_name = replmd_replPropertyMetaData1_find_attid(rmd, DRSUAPI_ATTID_name);
5366 omd_name = replmd_replPropertyMetaData1_find_attid(&omd, DRSUAPI_ATTID_name);
5368 DEBUG(0,(__location__ ": Failed to find name attribute in local LDB replPropertyMetaData for %s\n",
5369 ldb_dn_get_linearized(conflict_dn)));
5374 * Should we preserve the current record, and so rename the
5375 * incoming record to be a conflict?
5377 rename_incoming_record =
5378 !replmd_replPropertyMetaData1_new_should_be_taken(
5379 ar->objs->dsdb_repl_flags & DSDB_REPL_FLAG_PRIORITISE_INCOMING,
5380 omd_name, rmd_name);
5382 if (rename_incoming_record) {
5384 new_dn = replmd_conflict_dn(msg, msg->dn,
5385 &ar->objs->objects[ar->index_current].object_guid);
5386 if (new_dn == NULL) {
5387 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
5388 "Failed to form conflict DN for %s\n",
5389 ldb_dn_get_linearized(msg->dn));
5391 return replmd_replicated_request_werror(ar, WERR_NOT_ENOUGH_MEMORY);
5394 ret = dsdb_module_rename(ar->module, ar->search_msg->dn, new_dn,
5395 DSDB_FLAG_NEXT_MODULE, ar->req);
5396 if (ret != LDB_SUCCESS) {
5397 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
5398 "Failed to rename incoming conflicting dn '%s' (was '%s') to '%s' - %s\n",
5399 ldb_dn_get_linearized(conflict_dn),
5400 ldb_dn_get_linearized(ar->search_msg->dn),
5401 ldb_dn_get_linearized(new_dn),
5402 ldb_errstring(ldb_module_get_ctx(ar->module)));
5403 return replmd_replicated_request_werror(ar, WERR_DS_DRA_DB_ERROR);
5411 /* we are renaming the existing record */
5413 guid = samdb_result_guid(res->msgs[0], "objectGUID");
5414 if (GUID_all_zero(&guid)) {
5415 DEBUG(0,(__location__ ": Failed to find objectGUID for existing conflict record %s\n",
5416 ldb_dn_get_linearized(conflict_dn)));
5420 new_dn = replmd_conflict_dn(tmp_ctx, conflict_dn, &guid);
5421 if (new_dn == NULL) {
5422 DEBUG(0,(__location__ ": Failed to form conflict DN for %s\n",
5423 ldb_dn_get_linearized(conflict_dn)));
5427 DEBUG(2,(__location__ ": Resolving conflict record via existing-record rename '%s' -> '%s'\n",
5428 ldb_dn_get_linearized(conflict_dn), ldb_dn_get_linearized(new_dn)));
5430 ret = dsdb_module_rename(ar->module, conflict_dn, new_dn,
5431 DSDB_FLAG_OWN_MODULE, ar->req);
5432 if (ret != LDB_SUCCESS) {
5433 DEBUG(0,(__location__ ": Failed to rename conflict dn '%s' to '%s' - %s\n",
5434 ldb_dn_get_linearized(conflict_dn),
5435 ldb_dn_get_linearized(new_dn),
5436 ldb_errstring(ldb_module_get_ctx(ar->module))));
5441 * now we need to ensure that the rename is seen as an
5442 * originating update. We do that with a modify.
5444 ret = replmd_name_modify(ar, ar->req, new_dn);
5445 if (ret != LDB_SUCCESS) {
5449 DEBUG(2,(__location__ ": With conflicting record renamed, re-apply replicated rename '%s' -> '%s'\n",
5450 ldb_dn_get_linearized(ar->search_msg->dn),
5451 ldb_dn_get_linearized(msg->dn)));
5454 ret = dsdb_module_rename(ar->module, ar->search_msg->dn, msg->dn,
5455 DSDB_FLAG_NEXT_MODULE, ar->req);
5456 if (ret != LDB_SUCCESS) {
5457 DEBUG(0,(__location__ ": After conflict resolution, failed to rename dn '%s' to '%s' - %s\n",
5458 ldb_dn_get_linearized(ar->search_msg->dn),
5459 ldb_dn_get_linearized(msg->dn),
5460 ldb_errstring(ldb_module_get_ctx(ar->module))));
5466 * On failure make the caller get the error
5467 * This means replication will stop with an error,
5468 * but there is not much else we can do. In the
5469 * LDB_ERR_ENTRY_ALREADY_EXISTS case this is exactly what is
5473 talloc_free(tmp_ctx);
5478 static int replmd_replicated_apply_merge(struct replmd_replicated_request *ar)
5480 struct ldb_context *ldb;
5481 struct ldb_request *change_req;
5482 enum ndr_err_code ndr_err;
5483 struct ldb_message *msg;
5484 struct replPropertyMetaDataBlob *rmd;
5485 struct replPropertyMetaDataBlob omd;
5486 const struct ldb_val *omd_value;
5487 struct replPropertyMetaDataBlob nmd;
5488 struct ldb_val nmd_value;
5489 struct GUID remote_parent_guid;
5492 unsigned int removed_attrs = 0;
5494 int (*callback)(struct ldb_request *req, struct ldb_reply *ares) = replmd_op_callback;
5495 bool isDeleted = false;
5496 bool local_isDeleted = false;
5497 bool remote_isDeleted = false;
5498 bool take_remote_isDeleted = false;
5499 bool sd_updated = false;
5500 bool renamed = false;
5501 bool is_schema_nc = false;
5503 const struct ldb_val *old_rdn, *new_rdn;
5504 struct replmd_private *replmd_private =
5505 talloc_get_type(ldb_module_get_private(ar->module),
5506 struct replmd_private);
5508 time_t t = time(NULL);
5509 unix_to_nt_time(&now, t);
5511 ldb = ldb_module_get_ctx(ar->module);
5512 msg = ar->objs->objects[ar->index_current].msg;
5514 is_schema_nc = ldb_dn_compare_base(replmd_private->schema_dn, msg->dn) == 0;
5516 rmd = ar->objs->objects[ar->index_current].meta_data;
5520 /* find existing meta data */
5521 omd_value = ldb_msg_find_ldb_val(ar->search_msg, "replPropertyMetaData");
5523 ndr_err = ndr_pull_struct_blob(omd_value, ar, &omd,
5524 (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
5525 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
5526 nt_status = ndr_map_error2ntstatus(ndr_err);
5527 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
5530 if (omd.version != 1) {
5531 return replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
5536 struct GUID_txt_buf guid_txt;
5538 char *s = ldb_ldif_message_string(ldb, ar, LDB_CHANGETYPE_MODIFY, msg);
5539 DEBUG(5, ("Initial DRS replication modify message of %s is:\n%s\n"
5542 GUID_buf_string(&ar->objs->objects[ar->index_current].object_guid, &guid_txt),
5544 ndr_print_struct_string(s,
5545 (ndr_print_fn_t)ndr_print_replPropertyMetaDataBlob,
5546 "existing replPropertyMetaData",
5548 ndr_print_struct_string(s,
5549 (ndr_print_fn_t)ndr_print_replPropertyMetaDataBlob,
5550 "incoming replPropertyMetaData",
5555 local_isDeleted = ldb_msg_find_attr_as_bool(ar->search_msg,
5556 "isDeleted", false);
5557 remote_isDeleted = ldb_msg_find_attr_as_bool(msg,
5558 "isDeleted", false);
5561 * Fill in the remote_parent_guid with the GUID or an all-zero
5564 if (ar->objs->objects[ar->index_current].parent_guid != NULL) {
5565 remote_parent_guid = *ar->objs->objects[ar->index_current].parent_guid;
5567 remote_parent_guid = GUID_zero();
5571 * To ensure we follow a complex rename chain around, we have
5572 * to confirm that the DN is the same (mostly to confirm the
5573 * RDN) and the parentGUID is the same.
5575 * This ensures we keep things under the correct parent, which
5576 * replmd_replicated_handle_rename() will do.
5579 if (strcmp(ldb_dn_get_linearized(msg->dn), ldb_dn_get_linearized(ar->search_msg->dn)) == 0
5580 && GUID_equal(&remote_parent_guid, &ar->local_parent_guid)) {
5584 * handle renames, even just by case that come in over
5585 * DRS. Changes in the parent DN don't hit us here,
5586 * because the search for a parent will clean up those
5589 * We also have already filtered out the case where
5590 * the peer has an older name to what we have (see
5591 * replmd_replicated_apply_search_callback())
5593 ret = replmd_replicated_handle_rename(ar, msg, ar->req, &renamed);
5596 if (ret != LDB_SUCCESS) {
5597 ldb_debug(ldb, LDB_DEBUG_FATAL,
5598 "replmd_replicated_request rename %s => %s failed - %s\n",
5599 ldb_dn_get_linearized(ar->search_msg->dn),
5600 ldb_dn_get_linearized(msg->dn),
5601 ldb_errstring(ldb));
5602 return replmd_replicated_request_werror(ar, WERR_DS_DRA_DB_ERROR);
5605 if (renamed == true) {
5607 * Set the callback to one that will fix up the name
5608 * metadata on the new conflict DN
5610 callback = replmd_op_name_modify_callback;
5615 nmd.ctr.ctr1.count = omd.ctr.ctr1.count + rmd->ctr.ctr1.count;
5616 nmd.ctr.ctr1.array = talloc_array(ar,
5617 struct replPropertyMetaData1,
5618 nmd.ctr.ctr1.count);
5619 if (!nmd.ctr.ctr1.array) return replmd_replicated_request_werror(ar, WERR_NOT_ENOUGH_MEMORY);
5621 /* first copy the old meta data */
5622 for (i=0; i < omd.ctr.ctr1.count; i++) {
5623 nmd.ctr.ctr1.array[ni] = omd.ctr.ctr1.array[i];
5628 /* now merge in the new meta data */
5629 for (i=0; i < rmd->ctr.ctr1.count; i++) {
5632 for (j=0; j < ni; j++) {
5635 if (rmd->ctr.ctr1.array[i].attid != nmd.ctr.ctr1.array[j].attid) {
5639 cmp = replmd_replPropertyMetaData1_new_should_be_taken(
5640 ar->objs->dsdb_repl_flags,
5641 &nmd.ctr.ctr1.array[j],
5642 &rmd->ctr.ctr1.array[i]);
5644 /* replace the entry */
5645 nmd.ctr.ctr1.array[j] = rmd->ctr.ctr1.array[i];
5646 if (ar->seq_num == 0) {
5647 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &ar->seq_num);
5648 if (ret != LDB_SUCCESS) {
5649 return replmd_replicated_request_error(ar, ret);
5652 nmd.ctr.ctr1.array[j].local_usn = ar->seq_num;
5653 switch (nmd.ctr.ctr1.array[j].attid) {
5654 case DRSUAPI_ATTID_ntSecurityDescriptor:
5657 case DRSUAPI_ATTID_isDeleted:
5658 take_remote_isDeleted = true;
5667 if (rmd->ctr.ctr1.array[i].attid != DRSUAPI_ATTID_instanceType) {
5668 DEBUG(3,("Discarding older DRS attribute update to %s on %s from %s\n",
5669 msg->elements[i-removed_attrs].name,
5670 ldb_dn_get_linearized(msg->dn),
5671 GUID_string(ar, &rmd->ctr.ctr1.array[i].originating_invocation_id)));
5674 /* we don't want to apply this change so remove the attribute */
5675 ldb_msg_remove_element(msg, &msg->elements[i-removed_attrs]);
5682 if (found) continue;
5684 nmd.ctr.ctr1.array[ni] = rmd->ctr.ctr1.array[i];
5685 if (ar->seq_num == 0) {
5686 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &ar->seq_num);
5687 if (ret != LDB_SUCCESS) {
5688 return replmd_replicated_request_error(ar, ret);
5691 nmd.ctr.ctr1.array[ni].local_usn = ar->seq_num;
5692 switch (nmd.ctr.ctr1.array[ni].attid) {
5693 case DRSUAPI_ATTID_ntSecurityDescriptor:
5696 case DRSUAPI_ATTID_isDeleted:
5697 take_remote_isDeleted = true;
5706 * finally correct the size of the meta_data array
5708 nmd.ctr.ctr1.count = ni;
5710 new_rdn = ldb_dn_get_rdn_val(msg->dn);
5711 old_rdn = ldb_dn_get_rdn_val(ar->search_msg->dn);
5714 ret = replmd_update_rpmd_rdn_attr(ldb, msg, new_rdn, old_rdn,
5715 &nmd, ar, now, is_schema_nc,
5717 if (ret != LDB_SUCCESS) {
5718 ldb_asprintf_errstring(ldb, "%s: error during DRS repl merge: %s", __func__, ldb_errstring(ldb));
5719 return replmd_replicated_request_error(ar, ret);
5723 * sort the new meta data array
5725 ret = replmd_replPropertyMetaDataCtr1_sort_and_verify(ldb, &nmd.ctr.ctr1, msg->dn);
5726 if (ret != LDB_SUCCESS) {
5727 ldb_asprintf_errstring(ldb, "%s: error during DRS repl merge: %s", __func__, ldb_errstring(ldb));
5732 * Work out if this object is deleted, so we can prune any extra attributes. See MS-DRSR 4.1.10.6.9
5735 * This also controls SD propagation below
5737 if (take_remote_isDeleted) {
5738 isDeleted = remote_isDeleted;
5740 isDeleted = local_isDeleted;
5743 ar->isDeleted = isDeleted;
5746 * check if some replicated attributes left, otherwise skip the ldb_modify() call
5748 if (msg->num_elements == 0) {
5749 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_replicated_apply_merge[%u]: skip replace\n",
5752 return replmd_replicated_apply_isDeleted(ar);
5755 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_replicated_apply_merge[%u]: replace %u attributes\n",
5756 ar->index_current, msg->num_elements);
5762 if (sd_updated && !isDeleted) {
5763 ret = dsdb_module_schedule_sd_propagation(ar->module,
5764 ar->objs->partition_dn,
5766 if (ret != LDB_SUCCESS) {
5767 return ldb_operr(ldb);
5771 /* create the meta data value */
5772 ndr_err = ndr_push_struct_blob(&nmd_value, msg, &nmd,
5773 (ndr_push_flags_fn_t)ndr_push_replPropertyMetaDataBlob);
5774 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
5775 nt_status = ndr_map_error2ntstatus(ndr_err);
5776 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
5780 * when we know that we'll modify the record, add the whenChanged, uSNChanged
5781 * and replPopertyMetaData attributes
5783 ret = ldb_msg_add_string(msg, "whenChanged", ar->objs->objects[ar->index_current].when_changed);
5784 if (ret != LDB_SUCCESS) {
5785 return replmd_replicated_request_error(ar, ret);
5787 ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNChanged", ar->seq_num);
5788 if (ret != LDB_SUCCESS) {
5789 return replmd_replicated_request_error(ar, ret);
5791 ret = ldb_msg_add_value(msg, "replPropertyMetaData", &nmd_value, NULL);
5792 if (ret != LDB_SUCCESS) {
5793 return replmd_replicated_request_error(ar, ret);
5796 replmd_ldb_message_sort(msg, ar->schema);
5798 /* we want to replace the old values */
5799 for (i=0; i < msg->num_elements; i++) {
5800 msg->elements[i].flags = LDB_FLAG_MOD_REPLACE;
5801 if (ldb_attr_cmp(msg->elements[i].name, "objectClass") == 0) {
5802 if (msg->elements[i].num_values == 0) {
5803 ldb_asprintf_errstring(ldb, __location__
5804 ": objectClass removed on %s, aborting replication\n",
5805 ldb_dn_get_linearized(msg->dn));
5806 return replmd_replicated_request_error(ar, LDB_ERR_OBJECT_CLASS_VIOLATION);
5812 struct GUID_txt_buf guid_txt;
5814 char *s = ldb_ldif_message_string(ldb, ar, LDB_CHANGETYPE_MODIFY, msg);
5815 DEBUG(4, ("Final DRS replication modify message of %s:\n%s\n",
5816 GUID_buf_string(&ar->objs->objects[ar->index_current].object_guid, &guid_txt),
5821 ret = ldb_build_mod_req(&change_req,
5829 LDB_REQ_SET_LOCATION(change_req);
5830 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
5832 /* current partition control needed by "repmd_op_callback" */
5833 ret = ldb_request_add_control(change_req,
5834 DSDB_CONTROL_CURRENT_PARTITION_OID,
5836 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
5838 return ldb_next_request(ar->module, change_req);
5841 static int replmd_replicated_apply_search_callback(struct ldb_request *req,
5842 struct ldb_reply *ares)
5844 struct replmd_replicated_request *ar = talloc_get_type(req->context,
5845 struct replmd_replicated_request);
5849 return ldb_module_done(ar->req, NULL, NULL,
5850 LDB_ERR_OPERATIONS_ERROR);
5852 if (ares->error != LDB_SUCCESS &&
5853 ares->error != LDB_ERR_NO_SUCH_OBJECT) {
5854 return ldb_module_done(ar->req, ares->controls,
5855 ares->response, ares->error);
5858 switch (ares->type) {
5859 case LDB_REPLY_ENTRY:
5860 ar->search_msg = talloc_steal(ar, ares->message);
5863 case LDB_REPLY_REFERRAL:
5864 /* we ignore referrals */
5867 case LDB_REPLY_DONE:
5869 struct replPropertyMetaData1 *md_remote;
5870 struct replPropertyMetaData1 *md_local;
5872 struct replPropertyMetaDataBlob omd;
5873 const struct ldb_val *omd_value;
5874 struct replPropertyMetaDataBlob *rmd;
5875 struct ldb_message *msg;
5877 ar->objs->objects[ar->index_current].local_parent_dn = NULL;
5878 ar->objs->objects[ar->index_current].last_known_parent = NULL;
5881 * This is the ADD case, find the appropriate parent,
5882 * as this object doesn't exist locally:
5884 if (ar->search_msg == NULL) {
5885 ret = replmd_replicated_apply_search_for_parent(ar);
5886 if (ret != LDB_SUCCESS) {
5887 return ldb_module_done(ar->req, NULL, NULL, ret);
5894 * Otherwise, in the MERGE case, work out if we are
5895 * attempting a rename, and if so find the parent the
5896 * newly renamed object wants to belong under (which
5897 * may not be the parent in it's attached string DN
5899 rmd = ar->objs->objects[ar->index_current].meta_data;
5903 /* find existing meta data */
5904 omd_value = ldb_msg_find_ldb_val(ar->search_msg, "replPropertyMetaData");
5906 enum ndr_err_code ndr_err;
5907 ndr_err = ndr_pull_struct_blob(omd_value, ar, &omd,
5908 (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
5909 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
5910 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
5911 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
5914 if (omd.version != 1) {
5915 return replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
5919 ar->local_parent_guid = samdb_result_guid(ar->search_msg, "parentGUID");
5921 instanceType = ldb_msg_find_attr_as_int(ar->search_msg, "instanceType", 0);
5922 if (((instanceType & INSTANCE_TYPE_IS_NC_HEAD) == 0)
5923 && GUID_all_zero(&ar->local_parent_guid)) {
5924 DEBUG(0, ("Refusing to replicate new version of %s "
5925 "as local object has an all-zero parentGUID attribute, "
5926 "despite not being an NC root\n",
5927 ldb_dn_get_linearized(ar->search_msg->dn)));
5928 return replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
5932 * now we need to check for double renames. We could have a
5933 * local rename pending which our replication partner hasn't
5934 * received yet. We choose which one wins by looking at the
5935 * attribute stamps on the two objects, the newer one wins.
5937 * This also simply applies the correct algorithms for
5938 * determining if a change was made to name at all, or
5939 * if the object has just been renamed under the same
5942 md_remote = replmd_replPropertyMetaData1_find_attid(rmd, DRSUAPI_ATTID_name);
5943 md_local = replmd_replPropertyMetaData1_find_attid(&omd, DRSUAPI_ATTID_name);
5945 DEBUG(0,(__location__ ": Failed to find name attribute in local LDB replPropertyMetaData for %s\n",
5946 ldb_dn_get_linearized(ar->search_msg->dn)));
5947 return replmd_replicated_request_werror(ar, WERR_DS_DRA_DB_ERROR);
5951 * if there is no name attribute given then we have to assume the
5952 * object we've received has the older name
5954 if (replmd_replPropertyMetaData1_new_should_be_taken(
5955 ar->objs->dsdb_repl_flags & DSDB_REPL_FLAG_PRIORITISE_INCOMING,
5956 md_local, md_remote)) {
5957 struct GUID_txt_buf p_guid_local;
5958 struct GUID_txt_buf p_guid_remote;
5959 msg = ar->objs->objects[ar->index_current].msg;
5961 /* Merge on the existing object, with rename */
5963 DEBUG(4,(__location__ ": Looking for new parent for object %s currently under %s "
5964 "as incoming object changing to %s under %s\n",
5965 ldb_dn_get_linearized(ar->search_msg->dn),
5966 GUID_buf_string(&ar->local_parent_guid, &p_guid_local),
5967 ldb_dn_get_linearized(msg->dn),
5968 GUID_buf_string(ar->objs->objects[ar->index_current].parent_guid,
5970 ret = replmd_replicated_apply_search_for_parent(ar);
5972 struct GUID_txt_buf p_guid_local;
5973 struct GUID_txt_buf p_guid_remote;
5974 msg = ar->objs->objects[ar->index_current].msg;
5977 * Merge on the existing object, force no
5978 * rename (code below just to explain why in
5982 if (strcmp(ldb_dn_get_linearized(ar->search_msg->dn),
5983 ldb_dn_get_linearized(msg->dn)) == 0) {
5984 if (ar->objs->objects[ar->index_current].parent_guid != NULL &&
5985 GUID_equal(&ar->local_parent_guid,
5986 ar->objs->objects[ar->index_current].parent_guid)
5988 DEBUG(4,(__location__ ": Keeping object %s at under %s "
5989 "despite incoming object changing parent to %s\n",
5990 ldb_dn_get_linearized(ar->search_msg->dn),
5991 GUID_buf_string(&ar->local_parent_guid, &p_guid_local),
5992 GUID_buf_string(ar->objs->objects[ar->index_current].parent_guid,
5996 DEBUG(4,(__location__ ": Keeping object %s at under %s "
5997 " and rejecting older rename to %s under %s\n",
5998 ldb_dn_get_linearized(ar->search_msg->dn),
5999 GUID_buf_string(&ar->local_parent_guid, &p_guid_local),
6000 ldb_dn_get_linearized(msg->dn),
6001 GUID_buf_string(ar->objs->objects[ar->index_current].parent_guid,
6005 * This assignment ensures that the strcmp()
6006 * and GUID_equal() calls in
6007 * replmd_replicated_apply_merge() avoids the
6010 ar->objs->objects[ar->index_current].parent_guid =
6011 &ar->local_parent_guid;
6013 msg->dn = ar->search_msg->dn;
6014 ret = replmd_replicated_apply_merge(ar);
6016 if (ret != LDB_SUCCESS) {
6017 return ldb_module_done(ar->req, NULL, NULL, ret);
6026 static int replmd_replicated_uptodate_vector(struct replmd_replicated_request *ar);
6028 static int replmd_replicated_apply_next(struct replmd_replicated_request *ar)
6030 struct ldb_context *ldb;
6034 struct ldb_request *search_req;
6035 static const char *attrs[] = { "repsFrom", "replUpToDateVector",
6036 "parentGUID", "instanceType",
6037 "replPropertyMetaData", "nTSecurityDescriptor",
6038 "isDeleted", NULL };
6039 struct GUID_txt_buf guid_str_buf;
6041 if (ar->index_current >= ar->objs->num_objects) {
6042 /* done with it, go to next stage */
6043 return replmd_replicated_uptodate_vector(ar);
6046 ldb = ldb_module_get_ctx(ar->module);
6047 ar->search_msg = NULL;
6048 ar->isDeleted = false;
6050 tmp_str = GUID_buf_string(&ar->objs->objects[ar->index_current].object_guid,
6053 filter = talloc_asprintf(ar, "(objectGUID=%s)", tmp_str);
6054 if (!filter) return replmd_replicated_request_werror(ar, WERR_NOT_ENOUGH_MEMORY);
6056 ret = ldb_build_search_req(&search_req,
6059 ar->objs->partition_dn,
6065 replmd_replicated_apply_search_callback,
6067 LDB_REQ_SET_LOCATION(search_req);
6069 ret = dsdb_request_add_controls(search_req, DSDB_SEARCH_SHOW_RECYCLED);
6071 if (ret != LDB_SUCCESS) {
6075 return ldb_next_request(ar->module, search_req);
6079 * This is essentially a wrapper for replmd_replicated_apply_next()
6081 * This is needed to ensure that both codepaths call this handler.
6083 static int replmd_replicated_apply_isDeleted(struct replmd_replicated_request *ar)
6085 struct ldb_dn *deleted_objects_dn;
6086 struct ldb_message *msg = ar->objs->objects[ar->index_current].msg;
6087 int ret = dsdb_get_deleted_objects_dn(ldb_module_get_ctx(ar->module), msg, msg->dn,
6088 &deleted_objects_dn);
6089 if (ar->isDeleted && (ret != LDB_SUCCESS || ldb_dn_compare(msg->dn, deleted_objects_dn) != 0)) {
6091 * Do a delete here again, so that if there is
6092 * anything local that conflicts with this
6093 * object being deleted, it is removed. This
6094 * includes links. See MS-DRSR 4.1.10.6.9
6097 * If the object is already deleted, and there
6098 * is no more work required, it doesn't do
6102 /* This has been updated to point to the DN we eventually did the modify on */
6104 struct ldb_request *del_req;
6105 struct ldb_result *res;
6107 TALLOC_CTX *tmp_ctx = talloc_new(ar);
6109 ret = ldb_oom(ldb_module_get_ctx(ar->module));
6113 res = talloc_zero(tmp_ctx, struct ldb_result);
6115 ret = ldb_oom(ldb_module_get_ctx(ar->module));
6116 talloc_free(tmp_ctx);
6120 /* Build a delete request, which hopefully will artually turn into nothing */
6121 ret = ldb_build_del_req(&del_req, ldb_module_get_ctx(ar->module), tmp_ctx,
6125 ldb_modify_default_callback,
6127 LDB_REQ_SET_LOCATION(del_req);
6128 if (ret != LDB_SUCCESS) {
6129 talloc_free(tmp_ctx);
6134 * This is the guts of the call, call back
6135 * into our delete code, but setting the
6136 * re_delete flag so we delete anything that
6137 * shouldn't be there on a deleted or recycled
6140 ret = replmd_delete_internals(ar->module, del_req, true);
6141 if (ret == LDB_SUCCESS) {
6142 ret = ldb_wait(del_req->handle, LDB_WAIT_ALL);
6145 talloc_free(tmp_ctx);
6146 if (ret != LDB_SUCCESS) {
6151 ar->index_current++;
6152 return replmd_replicated_apply_next(ar);
6155 static int replmd_replicated_uptodate_modify_callback(struct ldb_request *req,
6156 struct ldb_reply *ares)
6158 struct ldb_context *ldb;
6159 struct replmd_replicated_request *ar = talloc_get_type(req->context,
6160 struct replmd_replicated_request);
6161 ldb = ldb_module_get_ctx(ar->module);
6164 return ldb_module_done(ar->req, NULL, NULL,
6165 LDB_ERR_OPERATIONS_ERROR);
6167 if (ares->error != LDB_SUCCESS) {
6168 return ldb_module_done(ar->req, ares->controls,
6169 ares->response, ares->error);
6172 if (ares->type != LDB_REPLY_DONE) {
6173 ldb_asprintf_errstring(ldb, "Invalid LDB reply type %d", ares->type);
6174 return ldb_module_done(ar->req, NULL, NULL,
6175 LDB_ERR_OPERATIONS_ERROR);
6180 return ldb_module_done(ar->req, NULL, NULL, LDB_SUCCESS);
6183 static int replmd_replicated_uptodate_modify(struct replmd_replicated_request *ar)
6185 struct ldb_context *ldb;
6186 struct ldb_request *change_req;
6187 enum ndr_err_code ndr_err;
6188 struct ldb_message *msg;
6189 struct replUpToDateVectorBlob ouv;
6190 const struct ldb_val *ouv_value;
6191 const struct drsuapi_DsReplicaCursor2CtrEx *ruv;
6192 struct replUpToDateVectorBlob nuv;
6193 struct ldb_val nuv_value;
6194 struct ldb_message_element *nuv_el = NULL;
6195 struct ldb_message_element *orf_el = NULL;
6196 struct repsFromToBlob nrf;
6197 struct ldb_val *nrf_value = NULL;
6198 struct ldb_message_element *nrf_el = NULL;
6202 time_t t = time(NULL);
6205 uint32_t instanceType;
6207 ldb = ldb_module_get_ctx(ar->module);
6208 ruv = ar->objs->uptodateness_vector;
6214 unix_to_nt_time(&now, t);
6216 if (ar->search_msg == NULL) {
6217 /* this happens for a REPL_OBJ call where we are
6218 creating the target object by replicating it. The
6219 subdomain join code does this for the partition DN
6221 DEBUG(4,(__location__ ": Skipping UDV and repsFrom update as no target DN\n"));
6222 return ldb_module_done(ar->req, NULL, NULL, LDB_SUCCESS);
6225 instanceType = ldb_msg_find_attr_as_uint(ar->search_msg, "instanceType", 0);
6226 if (! (instanceType & INSTANCE_TYPE_IS_NC_HEAD)) {
6227 DEBUG(4,(__location__ ": Skipping UDV and repsFrom update as not NC root: %s\n",
6228 ldb_dn_get_linearized(ar->search_msg->dn)));
6229 return ldb_module_done(ar->req, NULL, NULL, LDB_SUCCESS);
6233 * first create the new replUpToDateVector
6235 ouv_value = ldb_msg_find_ldb_val(ar->search_msg, "replUpToDateVector");
6237 ndr_err = ndr_pull_struct_blob(ouv_value, ar, &ouv,
6238 (ndr_pull_flags_fn_t)ndr_pull_replUpToDateVectorBlob);
6239 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
6240 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
6241 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
6244 if (ouv.version != 2) {
6245 return replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
6250 * the new uptodateness vector will at least
6251 * contain 1 entry, one for the source_dsa
6253 * plus optional values from our old vector and the one from the source_dsa
6255 nuv.ctr.ctr2.count = ouv.ctr.ctr2.count;
6256 if (ruv) nuv.ctr.ctr2.count += ruv->count;
6257 nuv.ctr.ctr2.cursors = talloc_array(ar,
6258 struct drsuapi_DsReplicaCursor2,
6259 nuv.ctr.ctr2.count);
6260 if (!nuv.ctr.ctr2.cursors) return replmd_replicated_request_werror(ar, WERR_NOT_ENOUGH_MEMORY);
6262 /* first copy the old vector */
6263 for (i=0; i < ouv.ctr.ctr2.count; i++) {
6264 nuv.ctr.ctr2.cursors[ni] = ouv.ctr.ctr2.cursors[i];
6268 /* merge in the source_dsa vector is available */
6269 for (i=0; (ruv && i < ruv->count); i++) {
6272 if (GUID_equal(&ruv->cursors[i].source_dsa_invocation_id,
6273 &ar->our_invocation_id)) {
6277 for (j=0; j < ni; j++) {
6278 if (!GUID_equal(&ruv->cursors[i].source_dsa_invocation_id,
6279 &nuv.ctr.ctr2.cursors[j].source_dsa_invocation_id)) {
6285 if (ruv->cursors[i].highest_usn > nuv.ctr.ctr2.cursors[j].highest_usn) {
6286 nuv.ctr.ctr2.cursors[j] = ruv->cursors[i];
6291 if (found) continue;
6293 /* if it's not there yet, add it */
6294 nuv.ctr.ctr2.cursors[ni] = ruv->cursors[i];
6299 * finally correct the size of the cursors array
6301 nuv.ctr.ctr2.count = ni;
6306 TYPESAFE_QSORT(nuv.ctr.ctr2.cursors, nuv.ctr.ctr2.count, drsuapi_DsReplicaCursor2_compare);
6309 * create the change ldb_message
6311 msg = ldb_msg_new(ar);
6312 if (!msg) return replmd_replicated_request_werror(ar, WERR_NOT_ENOUGH_MEMORY);
6313 msg->dn = ar->search_msg->dn;
6315 ndr_err = ndr_push_struct_blob(&nuv_value, msg, &nuv,
6316 (ndr_push_flags_fn_t)ndr_push_replUpToDateVectorBlob);
6317 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
6318 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
6319 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
6321 ret = ldb_msg_add_value(msg, "replUpToDateVector", &nuv_value, &nuv_el);
6322 if (ret != LDB_SUCCESS) {
6323 return replmd_replicated_request_error(ar, ret);
6325 nuv_el->flags = LDB_FLAG_MOD_REPLACE;
6328 * now create the new repsFrom value from the given repsFromTo1 structure
6332 nrf.ctr.ctr1 = *ar->objs->source_dsa;
6333 nrf.ctr.ctr1.last_attempt = now;
6334 nrf.ctr.ctr1.last_success = now;
6335 nrf.ctr.ctr1.result_last_attempt = WERR_OK;
6338 * first see if we already have a repsFrom value for the current source dsa
6339 * if so we'll later replace this value
6341 orf_el = ldb_msg_find_element(ar->search_msg, "repsFrom");
6343 for (i=0; i < orf_el->num_values; i++) {
6344 struct repsFromToBlob *trf;
6346 trf = talloc(ar, struct repsFromToBlob);
6347 if (!trf) return replmd_replicated_request_werror(ar, WERR_NOT_ENOUGH_MEMORY);
6349 ndr_err = ndr_pull_struct_blob(&orf_el->values[i], trf, trf,
6350 (ndr_pull_flags_fn_t)ndr_pull_repsFromToBlob);
6351 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
6352 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
6353 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
6356 if (trf->version != 1) {
6357 return replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
6361 * we compare the source dsa objectGUID not the invocation_id
6362 * because we want only one repsFrom value per source dsa
6363 * and when the invocation_id of the source dsa has changed we don't need
6364 * the old repsFrom with the old invocation_id
6366 if (!GUID_equal(&trf->ctr.ctr1.source_dsa_obj_guid,
6367 &ar->objs->source_dsa->source_dsa_obj_guid)) {
6373 nrf_value = &orf_el->values[i];
6378 * copy over all old values to the new ldb_message
6380 ret = ldb_msg_add_empty(msg, "repsFrom", 0, &nrf_el);
6381 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
6386 * if we haven't found an old repsFrom value for the current source dsa
6387 * we'll add a new value
6390 struct ldb_val zero_value;
6391 ZERO_STRUCT(zero_value);
6392 ret = ldb_msg_add_value(msg, "repsFrom", &zero_value, &nrf_el);
6393 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
6395 nrf_value = &nrf_el->values[nrf_el->num_values - 1];
6398 /* we now fill the value which is already attached to ldb_message */
6399 ndr_err = ndr_push_struct_blob(nrf_value, msg,
6401 (ndr_push_flags_fn_t)ndr_push_repsFromToBlob);
6402 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
6403 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
6404 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
6408 * the ldb_message_element for the attribute, has all the old values and the new one
6409 * so we'll replace the whole attribute with all values
6411 nrf_el->flags = LDB_FLAG_MOD_REPLACE;
6413 if (CHECK_DEBUGLVL(4)) {
6414 char *s = ldb_ldif_message_string(ldb, ar, LDB_CHANGETYPE_MODIFY, msg);
6415 DEBUG(4, ("DRS replication uptodate modify message:\n%s\n", s));
6419 /* prepare the ldb_modify() request */
6420 ret = ldb_build_mod_req(&change_req,
6426 replmd_replicated_uptodate_modify_callback,
6428 LDB_REQ_SET_LOCATION(change_req);
6429 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
6431 return ldb_next_request(ar->module, change_req);
6434 static int replmd_replicated_uptodate_search_callback(struct ldb_request *req,
6435 struct ldb_reply *ares)
6437 struct replmd_replicated_request *ar = talloc_get_type(req->context,
6438 struct replmd_replicated_request);
6442 return ldb_module_done(ar->req, NULL, NULL,
6443 LDB_ERR_OPERATIONS_ERROR);
6445 if (ares->error != LDB_SUCCESS &&
6446 ares->error != LDB_ERR_NO_SUCH_OBJECT) {
6447 return ldb_module_done(ar->req, ares->controls,
6448 ares->response, ares->error);
6451 switch (ares->type) {
6452 case LDB_REPLY_ENTRY:
6453 ar->search_msg = talloc_steal(ar, ares->message);
6456 case LDB_REPLY_REFERRAL:
6457 /* we ignore referrals */
6460 case LDB_REPLY_DONE:
6461 ret = replmd_replicated_uptodate_modify(ar);
6462 if (ret != LDB_SUCCESS) {
6463 return ldb_module_done(ar->req, NULL, NULL, ret);
6472 static int replmd_replicated_uptodate_vector(struct replmd_replicated_request *ar)
6474 struct ldb_context *ldb = ldb_module_get_ctx(ar->module);
6475 struct replmd_private *replmd_private =
6476 talloc_get_type_abort(ldb_module_get_private(ar->module),
6477 struct replmd_private);
6479 static const char *attrs[] = {
6480 "replUpToDateVector",
6485 struct ldb_request *search_req;
6487 ar->search_msg = NULL;
6490 * Let the caller know that we did an originating updates
6492 ar->objs->originating_updates = replmd_private->originating_updates;
6494 ret = ldb_build_search_req(&search_req,
6497 ar->objs->partition_dn,
6503 replmd_replicated_uptodate_search_callback,
6505 LDB_REQ_SET_LOCATION(search_req);
6506 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
6508 return ldb_next_request(ar->module, search_req);
6513 static int replmd_extended_replicated_objects(struct ldb_module *module, struct ldb_request *req)
6515 struct ldb_context *ldb;
6516 struct dsdb_extended_replicated_objects *objs;
6517 struct replmd_replicated_request *ar;
6518 struct ldb_control **ctrls;
6521 struct replmd_private *replmd_private =
6522 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
6524 ldb = ldb_module_get_ctx(module);
6526 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_extended_replicated_objects\n");
6528 objs = talloc_get_type(req->op.extended.data, struct dsdb_extended_replicated_objects);
6530 ldb_debug(ldb, LDB_DEBUG_FATAL, "replmd_extended_replicated_objects: invalid extended data\n");
6531 return LDB_ERR_PROTOCOL_ERROR;
6534 if (objs->version != DSDB_EXTENDED_REPLICATED_OBJECTS_VERSION) {
6535 ldb_debug(ldb, LDB_DEBUG_FATAL, "replmd_extended_replicated_objects: extended data invalid version [%u != %u]\n",
6536 objs->version, DSDB_EXTENDED_REPLICATED_OBJECTS_VERSION);
6537 return LDB_ERR_PROTOCOL_ERROR;
6540 ar = replmd_ctx_init(module, req);
6542 return LDB_ERR_OPERATIONS_ERROR;
6544 /* Set the flags to have the replmd_op_callback run over the full set of objects */
6545 ar->apply_mode = true;
6547 ar->schema = dsdb_get_schema(ldb, ar);
6549 ldb_debug_set(ldb, LDB_DEBUG_FATAL, "replmd_ctx_init: no loaded schema found\n");
6551 DEBUG(0,(__location__ ": %s\n", ldb_errstring(ldb)));
6552 return LDB_ERR_CONSTRAINT_VIOLATION;
6555 ctrls = req->controls;
6557 if (req->controls) {
6558 req->controls = talloc_memdup(ar, req->controls,
6559 talloc_get_size(req->controls));
6560 if (!req->controls) return replmd_replicated_request_werror(ar, WERR_NOT_ENOUGH_MEMORY);
6563 ret = ldb_request_add_control(req, DSDB_CONTROL_REPLICATED_UPDATE_OID, false, NULL);
6564 if (ret != LDB_SUCCESS) {
6568 /* If this change contained linked attributes in the body
6569 * (rather than in the links section) we need to update
6570 * backlinks in linked_attributes */
6571 ret = ldb_request_add_control(req, DSDB_CONTROL_APPLY_LINKS, false, NULL);
6572 if (ret != LDB_SUCCESS) {
6576 ar->controls = req->controls;
6577 req->controls = ctrls;
6579 DEBUG(4,("linked_attributes_count=%u\n", objs->linked_attributes_count));
6581 /* save away the linked attributes for the end of the
6583 for (i=0; i<ar->objs->linked_attributes_count; i++) {
6584 struct la_entry *la_entry;
6586 if (replmd_private->la_ctx == NULL) {
6587 replmd_private->la_ctx = talloc_new(replmd_private);
6589 la_entry = talloc(replmd_private->la_ctx, struct la_entry);
6590 if (la_entry == NULL) {
6592 return LDB_ERR_OPERATIONS_ERROR;
6594 la_entry->la = talloc(la_entry, struct drsuapi_DsReplicaLinkedAttribute);
6595 if (la_entry->la == NULL) {
6596 talloc_free(la_entry);
6598 return LDB_ERR_OPERATIONS_ERROR;
6600 *la_entry->la = ar->objs->linked_attributes[i];
6602 /* we need to steal the non-scalars so they stay
6603 around until the end of the transaction */
6604 talloc_steal(la_entry->la, la_entry->la->identifier);
6605 talloc_steal(la_entry->la, la_entry->la->value.blob);
6607 DLIST_ADD(replmd_private->la_list, la_entry);
6610 return replmd_replicated_apply_next(ar);
6614 process one linked attribute structure
6616 static int replmd_process_linked_attribute(struct ldb_module *module,
6617 struct replmd_private *replmd_private,
6618 struct la_entry *la_entry,
6619 struct ldb_request *parent)
6621 struct drsuapi_DsReplicaLinkedAttribute *la = la_entry->la;
6622 struct ldb_context *ldb = ldb_module_get_ctx(module);
6623 struct ldb_message *msg;
6624 struct ldb_message *target_msg = NULL;
6625 TALLOC_CTX *tmp_ctx = talloc_new(la_entry);
6626 const struct dsdb_schema *schema = dsdb_get_schema(ldb, tmp_ctx);
6628 const struct dsdb_attribute *attr;
6629 struct dsdb_dn *dsdb_dn;
6630 uint64_t seq_num = 0;
6631 struct ldb_message_element *old_el;
6633 time_t t = time(NULL);
6634 struct ldb_result *res;
6635 struct ldb_result *target_res;
6636 const char *attrs[4];
6637 const char *attrs2[] = { "isDeleted", "isRecycled", NULL };
6638 struct parsed_dn *pdn_list, *pdn, *next;
6639 struct GUID guid = GUID_zero();
6641 bool active = (la->flags & DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE)?true:false;
6643 enum deletion_state deletion_state = OBJECT_NOT_DELETED;
6644 enum deletion_state target_deletion_state = OBJECT_NOT_DELETED;
6647 linked_attributes[0]:
6648 &objs->linked_attributes[i]: struct drsuapi_DsReplicaLinkedAttribute
6650 identifier: struct drsuapi_DsReplicaObjectIdentifier
6651 __ndr_size : 0x0000003a (58)
6652 __ndr_size_sid : 0x00000000 (0)
6653 guid : 8e95b6a9-13dd-4158-89db-3220a5be5cc7
6655 __ndr_size_dn : 0x00000000 (0)
6657 attid : DRSUAPI_ATTID_member (0x1F)
6658 value: struct drsuapi_DsAttributeValue
6659 __ndr_size : 0x0000007e (126)
6661 blob : DATA_BLOB length=126
6662 flags : 0x00000001 (1)
6663 1: DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE
6664 originating_add_time : Wed Sep 2 22:20:01 2009 EST
6665 meta_data: struct drsuapi_DsReplicaMetaData
6666 version : 0x00000015 (21)
6667 originating_change_time : Wed Sep 2 23:39:07 2009 EST
6668 originating_invocation_id: 794640f3-18cf-40ee-a211-a93992b67a64
6669 originating_usn : 0x000000000001e19c (123292)
6671 (for cases where the link is to a normal DN)
6672 &target: struct drsuapi_DsReplicaObjectIdentifier3
6673 __ndr_size : 0x0000007e (126)
6674 __ndr_size_sid : 0x0000001c (28)
6675 guid : 7639e594-db75-4086-b0d4-67890ae46031
6676 sid : S-1-5-21-2848215498-2472035911-1947525656-19924
6677 __ndr_size_dn : 0x00000022 (34)
6678 dn : 'CN=UOne,OU=TestOU,DC=vsofs8,DC=com'
6681 /* find the attribute being modified */
6682 attr = dsdb_attribute_by_attributeID_id(schema, la->attid);
6684 struct GUID_txt_buf guid_str;
6685 ldb_asprintf_errstring(ldb, "Unable to find attributeID 0x%x for link on <GUID=%s>",
6687 GUID_buf_string(&la->identifier->guid,
6689 talloc_free(tmp_ctx);
6690 return LDB_ERR_OPERATIONS_ERROR;
6693 attrs[0] = attr->lDAPDisplayName;
6694 attrs[1] = "isDeleted";
6695 attrs[2] = "isRecycled";
6698 /* get the existing message from the db for the object with
6699 this GUID, returning attribute being modified. We will then
6700 use this msg as the basis for a modify call */
6701 ret = dsdb_module_search(module, tmp_ctx, &res, NULL, LDB_SCOPE_SUBTREE, attrs,
6702 DSDB_FLAG_NEXT_MODULE |
6703 DSDB_SEARCH_SEARCH_ALL_PARTITIONS |
6704 DSDB_SEARCH_SHOW_RECYCLED |
6705 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT |
6706 DSDB_SEARCH_REVEAL_INTERNALS,
6708 "objectGUID=%s", GUID_string(tmp_ctx, &la->identifier->guid));
6709 if (ret != LDB_SUCCESS) {
6710 talloc_free(tmp_ctx);
6713 if (res->count != 1) {
6714 ldb_asprintf_errstring(ldb, "DRS linked attribute for GUID %s - DN not found",
6715 GUID_string(tmp_ctx, &la->identifier->guid));
6716 talloc_free(tmp_ctx);
6717 return LDB_ERR_NO_SUCH_OBJECT;
6722 * Check for deleted objects per MS-DRSR 4.1.10.6.13
6723 * ProcessLinkValue, because link updates are not applied to
6724 * recycled and tombstone objects. We don't have to delete
6725 * any existing link, that should have happened when the
6726 * object deletion was replicated or initiated.
6729 replmd_deletion_state(module, msg, &deletion_state, NULL);
6731 if (deletion_state >= OBJECT_RECYCLED) {
6732 talloc_free(tmp_ctx);
6736 old_el = ldb_msg_find_element(msg, attr->lDAPDisplayName);
6737 if (old_el == NULL) {
6738 ret = ldb_msg_add_empty(msg, attr->lDAPDisplayName, LDB_FLAG_MOD_REPLACE, &old_el);
6739 if (ret != LDB_SUCCESS) {
6740 ldb_module_oom(module);
6741 talloc_free(tmp_ctx);
6742 return LDB_ERR_OPERATIONS_ERROR;
6745 old_el->flags = LDB_FLAG_MOD_REPLACE;
6748 /* parse the existing links */
6749 ret = get_parsed_dns_trusted(module, replmd_private, tmp_ctx, old_el, &pdn_list,
6750 attr->syntax->ldap_oid, parent);
6752 if (ret != LDB_SUCCESS) {
6753 talloc_free(tmp_ctx);
6757 status = dsdb_dn_la_from_blob(ldb, attr, schema, tmp_ctx, la->value.blob, &dsdb_dn);
6758 if (!W_ERROR_IS_OK(status)) {
6759 ldb_asprintf_errstring(ldb, "Failed to parsed linked attribute blob for %s on %s - %s\n",
6760 old_el->name, ldb_dn_get_linearized(msg->dn), win_errstr(status));
6761 talloc_free(tmp_ctx);
6762 return LDB_ERR_OPERATIONS_ERROR;
6765 ntstatus = dsdb_get_extended_dn_guid(dsdb_dn->dn, &guid, "GUID");
6766 if (!NT_STATUS_IS_OK(ntstatus) && !active) {
6768 * This strange behaviour (allowing a NULL/missing
6769 * GUID) originally comes from:
6771 * commit e3054ce0fe0f8f62d2f5b2a77893e7a1479128bd
6772 * Author: Andrew Tridgell <tridge@samba.org>
6773 * Date: Mon Dec 21 21:21:55 2009 +1100
6775 * s4-drs: cope better with NULL GUIDS from DRS
6777 * It is valid to get a NULL GUID over DRS for a deleted forward link. We
6778 * need to match by DN if possible when seeing if we should update an
6781 * Pair-Programmed-With: Andrew Bartlett <abartlet@samba.org>
6784 ret = dsdb_module_search_dn(module, tmp_ctx, &target_res,
6785 dsdb_dn->dn, attrs2,
6786 DSDB_FLAG_NEXT_MODULE |
6787 DSDB_SEARCH_SHOW_RECYCLED |
6788 DSDB_SEARCH_SEARCH_ALL_PARTITIONS |
6789 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT,
6791 } else if (!NT_STATUS_IS_OK(ntstatus)) {
6792 ldb_asprintf_errstring(ldb, "Failed to find GUID in linked attribute blob for %s on %s from %s",
6794 ldb_dn_get_linearized(dsdb_dn->dn),
6795 ldb_dn_get_linearized(msg->dn));
6796 talloc_free(tmp_ctx);
6797 return LDB_ERR_OPERATIONS_ERROR;
6799 ret = dsdb_module_search(module, tmp_ctx, &target_res,
6800 NULL, LDB_SCOPE_SUBTREE,
6802 DSDB_FLAG_NEXT_MODULE |
6803 DSDB_SEARCH_SHOW_RECYCLED |
6804 DSDB_SEARCH_SEARCH_ALL_PARTITIONS |
6805 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT,
6808 GUID_string(tmp_ctx, &guid));
6811 if (ret != LDB_SUCCESS) {
6812 ldb_asprintf_errstring(ldb_module_get_ctx(module), "Failed to re-resolve GUID %s: %s\n",
6813 GUID_string(tmp_ctx, &guid),
6814 ldb_errstring(ldb_module_get_ctx(module)));
6815 talloc_free(tmp_ctx);
6819 if (target_res->count == 0) {
6820 DEBUG(2,(__location__ ": WARNING: Failed to re-resolve GUID %s - using %s\n",
6821 GUID_string(tmp_ctx, &guid),
6822 ldb_dn_get_linearized(dsdb_dn->dn)));
6823 } else if (target_res->count != 1) {
6824 ldb_asprintf_errstring(ldb_module_get_ctx(module), "More than one object found matching objectGUID %s\n",
6825 GUID_string(tmp_ctx, &guid));
6826 talloc_free(tmp_ctx);
6827 return LDB_ERR_OPERATIONS_ERROR;
6829 target_msg = target_res->msgs[0];
6830 dsdb_dn->dn = talloc_steal(dsdb_dn, target_msg->dn);
6834 * Check for deleted objects per MS-DRSR 4.1.10.6.13
6835 * ProcessLinkValue, because link updates are not applied to
6836 * recycled and tombstone objects. We don't have to delete
6837 * any existing link, that should have happened when the
6838 * object deletion was replicated or initiated.
6840 replmd_deletion_state(module, target_msg,
6841 &target_deletion_state, NULL);
6843 if (target_deletion_state >= OBJECT_RECYCLED) {
6844 talloc_free(tmp_ctx);
6848 /* see if this link already exists */
6849 ret = parsed_dn_find(ldb, pdn_list, old_el->num_values,
6852 dsdb_dn->extra_part, 0,
6854 attr->syntax->ldap_oid,
6856 if (ret != LDB_SUCCESS) {
6857 talloc_free(tmp_ctx);
6863 /* see if this update is newer than what we have already */
6864 struct GUID invocation_id = GUID_zero();
6865 uint32_t version = 0;
6866 uint32_t originating_usn = 0;
6867 NTTIME change_time = 0;
6868 uint32_t rmd_flags = dsdb_dn_rmd_flags(pdn->dsdb_dn->dn);
6870 dsdb_get_extended_dn_guid(pdn->dsdb_dn->dn, &invocation_id, "RMD_INVOCID");
6871 dsdb_get_extended_dn_uint32(pdn->dsdb_dn->dn, &version, "RMD_VERSION");
6872 dsdb_get_extended_dn_uint32(pdn->dsdb_dn->dn, &originating_usn, "RMD_ORIGINATING_USN");
6873 dsdb_get_extended_dn_nttime(pdn->dsdb_dn->dn, &change_time, "RMD_CHANGETIME");
6875 if (!replmd_update_is_newer(&invocation_id,
6876 &la->meta_data.originating_invocation_id,
6878 la->meta_data.version,
6880 la->meta_data.originating_change_time)) {
6881 DEBUG(3,("Discarding older DRS linked attribute update to %s on %s from %s\n",
6882 old_el->name, ldb_dn_get_linearized(msg->dn),
6883 GUID_string(tmp_ctx, &la->meta_data.originating_invocation_id)));
6884 talloc_free(tmp_ctx);
6888 /* get a seq_num for this change */
6889 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &seq_num);
6890 if (ret != LDB_SUCCESS) {
6891 talloc_free(tmp_ctx);
6895 if (!(rmd_flags & DSDB_RMD_FLAG_DELETED)) {
6896 /* remove the existing backlink */
6897 ret = replmd_add_backlink(module, replmd_private,
6902 if (ret != LDB_SUCCESS) {
6903 talloc_free(tmp_ctx);
6908 ret = replmd_update_la_val(tmp_ctx, pdn->v, dsdb_dn, pdn->dsdb_dn,
6909 &la->meta_data.originating_invocation_id,
6910 la->meta_data.originating_usn, seq_num,
6911 la->meta_data.originating_change_time,
6912 la->meta_data.version,
6914 if (ret != LDB_SUCCESS) {
6915 talloc_free(tmp_ctx);
6920 /* add the new backlink */
6921 ret = replmd_add_backlink(module, replmd_private,
6926 if (ret != LDB_SUCCESS) {
6927 talloc_free(tmp_ctx);
6933 /* get a seq_num for this change */
6934 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &seq_num);
6935 if (ret != LDB_SUCCESS) {
6936 talloc_free(tmp_ctx);
6940 * We know where the new one needs to be, from the *next
6941 * pointer into pdn_list.
6944 offset = old_el->num_values;
6946 if (next->dsdb_dn == NULL) {
6947 ret = really_parse_trusted_dn(tmp_ctx, ldb, next,
6948 attr->syntax->ldap_oid);
6949 if (ret != LDB_SUCCESS) {
6953 offset = next - pdn_list;
6954 if (offset > old_el->num_values) {
6955 talloc_free(tmp_ctx);
6956 return LDB_ERR_OPERATIONS_ERROR;
6960 old_el->values = talloc_realloc(msg->elements, old_el->values,
6961 struct ldb_val, old_el->num_values+1);
6962 if (!old_el->values) {
6963 ldb_module_oom(module);
6964 return LDB_ERR_OPERATIONS_ERROR;
6967 if (offset != old_el->num_values) {
6968 memmove(&old_el->values[offset + 1], &old_el->values[offset],
6969 (old_el->num_values - offset) * sizeof(old_el->values[0]));
6972 old_el->num_values++;
6974 ret = replmd_build_la_val(tmp_ctx, &old_el->values[offset], dsdb_dn,
6975 &la->meta_data.originating_invocation_id,
6976 la->meta_data.originating_usn, seq_num,
6977 la->meta_data.originating_change_time,
6978 la->meta_data.version,
6980 if (ret != LDB_SUCCESS) {
6981 talloc_free(tmp_ctx);
6986 ret = replmd_add_backlink(module, replmd_private,
6991 if (ret != LDB_SUCCESS) {
6992 talloc_free(tmp_ctx);
6998 /* we only change whenChanged and uSNChanged if the seq_num
7000 ret = add_time_element(msg, "whenChanged", t);
7001 if (ret != LDB_SUCCESS) {
7002 talloc_free(tmp_ctx);
7007 ret = add_uint64_element(ldb, msg, "uSNChanged", seq_num);
7008 if (ret != LDB_SUCCESS) {
7009 talloc_free(tmp_ctx);
7014 old_el = ldb_msg_find_element(msg, attr->lDAPDisplayName);
7015 if (old_el == NULL) {
7016 talloc_free(tmp_ctx);
7017 return ldb_operr(ldb);
7020 ret = dsdb_check_single_valued_link(attr, old_el);
7021 if (ret != LDB_SUCCESS) {
7022 talloc_free(tmp_ctx);
7026 old_el->flags |= LDB_FLAG_INTERNAL_DISABLE_SINGLE_VALUE_CHECK;
7028 ret = linked_attr_modify(module, msg, parent);
7029 if (ret != LDB_SUCCESS) {
7030 ldb_debug(ldb, LDB_DEBUG_WARNING, "Failed to apply linked attribute change '%s'\n%s\n",
7032 ldb_ldif_message_string(ldb, tmp_ctx, LDB_CHANGETYPE_MODIFY, msg));
7033 talloc_free(tmp_ctx);
7037 talloc_free(tmp_ctx);
7042 static int replmd_extended(struct ldb_module *module, struct ldb_request *req)
7044 if (strcmp(req->op.extended.oid, DSDB_EXTENDED_REPLICATED_OBJECTS_OID) == 0) {
7045 return replmd_extended_replicated_objects(module, req);
7048 return ldb_next_request(module, req);
7053 we hook into the transaction operations to allow us to
7054 perform the linked attribute updates at the end of the whole
7055 transaction. This allows a forward linked attribute to be created
7056 before the object is created. During a vampire, w2k8 sends us linked
7057 attributes before the objects they are part of.
7059 static int replmd_start_transaction(struct ldb_module *module)
7061 /* create our private structure for this transaction */
7062 struct replmd_private *replmd_private = talloc_get_type(ldb_module_get_private(module),
7063 struct replmd_private);
7064 replmd_txn_cleanup(replmd_private);
7066 /* free any leftover mod_usn records from cancelled
7068 while (replmd_private->ncs) {
7069 struct nc_entry *e = replmd_private->ncs;
7070 DLIST_REMOVE(replmd_private->ncs, e);
7074 replmd_private->originating_updates = false;
7076 return ldb_next_start_trans(module);
7080 on prepare commit we loop over our queued la_context structures and
7083 static int replmd_prepare_commit(struct ldb_module *module)
7085 struct replmd_private *replmd_private =
7086 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
7087 struct la_entry *la, *prev;
7091 * Walk the list of linked attributes from DRS replication.
7093 * We walk backwards, to do the first entry first, as we
7094 * added the entries with DLIST_ADD() which puts them at the
7097 for (la = DLIST_TAIL(replmd_private->la_list); la; la=prev) {
7098 prev = DLIST_PREV(la);
7099 DLIST_REMOVE(replmd_private->la_list, la);
7100 ret = replmd_process_linked_attribute(module, replmd_private,
7102 if (ret != LDB_SUCCESS) {
7103 replmd_txn_cleanup(replmd_private);
7108 replmd_txn_cleanup(replmd_private);
7110 /* possibly change @REPLCHANGED */
7111 ret = replmd_notify_store(module, NULL);
7112 if (ret != LDB_SUCCESS) {
7116 return ldb_next_prepare_commit(module);
7119 static int replmd_del_transaction(struct ldb_module *module)
7121 struct replmd_private *replmd_private =
7122 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
7123 replmd_txn_cleanup(replmd_private);
7125 return ldb_next_del_trans(module);
7129 static const struct ldb_module_ops ldb_repl_meta_data_module_ops = {
7130 .name = "repl_meta_data",
7131 .init_context = replmd_init,
7133 .modify = replmd_modify,
7134 .rename = replmd_rename,
7135 .del = replmd_delete,
7136 .extended = replmd_extended,
7137 .start_transaction = replmd_start_transaction,
7138 .prepare_commit = replmd_prepare_commit,
7139 .del_transaction = replmd_del_transaction,
7142 int ldb_repl_meta_data_module_init(const char *version)
7144 LDB_MODULE_CHECK_VERSION(version);
7145 return ldb_register_module(&ldb_repl_meta_data_module_ops);