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 #define DBGC_CLASS DBGC_DRS_REPL
57 /* the RMD_VERSION for linked attributes starts from 1 */
58 #define RMD_VERSION_INITIAL 1
61 * It's 29/12/9999 at 23:59:59 UTC as specified in MS-ADTS 7.1.1.4.2
62 * Deleted Objects Container
64 static const NTTIME DELETED_OBJECT_CONTAINER_CHANGE_TIME = 2650466015990000000ULL;
66 struct replmd_private {
68 struct la_entry *la_list;
70 struct nc_entry *prev, *next;
73 uint64_t mod_usn_urgent;
75 struct ldb_dn *schema_dn;
76 bool originating_updates;
81 struct la_entry *next, *prev;
82 struct drsuapi_DsReplicaLinkedAttribute *la;
83 uint32_t dsdb_repl_flags;
86 struct replmd_replicated_request {
87 struct ldb_module *module;
88 struct ldb_request *req;
90 const struct dsdb_schema *schema;
91 struct GUID our_invocation_id;
93 /* the controls we pass down */
94 struct ldb_control **controls;
97 * Backlinks for the replmd_add() case (we want to create
98 * backlinks after creating the user, but before the end of
101 struct la_backlink *la_backlinks;
103 /* details for the mode where we apply a bunch of inbound replication meessages */
105 uint32_t index_current;
106 struct dsdb_extended_replicated_objects *objs;
108 struct ldb_message *search_msg;
109 struct GUID local_parent_guid;
117 static int replmd_replicated_apply_merge(struct replmd_replicated_request *ar);
118 static int replmd_delete_internals(struct ldb_module *module, struct ldb_request *req, bool re_delete);
119 static int replmd_check_upgrade_links(struct ldb_context *ldb,
120 struct parsed_dn *dns, uint32_t count,
121 struct ldb_message_element *el,
122 const char *ldap_oid);
123 static int replmd_verify_linked_attribute(struct replmd_replicated_request *ar,
124 struct la_entry *la);
125 static int replmd_set_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct dsdb_dn *dsdb_dn,
126 struct dsdb_dn *old_dsdb_dn, const struct GUID *invocation_id,
127 uint64_t usn, uint64_t local_usn, NTTIME nttime,
128 uint32_t version, bool deleted);
130 static int replmd_make_deleted_child_dn(TALLOC_CTX *tmp_ctx,
131 struct ldb_context *ldb,
133 const char *rdn_name,
134 const struct ldb_val *rdn_value,
137 enum urgent_situation {
138 REPL_URGENT_ON_CREATE = 1,
139 REPL_URGENT_ON_UPDATE = 2,
140 REPL_URGENT_ON_DELETE = 4
143 enum deletion_state {
144 OBJECT_NOT_DELETED=1,
151 static void replmd_deletion_state(struct ldb_module *module,
152 const struct ldb_message *msg,
153 enum deletion_state *current_state,
154 enum deletion_state *next_state)
157 bool enabled = false;
160 *current_state = OBJECT_REMOVED;
161 if (next_state != NULL) {
162 *next_state = OBJECT_REMOVED;
167 ret = dsdb_recyclebin_enabled(module, &enabled);
168 if (ret != LDB_SUCCESS) {
172 if (ldb_msg_check_string_attribute(msg, "isDeleted", "TRUE")) {
174 *current_state = OBJECT_TOMBSTONE;
175 if (next_state != NULL) {
176 *next_state = OBJECT_REMOVED;
181 if (ldb_msg_check_string_attribute(msg, "isRecycled", "TRUE")) {
182 *current_state = OBJECT_RECYCLED;
183 if (next_state != NULL) {
184 *next_state = OBJECT_REMOVED;
189 *current_state = OBJECT_DELETED;
190 if (next_state != NULL) {
191 *next_state = OBJECT_RECYCLED;
196 *current_state = OBJECT_NOT_DELETED;
197 if (next_state == NULL) {
202 *next_state = OBJECT_DELETED;
204 *next_state = OBJECT_TOMBSTONE;
208 static const struct {
209 const char *update_name;
210 enum urgent_situation repl_situation;
211 } urgent_objects[] = {
212 {"nTDSDSA", (REPL_URGENT_ON_CREATE | REPL_URGENT_ON_DELETE)},
213 {"crossRef", (REPL_URGENT_ON_CREATE | REPL_URGENT_ON_DELETE)},
214 {"attributeSchema", (REPL_URGENT_ON_CREATE | REPL_URGENT_ON_UPDATE)},
215 {"classSchema", (REPL_URGENT_ON_CREATE | REPL_URGENT_ON_UPDATE)},
216 {"secret", (REPL_URGENT_ON_CREATE | REPL_URGENT_ON_UPDATE)},
217 {"rIDManager", (REPL_URGENT_ON_CREATE | REPL_URGENT_ON_UPDATE)},
221 /* Attributes looked for when updating or deleting, to check for a urgent replication needed */
222 static const char *urgent_attrs[] = {
225 "userAccountControl",
230 static bool replmd_check_urgent_objectclass(const struct ldb_message_element *objectclass_el,
231 enum urgent_situation situation)
234 for (i=0; urgent_objects[i].update_name; i++) {
236 if ((situation & urgent_objects[i].repl_situation) == 0) {
240 for (j=0; j<objectclass_el->num_values; j++) {
241 const struct ldb_val *v = &objectclass_el->values[j];
242 if (ldb_attr_cmp((const char *)v->data, urgent_objects[i].update_name) == 0) {
250 static bool replmd_check_urgent_attribute(const struct ldb_message_element *el)
252 if (ldb_attr_in_list(urgent_attrs, el->name)) {
258 static int replmd_replicated_apply_isDeleted(struct replmd_replicated_request *ar);
261 initialise the module
262 allocate the private structure and build the list
263 of partition DNs for use by replmd_notify()
265 static int replmd_init(struct ldb_module *module)
267 struct replmd_private *replmd_private;
268 struct ldb_context *ldb = ldb_module_get_ctx(module);
269 static const char *samba_dsdb_attrs[] = { SAMBA_COMPATIBLE_FEATURES_ATTR, NULL };
270 struct ldb_dn *samba_dsdb_dn;
271 struct ldb_result *res;
273 TALLOC_CTX *frame = talloc_stackframe();
274 replmd_private = talloc_zero(module, struct replmd_private);
275 if (replmd_private == NULL) {
278 return LDB_ERR_OPERATIONS_ERROR;
280 ldb_module_set_private(module, replmd_private);
282 replmd_private->schema_dn = ldb_get_schema_basedn(ldb);
284 samba_dsdb_dn = ldb_dn_new(frame, ldb, "@SAMBA_DSDB");
285 if (!samba_dsdb_dn) {
290 ret = dsdb_module_search_dn(module, frame, &res, samba_dsdb_dn,
291 samba_dsdb_attrs, DSDB_FLAG_NEXT_MODULE, NULL);
292 if (ret == LDB_SUCCESS) {
293 replmd_private->sorted_links
294 = ldb_msg_check_string_attribute(res->msgs[0],
295 SAMBA_COMPATIBLE_FEATURES_ATTR,
296 SAMBA_SORTED_LINKS_FEATURE);
300 return ldb_next_init(module);
304 cleanup our per-transaction contexts
306 static void replmd_txn_cleanup(struct replmd_private *replmd_private)
308 talloc_free(replmd_private->la_ctx);
309 replmd_private->la_list = NULL;
310 replmd_private->la_ctx = NULL;
316 struct la_backlink *next, *prev;
317 const char *attr_name;
318 struct ldb_dn *forward_dn;
319 struct GUID target_guid;
324 a ldb_modify request operating on modules below the
327 static int linked_attr_modify(struct ldb_module *module,
328 const struct ldb_message *message,
329 struct ldb_request *parent)
331 struct ldb_request *mod_req;
333 struct ldb_context *ldb = ldb_module_get_ctx(module);
334 TALLOC_CTX *tmp_ctx = talloc_new(module);
335 struct ldb_result *res;
337 res = talloc_zero(tmp_ctx, struct ldb_result);
339 talloc_free(tmp_ctx);
340 return ldb_oom(ldb_module_get_ctx(module));
343 ret = ldb_build_mod_req(&mod_req, ldb, tmp_ctx,
347 ldb_modify_default_callback,
349 LDB_REQ_SET_LOCATION(mod_req);
350 if (ret != LDB_SUCCESS) {
351 talloc_free(tmp_ctx);
355 ret = ldb_request_add_control(mod_req, DSDB_CONTROL_REPLICATED_UPDATE_OID,
357 if (ret != LDB_SUCCESS) {
361 /* Run the new request */
362 ret = ldb_next_request(module, mod_req);
364 if (ret == LDB_SUCCESS) {
365 ret = ldb_wait(mod_req->handle, LDB_WAIT_ALL);
368 talloc_free(tmp_ctx);
373 process a backlinks we accumulated during a transaction, adding and
374 deleting the backlinks from the target objects
376 static int replmd_process_backlink(struct ldb_module *module, struct la_backlink *bl, struct ldb_request *parent)
378 struct ldb_dn *target_dn, *source_dn;
380 struct ldb_context *ldb = ldb_module_get_ctx(module);
381 struct ldb_message *msg;
382 TALLOC_CTX *frame = talloc_stackframe();
388 - construct ldb_message
389 - either an add or a delete
391 ret = dsdb_module_dn_by_guid(module, frame, &bl->target_guid, &target_dn, parent);
392 if (ret != LDB_SUCCESS) {
393 struct GUID_txt_buf guid_str;
394 DBG_WARNING("Failed to find target DN for linked attribute with GUID %s\n",
395 GUID_buf_string(&bl->target_guid, &guid_str));
396 DBG_WARNING("Please run 'samba-tool dbcheck' to resolve any missing backlinks.\n");
401 msg = ldb_msg_new(frame);
403 ldb_module_oom(module);
405 return LDB_ERR_OPERATIONS_ERROR;
408 source_dn = ldb_dn_copy(frame, bl->forward_dn);
410 ldb_module_oom(module);
412 return LDB_ERR_OPERATIONS_ERROR;
414 /* Filter down to the attributes we want in the backlink */
415 const char *accept[] = { "GUID", "SID", NULL };
416 ldb_dn_extended_filter(source_dn, accept);
419 /* construct a ldb_message for adding/deleting the backlink */
421 dn_string = ldb_dn_get_extended_linearized(frame, bl->forward_dn, 1);
423 ldb_module_oom(module);
425 return LDB_ERR_OPERATIONS_ERROR;
427 ret = ldb_msg_add_steal_string(msg, bl->attr_name, dn_string);
428 if (ret != LDB_SUCCESS) {
432 msg->elements[0].flags = bl->active?LDB_FLAG_MOD_ADD:LDB_FLAG_MOD_DELETE;
434 /* a backlink should never be single valued. Unfortunately the
435 exchange schema has a attribute
436 msExchBridgeheadedLocalConnectorsDNBL which is single
437 valued and a backlink. We need to cope with that by
438 ignoring the single value flag */
439 msg->elements[0].flags |= LDB_FLAG_INTERNAL_DISABLE_SINGLE_VALUE_CHECK;
441 ret = dsdb_module_modify(module, msg, DSDB_FLAG_NEXT_MODULE, parent);
442 if (ret == LDB_ERR_NO_SUCH_ATTRIBUTE && !bl->active) {
443 /* we allow LDB_ERR_NO_SUCH_ATTRIBUTE as success to
444 cope with possible corruption where the backlink has
445 already been removed */
446 DEBUG(3,("WARNING: backlink from %s already removed from %s - %s\n",
447 ldb_dn_get_linearized(target_dn),
448 ldb_dn_get_linearized(source_dn),
449 ldb_errstring(ldb)));
451 } else if (ret != LDB_SUCCESS) {
452 ldb_asprintf_errstring(ldb, "Failed to %s backlink from %s to %s - %s",
453 bl->active?"add":"remove",
454 ldb_dn_get_linearized(source_dn),
455 ldb_dn_get_linearized(target_dn),
465 add a backlink to the list of backlinks to add/delete in the prepare
468 forward_dn is stolen onto the defereed context
470 static int replmd_defer_add_backlink(struct ldb_module *module,
471 struct replmd_private *replmd_private,
472 const struct dsdb_schema *schema,
473 struct replmd_replicated_request *ac,
474 struct ldb_dn *forward_dn,
475 struct GUID *target_guid, bool active,
476 const struct dsdb_attribute *schema_attr,
477 struct ldb_request *parent)
479 const struct dsdb_attribute *target_attr;
480 struct la_backlink *bl;
482 bl = talloc(ac, struct la_backlink);
484 ldb_module_oom(module);
485 return LDB_ERR_OPERATIONS_ERROR;
488 target_attr = dsdb_attribute_by_linkID(schema, schema_attr->linkID ^ 1);
491 * windows 2003 has a broken schema where the
492 * definition of msDS-IsDomainFor is missing (which is
493 * supposed to be the backlink of the
494 * msDS-HasDomainNCs attribute
499 bl->attr_name = target_attr->lDAPDisplayName;
500 bl->forward_dn = talloc_steal(bl, forward_dn);
501 bl->target_guid = *target_guid;
504 DLIST_ADD(ac->la_backlinks, bl);
510 add a backlink to the list of backlinks to add/delete in the prepare
513 static int replmd_add_backlink(struct ldb_module *module,
514 struct replmd_private *replmd_private,
515 const struct dsdb_schema *schema,
516 struct ldb_dn *forward_dn,
517 struct GUID *target_guid, bool active,
518 const struct dsdb_attribute *schema_attr,
519 struct ldb_request *parent)
521 const struct dsdb_attribute *target_attr;
522 struct la_backlink bl;
525 target_attr = dsdb_attribute_by_linkID(schema, schema_attr->linkID ^ 1);
528 * windows 2003 has a broken schema where the
529 * definition of msDS-IsDomainFor is missing (which is
530 * supposed to be the backlink of the
531 * msDS-HasDomainNCs attribute
536 bl.attr_name = target_attr->lDAPDisplayName;
537 bl.forward_dn = forward_dn;
538 bl.target_guid = *target_guid;
541 ret = replmd_process_backlink(module, &bl, parent);
547 * Callback for most write operations in this module:
549 * notify the repl task that a object has changed. The notifies are
550 * gathered up in the replmd_private structure then written to the
551 * @REPLCHANGED object in each partition during the prepare_commit
553 static int replmd_op_callback(struct ldb_request *req, struct ldb_reply *ares)
556 struct replmd_replicated_request *ac =
557 talloc_get_type_abort(req->context, struct replmd_replicated_request);
558 struct replmd_private *replmd_private =
559 talloc_get_type_abort(ldb_module_get_private(ac->module), struct replmd_private);
560 struct nc_entry *modified_partition;
561 struct ldb_control *partition_ctrl;
562 const struct dsdb_control_current_partition *partition;
564 struct ldb_control **controls;
566 partition_ctrl = ldb_reply_get_control(ares, DSDB_CONTROL_CURRENT_PARTITION_OID);
568 controls = ares->controls;
569 if (ldb_request_get_control(ac->req,
570 DSDB_CONTROL_CURRENT_PARTITION_OID) == NULL) {
572 * Remove the current partition control from what we pass up
573 * the chain if it hasn't been requested manually.
575 controls = ldb_controls_except_specified(ares->controls, ares,
579 if (ares->error != LDB_SUCCESS) {
580 struct GUID_txt_buf guid_txt;
581 struct ldb_message *msg = NULL;
584 if (ac->apply_mode == false) {
585 DBG_NOTICE("Originating update failure. Error is: %s\n",
586 ldb_strerror(ares->error));
587 return ldb_module_done(ac->req, controls,
588 ares->response, ares->error);
591 msg = ac->objs->objects[ac->index_current].msg;
593 * Set at DBG_NOTICE as once these start to happe, they
594 * will happen a lot until resolved, due to repeated
595 * replication. The caller will probably print the
596 * ldb error string anyway.
598 DBG_NOTICE("DRS replication apply failure for %s. Error is: %s\n",
599 ldb_dn_get_linearized(msg->dn),
600 ldb_strerror(ares->error));
602 s = ldb_ldif_message_redacted_string(ldb_module_get_ctx(ac->module),
607 DBG_INFO("Failing DRS %s replication message was %s:\n%s\n",
608 ac->search_msg == NULL ? "ADD" : "MODIFY",
609 GUID_buf_string(&ac->objs->objects[ac->index_current].object_guid,
613 return ldb_module_done(ac->req, controls,
614 ares->response, ares->error);
617 if (ares->type != LDB_REPLY_DONE) {
618 ldb_set_errstring(ldb_module_get_ctx(ac->module), "Invalid reply type for notify\n!");
619 return ldb_module_done(ac->req, NULL,
620 NULL, LDB_ERR_OPERATIONS_ERROR);
623 if (ac->apply_mode == false) {
624 struct la_backlink *bl;
626 * process our backlink list after an replmd_add(),
627 * creating and deleting backlinks as necessary (this
628 * code is sync). The other cases are handled inline
631 for (bl=ac->la_backlinks; bl; bl=bl->next) {
632 ret = replmd_process_backlink(ac->module, bl, ac->req);
633 if (ret != LDB_SUCCESS) {
634 return ldb_module_done(ac->req, NULL,
640 if (!partition_ctrl) {
641 ldb_set_errstring(ldb_module_get_ctx(ac->module),"No partition control on reply");
642 return ldb_module_done(ac->req, NULL,
643 NULL, LDB_ERR_OPERATIONS_ERROR);
646 partition = talloc_get_type_abort(partition_ctrl->data,
647 struct dsdb_control_current_partition);
649 if (ac->seq_num > 0) {
650 for (modified_partition = replmd_private->ncs; modified_partition;
651 modified_partition = modified_partition->next) {
652 if (ldb_dn_compare(modified_partition->dn, partition->dn) == 0) {
657 if (modified_partition == NULL) {
658 modified_partition = talloc_zero(replmd_private, struct nc_entry);
659 if (!modified_partition) {
660 ldb_oom(ldb_module_get_ctx(ac->module));
661 return ldb_module_done(ac->req, NULL,
662 NULL, LDB_ERR_OPERATIONS_ERROR);
664 modified_partition->dn = ldb_dn_copy(modified_partition, partition->dn);
665 if (!modified_partition->dn) {
666 ldb_oom(ldb_module_get_ctx(ac->module));
667 return ldb_module_done(ac->req, NULL,
668 NULL, LDB_ERR_OPERATIONS_ERROR);
670 DLIST_ADD(replmd_private->ncs, modified_partition);
673 if (ac->seq_num > modified_partition->mod_usn) {
674 modified_partition->mod_usn = ac->seq_num;
676 modified_partition->mod_usn_urgent = ac->seq_num;
679 if (!ac->apply_mode) {
680 replmd_private->originating_updates = true;
684 if (ac->apply_mode) {
685 ret = replmd_replicated_apply_isDeleted(ac);
686 if (ret != LDB_SUCCESS) {
687 return ldb_module_done(ac->req, NULL, NULL, ret);
691 /* free the partition control container here, for the
692 * common path. Other cases will have it cleaned up
693 * eventually with the ares */
694 talloc_free(partition_ctrl);
695 return ldb_module_done(ac->req, controls,
696 ares->response, LDB_SUCCESS);
702 * update a @REPLCHANGED record in each partition if there have been
703 * any writes of replicated data in the partition
705 static int replmd_notify_store(struct ldb_module *module, struct ldb_request *parent)
707 struct replmd_private *replmd_private =
708 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
710 while (replmd_private->ncs) {
712 struct nc_entry *modified_partition = replmd_private->ncs;
714 ret = dsdb_module_save_partition_usn(module, modified_partition->dn,
715 modified_partition->mod_usn,
716 modified_partition->mod_usn_urgent, parent);
717 if (ret != LDB_SUCCESS) {
718 DEBUG(0,(__location__ ": Failed to save partition uSN for %s\n",
719 ldb_dn_get_linearized(modified_partition->dn)));
723 if (ldb_dn_compare(modified_partition->dn,
724 replmd_private->schema_dn) == 0) {
725 struct ldb_result *ext_res;
726 ret = dsdb_module_extended(module,
727 replmd_private->schema_dn,
729 DSDB_EXTENDED_SCHEMA_UPDATE_NOW_OID,
731 DSDB_FLAG_NEXT_MODULE,
733 if (ret != LDB_SUCCESS) {
736 talloc_free(ext_res);
739 DLIST_REMOVE(replmd_private->ncs, modified_partition);
740 talloc_free(modified_partition);
748 created a replmd_replicated_request context
750 static struct replmd_replicated_request *replmd_ctx_init(struct ldb_module *module,
751 struct ldb_request *req)
753 struct ldb_context *ldb;
754 struct replmd_replicated_request *ac;
755 const struct GUID *our_invocation_id;
757 ldb = ldb_module_get_ctx(module);
759 ac = talloc_zero(req, struct replmd_replicated_request);
768 ac->schema = dsdb_get_schema(ldb, ac);
770 ldb_debug_set(ldb, LDB_DEBUG_FATAL,
771 "replmd_modify: no dsdb_schema loaded");
772 DEBUG(0,(__location__ ": %s\n", ldb_errstring(ldb)));
777 /* get our invocationId */
778 our_invocation_id = samdb_ntds_invocation_id(ldb);
779 if (!our_invocation_id) {
780 ldb_debug_set(ldb, LDB_DEBUG_FATAL,
781 "replmd_add: unable to find invocationId\n");
785 ac->our_invocation_id = *our_invocation_id;
791 add a time element to a record
793 static int add_time_element(struct ldb_message *msg, const char *attr, time_t t)
795 struct ldb_message_element *el;
799 if (ldb_msg_find_element(msg, attr) != NULL) {
803 s = ldb_timestring(msg, t);
805 return LDB_ERR_OPERATIONS_ERROR;
808 ret = ldb_msg_add_string(msg, attr, s);
809 if (ret != LDB_SUCCESS) {
813 el = ldb_msg_find_element(msg, attr);
814 /* always set as replace. This works because on add ops, the flag
816 el->flags = LDB_FLAG_MOD_REPLACE;
822 add a uint64_t element to a record
824 static int add_uint64_element(struct ldb_context *ldb, struct ldb_message *msg,
825 const char *attr, uint64_t v)
827 struct ldb_message_element *el;
830 if (ldb_msg_find_element(msg, attr) != NULL) {
834 ret = samdb_msg_add_uint64(ldb, msg, msg, attr, v);
835 if (ret != LDB_SUCCESS) {
839 el = ldb_msg_find_element(msg, attr);
840 /* always set as replace. This works because on add ops, the flag
842 el->flags = LDB_FLAG_MOD_REPLACE;
847 static int replmd_replPropertyMetaData1_attid_sort(const struct replPropertyMetaData1 *m1,
848 const struct replPropertyMetaData1 *m2,
849 const uint32_t *rdn_attid)
852 * This assignment seems inoccous, but it is critical for the
853 * system, as we need to do the comparisons as a unsigned
854 * quantity, not signed (enums are signed integers)
856 uint32_t attid_1 = m1->attid;
857 uint32_t attid_2 = m2->attid;
859 if (attid_1 == attid_2) {
864 * See above regarding this being an unsigned comparison.
865 * Otherwise when the high bit is set on non-standard
866 * attributes, they would end up first, before objectClass
869 return attid_1 > attid_2 ? 1 : -1;
872 static int replmd_replPropertyMetaDataCtr1_verify(struct ldb_context *ldb,
873 struct replPropertyMetaDataCtr1 *ctr1,
876 if (ctr1->count == 0) {
877 ldb_debug_set(ldb, LDB_DEBUG_FATAL,
878 "No elements found in replPropertyMetaData for %s!\n",
879 ldb_dn_get_linearized(dn));
880 return LDB_ERR_CONSTRAINT_VIOLATION;
883 /* the objectClass attribute is value 0x00000000, so must be first */
884 if (ctr1->array[0].attid != DRSUAPI_ATTID_objectClass) {
885 ldb_debug_set(ldb, LDB_DEBUG_FATAL,
886 "No objectClass found in replPropertyMetaData for %s!\n",
887 ldb_dn_get_linearized(dn));
888 return LDB_ERR_OBJECT_CLASS_VIOLATION;
894 static int replmd_replPropertyMetaDataCtr1_sort_and_verify(struct ldb_context *ldb,
895 struct replPropertyMetaDataCtr1 *ctr1,
898 /* Note this is O(n^2) for the almost-sorted case, which this is */
899 LDB_TYPESAFE_QSORT(ctr1->array, ctr1->count, NULL,
900 replmd_replPropertyMetaData1_attid_sort);
901 return replmd_replPropertyMetaDataCtr1_verify(ldb, ctr1, dn);
904 static int replmd_ldb_message_element_attid_sort(const struct ldb_message_element *e1,
905 const struct ldb_message_element *e2,
906 const struct dsdb_schema *schema)
908 const struct dsdb_attribute *a1;
909 const struct dsdb_attribute *a2;
912 * TODO: make this faster by caching the dsdb_attribute pointer
913 * on the ldb_messag_element
916 a1 = dsdb_attribute_by_lDAPDisplayName(schema, e1->name);
917 a2 = dsdb_attribute_by_lDAPDisplayName(schema, e2->name);
920 * TODO: remove this check, we should rely on e1 and e2 having valid attribute names
924 return strcasecmp(e1->name, e2->name);
926 if (a1->attributeID_id == a2->attributeID_id) {
929 return a1->attributeID_id > a2->attributeID_id ? 1 : -1;
932 static void replmd_ldb_message_sort(struct ldb_message *msg,
933 const struct dsdb_schema *schema)
935 LDB_TYPESAFE_QSORT(msg->elements, msg->num_elements, schema, replmd_ldb_message_element_attid_sort);
938 static int replmd_build_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct dsdb_dn *dsdb_dn,
939 const struct GUID *invocation_id,
940 uint64_t local_usn, NTTIME nttime);
942 static int parsed_dn_compare(struct parsed_dn *pdn1, struct parsed_dn *pdn2);
944 static int get_parsed_dns(struct ldb_module *module, TALLOC_CTX *mem_ctx,
945 struct ldb_message_element *el, struct parsed_dn **pdn,
946 const char *ldap_oid, struct ldb_request *parent);
948 static int check_parsed_dn_duplicates(struct ldb_module *module,
949 struct ldb_message_element *el,
950 struct parsed_dn *pdn);
953 fix up linked attributes in replmd_add.
954 This involves setting up the right meta-data in extended DN
955 components, and creating backlinks to the object
957 static int replmd_add_fix_la(struct ldb_module *module, TALLOC_CTX *mem_ctx,
958 struct replmd_private *replmd_private,
959 struct ldb_message_element *el,
960 struct replmd_replicated_request *ac,
962 struct ldb_dn *forward_dn,
963 const struct dsdb_attribute *sa,
964 struct ldb_request *parent)
967 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
968 struct ldb_context *ldb = ldb_module_get_ctx(module);
969 struct parsed_dn *pdn;
970 /* We will take a reference to the schema in replmd_add_backlink */
971 const struct dsdb_schema *schema = dsdb_get_schema(ldb, NULL);
972 struct ldb_val *new_values = NULL;
975 if (dsdb_check_single_valued_link(sa, el) == LDB_SUCCESS) {
976 el->flags |= LDB_FLAG_INTERNAL_DISABLE_SINGLE_VALUE_CHECK;
978 ldb_asprintf_errstring(ldb,
979 "Attribute %s is single valued but "
980 "more than one value has been supplied",
982 talloc_free(tmp_ctx);
983 return LDB_ERR_CONSTRAINT_VIOLATION;
986 ret = get_parsed_dns(module, tmp_ctx, el, &pdn,
987 sa->syntax->ldap_oid, parent);
988 if (ret != LDB_SUCCESS) {
989 talloc_free(tmp_ctx);
993 ret = check_parsed_dn_duplicates(module, el, pdn);
994 if (ret != LDB_SUCCESS) {
995 talloc_free(tmp_ctx);
999 new_values = talloc_array(tmp_ctx, struct ldb_val, el->num_values);
1000 if (new_values == NULL) {
1001 ldb_module_oom(module);
1002 talloc_free(tmp_ctx);
1003 return LDB_ERR_OPERATIONS_ERROR;
1006 for (i = 0; i < el->num_values; i++) {
1007 struct parsed_dn *p = &pdn[i];
1008 ret = replmd_build_la_val(el->values, p->v, p->dsdb_dn,
1009 &ac->our_invocation_id,
1011 if (ret != LDB_SUCCESS) {
1012 talloc_free(tmp_ctx);
1016 ret = replmd_defer_add_backlink(module, replmd_private,
1018 forward_dn, &p->guid, true, sa,
1020 if (ret != LDB_SUCCESS) {
1021 talloc_free(tmp_ctx);
1025 new_values[i] = *p->v;
1027 el->values = talloc_steal(mem_ctx, new_values);
1029 talloc_free(tmp_ctx);
1033 static int replmd_add_make_extended_dn(struct ldb_request *req,
1034 const DATA_BLOB *guid_blob,
1035 struct ldb_dn **_extended_dn)
1038 const DATA_BLOB *sid_blob;
1039 /* Calculate an extended DN for any linked attributes */
1040 struct ldb_dn *extended_dn = ldb_dn_copy(req, req->op.add.message->dn);
1042 return LDB_ERR_OPERATIONS_ERROR;
1044 ret = ldb_dn_set_extended_component(extended_dn, "GUID", guid_blob);
1045 if (ret != LDB_SUCCESS) {
1049 sid_blob = ldb_msg_find_ldb_val(req->op.add.message, "objectSID");
1050 if (sid_blob != NULL) {
1051 ret = ldb_dn_set_extended_component(extended_dn, "SID", sid_blob);
1052 if (ret != LDB_SUCCESS) {
1056 *_extended_dn = extended_dn;
1061 intercept add requests
1063 static int replmd_add(struct ldb_module *module, struct ldb_request *req)
1065 struct ldb_context *ldb;
1066 struct ldb_control *control;
1067 struct replmd_replicated_request *ac;
1068 enum ndr_err_code ndr_err;
1069 struct ldb_request *down_req;
1070 struct ldb_message *msg;
1071 const DATA_BLOB *guid_blob;
1072 DATA_BLOB guid_blob_stack;
1074 uint8_t guid_data[16];
1075 struct replPropertyMetaDataBlob nmd;
1076 struct ldb_val nmd_value;
1077 struct ldb_dn *extended_dn = NULL;
1080 * The use of a time_t here seems odd, but as the NTTIME
1081 * elements are actually declared as NTTIME_1sec in the IDL,
1082 * getting a higher resolution timestamp is not required.
1084 time_t t = time(NULL);
1089 unsigned int functional_level;
1091 bool allow_add_guid = false;
1092 bool remove_current_guid = false;
1093 bool is_urgent = false;
1094 bool is_schema_nc = false;
1095 struct ldb_message_element *objectclass_el;
1096 struct replmd_private *replmd_private =
1097 talloc_get_type_abort(ldb_module_get_private(module), struct replmd_private);
1099 /* check if there's a show relax control (used by provision to say 'I know what I'm doing') */
1100 control = ldb_request_get_control(req, LDB_CONTROL_RELAX_OID);
1102 allow_add_guid = true;
1105 /* do not manipulate our control entries */
1106 if (ldb_dn_is_special(req->op.add.message->dn)) {
1107 return ldb_next_request(module, req);
1110 ldb = ldb_module_get_ctx(module);
1112 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_add\n");
1114 guid_blob = ldb_msg_find_ldb_val(req->op.add.message, "objectGUID");
1115 if (guid_blob != NULL) {
1116 if (!allow_add_guid) {
1117 ldb_set_errstring(ldb,
1118 "replmd_add: it's not allowed to add an object with objectGUID!");
1119 return LDB_ERR_UNWILLING_TO_PERFORM;
1121 NTSTATUS status = GUID_from_data_blob(guid_blob,&guid);
1122 if (!NT_STATUS_IS_OK(status)) {
1123 ldb_set_errstring(ldb,
1124 "replmd_add: Unable to parse the 'objectGUID' as a GUID!");
1125 return LDB_ERR_UNWILLING_TO_PERFORM;
1127 /* we remove this attribute as it can be a string and
1128 * will not be treated correctly and then we will re-add
1129 * it later on in the good format */
1130 remove_current_guid = true;
1134 guid = GUID_random();
1136 guid_blob_stack = data_blob_const(guid_data, sizeof(guid_data));
1138 /* This can't fail */
1139 ndr_push_struct_into_fixed_blob(&guid_blob_stack, &guid,
1140 (ndr_push_flags_fn_t)ndr_push_GUID);
1141 guid_blob = &guid_blob_stack;
1144 ac = replmd_ctx_init(module, req);
1146 return ldb_module_oom(module);
1149 functional_level = dsdb_functional_level(ldb);
1151 /* Get a sequence number from the backend */
1152 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &ac->seq_num);
1153 if (ret != LDB_SUCCESS) {
1158 /* we have to copy the message as the caller might have it as a const */
1159 msg = ldb_msg_copy_shallow(ac, req->op.add.message);
1163 return LDB_ERR_OPERATIONS_ERROR;
1166 /* generated times */
1167 unix_to_nt_time(&now, t);
1168 time_str = ldb_timestring(msg, t);
1172 return LDB_ERR_OPERATIONS_ERROR;
1174 if (remove_current_guid) {
1175 ldb_msg_remove_attr(msg,"objectGUID");
1179 * remove autogenerated attributes
1181 ldb_msg_remove_attr(msg, "whenCreated");
1182 ldb_msg_remove_attr(msg, "whenChanged");
1183 ldb_msg_remove_attr(msg, "uSNCreated");
1184 ldb_msg_remove_attr(msg, "uSNChanged");
1185 ldb_msg_remove_attr(msg, "replPropertyMetaData");
1188 * readd replicated attributes
1190 ret = ldb_msg_add_string(msg, "whenCreated", time_str);
1191 if (ret != LDB_SUCCESS) {
1197 /* build the replication meta_data */
1200 nmd.ctr.ctr1.count = msg->num_elements;
1201 nmd.ctr.ctr1.array = talloc_array(msg,
1202 struct replPropertyMetaData1,
1203 nmd.ctr.ctr1.count);
1204 if (!nmd.ctr.ctr1.array) {
1207 return LDB_ERR_OPERATIONS_ERROR;
1210 is_schema_nc = ldb_dn_compare_base(replmd_private->schema_dn, msg->dn) == 0;
1212 for (i=0; i < msg->num_elements;) {
1213 struct ldb_message_element *e = &msg->elements[i];
1214 struct replPropertyMetaData1 *m = &nmd.ctr.ctr1.array[ni];
1215 const struct dsdb_attribute *sa;
1217 if (e->name[0] == '@') {
1222 sa = dsdb_attribute_by_lDAPDisplayName(ac->schema, e->name);
1224 ldb_debug_set(ldb, LDB_DEBUG_ERROR,
1225 "replmd_add: attribute '%s' not defined in schema\n",
1228 return LDB_ERR_NO_SUCH_ATTRIBUTE;
1231 if ((sa->systemFlags & DS_FLAG_ATTR_NOT_REPLICATED) || (sa->systemFlags & DS_FLAG_ATTR_IS_CONSTRUCTED)) {
1232 /* if the attribute is not replicated (0x00000001)
1233 * or constructed (0x00000004) it has no metadata
1239 if (sa->linkID != 0 && functional_level > DS_DOMAIN_FUNCTION_2000) {
1240 if (extended_dn == NULL) {
1241 ret = replmd_add_make_extended_dn(req,
1244 if (ret != LDB_SUCCESS) {
1251 * Prepare the context for the backlinks and
1252 * create metadata for the forward links. The
1253 * backlinks are created in
1254 * replmd_op_callback() after the successful
1255 * ADD of the object.
1257 ret = replmd_add_fix_la(module, msg->elements,
1262 if (ret != LDB_SUCCESS) {
1266 /* linked attributes are not stored in
1267 replPropertyMetaData in FL above w2k */
1272 m->attid = dsdb_attribute_get_attid(sa, is_schema_nc);
1274 if (m->attid == DRSUAPI_ATTID_isDeleted) {
1275 const struct ldb_val *rdn_val = ldb_dn_get_rdn_val(msg->dn);
1278 if (rdn_val == NULL) {
1281 return LDB_ERR_OPERATIONS_ERROR;
1284 rdn = (const char*)rdn_val->data;
1285 if (strcmp(rdn, "Deleted Objects") == 0) {
1287 * Set the originating_change_time to 29/12/9999 at 23:59:59
1288 * as specified in MS-ADTS 7.1.1.4.2 Deleted Objects Container
1290 m->originating_change_time = DELETED_OBJECT_CONTAINER_CHANGE_TIME;
1292 m->originating_change_time = now;
1295 m->originating_change_time = now;
1297 m->originating_invocation_id = ac->our_invocation_id;
1298 m->originating_usn = ac->seq_num;
1299 m->local_usn = ac->seq_num;
1302 if (!(e->flags & DSDB_FLAG_INTERNAL_FORCE_META_DATA)) {
1307 e->flags &= ~DSDB_FLAG_INTERNAL_FORCE_META_DATA;
1309 if (e->num_values != 0) {
1314 ldb_msg_remove_element(msg, e);
1317 /* fix meta data count */
1318 nmd.ctr.ctr1.count = ni;
1321 * sort meta data array
1323 ret = replmd_replPropertyMetaDataCtr1_sort_and_verify(ldb, &nmd.ctr.ctr1, msg->dn);
1324 if (ret != LDB_SUCCESS) {
1325 ldb_asprintf_errstring(ldb, "%s: error during direct ADD: %s", __func__, ldb_errstring(ldb));
1330 /* generated NDR encoded values */
1331 ndr_err = ndr_push_struct_blob(&nmd_value, msg,
1333 (ndr_push_flags_fn_t)ndr_push_replPropertyMetaDataBlob);
1334 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1337 return LDB_ERR_OPERATIONS_ERROR;
1341 * add the autogenerated values
1343 ret = dsdb_msg_add_guid(msg, &guid, "objectGUID");
1344 if (ret != LDB_SUCCESS) {
1349 ret = ldb_msg_add_string(msg, "whenChanged", time_str);
1350 if (ret != LDB_SUCCESS) {
1355 ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNCreated", ac->seq_num);
1356 if (ret != LDB_SUCCESS) {
1361 ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNChanged", ac->seq_num);
1362 if (ret != LDB_SUCCESS) {
1367 ret = ldb_msg_add_value(msg, "replPropertyMetaData", &nmd_value, NULL);
1368 if (ret != LDB_SUCCESS) {
1375 * sort the attributes by attid before storing the object
1377 replmd_ldb_message_sort(msg, ac->schema);
1380 * Assert that we do have an objectClass
1382 objectclass_el = ldb_msg_find_element(msg, "objectClass");
1383 if (objectclass_el == NULL) {
1384 ldb_asprintf_errstring(ldb, __location__
1385 ": objectClass missing on %s\n",
1386 ldb_dn_get_linearized(msg->dn));
1388 return LDB_ERR_OBJECT_CLASS_VIOLATION;
1390 is_urgent = replmd_check_urgent_objectclass(objectclass_el,
1391 REPL_URGENT_ON_CREATE);
1393 ac->is_urgent = is_urgent;
1394 ret = ldb_build_add_req(&down_req, ldb, ac,
1397 ac, replmd_op_callback,
1400 LDB_REQ_SET_LOCATION(down_req);
1401 if (ret != LDB_SUCCESS) {
1406 /* current partition control is needed by "replmd_op_callback" */
1407 if (ldb_request_get_control(req, DSDB_CONTROL_CURRENT_PARTITION_OID) == NULL) {
1408 ret = ldb_request_add_control(down_req,
1409 DSDB_CONTROL_CURRENT_PARTITION_OID,
1411 if (ret != LDB_SUCCESS) {
1417 if (functional_level == DS_DOMAIN_FUNCTION_2000) {
1418 ret = ldb_request_add_control(down_req, DSDB_CONTROL_APPLY_LINKS, false, NULL);
1419 if (ret != LDB_SUCCESS) {
1425 /* mark the control done */
1427 control->critical = 0;
1429 /* go on with the call chain */
1430 return ldb_next_request(module, down_req);
1435 * update the replPropertyMetaData for one element
1437 static int replmd_update_rpmd_element(struct ldb_context *ldb,
1438 struct ldb_message *msg,
1439 struct ldb_message_element *el,
1440 struct ldb_message_element *old_el,
1441 struct replPropertyMetaDataBlob *omd,
1442 const struct dsdb_schema *schema,
1444 const struct GUID *our_invocation_id,
1447 bool is_forced_rodc,
1448 struct ldb_request *req)
1451 const struct dsdb_attribute *a;
1452 struct replPropertyMetaData1 *md1;
1453 bool may_skip = false;
1456 a = dsdb_attribute_by_lDAPDisplayName(schema, el->name);
1458 if (ldb_request_get_control(req, LDB_CONTROL_RELAX_OID)) {
1459 /* allow this to make it possible for dbcheck
1460 to remove bad attributes */
1464 DEBUG(0,(__location__ ": Unable to find attribute %s in schema\n",
1466 return LDB_ERR_OPERATIONS_ERROR;
1469 attid = dsdb_attribute_get_attid(a, is_schema_nc);
1471 if ((a->systemFlags & DS_FLAG_ATTR_NOT_REPLICATED) || (a->systemFlags & DS_FLAG_ATTR_IS_CONSTRUCTED)) {
1476 * if the attribute's value haven't changed, and this isn't
1477 * just a delete of everything then return LDB_SUCCESS Unless
1478 * we have the provision control or if the attribute is
1479 * interSiteTopologyGenerator as this page explain:
1480 * http://support.microsoft.com/kb/224815 this attribute is
1481 * periodicaly written by the DC responsible for the intersite
1482 * generation in a given site
1484 * Unchanged could be deleting or replacing an already-gone
1485 * thing with an unconstrained delete/empty replace or a
1486 * replace with the same value, but not an add with the same
1487 * value because that could be about adding a duplicate (which
1488 * is for someone else to error out on).
1490 if (old_el != NULL && ldb_msg_element_equal_ordered(el, old_el)) {
1491 if (LDB_FLAG_MOD_TYPE(el->flags) == LDB_FLAG_MOD_REPLACE) {
1494 } else if (old_el == NULL && el->num_values == 0) {
1495 if (LDB_FLAG_MOD_TYPE(el->flags) == LDB_FLAG_MOD_REPLACE) {
1497 } else if (LDB_FLAG_MOD_TYPE(el->flags) == LDB_FLAG_MOD_DELETE) {
1500 } else if (a->linkID != 0 && LDB_FLAG_MOD_TYPE(el->flags) == LDB_FLAG_MOD_DELETE &&
1501 ldb_request_get_control(req, DSDB_CONTROL_REPLMD_VANISH_LINKS) != NULL) {
1503 * We intentionally skip the version bump when attempting to
1506 * The control is set by dbcheck and expunge-tombstones which
1507 * both attempt to be non-replicating. Otherwise, making an
1508 * alteration to the replication state would trigger a
1509 * broadcast of all expunged objects.
1514 if (el->flags & DSDB_FLAG_INTERNAL_FORCE_META_DATA) {
1516 el->flags &= ~DSDB_FLAG_INTERNAL_FORCE_META_DATA;
1520 if (strcmp(el->name, "interSiteTopologyGenerator") != 0 &&
1521 !ldb_request_get_control(req, LDB_CONTROL_PROVISION_OID)) {
1523 * allow this to make it possible for dbcheck
1524 * to rebuild broken metadata
1530 for (i=0; i<omd->ctr.ctr1.count; i++) {
1532 * First check if we find it under the msDS-IntID,
1533 * then check if we find it under the OID and
1536 * This allows the administrator to simply re-write
1537 * the attributes and so restore replication, which is
1538 * likely what they will try to do.
1540 if (attid == omd->ctr.ctr1.array[i].attid) {
1544 if (a->attributeID_id == omd->ctr.ctr1.array[i].attid) {
1549 if (a->linkID != 0 && dsdb_functional_level(ldb) > DS_DOMAIN_FUNCTION_2000) {
1550 /* linked attributes are not stored in
1551 replPropertyMetaData in FL above w2k, but we do
1552 raise the seqnum for the object */
1553 if (*seq_num == 0 &&
1554 ldb_sequence_number(ldb, LDB_SEQ_NEXT, seq_num) != LDB_SUCCESS) {
1555 return LDB_ERR_OPERATIONS_ERROR;
1560 if (i == omd->ctr.ctr1.count) {
1561 /* we need to add a new one */
1562 omd->ctr.ctr1.array = talloc_realloc(msg, omd->ctr.ctr1.array,
1563 struct replPropertyMetaData1, omd->ctr.ctr1.count+1);
1564 if (omd->ctr.ctr1.array == NULL) {
1566 return LDB_ERR_OPERATIONS_ERROR;
1568 omd->ctr.ctr1.count++;
1569 ZERO_STRUCT(omd->ctr.ctr1.array[i]);
1572 /* Get a new sequence number from the backend. We only do this
1573 * if we have a change that requires a new
1574 * replPropertyMetaData element
1576 if (*seq_num == 0) {
1577 int ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, seq_num);
1578 if (ret != LDB_SUCCESS) {
1579 return LDB_ERR_OPERATIONS_ERROR;
1583 md1 = &omd->ctr.ctr1.array[i];
1587 if (md1->attid == DRSUAPI_ATTID_isDeleted) {
1588 const struct ldb_val *rdn_val = ldb_dn_get_rdn_val(msg->dn);
1591 if (rdn_val == NULL) {
1593 return LDB_ERR_OPERATIONS_ERROR;
1596 rdn = (const char*)rdn_val->data;
1597 if (strcmp(rdn, "Deleted Objects") == 0) {
1599 * Set the originating_change_time to 29/12/9999 at 23:59:59
1600 * as specified in MS-ADTS 7.1.1.4.2 Deleted Objects Container
1602 md1->originating_change_time = DELETED_OBJECT_CONTAINER_CHANGE_TIME;
1604 md1->originating_change_time = now;
1607 md1->originating_change_time = now;
1609 md1->originating_invocation_id = *our_invocation_id;
1610 md1->originating_usn = *seq_num;
1611 md1->local_usn = *seq_num;
1613 if (is_forced_rodc) {
1614 /* Force version to 0 to be overriden later via replication */
1622 * Bump the replPropertyMetaData version on an attribute, and if it
1623 * has changed (or forced by leaving rdn_old NULL), update the value
1626 * This is important, as calling a modify operation may not change the
1627 * version number if the values appear unchanged, but a rename between
1628 * parents bumps this value.
1631 static int replmd_update_rpmd_rdn_attr(struct ldb_context *ldb,
1632 struct ldb_message *msg,
1633 const struct ldb_val *rdn_new,
1634 const struct ldb_val *rdn_old,
1635 struct replPropertyMetaDataBlob *omd,
1636 struct replmd_replicated_request *ar,
1639 bool is_forced_rodc)
1641 const char *rdn_name = ldb_dn_get_rdn_name(msg->dn);
1642 const struct dsdb_attribute *rdn_attr =
1643 dsdb_attribute_by_lDAPDisplayName(ar->schema, rdn_name);
1644 const char *attr_name = rdn_attr != NULL ?
1645 rdn_attr->lDAPDisplayName :
1647 struct ldb_message_element new_el = {
1648 .flags = LDB_FLAG_MOD_REPLACE,
1651 .values = discard_const_p(struct ldb_val, rdn_new)
1653 struct ldb_message_element old_el = {
1654 .flags = LDB_FLAG_MOD_REPLACE,
1656 .num_values = rdn_old ? 1 : 0,
1657 .values = discard_const_p(struct ldb_val, rdn_old)
1660 if (ldb_msg_element_equal_ordered(&new_el, &old_el) == false) {
1661 int ret = ldb_msg_add(msg, &new_el, LDB_FLAG_MOD_REPLACE);
1662 if (ret != LDB_SUCCESS) {
1663 return ldb_oom(ldb);
1667 return replmd_update_rpmd_element(ldb, msg, &new_el, NULL,
1668 omd, ar->schema, &ar->seq_num,
1669 &ar->our_invocation_id,
1670 now, is_schema_nc, is_forced_rodc,
1675 static uint64_t find_max_local_usn(struct replPropertyMetaDataBlob omd)
1677 uint32_t count = omd.ctr.ctr1.count;
1680 for (i=0; i < count; i++) {
1681 struct replPropertyMetaData1 m = omd.ctr.ctr1.array[i];
1682 if (max < m.local_usn) {
1690 * update the replPropertyMetaData object each time we modify an
1691 * object. This is needed for DRS replication, as the merge on the
1692 * client is based on this object
1694 static int replmd_update_rpmd(struct ldb_module *module,
1695 const struct dsdb_schema *schema,
1696 struct ldb_request *req,
1697 const char * const *rename_attrs,
1698 struct ldb_message *msg, uint64_t *seq_num,
1699 time_t t, bool is_schema_nc,
1700 bool *is_urgent, bool *rodc)
1702 const struct ldb_val *omd_value;
1703 enum ndr_err_code ndr_err;
1704 struct replPropertyMetaDataBlob omd;
1707 const struct GUID *our_invocation_id;
1709 const char * const *attrs = NULL;
1710 const char * const attrs2[] = { "uSNChanged", "objectClass", "instanceType", NULL };
1711 struct ldb_result *res;
1712 struct ldb_context *ldb;
1713 struct ldb_message_element *objectclass_el;
1714 enum urgent_situation situation;
1715 bool rmd_is_provided;
1716 bool rmd_is_just_resorted = false;
1717 const char *not_rename_attrs[4 + msg->num_elements];
1718 bool is_forced_rodc = false;
1721 attrs = rename_attrs;
1723 for (i = 0; i < msg->num_elements; i++) {
1724 not_rename_attrs[i] = msg->elements[i].name;
1726 not_rename_attrs[i] = "replPropertyMetaData";
1727 not_rename_attrs[i+1] = "objectClass";
1728 not_rename_attrs[i+2] = "instanceType";
1729 not_rename_attrs[i+3] = NULL;
1730 attrs = not_rename_attrs;
1733 ldb = ldb_module_get_ctx(module);
1735 ret = samdb_rodc(ldb, rodc);
1736 if (ret != LDB_SUCCESS) {
1737 DEBUG(4, (__location__ ": unable to tell if we are an RODC\n"));
1742 ldb_request_get_control(req, DSDB_CONTROL_FORCE_RODC_LOCAL_CHANGE)) {
1743 is_forced_rodc = true;
1746 our_invocation_id = samdb_ntds_invocation_id(ldb);
1747 if (!our_invocation_id) {
1748 /* this happens during an initial vampire while
1749 updating the schema */
1750 DEBUG(5,("No invocationID - skipping replPropertyMetaData update\n"));
1754 unix_to_nt_time(&now, t);
1756 if (ldb_request_get_control(req, DSDB_CONTROL_CHANGEREPLMETADATA_OID)) {
1757 rmd_is_provided = true;
1758 if (ldb_request_get_control(req, DSDB_CONTROL_CHANGEREPLMETADATA_RESORT_OID)) {
1759 rmd_is_just_resorted = true;
1762 rmd_is_provided = false;
1765 /* if isDeleted is present and is TRUE, then we consider we are deleting,
1766 * otherwise we consider we are updating */
1767 if (ldb_msg_check_string_attribute(msg, "isDeleted", "TRUE")) {
1768 situation = REPL_URGENT_ON_DELETE;
1769 } else if (rename_attrs) {
1770 situation = REPL_URGENT_ON_CREATE | REPL_URGENT_ON_DELETE;
1772 situation = REPL_URGENT_ON_UPDATE;
1775 if (rmd_is_provided) {
1776 /* In this case the change_replmetadata control was supplied */
1777 /* We check that it's the only attribute that is provided
1778 * (it's a rare case so it's better to keep the code simplier)
1779 * We also check that the highest local_usn is bigger or the same as
1782 if( msg->num_elements != 1 ||
1783 strncmp(msg->elements[0].name,
1784 "replPropertyMetaData", 20) ) {
1785 DEBUG(0,(__location__ ": changereplmetada control called without "\
1786 "a specified replPropertyMetaData attribute or with others\n"));
1787 return LDB_ERR_OPERATIONS_ERROR;
1789 if (situation != REPL_URGENT_ON_UPDATE) {
1790 DEBUG(0,(__location__ ": changereplmetada control can't be called when deleting an object\n"));
1791 return LDB_ERR_OPERATIONS_ERROR;
1793 omd_value = ldb_msg_find_ldb_val(msg, "replPropertyMetaData");
1795 DEBUG(0,(__location__ ": replPropertyMetaData was not specified for Object %s\n",
1796 ldb_dn_get_linearized(msg->dn)));
1797 return LDB_ERR_OPERATIONS_ERROR;
1799 ndr_err = ndr_pull_struct_blob(omd_value, msg, &omd,
1800 (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
1801 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1802 DEBUG(0,(__location__ ": Failed to parse replPropertyMetaData for %s\n",
1803 ldb_dn_get_linearized(msg->dn)));
1804 return LDB_ERR_OPERATIONS_ERROR;
1807 ret = dsdb_module_search_dn(module, msg, &res, msg->dn, attrs2,
1808 DSDB_FLAG_NEXT_MODULE |
1809 DSDB_SEARCH_SHOW_RECYCLED |
1810 DSDB_SEARCH_SHOW_EXTENDED_DN |
1811 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT |
1812 DSDB_SEARCH_REVEAL_INTERNALS, req);
1814 if (ret != LDB_SUCCESS) {
1818 if (rmd_is_just_resorted == false) {
1819 *seq_num = find_max_local_usn(omd);
1821 db_seq = ldb_msg_find_attr_as_uint64(res->msgs[0], "uSNChanged", 0);
1824 * The test here now allows for a new
1825 * replPropertyMetaData with no change, if was
1826 * just dbcheck re-sorting the values.
1828 if (*seq_num <= db_seq) {
1829 DEBUG(0,(__location__ ": changereplmetada control provided but max(local_usn)" \
1830 " is less than uSNChanged (max = %lld uSNChanged = %lld)\n",
1831 (long long)*seq_num, (long long)db_seq));
1832 return LDB_ERR_OPERATIONS_ERROR;
1837 /* search for the existing replPropertyMetaDataBlob. We need
1838 * to use REVEAL and ask for DNs in storage format to support
1839 * the check for values being the same in
1840 * replmd_update_rpmd_element()
1842 ret = dsdb_module_search_dn(module, msg, &res, msg->dn, attrs,
1843 DSDB_FLAG_NEXT_MODULE |
1844 DSDB_SEARCH_SHOW_RECYCLED |
1845 DSDB_SEARCH_SHOW_EXTENDED_DN |
1846 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT |
1847 DSDB_SEARCH_REVEAL_INTERNALS, req);
1848 if (ret != LDB_SUCCESS) {
1852 omd_value = ldb_msg_find_ldb_val(res->msgs[0], "replPropertyMetaData");
1854 DEBUG(0,(__location__ ": Object %s does not have a replPropertyMetaData attribute\n",
1855 ldb_dn_get_linearized(msg->dn)));
1856 return LDB_ERR_OPERATIONS_ERROR;
1859 ndr_err = ndr_pull_struct_blob(omd_value, msg, &omd,
1860 (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
1861 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1862 DEBUG(0,(__location__ ": Failed to parse replPropertyMetaData for %s\n",
1863 ldb_dn_get_linearized(msg->dn)));
1864 return LDB_ERR_OPERATIONS_ERROR;
1867 if (omd.version != 1) {
1868 DEBUG(0,(__location__ ": bad version %u in replPropertyMetaData for %s\n",
1869 omd.version, ldb_dn_get_linearized(msg->dn)));
1870 return LDB_ERR_OPERATIONS_ERROR;
1873 for (i=0; i<msg->num_elements;) {
1874 struct ldb_message_element *el = &msg->elements[i];
1875 struct ldb_message_element *old_el;
1877 old_el = ldb_msg_find_element(res->msgs[0], el->name);
1878 ret = replmd_update_rpmd_element(ldb, msg, el, old_el,
1879 &omd, schema, seq_num,
1884 if (ret != LDB_SUCCESS) {
1888 if (!*is_urgent && (situation == REPL_URGENT_ON_UPDATE)) {
1889 *is_urgent = replmd_check_urgent_attribute(el);
1892 if (!(el->flags & DSDB_FLAG_INTERNAL_FORCE_META_DATA)) {
1897 el->flags &= ~DSDB_FLAG_INTERNAL_FORCE_META_DATA;
1899 if (el->num_values != 0) {
1904 ldb_msg_remove_element(msg, el);
1909 * Assert that we have an objectClass attribute - this is major
1910 * corruption if we don't have this!
1912 objectclass_el = ldb_msg_find_element(res->msgs[0], "objectClass");
1913 if (objectclass_el != NULL) {
1915 * Now check if this objectClass means we need to do urgent replication
1917 if (!*is_urgent && replmd_check_urgent_objectclass(objectclass_el,
1921 } else if (!ldb_request_get_control(req, DSDB_CONTROL_DBCHECK)) {
1922 ldb_asprintf_errstring(ldb, __location__
1923 ": objectClass missing on %s\n",
1924 ldb_dn_get_linearized(msg->dn));
1925 return LDB_ERR_OBJECT_CLASS_VIOLATION;
1929 * replmd_update_rpmd_element has done an update if the
1932 if (*seq_num != 0 || rmd_is_just_resorted == true) {
1933 struct ldb_val *md_value;
1934 struct ldb_message_element *el;
1936 /*if we are RODC and this is a DRSR update then its ok*/
1937 if (!ldb_request_get_control(req, DSDB_CONTROL_REPLICATED_UPDATE_OID)
1938 && !ldb_request_get_control(req, DSDB_CONTROL_DBCHECK_MODIFY_RO_REPLICA)
1939 && !is_forced_rodc) {
1940 unsigned instanceType;
1943 ldb_set_errstring(ldb, "RODC modify is forbidden!");
1944 return LDB_ERR_REFERRAL;
1947 instanceType = ldb_msg_find_attr_as_uint(res->msgs[0], "instanceType", INSTANCE_TYPE_WRITE);
1948 if (!(instanceType & INSTANCE_TYPE_WRITE)) {
1949 return ldb_error(ldb, LDB_ERR_UNWILLING_TO_PERFORM,
1950 "cannot change replicated attribute on partial replica");
1954 md_value = talloc(msg, struct ldb_val);
1955 if (md_value == NULL) {
1957 return LDB_ERR_OPERATIONS_ERROR;
1960 ret = replmd_replPropertyMetaDataCtr1_sort_and_verify(ldb, &omd.ctr.ctr1, msg->dn);
1961 if (ret != LDB_SUCCESS) {
1962 ldb_asprintf_errstring(ldb, "%s: %s", __func__, ldb_errstring(ldb));
1966 ndr_err = ndr_push_struct_blob(md_value, msg, &omd,
1967 (ndr_push_flags_fn_t)ndr_push_replPropertyMetaDataBlob);
1968 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1969 DEBUG(0,(__location__ ": Failed to marshall replPropertyMetaData for %s\n",
1970 ldb_dn_get_linearized(msg->dn)));
1971 return LDB_ERR_OPERATIONS_ERROR;
1974 ret = ldb_msg_add_empty(msg, "replPropertyMetaData", LDB_FLAG_MOD_REPLACE, &el);
1975 if (ret != LDB_SUCCESS) {
1976 DEBUG(0,(__location__ ": Failed to add updated replPropertyMetaData %s\n",
1977 ldb_dn_get_linearized(msg->dn)));
1982 el->values = md_value;
1988 static int parsed_dn_compare(struct parsed_dn *pdn1, struct parsed_dn *pdn2)
1990 int ret = ndr_guid_compare(&pdn1->guid, &pdn2->guid);
1992 return data_blob_cmp(&pdn1->dsdb_dn->extra_part,
1993 &pdn2->dsdb_dn->extra_part);
1999 get a series of message element values as an array of DNs and GUIDs
2000 the result is sorted by GUID
2002 static int get_parsed_dns(struct ldb_module *module, TALLOC_CTX *mem_ctx,
2003 struct ldb_message_element *el, struct parsed_dn **pdn,
2004 const char *ldap_oid, struct ldb_request *parent)
2007 bool values_are_sorted = true;
2008 struct ldb_context *ldb = ldb_module_get_ctx(module);
2015 (*pdn) = talloc_array(mem_ctx, struct parsed_dn, el->num_values);
2017 ldb_module_oom(module);
2018 return LDB_ERR_OPERATIONS_ERROR;
2021 for (i=0; i<el->num_values; i++) {
2022 struct ldb_val *v = &el->values[i];
2025 struct parsed_dn *p;
2029 p->dsdb_dn = dsdb_dn_parse(*pdn, ldb, v, ldap_oid);
2030 if (p->dsdb_dn == NULL) {
2031 return LDB_ERR_INVALID_DN_SYNTAX;
2034 dn = p->dsdb_dn->dn;
2036 status = dsdb_get_extended_dn_guid(dn, &p->guid, "GUID");
2037 if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND) ||
2038 unlikely(GUID_all_zero(&p->guid))) {
2039 /* we got a DN without a GUID - go find the GUID */
2040 int ret = dsdb_module_guid_by_dn(module, dn, &p->guid, parent);
2041 if (ret != LDB_SUCCESS) {
2042 ldb_asprintf_errstring(ldb, "Unable to find GUID for DN %s\n",
2043 ldb_dn_get_linearized(dn));
2044 if (ret == LDB_ERR_NO_SUCH_OBJECT &&
2045 LDB_FLAG_MOD_TYPE(el->flags) == LDB_FLAG_MOD_DELETE &&
2046 ldb_attr_cmp(el->name, "member") == 0) {
2047 return LDB_ERR_UNWILLING_TO_PERFORM;
2051 ret = dsdb_set_extended_dn_guid(dn, &p->guid, "GUID");
2052 if (ret != LDB_SUCCESS) {
2055 } else if (!NT_STATUS_IS_OK(status)) {
2056 return LDB_ERR_OPERATIONS_ERROR;
2058 if (i > 0 && values_are_sorted) {
2059 int cmp = parsed_dn_compare(p, &(*pdn)[i - 1]);
2061 values_are_sorted = false;
2064 /* keep a pointer to the original ldb_val */
2067 if (! values_are_sorted) {
2068 TYPESAFE_QSORT(*pdn, el->num_values, parsed_dn_compare);
2074 * Get a series of trusted message element values. The result is sorted by
2075 * GUID, even though the GUIDs might not be known. That works because we trust
2076 * the database to give us the elements like that if the
2077 * replmd_private->sorted_links flag is set.
2079 * We also ensure that the links are in the Functional Level 2003
2080 * linked attributes format.
2082 static int get_parsed_dns_trusted(struct ldb_module *module,
2083 struct replmd_private *replmd_private,
2084 TALLOC_CTX *mem_ctx,
2085 struct ldb_message_element *el,
2086 struct parsed_dn **pdn,
2087 const char *ldap_oid,
2088 struct ldb_request *parent)
2097 if (!replmd_private->sorted_links) {
2098 /* We need to sort the list. This is the slow old path we want
2101 ret = get_parsed_dns(module, mem_ctx, el, pdn, ldap_oid,
2103 if (ret != LDB_SUCCESS) {
2107 /* Here we get a list of 'struct parsed_dns' without the parsing */
2108 *pdn = talloc_zero_array(mem_ctx, struct parsed_dn,
2111 ldb_module_oom(module);
2112 return LDB_ERR_OPERATIONS_ERROR;
2115 for (i = 0; i < el->num_values; i++) {
2116 (*pdn)[i].v = &el->values[i];
2121 * This upgrades links to FL2003 style, and sorts the result
2122 * if that was needed.
2124 * TODO: Add a database feature that asserts we have no FL2000
2125 * style links to avoid this check or add a feature that
2126 * uses a similar check to find sorted/unsorted links
2127 * for an on-the-fly upgrade.
2130 ret = replmd_check_upgrade_links(ldb_module_get_ctx(module),
2131 *pdn, el->num_values,
2134 if (ret != LDB_SUCCESS) {
2142 Return LDB_SUCCESS if a parsed_dn list contains no duplicate values,
2143 otherwise an error code. For compatibility the error code differs depending
2144 on whether or not the attribute is "member".
2146 As always, the parsed_dn list is assumed to be sorted.
2148 static int check_parsed_dn_duplicates(struct ldb_module *module,
2149 struct ldb_message_element *el,
2150 struct parsed_dn *pdn)
2153 struct ldb_context *ldb = ldb_module_get_ctx(module);
2155 for (i = 1; i < el->num_values; i++) {
2156 struct parsed_dn *p = &pdn[i];
2157 if (parsed_dn_compare(p, &pdn[i - 1]) == 0) {
2158 ldb_asprintf_errstring(ldb,
2159 "Linked attribute %s has "
2160 "multiple identical values",
2162 if (ldb_attr_cmp(el->name, "member") == 0) {
2163 return LDB_ERR_ENTRY_ALREADY_EXISTS;
2165 return LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS;
2173 build a new extended DN, including all meta data fields
2175 RMD_FLAGS = DSDB_RMD_FLAG_* bits
2176 RMD_ADDTIME = originating_add_time
2177 RMD_INVOCID = originating_invocation_id
2178 RMD_CHANGETIME = originating_change_time
2179 RMD_ORIGINATING_USN = originating_usn
2180 RMD_LOCAL_USN = local_usn
2181 RMD_VERSION = version
2183 static int replmd_build_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v,
2184 struct dsdb_dn *dsdb_dn,
2185 const struct GUID *invocation_id,
2186 uint64_t local_usn, NTTIME nttime)
2188 return replmd_set_la_val(mem_ctx, v, dsdb_dn, NULL, invocation_id,
2189 local_usn, local_usn, nttime,
2190 RMD_VERSION_INITIAL, false);
2193 static int replmd_update_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct dsdb_dn *dsdb_dn,
2194 struct dsdb_dn *old_dsdb_dn, const struct GUID *invocation_id,
2195 uint64_t seq_num, uint64_t local_usn, NTTIME nttime,
2199 check if any links need upgrading from w2k format
2201 static int replmd_check_upgrade_links(struct ldb_context *ldb,
2202 struct parsed_dn *dns, uint32_t count,
2203 struct ldb_message_element *el,
2204 const char *ldap_oid)
2207 const struct GUID *invocation_id = NULL;
2208 for (i=0; i<count; i++) {
2212 if (dns[i].dsdb_dn == NULL) {
2213 ret = really_parse_trusted_dn(dns, ldb, &dns[i],
2215 if (ret != LDB_SUCCESS) {
2216 return LDB_ERR_INVALID_DN_SYNTAX;
2220 status = dsdb_get_extended_dn_uint32(dns[i].dsdb_dn->dn,
2221 &version, "RMD_VERSION");
2222 if (!NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
2224 * We optimistically assume they are all the same; if
2225 * the first one is fixed, they are all fixed.
2227 * If the first one was *not* fixed and we find a
2228 * later one that is, that is an occasion to shout
2234 DEBUG(0, ("Mixed w2k and fixed format "
2235 "linked attributes\n"));
2239 if (invocation_id == NULL) {
2240 invocation_id = samdb_ntds_invocation_id(ldb);
2241 if (invocation_id == NULL) {
2242 return LDB_ERR_OPERATIONS_ERROR;
2247 /* it's an old one that needs upgrading */
2248 ret = replmd_update_la_val(el->values, dns[i].v,
2249 dns[i].dsdb_dn, dns[i].dsdb_dn,
2250 invocation_id, 1, 1, 0, false);
2251 if (ret != LDB_SUCCESS) {
2257 * This sort() is critical for the operation of
2258 * get_parsed_dns_trusted() because callers of this function
2259 * expect a sorted list, and FL2000 style links are not
2260 * sorted. In particular, as well as the upgrade case,
2261 * get_parsed_dns_trusted() is called from
2262 * replmd_delete_remove_link() even in FL2000 mode
2264 * We do not normally pay the cost of the qsort() due to the
2265 * early return in the RMD_VERSION found case.
2267 TYPESAFE_QSORT(dns, count, parsed_dn_compare);
2272 Sets the value for a linked attribute, including all meta data fields
2274 see replmd_build_la_val for value names
2276 static int replmd_set_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct dsdb_dn *dsdb_dn,
2277 struct dsdb_dn *old_dsdb_dn, const struct GUID *invocation_id,
2278 uint64_t usn, uint64_t local_usn, NTTIME nttime,
2279 uint32_t version, bool deleted)
2281 struct ldb_dn *dn = dsdb_dn->dn;
2282 const char *tstring, *usn_string, *flags_string;
2283 struct ldb_val tval;
2285 struct ldb_val usnv, local_usnv;
2286 struct ldb_val vers, flagsv;
2287 const struct ldb_val *old_addtime = NULL;
2290 const char *dnstring;
2292 uint32_t rmd_flags = deleted?DSDB_RMD_FLAG_DELETED:0;
2294 tstring = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)nttime);
2296 return LDB_ERR_OPERATIONS_ERROR;
2298 tval = data_blob_string_const(tstring);
2300 usn_string = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)usn);
2302 return LDB_ERR_OPERATIONS_ERROR;
2304 usnv = data_blob_string_const(usn_string);
2306 usn_string = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)local_usn);
2308 return LDB_ERR_OPERATIONS_ERROR;
2310 local_usnv = data_blob_string_const(usn_string);
2312 status = GUID_to_ndr_blob(invocation_id, dn, &iid);
2313 if (!NT_STATUS_IS_OK(status)) {
2314 return LDB_ERR_OPERATIONS_ERROR;
2317 flags_string = talloc_asprintf(mem_ctx, "%u", rmd_flags);
2318 if (!flags_string) {
2319 return LDB_ERR_OPERATIONS_ERROR;
2321 flagsv = data_blob_string_const(flags_string);
2323 ret = ldb_dn_set_extended_component(dn, "RMD_FLAGS", &flagsv);
2324 if (ret != LDB_SUCCESS) return ret;
2326 /* get the ADDTIME from the original */
2327 if (old_dsdb_dn != NULL) {
2328 old_addtime = ldb_dn_get_extended_component(old_dsdb_dn->dn,
2331 if (old_addtime == NULL) {
2332 old_addtime = &tval;
2334 if (dsdb_dn != old_dsdb_dn ||
2335 ldb_dn_get_extended_component(dn, "RMD_ADDTIME") == NULL) {
2336 ret = ldb_dn_set_extended_component(dn, "RMD_ADDTIME", old_addtime);
2337 if (ret != LDB_SUCCESS) return ret;
2340 /* use our invocation id */
2341 ret = ldb_dn_set_extended_component(dn, "RMD_INVOCID", &iid);
2342 if (ret != LDB_SUCCESS) return ret;
2344 /* changetime is the current time */
2345 ret = ldb_dn_set_extended_component(dn, "RMD_CHANGETIME", &tval);
2346 if (ret != LDB_SUCCESS) return ret;
2348 /* update the USN */
2349 ret = ldb_dn_set_extended_component(dn, "RMD_ORIGINATING_USN", &usnv);
2350 if (ret != LDB_SUCCESS) return ret;
2352 ret = ldb_dn_set_extended_component(dn, "RMD_LOCAL_USN", &local_usnv);
2353 if (ret != LDB_SUCCESS) return ret;
2355 vstring = talloc_asprintf(mem_ctx, "%lu", (unsigned long)version);
2356 vers = data_blob_string_const(vstring);
2357 ret = ldb_dn_set_extended_component(dn, "RMD_VERSION", &vers);
2358 if (ret != LDB_SUCCESS) return ret;
2360 dnstring = dsdb_dn_get_extended_linearized(mem_ctx, dsdb_dn, 1);
2361 if (dnstring == NULL) {
2362 return LDB_ERR_OPERATIONS_ERROR;
2364 *v = data_blob_string_const(dnstring);
2370 * Updates the value for a linked attribute, including all meta data fields
2372 static int replmd_update_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct dsdb_dn *dsdb_dn,
2373 struct dsdb_dn *old_dsdb_dn, const struct GUID *invocation_id,
2374 uint64_t usn, uint64_t local_usn, NTTIME nttime,
2377 uint32_t old_version;
2378 uint32_t version = RMD_VERSION_INITIAL;
2382 * We're updating the linked attribute locally, so increase the version
2383 * by 1 so that other DCs will see the change when it gets replicated out
2385 status = dsdb_get_extended_dn_uint32(old_dsdb_dn->dn, &old_version,
2388 if (NT_STATUS_IS_OK(status)) {
2389 version = old_version + 1;
2392 return replmd_set_la_val(mem_ctx, v, dsdb_dn, old_dsdb_dn, invocation_id,
2393 usn, local_usn, nttime, version, deleted);
2397 handle adding a linked attribute
2399 static int replmd_modify_la_add(struct ldb_module *module,
2400 struct replmd_private *replmd_private,
2401 const struct dsdb_schema *schema,
2402 struct ldb_message *msg,
2403 struct ldb_message_element *el,
2404 struct ldb_message_element *old_el,
2405 const struct dsdb_attribute *schema_attr,
2408 struct ldb_dn *msg_dn,
2409 struct ldb_request *parent)
2412 struct parsed_dn *dns, *old_dns;
2413 TALLOC_CTX *tmp_ctx = talloc_new(msg);
2415 struct ldb_val *new_values = NULL;
2416 unsigned old_num_values = old_el ? old_el->num_values : 0;
2417 unsigned num_values = 0;
2418 unsigned max_num_values;
2419 const struct GUID *invocation_id;
2420 struct ldb_context *ldb = ldb_module_get_ctx(module);
2422 unix_to_nt_time(&now, t);
2424 invocation_id = samdb_ntds_invocation_id(ldb);
2425 if (!invocation_id) {
2426 talloc_free(tmp_ctx);
2427 return LDB_ERR_OPERATIONS_ERROR;
2430 /* get the DNs to be added, fully parsed.
2432 * We need full parsing because they came off the wire and we don't
2433 * trust them, besides which we need their details to know where to put
2436 ret = get_parsed_dns(module, tmp_ctx, el, &dns,
2437 schema_attr->syntax->ldap_oid, parent);
2438 if (ret != LDB_SUCCESS) {
2439 talloc_free(tmp_ctx);
2443 /* get the existing DNs, lazily parsed */
2444 ret = get_parsed_dns_trusted(module, replmd_private,
2445 tmp_ctx, old_el, &old_dns,
2446 schema_attr->syntax->ldap_oid, parent);
2448 if (ret != LDB_SUCCESS) {
2449 talloc_free(tmp_ctx);
2453 max_num_values = old_num_values + el->num_values;
2454 if (max_num_values < old_num_values) {
2455 DEBUG(0, ("we seem to have overflow in replmd_modify_la_add. "
2456 "old values: %u, new values: %u, sum: %u",
2457 old_num_values, el->num_values, max_num_values));
2458 talloc_free(tmp_ctx);
2459 return LDB_ERR_OPERATIONS_ERROR;
2462 new_values = talloc_zero_array(tmp_ctx, struct ldb_val, max_num_values);
2464 if (new_values == NULL) {
2465 ldb_module_oom(module);
2466 talloc_free(tmp_ctx);
2467 return LDB_ERR_OPERATIONS_ERROR;
2471 * For each new value, find where it would go in the list. If there is
2472 * a matching GUID there, we update the existing value; otherwise we
2476 for (i = 0; i < el->num_values; i++) {
2477 struct parsed_dn *exact;
2478 struct parsed_dn *next;
2480 int err = parsed_dn_find(ldb, old_dns, old_num_values,
2483 dns[i].dsdb_dn->extra_part, 0,
2485 schema_attr->syntax->ldap_oid,
2487 if (err != LDB_SUCCESS) {
2488 talloc_free(tmp_ctx);
2492 if (exact != NULL) {
2494 * We are trying to add one that exists, which is only
2495 * allowed if it was previously deleted.
2497 * When we do undelete a link we change it in place.
2498 * It will be copied across into the right spot in due
2502 rmd_flags = dsdb_dn_rmd_flags(exact->dsdb_dn->dn);
2504 if (!(rmd_flags & DSDB_RMD_FLAG_DELETED)) {
2505 struct GUID_txt_buf guid_str;
2506 ldb_asprintf_errstring(ldb,
2507 "Attribute %s already "
2508 "exists for target GUID %s",
2510 GUID_buf_string(&exact->guid,
2512 talloc_free(tmp_ctx);
2513 /* error codes for 'member' need to be
2515 if (ldb_attr_cmp(el->name, "member") == 0) {
2516 return LDB_ERR_ENTRY_ALREADY_EXISTS;
2518 return LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS;
2522 ret = replmd_update_la_val(new_values, exact->v,
2525 invocation_id, seq_num,
2526 seq_num, now, false);
2527 if (ret != LDB_SUCCESS) {
2528 talloc_free(tmp_ctx);
2532 ret = replmd_add_backlink(module, replmd_private,
2539 if (ret != LDB_SUCCESS) {
2540 talloc_free(tmp_ctx);
2546 * Here we don't have an exact match.
2548 * If next is NULL, this one goes beyond the end of the
2549 * existing list, so we need to add all of those ones first.
2551 * If next is not NULL, we need to add all the ones before
2555 offset = old_num_values;
2557 /* next should have been parsed, but let's make sure */
2558 if (next->dsdb_dn == NULL) {
2559 ret = really_parse_trusted_dn(tmp_ctx, ldb, next,
2560 schema_attr->syntax->ldap_oid);
2561 if (ret != LDB_SUCCESS) {
2565 offset = MIN(next - old_dns, old_num_values);
2568 /* put all the old ones before next on the list */
2569 for (; j < offset; j++) {
2570 new_values[num_values] = *old_dns[j].v;
2574 ret = replmd_add_backlink(module, replmd_private,
2579 /* Make the new linked attribute ldb_val. */
2580 ret = replmd_build_la_val(new_values, &new_values[num_values],
2581 dns[i].dsdb_dn, invocation_id,
2583 if (ret != LDB_SUCCESS) {
2584 talloc_free(tmp_ctx);
2588 if (ret != LDB_SUCCESS) {
2589 talloc_free(tmp_ctx);
2593 /* copy the rest of the old ones (if any) */
2594 for (; j < old_num_values; j++) {
2595 new_values[num_values] = *old_dns[j].v;
2599 talloc_steal(msg->elements, new_values);
2600 if (old_el != NULL) {
2601 talloc_steal(msg->elements, old_el->values);
2603 el->values = new_values;
2604 el->num_values = num_values;
2606 talloc_free(tmp_ctx);
2608 /* we now tell the backend to replace all existing values
2609 with the one we have constructed */
2610 el->flags = LDB_FLAG_MOD_REPLACE;
2617 handle deleting all active linked attributes
2619 static int replmd_modify_la_delete(struct ldb_module *module,
2620 struct replmd_private *replmd_private,
2621 const struct dsdb_schema *schema,
2622 struct ldb_message *msg,
2623 struct ldb_message_element *el,
2624 struct ldb_message_element *old_el,
2625 const struct dsdb_attribute *schema_attr,
2628 struct ldb_dn *msg_dn,
2629 struct ldb_request *parent)
2632 struct parsed_dn *dns, *old_dns;
2633 TALLOC_CTX *tmp_ctx = NULL;
2635 struct ldb_context *ldb = ldb_module_get_ctx(module);
2636 struct ldb_control *vanish_links_ctrl = NULL;
2637 bool vanish_links = false;
2638 unsigned int num_to_delete = el->num_values;
2640 const struct GUID *invocation_id;
2643 unix_to_nt_time(&now, t);
2645 invocation_id = samdb_ntds_invocation_id(ldb);
2646 if (!invocation_id) {
2647 return LDB_ERR_OPERATIONS_ERROR;
2650 if (old_el == NULL || old_el->num_values == 0) {
2651 /* there is nothing to delete... */
2652 if (num_to_delete == 0) {
2653 /* and we're deleting nothing, so that's OK */
2656 return LDB_ERR_NO_SUCH_ATTRIBUTE;
2659 tmp_ctx = talloc_new(msg);
2660 if (tmp_ctx == NULL) {
2661 return LDB_ERR_OPERATIONS_ERROR;
2664 ret = get_parsed_dns(module, tmp_ctx, el, &dns,
2665 schema_attr->syntax->ldap_oid, parent);
2666 if (ret != LDB_SUCCESS) {
2667 talloc_free(tmp_ctx);
2671 ret = get_parsed_dns_trusted(module, replmd_private,
2672 tmp_ctx, old_el, &old_dns,
2673 schema_attr->syntax->ldap_oid, parent);
2675 if (ret != LDB_SUCCESS) {
2676 talloc_free(tmp_ctx);
2681 vanish_links_ctrl = ldb_request_get_control(parent, DSDB_CONTROL_REPLMD_VANISH_LINKS);
2682 if (vanish_links_ctrl) {
2683 vanish_links = true;
2684 vanish_links_ctrl->critical = false;
2688 /* we empty out el->values here to avoid damage if we return early. */
2693 * If vanish links is set, we are actually removing members of
2694 * old_el->values; otherwise we are just marking them deleted.
2696 * There is a special case when no values are given: we remove them
2697 * all. When we have the vanish_links control we just have to remove
2698 * the backlinks and change our element to replace the existing values
2699 * with the empty list.
2702 if (num_to_delete == 0) {
2703 for (i = 0; i < old_el->num_values; i++) {
2704 struct parsed_dn *p = &old_dns[i];
2705 if (p->dsdb_dn == NULL) {
2706 ret = really_parse_trusted_dn(tmp_ctx, ldb, p,
2707 schema_attr->syntax->ldap_oid);
2708 if (ret != LDB_SUCCESS) {
2712 ret = replmd_add_backlink(module, replmd_private,
2713 schema, msg_dn, &p->guid,
2716 if (ret != LDB_SUCCESS) {
2717 talloc_free(tmp_ctx);
2724 rmd_flags = dsdb_dn_rmd_flags(p->dsdb_dn->dn);
2725 if (rmd_flags & DSDB_RMD_FLAG_DELETED) {
2729 ret = replmd_update_la_val(old_el->values, p->v,
2730 p->dsdb_dn, p->dsdb_dn,
2731 invocation_id, seq_num,
2732 seq_num, now, true);
2733 if (ret != LDB_SUCCESS) {
2734 talloc_free(tmp_ctx);
2740 el->flags = LDB_FLAG_MOD_REPLACE;
2741 talloc_free(tmp_ctx);
2747 for (i = 0; i < num_to_delete; i++) {
2748 struct parsed_dn *p = &dns[i];
2749 struct parsed_dn *exact = NULL;
2750 struct parsed_dn *next = NULL;
2751 ret = parsed_dn_find(ldb, old_dns, old_el->num_values,
2754 p->dsdb_dn->extra_part, 0,
2756 schema_attr->syntax->ldap_oid,
2758 if (ret != LDB_SUCCESS) {
2759 talloc_free(tmp_ctx);
2762 if (exact == NULL) {
2763 struct GUID_txt_buf buf;
2764 ldb_asprintf_errstring(ldb, "Attribute %s doesn't "
2765 "exist for target GUID %s",
2767 GUID_buf_string(&p->guid, &buf));
2768 if (ldb_attr_cmp(el->name, "member") == 0) {
2769 talloc_free(tmp_ctx);
2770 return LDB_ERR_UNWILLING_TO_PERFORM;
2772 talloc_free(tmp_ctx);
2773 return LDB_ERR_NO_SUCH_ATTRIBUTE;
2778 if (CHECK_DEBUGLVL(5)) {
2779 rmd_flags = dsdb_dn_rmd_flags(exact->dsdb_dn->dn);
2780 if ((rmd_flags & DSDB_RMD_FLAG_DELETED)) {
2781 struct GUID_txt_buf buf;
2782 const char *guid_str = \
2783 GUID_buf_string(&p->guid, &buf);
2784 DEBUG(5, ("Deleting deleted linked "
2785 "attribute %s to %s, because "
2786 "vanish_links control is set\n",
2787 el->name, guid_str));
2791 /* remove the backlink */
2792 ret = replmd_add_backlink(module,
2799 if (ret != LDB_SUCCESS) {
2800 talloc_free(tmp_ctx);
2804 /* We flag the deletion and tidy it up later. */
2809 rmd_flags = dsdb_dn_rmd_flags(exact->dsdb_dn->dn);
2811 if (rmd_flags & DSDB_RMD_FLAG_DELETED) {
2812 struct GUID_txt_buf buf;
2813 const char *guid_str = GUID_buf_string(&p->guid, &buf);
2814 ldb_asprintf_errstring(ldb, "Attribute %s already "
2815 "deleted for target GUID %s",
2816 el->name, guid_str);
2817 if (ldb_attr_cmp(el->name, "member") == 0) {
2818 talloc_free(tmp_ctx);
2819 return LDB_ERR_UNWILLING_TO_PERFORM;
2821 talloc_free(tmp_ctx);
2822 return LDB_ERR_NO_SUCH_ATTRIBUTE;
2826 ret = replmd_update_la_val(old_el->values, exact->v,
2827 exact->dsdb_dn, exact->dsdb_dn,
2828 invocation_id, seq_num, seq_num,
2830 if (ret != LDB_SUCCESS) {
2831 talloc_free(tmp_ctx);
2834 ret = replmd_add_backlink(module, replmd_private,
2839 if (ret != LDB_SUCCESS) {
2840 talloc_free(tmp_ctx);
2847 for (i = 0; i < old_el->num_values; i++) {
2848 if (old_dns[i].v != NULL) {
2849 old_el->values[j] = *old_dns[i].v;
2853 old_el->num_values = j;
2856 el->values = talloc_steal(msg->elements, old_el->values);
2857 el->num_values = old_el->num_values;
2859 talloc_free(tmp_ctx);
2861 /* we now tell the backend to replace all existing values
2862 with the one we have constructed */
2863 el->flags = LDB_FLAG_MOD_REPLACE;
2869 handle replacing a linked attribute
2871 static int replmd_modify_la_replace(struct ldb_module *module,
2872 struct replmd_private *replmd_private,
2873 const struct dsdb_schema *schema,
2874 struct ldb_message *msg,
2875 struct ldb_message_element *el,
2876 struct ldb_message_element *old_el,
2877 const struct dsdb_attribute *schema_attr,
2880 struct ldb_dn *msg_dn,
2881 struct ldb_request *parent)
2883 unsigned int i, old_i, new_i;
2884 struct parsed_dn *dns, *old_dns;
2885 TALLOC_CTX *tmp_ctx = talloc_new(msg);
2887 const struct GUID *invocation_id;
2888 struct ldb_context *ldb = ldb_module_get_ctx(module);
2889 struct ldb_val *new_values = NULL;
2890 const char *ldap_oid = schema_attr->syntax->ldap_oid;
2891 unsigned int old_num_values;
2892 unsigned int repl_num_values;
2893 unsigned int max_num_values;
2896 unix_to_nt_time(&now, t);
2898 invocation_id = samdb_ntds_invocation_id(ldb);
2899 if (!invocation_id) {
2900 return LDB_ERR_OPERATIONS_ERROR;
2904 * The replace operation is unlike the replace and delete cases in that
2905 * we need to look at every existing link to see whether it is being
2906 * retained or deleted. In other words, we can't avoid parsing the GUIDs.
2908 * As we are trying to combine two sorted lists, the algorithm we use
2909 * is akin to the merge phase of a merge sort. We interleave the two
2910 * lists, doing different things depending on which side the current
2913 * There are three main cases, with some sub-cases.
2915 * - a DN is in the old list but not the new one. It needs to be
2916 * marked as deleted (but left in the list).
2917 * - maybe it is already deleted, and we have less to do.
2919 * - a DN is in both lists. The old data gets replaced by the new,
2920 * and the list doesn't grow. The old link may have been marked as
2921 * deleted, in which case we undelete it.
2923 * - a DN is in the new list only. We add it in the right place.
2926 old_num_values = old_el ? old_el->num_values : 0;
2927 repl_num_values = el->num_values;
2928 max_num_values = old_num_values + repl_num_values;
2930 if (max_num_values == 0) {
2931 /* There is nothing to do! */
2935 ret = get_parsed_dns(module, tmp_ctx, el, &dns, ldap_oid, parent);
2936 if (ret != LDB_SUCCESS) {
2937 talloc_free(tmp_ctx);
2941 ret = check_parsed_dn_duplicates(module, el, dns);
2942 if (ret != LDB_SUCCESS) {
2943 talloc_free(tmp_ctx);
2947 ret = get_parsed_dns(module, tmp_ctx, old_el, &old_dns,
2949 if (ret != LDB_SUCCESS) {
2950 talloc_free(tmp_ctx);
2954 ret = replmd_check_upgrade_links(ldb, old_dns, old_num_values,
2956 if (ret != LDB_SUCCESS) {
2957 talloc_free(tmp_ctx);
2961 new_values = talloc_array(tmp_ctx, struct ldb_val, max_num_values);
2962 if (new_values == NULL) {
2963 ldb_module_oom(module);
2964 talloc_free(tmp_ctx);
2965 return LDB_ERR_OPERATIONS_ERROR;
2970 for (i = 0; i < max_num_values; i++) {
2972 struct parsed_dn *old_p, *new_p;
2973 if (old_i < old_num_values && new_i < repl_num_values) {
2974 old_p = &old_dns[old_i];
2975 new_p = &dns[new_i];
2976 cmp = parsed_dn_compare(old_p, new_p);
2977 } else if (old_i < old_num_values) {
2978 /* the new list is empty, read the old list */
2979 old_p = &old_dns[old_i];
2982 } else if (new_i < repl_num_values) {
2983 /* the old list is empty, read new list */
2985 new_p = &dns[new_i];
2993 * An old ones that come before the next replacement
2994 * (if any). We mark it as deleted and add it to the
2997 uint32_t rmd_flags = dsdb_dn_rmd_flags(old_p->dsdb_dn->dn);
2998 if ((rmd_flags & DSDB_RMD_FLAG_DELETED) == 0) {
2999 ret = replmd_update_la_val(new_values, old_p->v,
3005 if (ret != LDB_SUCCESS) {
3006 talloc_free(tmp_ctx);
3010 ret = replmd_add_backlink(module, replmd_private,
3013 &old_p->guid, false,
3016 if (ret != LDB_SUCCESS) {
3017 talloc_free(tmp_ctx);
3021 new_values[i] = *old_p->v;
3023 } else if (cmp == 0) {
3025 * We are overwriting one. If it was previously
3026 * deleted, we need to add a backlink.
3028 * Note that if any RMD_FLAGs in an extended new DN
3033 ret = replmd_update_la_val(new_values, old_p->v,
3039 if (ret != LDB_SUCCESS) {
3040 talloc_free(tmp_ctx);
3044 rmd_flags = dsdb_dn_rmd_flags(old_p->dsdb_dn->dn);
3045 if ((rmd_flags & DSDB_RMD_FLAG_DELETED) != 0) {
3046 ret = replmd_add_backlink(module, replmd_private,
3052 if (ret != LDB_SUCCESS) {
3053 talloc_free(tmp_ctx);
3058 new_values[i] = *old_p->v;
3063 * Replacements that don't match an existing one. We
3064 * just add them to the final list.
3066 ret = replmd_build_la_val(new_values,
3071 if (ret != LDB_SUCCESS) {
3072 talloc_free(tmp_ctx);
3075 ret = replmd_add_backlink(module, replmd_private,
3081 if (ret != LDB_SUCCESS) {
3082 talloc_free(tmp_ctx);
3085 new_values[i] = *new_p->v;
3089 if (old_el != NULL) {
3090 talloc_steal(msg->elements, old_el->values);
3092 el->values = talloc_steal(msg->elements, new_values);
3094 talloc_free(tmp_ctx);
3096 el->flags = LDB_FLAG_MOD_REPLACE;
3103 handle linked attributes in modify requests
3105 static int replmd_modify_handle_linked_attribs(struct ldb_module *module,
3106 struct replmd_private *replmd_private,
3107 struct ldb_message *msg,
3108 uint64_t seq_num, time_t t,
3109 struct ldb_request *parent)
3111 struct ldb_result *res;
3114 struct ldb_context *ldb = ldb_module_get_ctx(module);
3115 struct ldb_message *old_msg;
3117 const struct dsdb_schema *schema;
3119 if (dsdb_functional_level(ldb) == DS_DOMAIN_FUNCTION_2000) {
3121 * Nothing special is required for modifying or vanishing links
3122 * in fl2000 since they are just strings in a multi-valued
3125 struct ldb_control *ctrl = ldb_request_get_control(parent,
3126 DSDB_CONTROL_REPLMD_VANISH_LINKS);
3128 ctrl->critical = false;
3136 * We should restrict this to the intersection of the list of
3137 * linked attributes in the schema and the list of attributes
3140 * This will help performance a little, as otherwise we have
3141 * to allocate the entire object value-by-value.
3143 ret = dsdb_module_search_dn(module, msg, &res, msg->dn, NULL,
3144 DSDB_FLAG_NEXT_MODULE |
3145 DSDB_SEARCH_SHOW_RECYCLED |
3146 DSDB_SEARCH_REVEAL_INTERNALS |
3147 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT,
3149 if (ret != LDB_SUCCESS) {
3152 schema = dsdb_get_schema(ldb, res);
3154 return LDB_ERR_OPERATIONS_ERROR;
3157 old_msg = res->msgs[0];
3159 for (i=0; i<msg->num_elements; i++) {
3160 struct ldb_message_element *el = &msg->elements[i];
3161 struct ldb_message_element *old_el, *new_el;
3162 unsigned int mod_type = LDB_FLAG_MOD_TYPE(el->flags);
3163 const struct dsdb_attribute *schema_attr
3164 = dsdb_attribute_by_lDAPDisplayName(schema, el->name);
3166 ldb_asprintf_errstring(ldb,
3167 "%s: attribute %s is not a valid attribute in schema",
3168 __FUNCTION__, el->name);
3169 return LDB_ERR_OBJECT_CLASS_VIOLATION;
3171 if (schema_attr->linkID == 0) {
3174 if ((schema_attr->linkID & 1) == 1) {
3175 if (parent && ldb_request_get_control(parent, DSDB_CONTROL_DBCHECK)) {
3178 /* Odd is for the target. Illegal to modify */
3179 ldb_asprintf_errstring(ldb,
3180 "attribute %s must not be modified directly, it is a linked attribute", el->name);
3181 return LDB_ERR_UNWILLING_TO_PERFORM;
3183 old_el = ldb_msg_find_element(old_msg, el->name);
3185 case LDB_FLAG_MOD_REPLACE:
3186 ret = replmd_modify_la_replace(module, replmd_private,
3187 schema, msg, el, old_el,
3188 schema_attr, seq_num, t,
3192 case LDB_FLAG_MOD_DELETE:
3193 ret = replmd_modify_la_delete(module, replmd_private,
3194 schema, msg, el, old_el,
3195 schema_attr, seq_num, t,
3199 case LDB_FLAG_MOD_ADD:
3200 ret = replmd_modify_la_add(module, replmd_private,
3201 schema, msg, el, old_el,
3202 schema_attr, seq_num, t,
3207 ldb_asprintf_errstring(ldb,
3208 "invalid flags 0x%x for %s linked attribute",
3209 el->flags, el->name);
3210 return LDB_ERR_UNWILLING_TO_PERFORM;
3212 if (dsdb_check_single_valued_link(schema_attr, el) != LDB_SUCCESS) {
3213 ldb_asprintf_errstring(ldb,
3214 "Attribute %s is single valued but more than one value has been supplied",
3216 /* Return codes as found on Windows 2012r2 */
3217 if (mod_type == LDB_FLAG_MOD_REPLACE) {
3218 return LDB_ERR_CONSTRAINT_VIOLATION;
3220 return LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS;
3223 el->flags |= LDB_FLAG_INTERNAL_DISABLE_SINGLE_VALUE_CHECK;
3226 if (ret != LDB_SUCCESS) {
3230 ldb_msg_remove_attr(old_msg, el->name);
3232 ldb_msg_add_empty(old_msg, el->name, 0, &new_el);
3233 new_el->num_values = el->num_values;
3234 new_el->values = talloc_steal(msg->elements, el->values);
3236 /* TODO: this relises a bit too heavily on the exact
3237 behaviour of ldb_msg_find_element and
3238 ldb_msg_remove_element */
3239 old_el = ldb_msg_find_element(msg, el->name);
3241 ldb_msg_remove_element(msg, old_el);
3251 static int send_rodc_referral(struct ldb_request *req,
3252 struct ldb_context *ldb,
3255 char *referral = NULL;
3256 struct loadparm_context *lp_ctx = NULL;
3257 struct ldb_dn *fsmo_role_dn = NULL;
3258 struct ldb_dn *role_owner_dn = NULL;
3259 const char *domain = NULL;
3262 lp_ctx = talloc_get_type(ldb_get_opaque(ldb, "loadparm"),
3263 struct loadparm_context);
3265 werr = dsdb_get_fsmo_role_info(req, ldb, DREPL_PDC_MASTER,
3266 &fsmo_role_dn, &role_owner_dn);
3268 if (W_ERROR_IS_OK(werr)) {
3269 struct ldb_dn *server_dn = ldb_dn_copy(req, role_owner_dn);
3270 if (server_dn != NULL) {
3271 ldb_dn_remove_child_components(server_dn, 1);
3272 domain = samdb_dn_to_dnshostname(ldb, req,
3277 if (domain == NULL) {
3278 domain = lpcfg_dnsdomain(lp_ctx);
3281 referral = talloc_asprintf(req, "ldap://%s/%s",
3283 ldb_dn_get_linearized(dn));
3284 if (referral == NULL) {
3286 return LDB_ERR_OPERATIONS_ERROR;
3289 return ldb_module_send_referral(req, referral);
3293 static int replmd_modify(struct ldb_module *module, struct ldb_request *req)
3295 struct ldb_context *ldb;
3296 struct replmd_replicated_request *ac;
3297 struct ldb_request *down_req;
3298 struct ldb_message *msg;
3299 time_t t = time(NULL);
3301 bool is_urgent = false, rodc = false;
3302 bool is_schema_nc = false;
3303 unsigned int functional_level;
3304 const struct ldb_message_element *guid_el = NULL;
3305 struct ldb_control *sd_propagation_control;
3306 struct replmd_private *replmd_private =
3307 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
3309 /* do not manipulate our control entries */
3310 if (ldb_dn_is_special(req->op.mod.message->dn)) {
3311 return ldb_next_request(module, req);
3314 sd_propagation_control = ldb_request_get_control(req,
3315 DSDB_CONTROL_SEC_DESC_PROPAGATION_OID);
3316 if (sd_propagation_control != NULL) {
3317 if (req->op.mod.message->num_elements != 1) {
3318 return ldb_module_operr(module);
3320 ret = strcmp(req->op.mod.message->elements[0].name,
3321 "nTSecurityDescriptor");
3323 return ldb_module_operr(module);
3326 return ldb_next_request(module, req);
3329 ldb = ldb_module_get_ctx(module);
3331 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_modify\n");
3333 guid_el = ldb_msg_find_element(req->op.mod.message, "objectGUID");
3334 if (guid_el != NULL) {
3335 ldb_set_errstring(ldb,
3336 "replmd_modify: it's not allowed to change the objectGUID!");
3337 return LDB_ERR_CONSTRAINT_VIOLATION;
3340 ac = replmd_ctx_init(module, req);
3342 return ldb_module_oom(module);
3345 functional_level = dsdb_functional_level(ldb);
3347 /* we have to copy the message as the caller might have it as a const */
3348 msg = ldb_msg_copy_shallow(ac, req->op.mod.message);
3352 return LDB_ERR_OPERATIONS_ERROR;
3355 ldb_msg_remove_attr(msg, "whenChanged");
3356 ldb_msg_remove_attr(msg, "uSNChanged");
3358 is_schema_nc = ldb_dn_compare_base(replmd_private->schema_dn, msg->dn) == 0;
3360 ret = replmd_update_rpmd(module, ac->schema, req, NULL,
3361 msg, &ac->seq_num, t, is_schema_nc,
3363 if (rodc && (ret == LDB_ERR_REFERRAL)) {
3364 ret = send_rodc_referral(req, ldb, msg->dn);
3370 if (ret != LDB_SUCCESS) {
3375 ret = replmd_modify_handle_linked_attribs(module, replmd_private,
3376 msg, ac->seq_num, t, req);
3377 if (ret != LDB_SUCCESS) {
3383 * - replace the old object with the newly constructed one
3386 ac->is_urgent = is_urgent;
3388 ret = ldb_build_mod_req(&down_req, ldb, ac,
3391 ac, replmd_op_callback,
3393 LDB_REQ_SET_LOCATION(down_req);
3394 if (ret != LDB_SUCCESS) {
3399 /* current partition control is needed by "replmd_op_callback" */
3400 if (ldb_request_get_control(req, DSDB_CONTROL_CURRENT_PARTITION_OID) == NULL) {
3401 ret = ldb_request_add_control(down_req,
3402 DSDB_CONTROL_CURRENT_PARTITION_OID,
3404 if (ret != LDB_SUCCESS) {
3410 /* If we are in functional level 2000, then
3411 * replmd_modify_handle_linked_attribs will have done
3413 if (functional_level == DS_DOMAIN_FUNCTION_2000) {
3414 ret = ldb_request_add_control(down_req, DSDB_CONTROL_APPLY_LINKS, false, NULL);
3415 if (ret != LDB_SUCCESS) {
3421 talloc_steal(down_req, msg);
3423 /* we only change whenChanged and uSNChanged if the seq_num
3425 if (ac->seq_num != 0) {
3426 ret = add_time_element(msg, "whenChanged", t);
3427 if (ret != LDB_SUCCESS) {
3433 ret = add_uint64_element(ldb, msg, "uSNChanged", ac->seq_num);
3434 if (ret != LDB_SUCCESS) {
3441 /* go on with the call chain */
3442 return ldb_next_request(module, down_req);
3445 static int replmd_rename_callback(struct ldb_request *req, struct ldb_reply *ares);
3448 handle a rename request
3450 On a rename we need to do an extra ldb_modify which sets the
3451 whenChanged and uSNChanged attributes. We do this in a callback after the success.
3453 static int replmd_rename(struct ldb_module *module, struct ldb_request *req)
3455 struct ldb_context *ldb;
3456 struct replmd_replicated_request *ac;
3458 struct ldb_request *down_req;
3460 /* do not manipulate our control entries */
3461 if (ldb_dn_is_special(req->op.mod.message->dn)) {
3462 return ldb_next_request(module, req);
3465 ldb = ldb_module_get_ctx(module);
3467 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_rename\n");
3469 ac = replmd_ctx_init(module, req);
3471 return ldb_module_oom(module);
3474 ret = ldb_build_rename_req(&down_req, ldb, ac,
3475 ac->req->op.rename.olddn,
3476 ac->req->op.rename.newdn,
3478 ac, replmd_rename_callback,
3480 LDB_REQ_SET_LOCATION(down_req);
3481 if (ret != LDB_SUCCESS) {
3486 /* go on with the call chain */
3487 return ldb_next_request(module, down_req);
3490 /* After the rename is compleated, update the whenchanged etc */
3491 static int replmd_rename_callback(struct ldb_request *req, struct ldb_reply *ares)
3493 struct ldb_context *ldb;
3494 struct ldb_request *down_req;
3495 struct ldb_message *msg;
3496 const struct dsdb_attribute *rdn_attr;
3497 const char *rdn_name;
3498 const struct ldb_val *rdn_val;
3499 const char *attrs[5] = { NULL, };
3500 time_t t = time(NULL);
3502 bool is_urgent = false, rodc = false;
3504 struct replmd_replicated_request *ac =
3505 talloc_get_type(req->context, struct replmd_replicated_request);
3506 struct replmd_private *replmd_private =
3507 talloc_get_type(ldb_module_get_private(ac->module),
3508 struct replmd_private);
3510 ldb = ldb_module_get_ctx(ac->module);
3512 if (ares->error != LDB_SUCCESS) {
3513 return ldb_module_done(ac->req, ares->controls,
3514 ares->response, ares->error);
3517 if (ares->type != LDB_REPLY_DONE) {
3518 ldb_set_errstring(ldb,
3519 "invalid ldb_reply_type in callback");
3521 return ldb_module_done(ac->req, NULL, NULL,
3522 LDB_ERR_OPERATIONS_ERROR);
3526 * - replace the old object with the newly constructed one
3529 msg = ldb_msg_new(ac);
3532 return LDB_ERR_OPERATIONS_ERROR;
3535 msg->dn = ac->req->op.rename.newdn;
3537 is_schema_nc = ldb_dn_compare_base(replmd_private->schema_dn, msg->dn) == 0;
3539 rdn_name = ldb_dn_get_rdn_name(msg->dn);
3540 if (rdn_name == NULL) {
3542 return ldb_module_done(ac->req, NULL, NULL,
3546 /* normalize the rdn attribute name */
3547 rdn_attr = dsdb_attribute_by_lDAPDisplayName(ac->schema, rdn_name);
3548 if (rdn_attr == NULL) {
3550 return ldb_module_done(ac->req, NULL, NULL,
3553 rdn_name = rdn_attr->lDAPDisplayName;
3555 rdn_val = ldb_dn_get_rdn_val(msg->dn);
3556 if (rdn_val == NULL) {
3558 return ldb_module_done(ac->req, NULL, NULL,
3562 if (ldb_msg_add_empty(msg, rdn_name, LDB_FLAG_MOD_REPLACE, NULL) != 0) {
3564 return ldb_module_done(ac->req, NULL, NULL,
3567 if (ldb_msg_add_value(msg, rdn_name, rdn_val, NULL) != 0) {
3569 return ldb_module_done(ac->req, NULL, NULL,
3572 if (ldb_msg_add_empty(msg, "name", LDB_FLAG_MOD_REPLACE, NULL) != 0) {
3574 return ldb_module_done(ac->req, NULL, NULL,
3577 if (ldb_msg_add_value(msg, "name", rdn_val, NULL) != 0) {
3579 return ldb_module_done(ac->req, NULL, NULL,
3584 * here we let replmd_update_rpmd() only search for
3585 * the existing "replPropertyMetaData" and rdn_name attributes.
3587 * We do not want the existing "name" attribute as
3588 * the "name" attribute needs to get the version
3589 * updated on rename even if the rdn value hasn't changed.
3591 * This is the diff of the meta data, for a moved user
3592 * on a w2k8r2 server:
3595 * -dn: CN=sdf df,CN=Users,DC=bla,DC=base
3596 * +dn: CN=sdf df,OU=TestOU,DC=bla,DC=base
3597 * replPropertyMetaData: NDR: struct replPropertyMetaDataBlob
3598 * version : 0x00000001 (1)
3599 * reserved : 0x00000000 (0)
3600 * @@ -66,11 +66,11 @@ replPropertyMetaData: NDR: struct re
3601 * local_usn : 0x00000000000037a5 (14245)
3602 * array: struct replPropertyMetaData1
3603 * attid : DRSUAPI_ATTID_name (0x90001)
3604 * - version : 0x00000001 (1)
3605 * - originating_change_time : Wed Feb 9 17:20:49 2011 CET
3606 * + version : 0x00000002 (2)
3607 * + originating_change_time : Wed Apr 6 15:21:01 2011 CEST
3608 * originating_invocation_id: 0d36ca05-5507-4e62-aca3-354bab0d39e1
3609 * - originating_usn : 0x00000000000037a5 (14245)
3610 * - local_usn : 0x00000000000037a5 (14245)
3611 * + originating_usn : 0x0000000000003834 (14388)
3612 * + local_usn : 0x0000000000003834 (14388)
3613 * array: struct replPropertyMetaData1
3614 * attid : DRSUAPI_ATTID_userAccountControl (0x90008)
3615 * version : 0x00000004 (4)
3617 attrs[0] = "replPropertyMetaData";
3618 attrs[1] = "objectClass";
3619 attrs[2] = "instanceType";
3620 attrs[3] = rdn_name;
3623 ret = replmd_update_rpmd(ac->module, ac->schema, req, attrs,
3624 msg, &ac->seq_num, t,
3625 is_schema_nc, &is_urgent, &rodc);
3626 if (rodc && (ret == LDB_ERR_REFERRAL)) {
3627 ret = send_rodc_referral(req, ldb, ac->req->op.rename.olddn);
3629 return ldb_module_done(req, NULL, NULL, ret);
3632 if (ret != LDB_SUCCESS) {
3634 return ldb_module_done(ac->req, NULL, NULL, ret);
3637 if (ac->seq_num == 0) {
3639 return ldb_module_done(ac->req, NULL, NULL,
3641 "internal error seq_num == 0"));
3643 ac->is_urgent = is_urgent;
3645 ret = ldb_build_mod_req(&down_req, ldb, ac,
3648 ac, replmd_op_callback,
3650 LDB_REQ_SET_LOCATION(down_req);
3651 if (ret != LDB_SUCCESS) {
3656 /* current partition control is needed by "replmd_op_callback" */
3657 if (ldb_request_get_control(req, DSDB_CONTROL_CURRENT_PARTITION_OID) == NULL) {
3658 ret = ldb_request_add_control(down_req,
3659 DSDB_CONTROL_CURRENT_PARTITION_OID,
3661 if (ret != LDB_SUCCESS) {
3667 talloc_steal(down_req, msg);
3669 ret = add_time_element(msg, "whenChanged", t);
3670 if (ret != LDB_SUCCESS) {
3676 ret = add_uint64_element(ldb, msg, "uSNChanged", ac->seq_num);
3677 if (ret != LDB_SUCCESS) {
3683 /* go on with the call chain - do the modify after the rename */
3684 return ldb_next_request(ac->module, down_req);
3688 * remove links from objects that point at this object when an object
3689 * is deleted. We remove it from the NEXT module per MS-DRSR 5.160
3690 * RemoveObj which states that link removal due to the object being
3691 * deleted is NOT an originating update - they just go away!
3694 static int replmd_delete_remove_link(struct ldb_module *module,
3695 const struct dsdb_schema *schema,
3696 struct replmd_private *replmd_private,
3699 struct ldb_message_element *el,
3700 const struct dsdb_attribute *sa,
3701 struct ldb_request *parent)
3704 TALLOC_CTX *tmp_ctx = talloc_new(module);
3705 struct ldb_context *ldb = ldb_module_get_ctx(module);
3707 for (i=0; i<el->num_values; i++) {
3708 struct dsdb_dn *dsdb_dn;
3710 struct ldb_message *msg;
3711 const struct dsdb_attribute *target_attr;
3712 struct ldb_message_element *el2;
3714 struct ldb_val dn_val;
3715 uint32_t dsdb_flags = 0;
3716 const char *attrs[] = { NULL, NULL };
3717 struct ldb_result *link_res;
3718 struct ldb_message *link_msg;
3719 struct ldb_message_element *link_el;
3720 struct parsed_dn *link_dns;
3721 struct parsed_dn *p = NULL, *unused = NULL;
3723 if (dsdb_dn_is_deleted_val(&el->values[i])) {
3727 dsdb_dn = dsdb_dn_parse(tmp_ctx, ldb, &el->values[i], sa->syntax->ldap_oid);
3729 talloc_free(tmp_ctx);
3730 return LDB_ERR_OPERATIONS_ERROR;
3733 /* remove the link */
3734 msg = ldb_msg_new(tmp_ctx);
3736 ldb_module_oom(module);
3737 talloc_free(tmp_ctx);
3738 return LDB_ERR_OPERATIONS_ERROR;
3742 msg->dn = dsdb_dn->dn;
3744 target_attr = dsdb_attribute_by_linkID(schema, sa->linkID ^ 1);
3745 if (target_attr == NULL) {
3748 attrs[0] = target_attr->lDAPDisplayName;
3750 ret = ldb_msg_add_empty(msg, target_attr->lDAPDisplayName,
3751 LDB_FLAG_MOD_DELETE, &el2);
3752 if (ret != LDB_SUCCESS) {
3753 ldb_module_oom(module);
3754 talloc_free(tmp_ctx);
3755 return LDB_ERR_OPERATIONS_ERROR;
3758 ret = dsdb_module_search_dn(module, tmp_ctx, &link_res,
3760 DSDB_FLAG_NEXT_MODULE |
3761 DSDB_SEARCH_SHOW_EXTENDED_DN,
3764 if (ret != LDB_SUCCESS) {
3765 talloc_free(tmp_ctx);
3769 link_msg = link_res->msgs[0];
3770 link_el = ldb_msg_find_element(link_msg,
3771 target_attr->lDAPDisplayName);
3772 if (link_el == NULL) {
3773 talloc_free(tmp_ctx);
3774 return LDB_ERR_NO_SUCH_ATTRIBUTE;
3778 * This call 'upgrades' the links in link_dns, but we
3779 * do not commit the result back into the database, so
3780 * this is safe to call in FL2000 or on databases that
3781 * have been run at that level in the past.
3783 ret = get_parsed_dns_trusted(module, replmd_private, tmp_ctx,
3785 target_attr->syntax->ldap_oid, parent);
3786 if (ret != LDB_SUCCESS) {
3787 talloc_free(tmp_ctx);
3791 ret = parsed_dn_find(ldb, link_dns, link_el->num_values,
3795 target_attr->syntax->ldap_oid, false);
3796 if (ret != LDB_SUCCESS) {
3797 talloc_free(tmp_ctx);
3802 ldb_asprintf_errstring(ldb_module_get_ctx(module),
3803 "Failed to find forward link on %s "
3804 "as %s to remove backlink %s on %s",
3805 ldb_dn_get_linearized(msg->dn),
3806 target_attr->lDAPDisplayName,
3807 sa->lDAPDisplayName,
3808 ldb_dn_get_linearized(dn));
3809 talloc_free(tmp_ctx);
3810 return LDB_ERR_NO_SUCH_ATTRIBUTE;
3814 /* This needs to get the Binary DN, by first searching */
3815 dn_str = dsdb_dn_get_linearized(tmp_ctx,
3818 dn_val = data_blob_string_const(dn_str);
3819 el2->values = &dn_val;
3820 el2->num_values = 1;
3823 * Ensure that we tell the modification to vanish any linked
3824 * attributes (not simply mark them as isDeleted = TRUE)
3826 dsdb_flags |= DSDB_REPLMD_VANISH_LINKS;
3828 ret = dsdb_module_modify(module, msg, dsdb_flags|DSDB_FLAG_OWN_MODULE, parent);
3829 if (ret != LDB_SUCCESS) {
3830 talloc_free(tmp_ctx);
3834 talloc_free(tmp_ctx);
3840 handle update of replication meta data for deletion of objects
3842 This also handles the mapping of delete to a rename operation
3843 to allow deletes to be replicated.
3845 It also handles the incoming deleted objects, to ensure they are
3846 fully deleted here. In that case re_delete is true, and we do not
3847 use this as a signal to change the deleted state, just reinforce it.
3850 static int replmd_delete_internals(struct ldb_module *module, struct ldb_request *req, bool re_delete)
3852 int ret = LDB_ERR_OTHER;
3853 bool retb, disallow_move_on_delete;
3854 struct ldb_dn *old_dn = NULL, *new_dn = NULL;
3855 const char *rdn_name;
3856 const struct ldb_val *rdn_value, *new_rdn_value;
3858 struct ldb_context *ldb = ldb_module_get_ctx(module);
3859 const struct dsdb_schema *schema;
3860 struct ldb_message *msg, *old_msg;
3861 struct ldb_message_element *el;
3862 TALLOC_CTX *tmp_ctx;
3863 struct ldb_result *res, *parent_res;
3864 static const char * const preserved_attrs[] = {
3865 /* yes, this really is a hard coded list. See MS-ADTS
3866 section 3.1.1.5.5.1.1 */
3869 "dNReferenceUpdate",
3880 "msDS-LastKnownRDN",
3886 "distinguishedName",
3890 "proxiedObjectName",
3892 "nTSecurityDescriptor",
3893 "replPropertyMetaData",
3895 "securityIdentifier",
3903 "userAccountControl",
3910 static const char * const all_attrs[] = {
3911 DSDB_SECRET_ATTRIBUTES,
3915 unsigned int i, el_count = 0;
3916 uint32_t dsdb_flags = 0;
3917 struct replmd_private *replmd_private;
3918 enum deletion_state deletion_state, next_deletion_state;
3920 if (ldb_dn_is_special(req->op.del.dn)) {
3921 return ldb_next_request(module, req);
3925 * We have to allow dbcheck to remove an object that
3926 * is beyond repair, and to do so totally. This could
3927 * mean we we can get a partial object from the other
3928 * DC, causing havoc, so dbcheck suggests
3929 * re-replication first. dbcheck sets both DBCHECK
3930 * and RELAX in this situation.
3932 if (ldb_request_get_control(req, LDB_CONTROL_RELAX_OID)
3933 && ldb_request_get_control(req, DSDB_CONTROL_DBCHECK)) {
3934 /* really, really remove it */
3935 return ldb_next_request(module, req);
3938 tmp_ctx = talloc_new(ldb);
3941 return LDB_ERR_OPERATIONS_ERROR;
3944 schema = dsdb_get_schema(ldb, tmp_ctx);
3946 talloc_free(tmp_ctx);
3947 return LDB_ERR_OPERATIONS_ERROR;
3950 old_dn = ldb_dn_copy(tmp_ctx, req->op.del.dn);
3952 /* we need the complete msg off disk, so we can work out which
3953 attributes need to be removed */
3954 ret = dsdb_module_search_dn(module, tmp_ctx, &res, old_dn, all_attrs,
3955 DSDB_FLAG_NEXT_MODULE |
3956 DSDB_SEARCH_SHOW_RECYCLED |
3957 DSDB_SEARCH_REVEAL_INTERNALS |
3958 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT, req);
3959 if (ret != LDB_SUCCESS) {
3960 ldb_asprintf_errstring(ldb_module_get_ctx(module),
3961 "repmd_delete: Failed to %s %s, because we failed to find it: %s",
3962 re_delete ? "re-delete" : "delete",
3963 ldb_dn_get_linearized(old_dn),
3964 ldb_errstring(ldb_module_get_ctx(module)));
3965 talloc_free(tmp_ctx);
3968 old_msg = res->msgs[0];
3970 replmd_deletion_state(module, old_msg,
3972 &next_deletion_state);
3974 /* This supports us noticing an incoming isDeleted and acting on it */
3976 SMB_ASSERT(deletion_state > OBJECT_NOT_DELETED);
3977 next_deletion_state = deletion_state;
3980 if (next_deletion_state == OBJECT_REMOVED) {
3982 * We have to prevent objects being deleted, even if
3983 * the administrator really wants them gone, as
3984 * without the tombstone, we can get a partial object
3985 * from the other DC, causing havoc.
3987 * The only other valid case is when the 180 day
3988 * timeout has expired, when relax is specified.
3990 if (ldb_request_get_control(req, LDB_CONTROL_RELAX_OID)) {
3991 /* it is already deleted - really remove it this time */
3992 talloc_free(tmp_ctx);
3993 return ldb_next_request(module, req);
3996 ldb_asprintf_errstring(ldb, "Refusing to delete tombstone object %s. "
3997 "This check is to prevent corruption of the replicated state.",
3998 ldb_dn_get_linearized(old_msg->dn));
3999 return LDB_ERR_UNWILLING_TO_PERFORM;
4002 rdn_name = ldb_dn_get_rdn_name(old_dn);
4003 rdn_value = ldb_dn_get_rdn_val(old_dn);
4004 if ((rdn_name == NULL) || (rdn_value == NULL)) {
4005 talloc_free(tmp_ctx);
4006 return ldb_operr(ldb);
4009 msg = ldb_msg_new(tmp_ctx);
4011 ldb_module_oom(module);
4012 talloc_free(tmp_ctx);
4013 return LDB_ERR_OPERATIONS_ERROR;
4018 /* consider the SYSTEM_FLAG_DISALLOW_MOVE_ON_DELETE flag */
4019 disallow_move_on_delete =
4020 (ldb_msg_find_attr_as_int(old_msg, "systemFlags", 0)
4021 & SYSTEM_FLAG_DISALLOW_MOVE_ON_DELETE);
4023 /* work out where we will be renaming this object to */
4024 if (!disallow_move_on_delete) {
4025 struct ldb_dn *deleted_objects_dn;
4026 ret = dsdb_get_deleted_objects_dn(ldb, tmp_ctx, old_dn,
4027 &deleted_objects_dn);
4030 * We should not move objects if we can't find the
4031 * deleted objects DN. Not moving (or otherwise
4032 * harming) the Deleted Objects DN itself is handled
4035 if (re_delete && (ret != LDB_SUCCESS)) {
4036 new_dn = ldb_dn_get_parent(tmp_ctx, old_dn);
4037 if (new_dn == NULL) {
4038 ldb_module_oom(module);
4039 talloc_free(tmp_ctx);
4040 return LDB_ERR_OPERATIONS_ERROR;
4042 } else if (ret != LDB_SUCCESS) {
4043 /* this is probably an attempted delete on a partition
4044 * that doesn't allow delete operations, such as the
4045 * schema partition */
4046 ldb_asprintf_errstring(ldb, "No Deleted Objects container for DN %s",
4047 ldb_dn_get_linearized(old_dn));
4048 talloc_free(tmp_ctx);
4049 return LDB_ERR_UNWILLING_TO_PERFORM;
4051 new_dn = deleted_objects_dn;
4054 new_dn = ldb_dn_get_parent(tmp_ctx, old_dn);
4055 if (new_dn == NULL) {
4056 ldb_module_oom(module);
4057 talloc_free(tmp_ctx);
4058 return LDB_ERR_OPERATIONS_ERROR;
4062 /* get the objects GUID from the search we just did */
4063 guid = samdb_result_guid(old_msg, "objectGUID");
4065 if (deletion_state == OBJECT_NOT_DELETED) {
4067 ret = replmd_make_deleted_child_dn(tmp_ctx,
4070 rdn_name, rdn_value,
4073 if (ret != LDB_SUCCESS) {
4074 talloc_free(tmp_ctx);
4078 ret = ldb_msg_add_string(msg, "isDeleted", "TRUE");
4079 if (ret != LDB_SUCCESS) {
4080 ldb_asprintf_errstring(ldb, __location__
4081 ": Failed to add isDeleted string to the msg");
4082 talloc_free(tmp_ctx);
4085 msg->elements[el_count++].flags = LDB_FLAG_MOD_REPLACE;
4088 * No matter what has happened with other renames etc, try again to
4089 * get this to be under the deleted DN. See MS-DRSR 5.160 RemoveObj
4092 struct ldb_dn *rdn = ldb_dn_copy(tmp_ctx, old_dn);
4093 retb = ldb_dn_remove_base_components(rdn, ldb_dn_get_comp_num(rdn) - 1);
4095 ldb_asprintf_errstring(ldb, __location__
4096 ": Unable to add a prepare rdn of %s",
4097 ldb_dn_get_linearized(rdn));
4098 talloc_free(tmp_ctx);
4099 return LDB_ERR_OPERATIONS_ERROR;
4101 SMB_ASSERT(ldb_dn_get_comp_num(rdn) == 1);
4103 retb = ldb_dn_add_child(new_dn, rdn);
4105 ldb_asprintf_errstring(ldb, __location__
4106 ": Unable to add rdn %s to base dn: %s",
4107 ldb_dn_get_linearized(rdn),
4108 ldb_dn_get_linearized(new_dn));
4109 talloc_free(tmp_ctx);
4110 return LDB_ERR_OPERATIONS_ERROR;
4115 now we need to modify the object in the following ways:
4117 - add isDeleted=TRUE
4118 - update rDN and name, with new rDN
4119 - remove linked attributes
4120 - remove objectCategory and sAMAccountType
4121 - remove attribs not on the preserved list
4122 - preserved if in above list, or is rDN
4123 - remove all linked attribs from this object
4124 - remove all links from other objects to this object
4125 - add lastKnownParent
4126 - update replPropertyMetaData?
4128 see MS-ADTS "Tombstone Requirements" section 3.1.1.5.5.1.1
4131 if (deletion_state == OBJECT_NOT_DELETED) {
4132 struct ldb_dn *parent_dn = ldb_dn_get_parent(tmp_ctx, old_dn);
4133 char *parent_dn_str = NULL;
4135 /* we need the storage form of the parent GUID */
4136 ret = dsdb_module_search_dn(module, tmp_ctx, &parent_res,
4138 DSDB_FLAG_NEXT_MODULE |
4139 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT |
4140 DSDB_SEARCH_REVEAL_INTERNALS|
4141 DSDB_SEARCH_SHOW_RECYCLED, req);
4142 if (ret != LDB_SUCCESS) {
4143 ldb_asprintf_errstring(ldb_module_get_ctx(module),
4144 "repmd_delete: Failed to %s %s, "
4145 "because we failed to find it's parent (%s): %s",
4146 re_delete ? "re-delete" : "delete",
4147 ldb_dn_get_linearized(old_dn),
4148 ldb_dn_get_linearized(parent_dn),
4149 ldb_errstring(ldb_module_get_ctx(module)));
4150 talloc_free(tmp_ctx);
4155 * Now we can use the DB version,
4156 * it will have the extended DN info in it
4158 parent_dn = parent_res->msgs[0]->dn;
4159 parent_dn_str = ldb_dn_get_extended_linearized(tmp_ctx,
4162 if (parent_dn_str == NULL) {
4163 talloc_free(tmp_ctx);
4164 return ldb_module_oom(module);
4167 ret = ldb_msg_add_steal_string(msg, "lastKnownParent",
4169 if (ret != LDB_SUCCESS) {
4170 ldb_asprintf_errstring(ldb, __location__
4171 ": Failed to add lastKnownParent "
4172 "string when deleting %s",
4173 ldb_dn_get_linearized(old_dn));
4174 talloc_free(tmp_ctx);
4177 msg->elements[el_count++].flags = LDB_FLAG_MOD_REPLACE;
4179 if (next_deletion_state == OBJECT_DELETED) {
4180 ret = ldb_msg_add_value(msg, "msDS-LastKnownRDN", rdn_value, NULL);
4181 if (ret != LDB_SUCCESS) {
4182 ldb_asprintf_errstring(ldb, __location__
4183 ": Failed to add msDS-LastKnownRDN "
4184 "string when deleting %s",
4185 ldb_dn_get_linearized(old_dn));
4186 talloc_free(tmp_ctx);
4189 msg->elements[el_count++].flags = LDB_FLAG_MOD_ADD;
4193 switch (next_deletion_state) {
4195 case OBJECT_RECYCLED:
4196 case OBJECT_TOMBSTONE:
4199 * MS-ADTS 3.1.1.5.5.1.1 Tombstone Requirements
4200 * describes what must be removed from a tombstone
4203 * MS-ADTS 3.1.1.5.5.1.3 Recycled-Object Requirements
4204 * describes what must be removed from a recycled
4210 * we also mark it as recycled, meaning this object can't be
4211 * recovered (we are stripping its attributes).
4212 * This is done only if we have this schema object of course ...
4213 * This behavior is identical to the one of Windows 2008R2 which
4214 * always set the isRecycled attribute, even if the recycle-bin is
4215 * not activated and what ever the forest level is.
4217 if (dsdb_attribute_by_lDAPDisplayName(schema, "isRecycled") != NULL) {
4218 ret = ldb_msg_add_string(msg, "isRecycled", "TRUE");
4219 if (ret != LDB_SUCCESS) {
4220 DEBUG(0,(__location__ ": Failed to add isRecycled string to the msg\n"));
4221 ldb_module_oom(module);
4222 talloc_free(tmp_ctx);
4225 msg->elements[el_count++].flags = LDB_FLAG_MOD_REPLACE;
4228 replmd_private = talloc_get_type(ldb_module_get_private(module),
4229 struct replmd_private);
4230 /* work out which of the old attributes we will be removing */
4231 for (i=0; i<old_msg->num_elements; i++) {
4232 const struct dsdb_attribute *sa;
4233 el = &old_msg->elements[i];
4234 sa = dsdb_attribute_by_lDAPDisplayName(schema, el->name);
4236 talloc_free(tmp_ctx);
4237 return LDB_ERR_OPERATIONS_ERROR;
4239 if (ldb_attr_cmp(el->name, rdn_name) == 0) {
4240 /* don't remove the rDN */
4243 if (sa->linkID & 1) {
4245 we have a backlink in this object
4246 that needs to be removed. We're not
4247 allowed to remove it directly
4248 however, so we instead setup a
4249 modify to delete the corresponding
4252 ret = replmd_delete_remove_link(module, schema,
4256 if (ret != LDB_SUCCESS) {
4257 const char *old_dn_str
4258 = ldb_dn_get_linearized(old_dn);
4259 ldb_asprintf_errstring(ldb,
4261 ": Failed to remove backlink of "
4262 "%s when deleting %s: %s",
4265 ldb_errstring(ldb));
4266 talloc_free(tmp_ctx);
4267 return LDB_ERR_OPERATIONS_ERROR;
4269 /* now we continue, which means we
4270 won't remove this backlink
4274 } else if (sa->linkID == 0) {
4275 if (ldb_attr_in_list(preserved_attrs, el->name)) {
4278 if (sa->searchFlags & SEARCH_FLAG_PRESERVEONDELETE) {
4283 * Ensure that we tell the modification to vanish any linked
4284 * attributes (not simply mark them as isDeleted = TRUE)
4286 dsdb_flags |= DSDB_REPLMD_VANISH_LINKS;
4288 ret = ldb_msg_add_empty(msg, el->name, LDB_FLAG_MOD_DELETE, &el);
4289 if (ret != LDB_SUCCESS) {
4290 talloc_free(tmp_ctx);
4291 ldb_module_oom(module);
4298 case OBJECT_DELETED:
4300 * MS-ADTS 3.1.1.5.5.1.2 Deleted-Object Requirements
4301 * describes what must be removed from a deleted
4305 ret = ldb_msg_add_empty(msg, "objectCategory", LDB_FLAG_MOD_REPLACE, NULL);
4306 if (ret != LDB_SUCCESS) {
4307 talloc_free(tmp_ctx);
4308 ldb_module_oom(module);
4312 ret = ldb_msg_add_empty(msg, "sAMAccountType", LDB_FLAG_MOD_REPLACE, NULL);
4313 if (ret != LDB_SUCCESS) {
4314 talloc_free(tmp_ctx);
4315 ldb_module_oom(module);
4325 if (deletion_state == OBJECT_NOT_DELETED) {
4326 const struct dsdb_attribute *sa;
4328 /* work out what the new rdn value is, for updating the
4329 rDN and name fields */
4330 new_rdn_value = ldb_dn_get_rdn_val(new_dn);
4331 if (new_rdn_value == NULL) {
4332 talloc_free(tmp_ctx);
4333 return ldb_operr(ldb);
4336 sa = dsdb_attribute_by_lDAPDisplayName(schema, rdn_name);
4338 talloc_free(tmp_ctx);
4339 return LDB_ERR_OPERATIONS_ERROR;
4342 ret = ldb_msg_add_value(msg, sa->lDAPDisplayName, new_rdn_value,
4344 if (ret != LDB_SUCCESS) {
4345 talloc_free(tmp_ctx);
4348 el->flags = LDB_FLAG_MOD_REPLACE;
4350 el = ldb_msg_find_element(old_msg, "name");
4352 ret = ldb_msg_add_value(msg, "name", new_rdn_value, &el);
4353 if (ret != LDB_SUCCESS) {
4354 talloc_free(tmp_ctx);
4357 el->flags = LDB_FLAG_MOD_REPLACE;
4362 * TODO: Per MS-DRSR 5.160 RemoveObj we should remove links directly, not as an originating update!
4367 * No matter what has happned with other renames, try again to
4368 * get this to be under the deleted DN.
4370 if (strcmp(ldb_dn_get_linearized(old_dn), ldb_dn_get_linearized(new_dn)) != 0) {
4371 /* now rename onto the new DN */
4372 ret = dsdb_module_rename(module, old_dn, new_dn, DSDB_FLAG_NEXT_MODULE, req);
4373 if (ret != LDB_SUCCESS){
4374 DEBUG(0,(__location__ ": Failed to rename object from '%s' to '%s' - %s\n",
4375 ldb_dn_get_linearized(old_dn),
4376 ldb_dn_get_linearized(new_dn),
4377 ldb_errstring(ldb)));
4378 talloc_free(tmp_ctx);
4384 ret = dsdb_module_modify(module, msg, dsdb_flags|DSDB_FLAG_OWN_MODULE, req);
4385 if (ret != LDB_SUCCESS) {
4386 ldb_asprintf_errstring(ldb, "replmd_delete: Failed to modify object %s in delete - %s",
4387 ldb_dn_get_linearized(old_dn), ldb_errstring(ldb));
4388 talloc_free(tmp_ctx);
4392 talloc_free(tmp_ctx);
4394 return ldb_module_done(req, NULL, NULL, LDB_SUCCESS);
4397 static int replmd_delete(struct ldb_module *module, struct ldb_request *req)
4399 return replmd_delete_internals(module, req, false);
4403 static int replmd_replicated_request_error(struct replmd_replicated_request *ar, int ret)
4408 static int replmd_replicated_request_werror(struct replmd_replicated_request *ar, WERROR status)
4410 int ret = LDB_ERR_OTHER;
4411 /* TODO: do some error mapping */
4413 /* Let the caller know the full WERROR */
4414 ar->objs->error = status;
4420 static struct replPropertyMetaData1 *
4421 replmd_replPropertyMetaData1_find_attid(struct replPropertyMetaDataBlob *md_blob,
4422 enum drsuapi_DsAttributeId attid)
4425 struct replPropertyMetaDataCtr1 *rpmd_ctr = &md_blob->ctr.ctr1;
4427 for (i = 0; i < rpmd_ctr->count; i++) {
4428 if (rpmd_ctr->array[i].attid == attid) {
4429 return &rpmd_ctr->array[i];
4437 return true if an update is newer than an existing entry
4438 see section 5.11 of MS-ADTS
4440 static bool replmd_update_is_newer(const struct GUID *current_invocation_id,
4441 const struct GUID *update_invocation_id,
4442 uint32_t current_version,
4443 uint32_t update_version,
4444 NTTIME current_change_time,
4445 NTTIME update_change_time)
4447 if (update_version != current_version) {
4448 return update_version > current_version;
4450 if (update_change_time != current_change_time) {
4451 return update_change_time > current_change_time;
4453 return GUID_compare(update_invocation_id, current_invocation_id) > 0;
4456 static bool replmd_replPropertyMetaData1_is_newer(struct replPropertyMetaData1 *cur_m,
4457 struct replPropertyMetaData1 *new_m)
4459 return replmd_update_is_newer(&cur_m->originating_invocation_id,
4460 &new_m->originating_invocation_id,
4463 cur_m->originating_change_time,
4464 new_m->originating_change_time);
4467 static bool replmd_replPropertyMetaData1_new_should_be_taken(uint32_t dsdb_repl_flags,
4468 struct replPropertyMetaData1 *cur_m,
4469 struct replPropertyMetaData1 *new_m)
4474 * If the new replPropertyMetaData entry for this attribute is
4475 * not provided (this happens in the case where we look for
4476 * ATTID_name, but the name was not changed), then the local
4477 * state is clearly still current, as the remote
4478 * server didn't send it due to being older the high watermark
4481 if (new_m == NULL) {
4485 if (dsdb_repl_flags & DSDB_REPL_FLAG_PRIORITISE_INCOMING) {
4487 * if we compare equal then do an
4488 * update. This is used when a client
4489 * asks for a FULL_SYNC, and can be
4490 * used to recover a corrupt
4493 * This call is a bit tricky, what we
4494 * are doing it turning the 'is_newer'
4495 * call into a 'not is older' by
4496 * swapping cur_m and new_m, and negating the
4499 cmp = !replmd_replPropertyMetaData1_is_newer(new_m,
4502 cmp = replmd_replPropertyMetaData1_is_newer(cur_m,
4512 static struct ldb_dn *replmd_conflict_dn(TALLOC_CTX *mem_ctx, struct ldb_dn *dn, struct GUID *guid)
4514 const struct ldb_val *rdn_val;
4515 const char *rdn_name;
4516 struct ldb_dn *new_dn;
4518 rdn_val = ldb_dn_get_rdn_val(dn);
4519 rdn_name = ldb_dn_get_rdn_name(dn);
4520 if (!rdn_val || !rdn_name) {
4524 new_dn = ldb_dn_copy(mem_ctx, dn);
4529 if (!ldb_dn_remove_child_components(new_dn, 1)) {
4533 if (!ldb_dn_add_child_fmt(new_dn, "%s=%s\\0ACNF:%s",
4535 ldb_dn_escape_value(new_dn, *rdn_val),
4536 GUID_string(new_dn, guid))) {
4546 static int replmd_make_prefix_child_dn(TALLOC_CTX *tmp_ctx,
4547 struct ldb_context *ldb,
4549 const char *four_char_prefix,
4550 const char *rdn_name,
4551 const struct ldb_val *rdn_value,
4554 struct ldb_val deleted_child_rdn_val;
4555 struct GUID_txt_buf guid_str;
4558 GUID_buf_string(&guid, &guid_str);
4560 retb = ldb_dn_add_child_fmt(dn, "X=Y");
4562 ldb_asprintf_errstring(ldb, __location__
4563 ": Unable to add a formatted child to dn: %s",
4564 ldb_dn_get_linearized(dn));
4565 return LDB_ERR_OPERATIONS_ERROR;
4569 deleted_child_rdn_val = ldb_val_dup(tmp_ctx, rdn_value);
4572 * sizeof(guid_str.buf) will always be longer than
4573 * strlen(guid_str.buf) but we allocate using this and
4574 * waste the trailing bytes to avoid scaring folks
4575 * with memcpy() using strlen() below
4578 deleted_child_rdn_val.data
4579 = talloc_realloc(tmp_ctx, deleted_child_rdn_val.data,
4581 rdn_value->length + 5
4582 + sizeof(guid_str.buf));
4583 if (!deleted_child_rdn_val.data) {
4584 ldb_asprintf_errstring(ldb, __location__
4585 ": Unable to add a formatted child to dn: %s",
4586 ldb_dn_get_linearized(dn));
4587 return LDB_ERR_OPERATIONS_ERROR;
4590 deleted_child_rdn_val.length =
4591 rdn_value->length + 5
4592 + strlen(guid_str.buf);
4594 SMB_ASSERT(deleted_child_rdn_val.length <
4595 talloc_get_size(deleted_child_rdn_val.data));
4598 * talloc won't allocate more than 256MB so we can't
4599 * overflow but just to be sure
4601 if (deleted_child_rdn_val.length < rdn_value->length) {
4602 return LDB_ERR_OPERATIONS_ERROR;
4605 deleted_child_rdn_val.data[rdn_value->length] = 0x0a;
4606 memcpy(&deleted_child_rdn_val.data[rdn_value->length + 1],
4607 four_char_prefix, 4);
4608 memcpy(&deleted_child_rdn_val.data[rdn_value->length + 5],
4610 sizeof(guid_str.buf));
4612 /* Now set the value into the RDN, without parsing it */
4613 ldb_dn_set_component(dn, 0, rdn_name,
4614 deleted_child_rdn_val);
4623 static struct ldb_dn *replmd_conflict_dn(TALLOC_CTX *mem_ctx,
4624 struct ldb_context *ldb,
4628 const struct ldb_val *rdn_val;
4629 const char *rdn_name;
4630 struct ldb_dn *new_dn;
4633 rdn_val = ldb_dn_get_rdn_val(dn);
4634 rdn_name = ldb_dn_get_rdn_name(dn);
4635 if (!rdn_val || !rdn_name) {
4639 new_dn = ldb_dn_get_parent(mem_ctx, dn);
4644 ret = replmd_make_prefix_child_dn(mem_ctx,
4650 if (ret != LDB_SUCCESS) {
4659 static int replmd_make_deleted_child_dn(TALLOC_CTX *tmp_ctx,
4660 struct ldb_context *ldb,
4662 const char *rdn_name,
4663 const struct ldb_val *rdn_value,
4666 return replmd_make_prefix_child_dn(tmp_ctx,
4676 perform a modify operation which sets the rDN and name attributes to
4677 their current values. This has the effect of changing these
4678 attributes to have been last updated by the current DC. This is
4679 needed to ensure that renames performed as part of conflict
4680 resolution are propogated to other DCs
4682 static int replmd_name_modify(struct replmd_replicated_request *ar,
4683 struct ldb_request *req, struct ldb_dn *dn)
4685 struct ldb_message *msg;
4686 const char *rdn_name;
4687 const struct ldb_val *rdn_val;
4688 const struct dsdb_attribute *rdn_attr;
4691 msg = ldb_msg_new(req);
4697 rdn_name = ldb_dn_get_rdn_name(dn);
4698 if (rdn_name == NULL) {
4702 /* normalize the rdn attribute name */
4703 rdn_attr = dsdb_attribute_by_lDAPDisplayName(ar->schema, rdn_name);
4704 if (rdn_attr == NULL) {
4707 rdn_name = rdn_attr->lDAPDisplayName;
4709 rdn_val = ldb_dn_get_rdn_val(dn);
4710 if (rdn_val == NULL) {
4714 if (ldb_msg_add_empty(msg, rdn_name, LDB_FLAG_MOD_REPLACE, NULL) != 0) {
4717 if (ldb_msg_add_value(msg, rdn_name, rdn_val, NULL) != 0) {
4720 if (ldb_msg_add_empty(msg, "name", LDB_FLAG_MOD_REPLACE, NULL) != 0) {
4723 if (ldb_msg_add_value(msg, "name", rdn_val, NULL) != 0) {
4728 * We have to mark this as a replicated update otherwise
4729 * schema_data may reject a rename in the schema partition
4732 ret = dsdb_module_modify(ar->module, msg,
4733 DSDB_FLAG_OWN_MODULE|DSDB_FLAG_REPLICATED_UPDATE,
4735 if (ret != LDB_SUCCESS) {
4736 DEBUG(0,(__location__ ": Failed to modify rDN/name of DN being DRS renamed '%s' - %s",
4737 ldb_dn_get_linearized(dn),
4738 ldb_errstring(ldb_module_get_ctx(ar->module))));
4748 DEBUG(0,(__location__ ": Failed to setup modify rDN/name of DN being DRS renamed '%s'",
4749 ldb_dn_get_linearized(dn)));
4750 return LDB_ERR_OPERATIONS_ERROR;
4755 callback for conflict DN handling where we have renamed the incoming
4756 record. After renaming it, we need to ensure the change of name and
4757 rDN for the incoming record is seen as an originating update by this DC.
4759 This also handles updating lastKnownParent for entries sent to lostAndFound
4761 static int replmd_op_name_modify_callback(struct ldb_request *req, struct ldb_reply *ares)
4763 struct replmd_replicated_request *ar =
4764 talloc_get_type_abort(req->context, struct replmd_replicated_request);
4765 struct ldb_dn *conflict_dn = NULL;
4768 if (ares->error != LDB_SUCCESS) {
4769 /* call the normal callback for everything except success */
4770 return replmd_op_callback(req, ares);
4773 switch (req->operation) {
4775 conflict_dn = req->op.add.message->dn;
4778 conflict_dn = req->op.mod.message->dn;
4781 smb_panic("replmd_op_name_modify_callback called in unknown circumstances");
4784 /* perform a modify of the rDN and name of the record */
4785 ret = replmd_name_modify(ar, req, conflict_dn);
4786 if (ret != LDB_SUCCESS) {
4788 return replmd_op_callback(req, ares);
4791 if (ar->objs->objects[ar->index_current].last_known_parent) {
4792 struct ldb_message *msg = ldb_msg_new(req);
4794 ldb_module_oom(ar->module);
4795 return LDB_ERR_OPERATIONS_ERROR;
4798 msg->dn = req->op.add.message->dn;
4800 ret = ldb_msg_add_steal_string(msg, "lastKnownParent",
4801 ldb_dn_get_extended_linearized(msg, ar->objs->objects[ar->index_current].last_known_parent, 1));
4802 if (ret != LDB_SUCCESS) {
4803 DEBUG(0,(__location__ ": Failed to add lastKnownParent string to the msg\n"));
4804 ldb_module_oom(ar->module);
4807 msg->elements[0].flags = LDB_FLAG_MOD_REPLACE;
4809 ret = dsdb_module_modify(ar->module, msg, DSDB_FLAG_OWN_MODULE, req);
4810 if (ret != LDB_SUCCESS) {
4811 DEBUG(0,(__location__ ": Failed to modify lastKnownParent of lostAndFound DN '%s' - %s",
4812 ldb_dn_get_linearized(msg->dn),
4813 ldb_errstring(ldb_module_get_ctx(ar->module))));
4819 return replmd_op_callback(req, ares);
4823 callback for replmd_replicated_apply_add()
4824 This copes with the creation of conflict records in the case where
4825 the DN exists, but with a different objectGUID
4827 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))
4829 struct ldb_dn *conflict_dn;
4830 struct replmd_replicated_request *ar =
4831 talloc_get_type_abort(req->context, struct replmd_replicated_request);
4832 struct ldb_result *res;
4833 const char *attrs[] = { "replPropertyMetaData", "objectGUID", NULL };
4835 const struct ldb_val *omd_value;
4836 struct replPropertyMetaDataBlob omd, *rmd;
4837 enum ndr_err_code ndr_err;
4838 bool rename_incoming_record, rodc;
4839 struct replPropertyMetaData1 *rmd_name, *omd_name;
4840 struct ldb_message *msg;
4841 struct ldb_request *down_req = NULL;
4843 /* call the normal callback for success */
4844 if (ares->error == LDB_SUCCESS) {
4845 return callback(req, ares);
4849 * we have a conflict, and need to decide if we will keep the
4850 * new record or the old record
4853 msg = ar->objs->objects[ar->index_current].msg;
4854 conflict_dn = msg->dn;
4856 /* For failures other than conflicts, fail the whole operation here */
4857 if (ares->error != LDB_ERR_ENTRY_ALREADY_EXISTS) {
4858 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module), "Failed to locally apply remote add of %s: %s",
4859 ldb_dn_get_linearized(conflict_dn),
4860 ldb_errstring(ldb_module_get_ctx(ar->module)));
4862 return ldb_module_done(ar->req, NULL, NULL,
4863 LDB_ERR_OPERATIONS_ERROR);
4866 ret = samdb_rodc(ldb_module_get_ctx(ar->module), &rodc);
4867 if (ret != LDB_SUCCESS) {
4868 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)));
4869 return ldb_module_done(ar->req, NULL, NULL,
4870 LDB_ERR_OPERATIONS_ERROR);
4876 * We are on an RODC, or were a GC for this
4877 * partition, so we have to fail this until
4878 * someone who owns the partition sorts it
4881 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
4882 "Conflict adding object '%s' from incoming replication as we are read only for the partition. \n"
4883 " - We must fail the operation until a master for this partition resolves the conflict",
4884 ldb_dn_get_linearized(conflict_dn));
4889 * first we need the replPropertyMetaData attribute from the
4890 * local, conflicting record
4892 ret = dsdb_module_search_dn(ar->module, req, &res, conflict_dn,
4894 DSDB_FLAG_NEXT_MODULE |
4895 DSDB_SEARCH_SHOW_DELETED |
4896 DSDB_SEARCH_SHOW_RECYCLED, req);
4897 if (ret != LDB_SUCCESS) {
4898 DEBUG(0,(__location__ ": Unable to find object for conflicting record '%s'\n",
4899 ldb_dn_get_linearized(conflict_dn)));
4903 omd_value = ldb_msg_find_ldb_val(res->msgs[0], "replPropertyMetaData");
4904 if (omd_value == NULL) {
4905 DEBUG(0,(__location__ ": Unable to find replPropertyMetaData for conflicting record '%s'\n",
4906 ldb_dn_get_linearized(conflict_dn)));
4910 ndr_err = ndr_pull_struct_blob(omd_value, res->msgs[0], &omd,
4911 (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
4912 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
4913 DEBUG(0,(__location__ ": Failed to parse old replPropertyMetaData for %s\n",
4914 ldb_dn_get_linearized(conflict_dn)));
4918 rmd = ar->objs->objects[ar->index_current].meta_data;
4921 * we decide which is newer based on the RPMD on the name
4922 * attribute. See [MS-DRSR] ResolveNameConflict.
4924 * We expect omd_name to be present, as this is from a local
4925 * search, but while rmd_name should have been given to us by
4926 * the remote server, if it is missing we just prefer the
4928 * replmd_replPropertyMetaData1_new_should_be_taken()
4930 rmd_name = replmd_replPropertyMetaData1_find_attid(rmd, DRSUAPI_ATTID_name);
4931 omd_name = replmd_replPropertyMetaData1_find_attid(&omd, DRSUAPI_ATTID_name);
4933 DEBUG(0,(__location__ ": Failed to find name attribute in local LDB replPropertyMetaData for %s\n",
4934 ldb_dn_get_linearized(conflict_dn)));
4939 * Should we preserve the current record, and so rename the
4940 * incoming record to be a conflict?
4942 rename_incoming_record
4943 = !replmd_replPropertyMetaData1_new_should_be_taken(ar->objs->dsdb_repl_flags & DSDB_REPL_FLAG_PRIORITISE_INCOMING,
4944 omd_name, rmd_name);
4946 if (rename_incoming_record) {
4948 struct ldb_dn *new_dn;
4950 guid = samdb_result_guid(msg, "objectGUID");
4951 if (GUID_all_zero(&guid)) {
4952 DEBUG(0,(__location__ ": Failed to find objectGUID for conflicting incoming record %s\n",
4953 ldb_dn_get_linearized(conflict_dn)));
4956 new_dn = replmd_conflict_dn(req, conflict_dn, &guid);
4957 if (new_dn == NULL) {
4958 DEBUG(0,(__location__ ": Failed to form conflict DN for %s\n",
4959 ldb_dn_get_linearized(conflict_dn)));
4963 DEBUG(2,(__location__ ": Resolving conflict record via incoming rename '%s' -> '%s'\n",
4964 ldb_dn_get_linearized(conflict_dn), ldb_dn_get_linearized(new_dn)));
4966 /* re-submit the request, but with the new DN */
4967 callback = replmd_op_name_modify_callback;
4970 /* we are renaming the existing record */
4972 struct ldb_dn *new_dn;
4974 guid = samdb_result_guid(res->msgs[0], "objectGUID");
4975 if (GUID_all_zero(&guid)) {
4976 DEBUG(0,(__location__ ": Failed to find objectGUID for existing conflict record %s\n",
4977 ldb_dn_get_linearized(conflict_dn)));
4981 new_dn = replmd_conflict_dn(req, conflict_dn, &guid);
4982 if (new_dn == NULL) {
4983 DEBUG(0,(__location__ ": Failed to form conflict DN for %s\n",
4984 ldb_dn_get_linearized(conflict_dn)));
4988 DEBUG(2,(__location__ ": Resolving conflict record via existing-record rename '%s' -> '%s'\n",
4989 ldb_dn_get_linearized(conflict_dn), ldb_dn_get_linearized(new_dn)));
4991 ret = dsdb_module_rename(ar->module, conflict_dn, new_dn,
4992 DSDB_FLAG_OWN_MODULE, req);
4993 if (ret != LDB_SUCCESS) {
4994 DEBUG(0,(__location__ ": Failed to rename conflict dn '%s' to '%s' - %s\n",
4995 ldb_dn_get_linearized(conflict_dn),
4996 ldb_dn_get_linearized(new_dn),
4997 ldb_errstring(ldb_module_get_ctx(ar->module))));
5002 * now we need to ensure that the rename is seen as an
5003 * originating update. We do that with a modify.
5005 ret = replmd_name_modify(ar, req, new_dn);
5006 if (ret != LDB_SUCCESS) {
5010 DEBUG(2,(__location__ ": With conflicting record renamed, re-apply replicated creation of '%s'\n",
5011 ldb_dn_get_linearized(req->op.add.message->dn)));
5014 ret = ldb_build_add_req(&down_req,
5015 ldb_module_get_ctx(ar->module),
5022 if (ret != LDB_SUCCESS) {
5025 LDB_REQ_SET_LOCATION(down_req);
5027 /* current partition control needed by "repmd_op_callback" */
5028 ret = ldb_request_add_control(down_req,
5029 DSDB_CONTROL_CURRENT_PARTITION_OID,
5031 if (ret != LDB_SUCCESS) {
5032 return replmd_replicated_request_error(ar, ret);
5035 if (ar->objs->dsdb_repl_flags & DSDB_REPL_FLAG_PARTIAL_REPLICA) {
5036 /* this tells the partition module to make it a
5037 partial replica if creating an NC */
5038 ret = ldb_request_add_control(down_req,
5039 DSDB_CONTROL_PARTIAL_REPLICA,
5041 if (ret != LDB_SUCCESS) {
5042 return replmd_replicated_request_error(ar, ret);
5047 * Finally we re-run the add, otherwise the new record won't
5048 * exist, as we are here because of that exact failure!
5050 return ldb_next_request(ar->module, down_req);
5053 /* on failure make the caller get the error. This means
5054 * replication will stop with an error, but there is not much
5057 return ldb_module_done(ar->req, NULL, NULL,
5062 callback for replmd_replicated_apply_add()
5063 This copes with the creation of conflict records in the case where
5064 the DN exists, but with a different objectGUID
5066 static int replmd_op_add_callback(struct ldb_request *req, struct ldb_reply *ares)
5068 struct replmd_replicated_request *ar =
5069 talloc_get_type_abort(req->context, struct replmd_replicated_request);
5071 if (ar->objs->objects[ar->index_current].last_known_parent) {
5072 /* This is like a conflict DN, where we put the object in LostAndFound
5073 see MS-DRSR 4.1.10.6.10 FindBestParentObject */
5074 return replmd_op_possible_conflict_callback(req, ares, replmd_op_name_modify_callback);
5077 return replmd_op_possible_conflict_callback(req, ares, replmd_op_callback);
5081 this is called when a new object comes in over DRS
5083 static int replmd_replicated_apply_add(struct replmd_replicated_request *ar)
5085 struct ldb_context *ldb;
5086 struct ldb_request *change_req;
5087 enum ndr_err_code ndr_err;
5088 struct ldb_message *msg;
5089 struct replPropertyMetaDataBlob *md;
5090 struct ldb_val md_value;
5093 bool remote_isDeleted = false;
5096 time_t t = time(NULL);
5097 const struct ldb_val *rdn_val;
5098 struct replmd_private *replmd_private =
5099 talloc_get_type(ldb_module_get_private(ar->module),
5100 struct replmd_private);
5101 unix_to_nt_time(&now, t);
5103 ldb = ldb_module_get_ctx(ar->module);
5104 msg = ar->objs->objects[ar->index_current].msg;
5105 md = ar->objs->objects[ar->index_current].meta_data;
5106 is_schema_nc = ldb_dn_compare_base(replmd_private->schema_dn, msg->dn) == 0;
5108 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &ar->seq_num);
5109 if (ret != LDB_SUCCESS) {
5110 return replmd_replicated_request_error(ar, ret);
5113 ret = dsdb_msg_add_guid(msg,
5114 &ar->objs->objects[ar->index_current].object_guid,
5116 if (ret != LDB_SUCCESS) {
5117 return replmd_replicated_request_error(ar, ret);
5120 ret = ldb_msg_add_string(msg, "whenChanged", ar->objs->objects[ar->index_current].when_changed);
5121 if (ret != LDB_SUCCESS) {
5122 return replmd_replicated_request_error(ar, ret);
5125 ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNCreated", ar->seq_num);
5126 if (ret != LDB_SUCCESS) {
5127 return replmd_replicated_request_error(ar, ret);
5130 ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNChanged", ar->seq_num);
5131 if (ret != LDB_SUCCESS) {
5132 return replmd_replicated_request_error(ar, ret);
5135 /* remove any message elements that have zero values */
5136 for (i=0; i<msg->num_elements; i++) {
5137 struct ldb_message_element *el = &msg->elements[i];
5139 if (el->num_values == 0) {
5140 if (ldb_attr_cmp(msg->elements[i].name, "objectClass") == 0) {
5141 ldb_asprintf_errstring(ldb, __location__
5142 ": empty objectClass sent on %s, aborting replication\n",
5143 ldb_dn_get_linearized(msg->dn));
5144 return replmd_replicated_request_error(ar, LDB_ERR_OBJECT_CLASS_VIOLATION);
5147 DEBUG(4,(__location__ ": Removing attribute %s with num_values==0\n",
5149 memmove(el, el+1, sizeof(*el)*(msg->num_elements - (i+1)));
5150 msg->num_elements--;
5157 struct GUID_txt_buf guid_txt;
5159 char *s = ldb_ldif_message_redacted_string(ldb, ar,
5162 DEBUG(8, ("DRS replication add message of %s:\n%s\n",
5163 GUID_buf_string(&ar->objs->objects[ar->index_current].object_guid, &guid_txt),
5166 } else if (DEBUGLVL(4)) {
5167 struct GUID_txt_buf guid_txt;
5168 DEBUG(4, ("DRS replication add DN of %s is %s\n",
5169 GUID_buf_string(&ar->objs->objects[ar->index_current].object_guid, &guid_txt),
5170 ldb_dn_get_linearized(msg->dn)));
5172 remote_isDeleted = ldb_msg_find_attr_as_bool(msg,
5173 "isDeleted", false);
5176 * the meta data array is already sorted by the caller, except
5177 * for the RDN, which needs to be added.
5181 rdn_val = ldb_dn_get_rdn_val(msg->dn);
5182 ret = replmd_update_rpmd_rdn_attr(ldb, msg, rdn_val, NULL,
5183 md, ar, now, is_schema_nc,
5185 if (ret != LDB_SUCCESS) {
5186 ldb_asprintf_errstring(ldb, "%s: error during DRS repl ADD: %s", __func__, ldb_errstring(ldb));
5187 return replmd_replicated_request_error(ar, ret);
5190 ret = replmd_replPropertyMetaDataCtr1_sort_and_verify(ldb, &md->ctr.ctr1, msg->dn);
5191 if (ret != LDB_SUCCESS) {
5192 ldb_asprintf_errstring(ldb, "%s: error during DRS repl ADD: %s", __func__, ldb_errstring(ldb));
5193 return replmd_replicated_request_error(ar, ret);
5196 for (i=0; i < md->ctr.ctr1.count; i++) {
5197 md->ctr.ctr1.array[i].local_usn = ar->seq_num;
5199 ndr_err = ndr_push_struct_blob(&md_value, msg, md,
5200 (ndr_push_flags_fn_t)ndr_push_replPropertyMetaDataBlob);
5201 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
5202 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
5203 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
5205 ret = ldb_msg_add_value(msg, "replPropertyMetaData", &md_value, NULL);
5206 if (ret != LDB_SUCCESS) {
5207 return replmd_replicated_request_error(ar, ret);
5210 replmd_ldb_message_sort(msg, ar->schema);
5212 if (!remote_isDeleted) {
5213 ret = dsdb_module_schedule_sd_propagation(ar->module,
5214 ar->objs->partition_dn,
5216 if (ret != LDB_SUCCESS) {
5217 return replmd_replicated_request_error(ar, ret);
5221 ar->isDeleted = remote_isDeleted;
5223 ret = ldb_build_add_req(&change_req,
5229 replmd_op_add_callback,
5231 LDB_REQ_SET_LOCATION(change_req);
5232 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
5234 /* current partition control needed by "repmd_op_callback" */
5235 ret = ldb_request_add_control(change_req,
5236 DSDB_CONTROL_CURRENT_PARTITION_OID,
5238 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
5240 if (ar->objs->dsdb_repl_flags & DSDB_REPL_FLAG_PARTIAL_REPLICA) {
5241 /* this tells the partition module to make it a
5242 partial replica if creating an NC */
5243 ret = ldb_request_add_control(change_req,
5244 DSDB_CONTROL_PARTIAL_REPLICA,
5246 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
5249 return ldb_next_request(ar->module, change_req);
5252 static int replmd_replicated_apply_search_for_parent_callback(struct ldb_request *req,
5253 struct ldb_reply *ares)
5255 struct replmd_replicated_request *ar = talloc_get_type(req->context,
5256 struct replmd_replicated_request);
5260 return ldb_module_done(ar->req, NULL, NULL,
5261 LDB_ERR_OPERATIONS_ERROR);
5265 * The error NO_SUCH_OBJECT is not expected, unless the search
5266 * base is the partition DN, and that case doesn't happen here
5267 * because then we wouldn't get a parent_guid_value in any
5270 if (ares->error != LDB_SUCCESS) {
5271 return ldb_module_done(ar->req, ares->controls,
5272 ares->response, ares->error);
5275 switch (ares->type) {
5276 case LDB_REPLY_ENTRY:
5278 struct ldb_message *parent_msg = ares->message;
5279 struct ldb_message *msg = ar->objs->objects[ar->index_current].msg;
5280 struct ldb_dn *parent_dn;
5283 if (!ldb_msg_check_string_attribute(msg, "isDeleted", "TRUE")
5284 && ldb_msg_check_string_attribute(parent_msg, "isDeleted", "TRUE")) {
5285 /* Per MS-DRSR 4.1.10.6.10
5286 * FindBestParentObject we need to move this
5287 * new object under a deleted object to
5289 struct ldb_dn *nc_root;
5291 ret = dsdb_find_nc_root(ldb_module_get_ctx(ar->module), msg, msg->dn, &nc_root);
5292 if (ret == LDB_ERR_NO_SUCH_OBJECT) {
5293 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
5294 "No suitable NC root found for %s. "
5295 "We need to move this object because parent object %s "
5296 "is deleted, but this object is not.",
5297 ldb_dn_get_linearized(msg->dn),
5298 ldb_dn_get_linearized(parent_msg->dn));
5299 return ldb_module_done(ar->req, NULL, NULL, LDB_ERR_OPERATIONS_ERROR);
5300 } else if (ret != LDB_SUCCESS) {
5301 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
5302 "Unable to find NC root for %s: %s. "
5303 "We need to move this object because parent object %s "
5304 "is deleted, but this object is not.",
5305 ldb_dn_get_linearized(msg->dn),
5306 ldb_errstring(ldb_module_get_ctx(ar->module)),
5307 ldb_dn_get_linearized(parent_msg->dn));
5308 return ldb_module_done(ar->req, NULL, NULL, LDB_ERR_OPERATIONS_ERROR);
5311 ret = dsdb_wellknown_dn(ldb_module_get_ctx(ar->module), msg,
5313 DS_GUID_LOSTANDFOUND_CONTAINER,
5315 if (ret != LDB_SUCCESS) {
5316 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
5317 "Unable to find LostAndFound Container for %s "
5318 "in partition %s: %s. "
5319 "We need to move this object because parent object %s "
5320 "is deleted, but this object is not.",
5321 ldb_dn_get_linearized(msg->dn), ldb_dn_get_linearized(nc_root),
5322 ldb_errstring(ldb_module_get_ctx(ar->module)),
5323 ldb_dn_get_linearized(parent_msg->dn));
5324 return ldb_module_done(ar->req, NULL, NULL, LDB_ERR_OPERATIONS_ERROR);
5326 ar->objs->objects[ar->index_current].last_known_parent
5327 = talloc_steal(ar->objs->objects[ar->index_current].msg, parent_msg->dn);
5331 = talloc_steal(ar->objs->objects[ar->index_current].msg, parent_msg->dn);
5334 ar->objs->objects[ar->index_current].local_parent_dn = parent_dn;
5336 comp_num = ldb_dn_get_comp_num(msg->dn);
5338 if (!ldb_dn_remove_base_components(msg->dn, comp_num - 1)) {
5340 return ldb_module_done(ar->req, NULL, NULL, ldb_module_operr(ar->module));
5343 if (!ldb_dn_add_base(msg->dn, parent_dn)) {
5345 return ldb_module_done(ar->req, NULL, NULL, ldb_module_operr(ar->module));
5349 case LDB_REPLY_REFERRAL:
5350 /* we ignore referrals */
5353 case LDB_REPLY_DONE:
5355 if (ar->objs->objects[ar->index_current].local_parent_dn == NULL) {
5356 struct GUID_txt_buf str_buf;
5357 if (ar->search_msg != NULL) {
5358 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
5359 "No parent with GUID %s found for object locally known as %s",
5360 GUID_buf_string(ar->objs->objects[ar->index_current].parent_guid, &str_buf),
5361 ldb_dn_get_linearized(ar->search_msg->dn));
5363 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
5364 "No parent with GUID %s found for object remotely known as %s",
5365 GUID_buf_string(ar->objs->objects[ar->index_current].parent_guid, &str_buf),
5366 ldb_dn_get_linearized(ar->objs->objects[ar->index_current].msg->dn));
5370 * This error code is really important, as it
5371 * is the flag back to the callers to retry
5372 * this with DRSUAPI_DRS_GET_ANC, and so get
5373 * the parent objects before the child
5376 return ldb_module_done(ar->req, NULL, NULL,
5377 replmd_replicated_request_werror(ar, WERR_DS_DRA_MISSING_PARENT));
5380 if (ar->search_msg != NULL) {
5381 ret = replmd_replicated_apply_merge(ar);
5383 ret = replmd_replicated_apply_add(ar);
5385 if (ret != LDB_SUCCESS) {
5386 return ldb_module_done(ar->req, NULL, NULL, ret);
5395 * Look for the parent object, so we put the new object in the right
5396 * place This is akin to NameObject in MS-DRSR - this routine and the
5397 * callbacks find the right parent name, and correct name for this
5401 static int replmd_replicated_apply_search_for_parent(struct replmd_replicated_request *ar)
5403 struct ldb_context *ldb;
5407 struct ldb_request *search_req;
5408 static const char *attrs[] = {"isDeleted", NULL};
5409 struct GUID_txt_buf guid_str_buf;
5411 ldb = ldb_module_get_ctx(ar->module);
5413 if (ar->objs->objects[ar->index_current].parent_guid == NULL) {
5414 if (ar->search_msg != NULL) {
5415 return replmd_replicated_apply_merge(ar);
5417 return replmd_replicated_apply_add(ar);
5421 tmp_str = GUID_buf_string(ar->objs->objects[ar->index_current].parent_guid,
5424 filter = talloc_asprintf(ar, "(objectGUID=%s)", tmp_str);
5425 if (!filter) return replmd_replicated_request_werror(ar, WERR_NOT_ENOUGH_MEMORY);
5427 ret = ldb_build_search_req(&search_req,
5430 ar->objs->partition_dn,
5436 replmd_replicated_apply_search_for_parent_callback,
5438 LDB_REQ_SET_LOCATION(search_req);
5440 ret = dsdb_request_add_controls(search_req,
5441 DSDB_SEARCH_SHOW_RECYCLED|
5442 DSDB_SEARCH_SHOW_DELETED|
5443 DSDB_SEARCH_SHOW_EXTENDED_DN);
5444 if (ret != LDB_SUCCESS) {
5448 return ldb_next_request(ar->module, search_req);
5452 handle renames that come in over DRS replication
5454 static int replmd_replicated_handle_rename(struct replmd_replicated_request *ar,
5455 struct ldb_message *msg,
5456 struct ldb_request *parent,
5460 TALLOC_CTX *tmp_ctx = talloc_new(msg);
5461 struct ldb_result *res;
5462 struct ldb_dn *conflict_dn;
5463 const char *attrs[] = { "replPropertyMetaData", "objectGUID", NULL };
5464 const struct ldb_val *omd_value;
5465 struct replPropertyMetaDataBlob omd, *rmd;
5466 enum ndr_err_code ndr_err;
5467 bool rename_incoming_record, rodc;
5468 struct replPropertyMetaData1 *rmd_name, *omd_name;
5469 struct ldb_dn *new_dn;
5472 DEBUG(4,("replmd_replicated_request rename %s => %s\n",
5473 ldb_dn_get_linearized(ar->search_msg->dn),
5474 ldb_dn_get_linearized(msg->dn)));
5477 ret = dsdb_module_rename(ar->module, ar->search_msg->dn, msg->dn,
5478 DSDB_FLAG_NEXT_MODULE, ar->req);
5479 if (ret == LDB_SUCCESS) {
5480 talloc_free(tmp_ctx);
5485 if (ret != LDB_ERR_ENTRY_ALREADY_EXISTS) {
5486 talloc_free(tmp_ctx);
5487 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module), "Failed to locally apply remote rename from %s to %s: %s",
5488 ldb_dn_get_linearized(ar->search_msg->dn),
5489 ldb_dn_get_linearized(msg->dn),
5490 ldb_errstring(ldb_module_get_ctx(ar->module)));
5494 ret = samdb_rodc(ldb_module_get_ctx(ar->module), &rodc);
5495 if (ret != LDB_SUCCESS) {
5496 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
5497 "Failed to determine if we are an RODC when attempting to form conflict DN: %s",
5498 ldb_errstring(ldb_module_get_ctx(ar->module)));
5499 return LDB_ERR_OPERATIONS_ERROR;
5502 * we have a conflict, and need to decide if we will keep the
5503 * new record or the old record
5506 conflict_dn = msg->dn;
5510 * We are on an RODC, or were a GC for this
5511 * partition, so we have to fail this until
5512 * someone who owns the partition sorts it
5515 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
5516 "Conflict adding object '%s' from incoming replication but we are read only for the partition. \n"
5517 " - We must fail the operation until a master for this partition resolves the conflict",
5518 ldb_dn_get_linearized(conflict_dn));
5523 * first we need the replPropertyMetaData attribute from the
5526 ret = dsdb_module_search_dn(ar->module, tmp_ctx, &res, conflict_dn,
5528 DSDB_FLAG_NEXT_MODULE |
5529 DSDB_SEARCH_SHOW_DELETED |
5530 DSDB_SEARCH_SHOW_RECYCLED, ar->req);
5531 if (ret != LDB_SUCCESS) {
5532 DEBUG(0,(__location__ ": Unable to find object for conflicting record '%s'\n",
5533 ldb_dn_get_linearized(conflict_dn)));
5537 omd_value = ldb_msg_find_ldb_val(res->msgs[0], "replPropertyMetaData");
5538 if (omd_value == NULL) {
5539 DEBUG(0,(__location__ ": Unable to find replPropertyMetaData for conflicting record '%s'\n",
5540 ldb_dn_get_linearized(conflict_dn)));
5544 ndr_err = ndr_pull_struct_blob(omd_value, res->msgs[0], &omd,
5545 (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
5546 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
5547 DEBUG(0,(__location__ ": Failed to parse old replPropertyMetaData for %s\n",
5548 ldb_dn_get_linearized(conflict_dn)));
5552 rmd = ar->objs->objects[ar->index_current].meta_data;
5555 * we decide which is newer based on the RPMD on the name
5556 * attribute. See [MS-DRSR] ResolveNameConflict.
5558 * We expect omd_name to be present, as this is from a local
5559 * search, but while rmd_name should have been given to us by
5560 * the remote server, if it is missing we just prefer the
5562 * replmd_replPropertyMetaData1_new_should_be_taken()
5564 rmd_name = replmd_replPropertyMetaData1_find_attid(rmd, DRSUAPI_ATTID_name);
5565 omd_name = replmd_replPropertyMetaData1_find_attid(&omd, DRSUAPI_ATTID_name);
5567 DEBUG(0,(__location__ ": Failed to find name attribute in local LDB replPropertyMetaData for %s\n",
5568 ldb_dn_get_linearized(conflict_dn)));
5573 * Should we preserve the current record, and so rename the
5574 * incoming record to be a conflict?
5576 rename_incoming_record =
5577 !replmd_replPropertyMetaData1_new_should_be_taken(
5578 ar->objs->dsdb_repl_flags & DSDB_REPL_FLAG_PRIORITISE_INCOMING,
5579 omd_name, rmd_name);
5581 if (rename_incoming_record) {
5583 new_dn = replmd_conflict_dn(msg, msg->dn,
5584 &ar->objs->objects[ar->index_current].object_guid);
5585 if (new_dn == NULL) {
5586 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
5587 "Failed to form conflict DN for %s\n",
5588 ldb_dn_get_linearized(msg->dn));
5590 return replmd_replicated_request_werror(ar, WERR_NOT_ENOUGH_MEMORY);
5593 ret = dsdb_module_rename(ar->module, ar->search_msg->dn, new_dn,
5594 DSDB_FLAG_NEXT_MODULE, ar->req);
5595 if (ret != LDB_SUCCESS) {
5596 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
5597 "Failed to rename incoming conflicting dn '%s' (was '%s') to '%s' - %s\n",
5598 ldb_dn_get_linearized(conflict_dn),
5599 ldb_dn_get_linearized(ar->search_msg->dn),
5600 ldb_dn_get_linearized(new_dn),
5601 ldb_errstring(ldb_module_get_ctx(ar->module)));
5602 return replmd_replicated_request_werror(ar, WERR_DS_DRA_DB_ERROR);
5610 /* we are renaming the existing record */
5612 guid = samdb_result_guid(res->msgs[0], "objectGUID");
5613 if (GUID_all_zero(&guid)) {
5614 DEBUG(0,(__location__ ": Failed to find objectGUID for existing conflict record %s\n",
5615 ldb_dn_get_linearized(conflict_dn)));
5619 new_dn = replmd_conflict_dn(tmp_ctx, conflict_dn, &guid);
5620 if (new_dn == NULL) {
5621 DEBUG(0,(__location__ ": Failed to form conflict DN for %s\n",
5622 ldb_dn_get_linearized(conflict_dn)));
5626 DEBUG(2,(__location__ ": Resolving conflict record via existing-record rename '%s' -> '%s'\n",
5627 ldb_dn_get_linearized(conflict_dn), ldb_dn_get_linearized(new_dn)));
5629 ret = dsdb_module_rename(ar->module, conflict_dn, new_dn,
5630 DSDB_FLAG_OWN_MODULE, ar->req);
5631 if (ret != LDB_SUCCESS) {
5632 DEBUG(0,(__location__ ": Failed to rename conflict dn '%s' to '%s' - %s\n",
5633 ldb_dn_get_linearized(conflict_dn),
5634 ldb_dn_get_linearized(new_dn),
5635 ldb_errstring(ldb_module_get_ctx(ar->module))));
5640 * now we need to ensure that the rename is seen as an
5641 * originating update. We do that with a modify.
5643 ret = replmd_name_modify(ar, ar->req, new_dn);
5644 if (ret != LDB_SUCCESS) {
5648 DEBUG(2,(__location__ ": With conflicting record renamed, re-apply replicated rename '%s' -> '%s'\n",
5649 ldb_dn_get_linearized(ar->search_msg->dn),
5650 ldb_dn_get_linearized(msg->dn)));
5653 ret = dsdb_module_rename(ar->module, ar->search_msg->dn, msg->dn,
5654 DSDB_FLAG_NEXT_MODULE, ar->req);
5655 if (ret != LDB_SUCCESS) {
5656 DEBUG(0,(__location__ ": After conflict resolution, failed to rename dn '%s' to '%s' - %s\n",
5657 ldb_dn_get_linearized(ar->search_msg->dn),
5658 ldb_dn_get_linearized(msg->dn),
5659 ldb_errstring(ldb_module_get_ctx(ar->module))));
5665 * On failure make the caller get the error
5666 * This means replication will stop with an error,
5667 * but there is not much else we can do. In the
5668 * LDB_ERR_ENTRY_ALREADY_EXISTS case this is exactly what is
5672 talloc_free(tmp_ctx);
5677 static int replmd_replicated_apply_merge(struct replmd_replicated_request *ar)
5679 struct ldb_context *ldb;
5680 struct ldb_request *change_req;
5681 enum ndr_err_code ndr_err;
5682 struct ldb_message *msg;
5683 struct replPropertyMetaDataBlob *rmd;
5684 struct replPropertyMetaDataBlob omd;
5685 const struct ldb_val *omd_value;
5686 struct replPropertyMetaDataBlob nmd;
5687 struct ldb_val nmd_value;
5688 struct GUID remote_parent_guid;
5691 unsigned int removed_attrs = 0;
5693 int (*callback)(struct ldb_request *req, struct ldb_reply *ares) = replmd_op_callback;
5694 bool isDeleted = false;
5695 bool local_isDeleted = false;
5696 bool remote_isDeleted = false;
5697 bool take_remote_isDeleted = false;
5698 bool sd_updated = false;
5699 bool renamed = false;
5700 bool is_schema_nc = false;
5702 const struct ldb_val *old_rdn, *new_rdn;
5703 struct replmd_private *replmd_private =
5704 talloc_get_type(ldb_module_get_private(ar->module),
5705 struct replmd_private);
5707 time_t t = time(NULL);
5708 unix_to_nt_time(&now, t);
5710 ldb = ldb_module_get_ctx(ar->module);
5711 msg = ar->objs->objects[ar->index_current].msg;
5713 is_schema_nc = ldb_dn_compare_base(replmd_private->schema_dn, msg->dn) == 0;
5715 rmd = ar->objs->objects[ar->index_current].meta_data;
5719 /* find existing meta data */
5720 omd_value = ldb_msg_find_ldb_val(ar->search_msg, "replPropertyMetaData");
5722 ndr_err = ndr_pull_struct_blob(omd_value, ar, &omd,
5723 (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
5724 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
5725 nt_status = ndr_map_error2ntstatus(ndr_err);
5726 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
5729 if (omd.version != 1) {
5730 return replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
5735 struct GUID_txt_buf guid_txt;
5737 char *s = ldb_ldif_message_redacted_string(ldb, ar,
5738 LDB_CHANGETYPE_MODIFY, msg);
5739 DEBUG(8, ("Initial DRS replication modify message of %s is:\n%s\n"
5742 GUID_buf_string(&ar->objs->objects[ar->index_current].object_guid, &guid_txt),
5744 ndr_print_struct_string(s,
5745 (ndr_print_fn_t)ndr_print_replPropertyMetaDataBlob,
5746 "existing replPropertyMetaData",
5748 ndr_print_struct_string(s,
5749 (ndr_print_fn_t)ndr_print_replPropertyMetaDataBlob,
5750 "incoming replPropertyMetaData",
5753 } else if (DEBUGLVL(4)) {
5754 struct GUID_txt_buf guid_txt;
5756 DEBUG(4, ("Initial DRS replication modify DN of %s is: %s\n",
5757 GUID_buf_string(&ar->objs->objects[ar->index_current].object_guid,
5759 ldb_dn_get_linearized(msg->dn)));
5762 local_isDeleted = ldb_msg_find_attr_as_bool(ar->search_msg,
5763 "isDeleted", false);
5764 remote_isDeleted = ldb_msg_find_attr_as_bool(msg,
5765 "isDeleted", false);
5768 * Fill in the remote_parent_guid with the GUID or an all-zero
5771 if (ar->objs->objects[ar->index_current].parent_guid != NULL) {
5772 remote_parent_guid = *ar->objs->objects[ar->index_current].parent_guid;
5774 remote_parent_guid = GUID_zero();
5778 * To ensure we follow a complex rename chain around, we have
5779 * to confirm that the DN is the same (mostly to confirm the
5780 * RDN) and the parentGUID is the same.
5782 * This ensures we keep things under the correct parent, which
5783 * replmd_replicated_handle_rename() will do.
5786 if (strcmp(ldb_dn_get_linearized(msg->dn), ldb_dn_get_linearized(ar->search_msg->dn)) == 0
5787 && GUID_equal(&remote_parent_guid, &ar->local_parent_guid)) {
5791 * handle renames, even just by case that come in over
5792 * DRS. Changes in the parent DN don't hit us here,
5793 * because the search for a parent will clean up those
5796 * We also have already filtered out the case where
5797 * the peer has an older name to what we have (see
5798 * replmd_replicated_apply_search_callback())
5800 ret = replmd_replicated_handle_rename(ar, msg, ar->req, &renamed);
5803 if (ret != LDB_SUCCESS) {
5804 ldb_debug(ldb, LDB_DEBUG_FATAL,
5805 "replmd_replicated_request rename %s => %s failed - %s\n",
5806 ldb_dn_get_linearized(ar->search_msg->dn),
5807 ldb_dn_get_linearized(msg->dn),
5808 ldb_errstring(ldb));
5809 return replmd_replicated_request_werror(ar, WERR_DS_DRA_DB_ERROR);
5812 if (renamed == true) {
5814 * Set the callback to one that will fix up the name
5815 * metadata on the new conflict DN
5817 callback = replmd_op_name_modify_callback;
5822 nmd.ctr.ctr1.count = omd.ctr.ctr1.count + rmd->ctr.ctr1.count;
5823 nmd.ctr.ctr1.array = talloc_array(ar,
5824 struct replPropertyMetaData1,
5825 nmd.ctr.ctr1.count);
5826 if (!nmd.ctr.ctr1.array) return replmd_replicated_request_werror(ar, WERR_NOT_ENOUGH_MEMORY);
5828 /* first copy the old meta data */
5829 for (i=0; i < omd.ctr.ctr1.count; i++) {
5830 nmd.ctr.ctr1.array[ni] = omd.ctr.ctr1.array[i];
5835 /* now merge in the new meta data */
5836 for (i=0; i < rmd->ctr.ctr1.count; i++) {
5839 for (j=0; j < ni; j++) {
5842 if (rmd->ctr.ctr1.array[i].attid != nmd.ctr.ctr1.array[j].attid) {
5846 cmp = replmd_replPropertyMetaData1_new_should_be_taken(
5847 ar->objs->dsdb_repl_flags,
5848 &nmd.ctr.ctr1.array[j],
5849 &rmd->ctr.ctr1.array[i]);
5851 /* replace the entry */
5852 nmd.ctr.ctr1.array[j] = rmd->ctr.ctr1.array[i];
5853 if (ar->seq_num == 0) {
5854 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &ar->seq_num);
5855 if (ret != LDB_SUCCESS) {
5856 return replmd_replicated_request_error(ar, ret);
5859 nmd.ctr.ctr1.array[j].local_usn = ar->seq_num;
5860 switch (nmd.ctr.ctr1.array[j].attid) {
5861 case DRSUAPI_ATTID_ntSecurityDescriptor:
5864 case DRSUAPI_ATTID_isDeleted:
5865 take_remote_isDeleted = true;
5874 if (rmd->ctr.ctr1.array[i].attid != DRSUAPI_ATTID_instanceType) {
5875 DEBUG(3,("Discarding older DRS attribute update to %s on %s from %s\n",
5876 msg->elements[i-removed_attrs].name,
5877 ldb_dn_get_linearized(msg->dn),
5878 GUID_string(ar, &rmd->ctr.ctr1.array[i].originating_invocation_id)));
5881 /* we don't want to apply this change so remove the attribute */
5882 ldb_msg_remove_element(msg, &msg->elements[i-removed_attrs]);
5889 if (found) continue;
5891 nmd.ctr.ctr1.array[ni] = rmd->ctr.ctr1.array[i];
5892 if (ar->seq_num == 0) {
5893 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &ar->seq_num);
5894 if (ret != LDB_SUCCESS) {
5895 return replmd_replicated_request_error(ar, ret);
5898 nmd.ctr.ctr1.array[ni].local_usn = ar->seq_num;
5899 switch (nmd.ctr.ctr1.array[ni].attid) {
5900 case DRSUAPI_ATTID_ntSecurityDescriptor:
5903 case DRSUAPI_ATTID_isDeleted:
5904 take_remote_isDeleted = true;
5913 * finally correct the size of the meta_data array
5915 nmd.ctr.ctr1.count = ni;
5917 new_rdn = ldb_dn_get_rdn_val(msg->dn);
5918 old_rdn = ldb_dn_get_rdn_val(ar->search_msg->dn);
5921 ret = replmd_update_rpmd_rdn_attr(ldb, msg, new_rdn, old_rdn,
5922 &nmd, ar, now, is_schema_nc,
5924 if (ret != LDB_SUCCESS) {
5925 ldb_asprintf_errstring(ldb, "%s: error during DRS repl merge: %s", __func__, ldb_errstring(ldb));
5926 return replmd_replicated_request_error(ar, ret);
5930 * sort the new meta data array
5932 ret = replmd_replPropertyMetaDataCtr1_sort_and_verify(ldb, &nmd.ctr.ctr1, msg->dn);
5933 if (ret != LDB_SUCCESS) {
5934 ldb_asprintf_errstring(ldb, "%s: error during DRS repl merge: %s", __func__, ldb_errstring(ldb));
5939 * Work out if this object is deleted, so we can prune any extra attributes. See MS-DRSR 4.1.10.6.9
5942 * This also controls SD propagation below
5944 if (take_remote_isDeleted) {
5945 isDeleted = remote_isDeleted;
5947 isDeleted = local_isDeleted;
5950 ar->isDeleted = isDeleted;
5953 * check if some replicated attributes left, otherwise skip the ldb_modify() call
5955 if (msg->num_elements == 0) {
5956 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_replicated_apply_merge[%u]: skip replace\n",
5959 return replmd_replicated_apply_isDeleted(ar);
5962 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_replicated_apply_merge[%u]: replace %u attributes\n",
5963 ar->index_current, msg->num_elements);
5969 if (sd_updated && !isDeleted) {
5970 ret = dsdb_module_schedule_sd_propagation(ar->module,
5971 ar->objs->partition_dn,
5973 if (ret != LDB_SUCCESS) {
5974 return ldb_operr(ldb);
5978 /* create the meta data value */
5979 ndr_err = ndr_push_struct_blob(&nmd_value, msg, &nmd,
5980 (ndr_push_flags_fn_t)ndr_push_replPropertyMetaDataBlob);
5981 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
5982 nt_status = ndr_map_error2ntstatus(ndr_err);
5983 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
5987 * when we know that we'll modify the record, add the whenChanged, uSNChanged
5988 * and replPopertyMetaData attributes
5990 ret = ldb_msg_add_string(msg, "whenChanged", ar->objs->objects[ar->index_current].when_changed);
5991 if (ret != LDB_SUCCESS) {
5992 return replmd_replicated_request_error(ar, ret);
5994 ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNChanged", ar->seq_num);
5995 if (ret != LDB_SUCCESS) {
5996 return replmd_replicated_request_error(ar, ret);
5998 ret = ldb_msg_add_value(msg, "replPropertyMetaData", &nmd_value, NULL);
5999 if (ret != LDB_SUCCESS) {
6000 return replmd_replicated_request_error(ar, ret);
6003 replmd_ldb_message_sort(msg, ar->schema);
6005 /* we want to replace the old values */
6006 for (i=0; i < msg->num_elements; i++) {
6007 msg->elements[i].flags = LDB_FLAG_MOD_REPLACE;
6008 if (ldb_attr_cmp(msg->elements[i].name, "objectClass") == 0) {
6009 if (msg->elements[i].num_values == 0) {
6010 ldb_asprintf_errstring(ldb, __location__
6011 ": objectClass removed on %s, aborting replication\n",
6012 ldb_dn_get_linearized(msg->dn));
6013 return replmd_replicated_request_error(ar, LDB_ERR_OBJECT_CLASS_VIOLATION);
6019 struct GUID_txt_buf guid_txt;
6021 char *s = ldb_ldif_message_redacted_string(ldb, ar,
6022 LDB_CHANGETYPE_MODIFY,
6024 DEBUG(8, ("Final DRS replication modify message of %s:\n%s\n",
6025 GUID_buf_string(&ar->objs->objects[ar->index_current].object_guid,
6029 } else if (DEBUGLVL(4)) {
6030 struct GUID_txt_buf guid_txt;
6032 DEBUG(4, ("Final DRS replication modify DN of %s is %s\n",
6033 GUID_buf_string(&ar->objs->objects[ar->index_current].object_guid,
6035 ldb_dn_get_linearized(msg->dn)));
6038 ret = ldb_build_mod_req(&change_req,
6046 LDB_REQ_SET_LOCATION(change_req);
6047 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
6049 /* current partition control needed by "repmd_op_callback" */
6050 ret = ldb_request_add_control(change_req,
6051 DSDB_CONTROL_CURRENT_PARTITION_OID,
6053 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
6055 return ldb_next_request(ar->module, change_req);
6058 static int replmd_replicated_apply_search_callback(struct ldb_request *req,
6059 struct ldb_reply *ares)
6061 struct replmd_replicated_request *ar = talloc_get_type(req->context,
6062 struct replmd_replicated_request);
6066 return ldb_module_done(ar->req, NULL, NULL,
6067 LDB_ERR_OPERATIONS_ERROR);
6069 if (ares->error != LDB_SUCCESS &&
6070 ares->error != LDB_ERR_NO_SUCH_OBJECT) {
6071 return ldb_module_done(ar->req, ares->controls,
6072 ares->response, ares->error);
6075 switch (ares->type) {
6076 case LDB_REPLY_ENTRY:
6077 ar->search_msg = talloc_steal(ar, ares->message);
6080 case LDB_REPLY_REFERRAL:
6081 /* we ignore referrals */
6084 case LDB_REPLY_DONE:
6086 struct replPropertyMetaData1 *md_remote;
6087 struct replPropertyMetaData1 *md_local;
6089 struct replPropertyMetaDataBlob omd;
6090 const struct ldb_val *omd_value;
6091 struct replPropertyMetaDataBlob *rmd;
6092 struct ldb_message *msg;
6094 ar->objs->objects[ar->index_current].local_parent_dn = NULL;
6095 ar->objs->objects[ar->index_current].last_known_parent = NULL;
6098 * This is the ADD case, find the appropriate parent,
6099 * as this object doesn't exist locally:
6101 if (ar->search_msg == NULL) {
6102 ret = replmd_replicated_apply_search_for_parent(ar);
6103 if (ret != LDB_SUCCESS) {
6104 return ldb_module_done(ar->req, NULL, NULL, ret);
6111 * Otherwise, in the MERGE case, work out if we are
6112 * attempting a rename, and if so find the parent the
6113 * newly renamed object wants to belong under (which
6114 * may not be the parent in it's attached string DN
6116 rmd = ar->objs->objects[ar->index_current].meta_data;
6120 /* find existing meta data */
6121 omd_value = ldb_msg_find_ldb_val(ar->search_msg, "replPropertyMetaData");
6123 enum ndr_err_code ndr_err;
6124 ndr_err = ndr_pull_struct_blob(omd_value, ar, &omd,
6125 (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
6126 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
6127 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
6128 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
6131 if (omd.version != 1) {
6132 return replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
6136 ar->local_parent_guid = samdb_result_guid(ar->search_msg, "parentGUID");
6138 instanceType = ldb_msg_find_attr_as_int(ar->search_msg, "instanceType", 0);
6139 if (((instanceType & INSTANCE_TYPE_IS_NC_HEAD) == 0)
6140 && GUID_all_zero(&ar->local_parent_guid)) {
6141 DEBUG(0, ("Refusing to replicate new version of %s "
6142 "as local object has an all-zero parentGUID attribute, "
6143 "despite not being an NC root\n",
6144 ldb_dn_get_linearized(ar->search_msg->dn)));
6145 return replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
6149 * now we need to check for double renames. We could have a
6150 * local rename pending which our replication partner hasn't
6151 * received yet. We choose which one wins by looking at the
6152 * attribute stamps on the two objects, the newer one wins.
6154 * This also simply applies the correct algorithms for
6155 * determining if a change was made to name at all, or
6156 * if the object has just been renamed under the same
6159 md_remote = replmd_replPropertyMetaData1_find_attid(rmd, DRSUAPI_ATTID_name);
6160 md_local = replmd_replPropertyMetaData1_find_attid(&omd, DRSUAPI_ATTID_name);
6162 DEBUG(0,(__location__ ": Failed to find name attribute in local LDB replPropertyMetaData for %s\n",
6163 ldb_dn_get_linearized(ar->search_msg->dn)));
6164 return replmd_replicated_request_werror(ar, WERR_DS_DRA_DB_ERROR);
6168 * if there is no name attribute given then we have to assume the
6169 * object we've received has the older name
6171 if (replmd_replPropertyMetaData1_new_should_be_taken(
6172 ar->objs->dsdb_repl_flags & DSDB_REPL_FLAG_PRIORITISE_INCOMING,
6173 md_local, md_remote)) {
6174 struct GUID_txt_buf p_guid_local;
6175 struct GUID_txt_buf p_guid_remote;
6176 msg = ar->objs->objects[ar->index_current].msg;
6178 /* Merge on the existing object, with rename */
6180 DEBUG(4,(__location__ ": Looking for new parent for object %s currently under %s "
6181 "as incoming object changing to %s under %s\n",
6182 ldb_dn_get_linearized(ar->search_msg->dn),
6183 GUID_buf_string(&ar->local_parent_guid, &p_guid_local),
6184 ldb_dn_get_linearized(msg->dn),
6185 GUID_buf_string(ar->objs->objects[ar->index_current].parent_guid,
6187 ret = replmd_replicated_apply_search_for_parent(ar);
6189 struct GUID_txt_buf p_guid_local;
6190 struct GUID_txt_buf p_guid_remote;
6191 msg = ar->objs->objects[ar->index_current].msg;
6194 * Merge on the existing object, force no
6195 * rename (code below just to explain why in
6199 if (strcmp(ldb_dn_get_linearized(ar->search_msg->dn),
6200 ldb_dn_get_linearized(msg->dn)) == 0) {
6201 if (ar->objs->objects[ar->index_current].parent_guid != NULL &&
6202 GUID_equal(&ar->local_parent_guid,
6203 ar->objs->objects[ar->index_current].parent_guid)
6205 DEBUG(4,(__location__ ": Keeping object %s at under %s "
6206 "despite incoming object changing parent to %s\n",
6207 ldb_dn_get_linearized(ar->search_msg->dn),
6208 GUID_buf_string(&ar->local_parent_guid, &p_guid_local),
6209 GUID_buf_string(ar->objs->objects[ar->index_current].parent_guid,
6213 DEBUG(4,(__location__ ": Keeping object %s at under %s "
6214 " and rejecting older rename to %s under %s\n",
6215 ldb_dn_get_linearized(ar->search_msg->dn),
6216 GUID_buf_string(&ar->local_parent_guid, &p_guid_local),
6217 ldb_dn_get_linearized(msg->dn),
6218 GUID_buf_string(ar->objs->objects[ar->index_current].parent_guid,
6222 * This assignment ensures that the strcmp()
6223 * and GUID_equal() calls in
6224 * replmd_replicated_apply_merge() avoids the
6227 ar->objs->objects[ar->index_current].parent_guid =
6228 &ar->local_parent_guid;
6230 msg->dn = ar->search_msg->dn;
6231 ret = replmd_replicated_apply_merge(ar);
6233 if (ret != LDB_SUCCESS) {
6234 return ldb_module_done(ar->req, NULL, NULL, ret);
6244 * Stores the linked attributes received in the replication chunk - these get
6245 * applied at the end of the transaction. We also check that each linked
6246 * attribute is valid, i.e. source and target objects are known.
6248 static int replmd_store_linked_attributes(struct replmd_replicated_request *ar)
6250 int ret = LDB_SUCCESS;
6252 struct ldb_module *module = ar->module;
6253 struct replmd_private *replmd_private =
6254 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
6255 struct ldb_context *ldb;
6257 ldb = ldb_module_get_ctx(module);
6259 DEBUG(4,("linked_attributes_count=%u\n", ar->objs->linked_attributes_count));
6261 /* save away the linked attributes for the end of the transaction */
6262 for (i = 0; i < ar->objs->linked_attributes_count; i++) {
6263 struct la_entry *la_entry;
6265 if (replmd_private->la_ctx == NULL) {
6266 replmd_private->la_ctx = talloc_new(replmd_private);
6268 la_entry = talloc(replmd_private->la_ctx, struct la_entry);
6269 if (la_entry == NULL) {
6271 return LDB_ERR_OPERATIONS_ERROR;
6273 la_entry->la = talloc(la_entry, struct drsuapi_DsReplicaLinkedAttribute);
6274 if (la_entry->la == NULL) {
6275 talloc_free(la_entry);
6277 return LDB_ERR_OPERATIONS_ERROR;
6279 *la_entry->la = ar->objs->linked_attributes[i];
6280 la_entry->dsdb_repl_flags = ar->objs->dsdb_repl_flags;
6282 /* we need to steal the non-scalars so they stay
6283 around until the end of the transaction */
6284 talloc_steal(la_entry->la, la_entry->la->identifier);
6285 talloc_steal(la_entry->la, la_entry->la->value.blob);
6287 ret = replmd_verify_linked_attribute(ar, la_entry);
6289 if (ret != LDB_SUCCESS) {
6293 DLIST_ADD(replmd_private->la_list, la_entry);
6299 static int replmd_replicated_uptodate_vector(struct replmd_replicated_request *ar);
6301 static int replmd_replicated_apply_next(struct replmd_replicated_request *ar)
6303 struct ldb_context *ldb;
6307 struct ldb_request *search_req;
6308 static const char *attrs[] = { "repsFrom", "replUpToDateVector",
6309 "parentGUID", "instanceType",
6310 "replPropertyMetaData", "nTSecurityDescriptor",
6311 "isDeleted", NULL };
6312 struct GUID_txt_buf guid_str_buf;
6314 if (ar->index_current >= ar->objs->num_objects) {
6317 * Now that we've applied all the objects, check the new linked
6318 * attributes and store them (we apply them in .prepare_commit)
6320 ret = replmd_store_linked_attributes(ar);
6322 if (ret != LDB_SUCCESS) {
6326 /* done applying objects, move on to the next stage */
6327 return replmd_replicated_uptodate_vector(ar);
6330 ldb = ldb_module_get_ctx(ar->module);
6331 ar->search_msg = NULL;
6332 ar->isDeleted = false;
6334 tmp_str = GUID_buf_string(&ar->objs->objects[ar->index_current].object_guid,
6337 filter = talloc_asprintf(ar, "(objectGUID=%s)", tmp_str);
6338 if (!filter) return replmd_replicated_request_werror(ar, WERR_NOT_ENOUGH_MEMORY);
6340 ret = ldb_build_search_req(&search_req,
6343 ar->objs->partition_dn,
6349 replmd_replicated_apply_search_callback,
6351 LDB_REQ_SET_LOCATION(search_req);
6353 ret = dsdb_request_add_controls(search_req, DSDB_SEARCH_SHOW_RECYCLED);
6355 if (ret != LDB_SUCCESS) {
6359 return ldb_next_request(ar->module, search_req);
6363 * This is essentially a wrapper for replmd_replicated_apply_next()
6365 * This is needed to ensure that both codepaths call this handler.
6367 static int replmd_replicated_apply_isDeleted(struct replmd_replicated_request *ar)
6369 struct ldb_dn *deleted_objects_dn;
6370 struct ldb_message *msg = ar->objs->objects[ar->index_current].msg;
6371 int ret = dsdb_get_deleted_objects_dn(ldb_module_get_ctx(ar->module), msg, msg->dn,
6372 &deleted_objects_dn);
6373 if (ar->isDeleted && (ret != LDB_SUCCESS || ldb_dn_compare(msg->dn, deleted_objects_dn) != 0)) {
6375 * Do a delete here again, so that if there is
6376 * anything local that conflicts with this
6377 * object being deleted, it is removed. This
6378 * includes links. See MS-DRSR 4.1.10.6.9
6381 * If the object is already deleted, and there
6382 * is no more work required, it doesn't do
6386 /* This has been updated to point to the DN we eventually did the modify on */
6388 struct ldb_request *del_req;
6389 struct ldb_result *res;
6391 TALLOC_CTX *tmp_ctx = talloc_new(ar);
6393 ret = ldb_oom(ldb_module_get_ctx(ar->module));
6397 res = talloc_zero(tmp_ctx, struct ldb_result);
6399 ret = ldb_oom(ldb_module_get_ctx(ar->module));
6400 talloc_free(tmp_ctx);
6404 /* Build a delete request, which hopefully will artually turn into nothing */
6405 ret = ldb_build_del_req(&del_req, ldb_module_get_ctx(ar->module), tmp_ctx,
6409 ldb_modify_default_callback,
6411 LDB_REQ_SET_LOCATION(del_req);
6412 if (ret != LDB_SUCCESS) {
6413 talloc_free(tmp_ctx);
6418 * This is the guts of the call, call back
6419 * into our delete code, but setting the
6420 * re_delete flag so we delete anything that
6421 * shouldn't be there on a deleted or recycled
6424 ret = replmd_delete_internals(ar->module, del_req, true);
6425 if (ret == LDB_SUCCESS) {
6426 ret = ldb_wait(del_req->handle, LDB_WAIT_ALL);
6429 talloc_free(tmp_ctx);
6430 if (ret != LDB_SUCCESS) {
6435 ar->index_current++;
6436 return replmd_replicated_apply_next(ar);
6439 static int replmd_replicated_uptodate_modify_callback(struct ldb_request *req,
6440 struct ldb_reply *ares)
6442 struct ldb_context *ldb;
6443 struct replmd_replicated_request *ar = talloc_get_type(req->context,
6444 struct replmd_replicated_request);
6445 ldb = ldb_module_get_ctx(ar->module);
6448 return ldb_module_done(ar->req, NULL, NULL,
6449 LDB_ERR_OPERATIONS_ERROR);
6451 if (ares->error != LDB_SUCCESS) {
6452 return ldb_module_done(ar->req, ares->controls,
6453 ares->response, ares->error);
6456 if (ares->type != LDB_REPLY_DONE) {
6457 ldb_asprintf_errstring(ldb, "Invalid LDB reply type %d", ares->type);
6458 return ldb_module_done(ar->req, NULL, NULL,
6459 LDB_ERR_OPERATIONS_ERROR);
6464 return ldb_module_done(ar->req, NULL, NULL, LDB_SUCCESS);
6467 static int replmd_replicated_uptodate_modify(struct replmd_replicated_request *ar)
6469 struct ldb_context *ldb;
6470 struct ldb_request *change_req;
6471 enum ndr_err_code ndr_err;
6472 struct ldb_message *msg;
6473 struct replUpToDateVectorBlob ouv;
6474 const struct ldb_val *ouv_value;
6475 const struct drsuapi_DsReplicaCursor2CtrEx *ruv;
6476 struct replUpToDateVectorBlob nuv;
6477 struct ldb_val nuv_value;
6478 struct ldb_message_element *nuv_el = NULL;
6479 struct ldb_message_element *orf_el = NULL;
6480 struct repsFromToBlob nrf;
6481 struct ldb_val *nrf_value = NULL;
6482 struct ldb_message_element *nrf_el = NULL;
6486 time_t t = time(NULL);
6489 uint32_t instanceType;
6491 ldb = ldb_module_get_ctx(ar->module);
6492 ruv = ar->objs->uptodateness_vector;
6498 unix_to_nt_time(&now, t);
6500 if (ar->search_msg == NULL) {
6501 /* this happens for a REPL_OBJ call where we are
6502 creating the target object by replicating it. The
6503 subdomain join code does this for the partition DN
6505 DEBUG(4,(__location__ ": Skipping UDV and repsFrom update as no target DN\n"));
6506 return ldb_module_done(ar->req, NULL, NULL, LDB_SUCCESS);
6509 instanceType = ldb_msg_find_attr_as_uint(ar->search_msg, "instanceType", 0);
6510 if (! (instanceType & INSTANCE_TYPE_IS_NC_HEAD)) {
6511 DEBUG(4,(__location__ ": Skipping UDV and repsFrom update as not NC root: %s\n",
6512 ldb_dn_get_linearized(ar->search_msg->dn)));
6513 return ldb_module_done(ar->req, NULL, NULL, LDB_SUCCESS);
6517 * first create the new replUpToDateVector
6519 ouv_value = ldb_msg_find_ldb_val(ar->search_msg, "replUpToDateVector");
6521 ndr_err = ndr_pull_struct_blob(ouv_value, ar, &ouv,
6522 (ndr_pull_flags_fn_t)ndr_pull_replUpToDateVectorBlob);
6523 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
6524 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
6525 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
6528 if (ouv.version != 2) {
6529 return replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
6534 * the new uptodateness vector will at least
6535 * contain 1 entry, one for the source_dsa
6537 * plus optional values from our old vector and the one from the source_dsa
6539 nuv.ctr.ctr2.count = ouv.ctr.ctr2.count;
6540 if (ruv) nuv.ctr.ctr2.count += ruv->count;
6541 nuv.ctr.ctr2.cursors = talloc_array(ar,
6542 struct drsuapi_DsReplicaCursor2,
6543 nuv.ctr.ctr2.count);
6544 if (!nuv.ctr.ctr2.cursors) return replmd_replicated_request_werror(ar, WERR_NOT_ENOUGH_MEMORY);
6546 /* first copy the old vector */
6547 for (i=0; i < ouv.ctr.ctr2.count; i++) {
6548 nuv.ctr.ctr2.cursors[ni] = ouv.ctr.ctr2.cursors[i];
6552 /* merge in the source_dsa vector is available */
6553 for (i=0; (ruv && i < ruv->count); i++) {
6556 if (GUID_equal(&ruv->cursors[i].source_dsa_invocation_id,
6557 &ar->our_invocation_id)) {
6561 for (j=0; j < ni; j++) {
6562 if (!GUID_equal(&ruv->cursors[i].source_dsa_invocation_id,
6563 &nuv.ctr.ctr2.cursors[j].source_dsa_invocation_id)) {
6569 if (ruv->cursors[i].highest_usn > nuv.ctr.ctr2.cursors[j].highest_usn) {
6570 nuv.ctr.ctr2.cursors[j] = ruv->cursors[i];
6575 if (found) continue;
6577 /* if it's not there yet, add it */
6578 nuv.ctr.ctr2.cursors[ni] = ruv->cursors[i];
6583 * finally correct the size of the cursors array
6585 nuv.ctr.ctr2.count = ni;
6590 TYPESAFE_QSORT(nuv.ctr.ctr2.cursors, nuv.ctr.ctr2.count, drsuapi_DsReplicaCursor2_compare);
6593 * create the change ldb_message
6595 msg = ldb_msg_new(ar);
6596 if (!msg) return replmd_replicated_request_werror(ar, WERR_NOT_ENOUGH_MEMORY);
6597 msg->dn = ar->search_msg->dn;
6599 ndr_err = ndr_push_struct_blob(&nuv_value, msg, &nuv,
6600 (ndr_push_flags_fn_t)ndr_push_replUpToDateVectorBlob);
6601 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
6602 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
6603 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
6605 ret = ldb_msg_add_value(msg, "replUpToDateVector", &nuv_value, &nuv_el);
6606 if (ret != LDB_SUCCESS) {
6607 return replmd_replicated_request_error(ar, ret);
6609 nuv_el->flags = LDB_FLAG_MOD_REPLACE;
6612 * now create the new repsFrom value from the given repsFromTo1 structure
6616 nrf.ctr.ctr1 = *ar->objs->source_dsa;
6617 nrf.ctr.ctr1.last_attempt = now;
6618 nrf.ctr.ctr1.last_success = now;
6619 nrf.ctr.ctr1.result_last_attempt = WERR_OK;
6622 * first see if we already have a repsFrom value for the current source dsa
6623 * if so we'll later replace this value
6625 orf_el = ldb_msg_find_element(ar->search_msg, "repsFrom");
6627 for (i=0; i < orf_el->num_values; i++) {
6628 struct repsFromToBlob *trf;
6630 trf = talloc(ar, struct repsFromToBlob);
6631 if (!trf) return replmd_replicated_request_werror(ar, WERR_NOT_ENOUGH_MEMORY);
6633 ndr_err = ndr_pull_struct_blob(&orf_el->values[i], trf, trf,
6634 (ndr_pull_flags_fn_t)ndr_pull_repsFromToBlob);
6635 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
6636 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
6637 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
6640 if (trf->version != 1) {
6641 return replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
6645 * we compare the source dsa objectGUID not the invocation_id
6646 * because we want only one repsFrom value per source dsa
6647 * and when the invocation_id of the source dsa has changed we don't need
6648 * the old repsFrom with the old invocation_id
6650 if (!GUID_equal(&trf->ctr.ctr1.source_dsa_obj_guid,
6651 &ar->objs->source_dsa->source_dsa_obj_guid)) {
6657 nrf_value = &orf_el->values[i];
6662 * copy over all old values to the new ldb_message
6664 ret = ldb_msg_add_empty(msg, "repsFrom", 0, &nrf_el);
6665 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
6670 * if we haven't found an old repsFrom value for the current source dsa
6671 * we'll add a new value
6674 struct ldb_val zero_value;
6675 ZERO_STRUCT(zero_value);
6676 ret = ldb_msg_add_value(msg, "repsFrom", &zero_value, &nrf_el);
6677 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
6679 nrf_value = &nrf_el->values[nrf_el->num_values - 1];
6682 /* we now fill the value which is already attached to ldb_message */
6683 ndr_err = ndr_push_struct_blob(nrf_value, msg,
6685 (ndr_push_flags_fn_t)ndr_push_repsFromToBlob);
6686 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
6687 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
6688 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
6692 * the ldb_message_element for the attribute, has all the old values and the new one
6693 * so we'll replace the whole attribute with all values
6695 nrf_el->flags = LDB_FLAG_MOD_REPLACE;
6697 if (CHECK_DEBUGLVL(4)) {
6698 char *s = ldb_ldif_message_redacted_string(ldb, ar,
6699 LDB_CHANGETYPE_MODIFY,
6701 DEBUG(4, ("DRS replication uptodate modify message:\n%s\n", s));
6705 /* prepare the ldb_modify() request */
6706 ret = ldb_build_mod_req(&change_req,
6712 replmd_replicated_uptodate_modify_callback,
6714 LDB_REQ_SET_LOCATION(change_req);
6715 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
6717 return ldb_next_request(ar->module, change_req);
6720 static int replmd_replicated_uptodate_search_callback(struct ldb_request *req,
6721 struct ldb_reply *ares)
6723 struct replmd_replicated_request *ar = talloc_get_type(req->context,
6724 struct replmd_replicated_request);
6728 return ldb_module_done(ar->req, NULL, NULL,
6729 LDB_ERR_OPERATIONS_ERROR);
6731 if (ares->error != LDB_SUCCESS &&
6732 ares->error != LDB_ERR_NO_SUCH_OBJECT) {
6733 return ldb_module_done(ar->req, ares->controls,
6734 ares->response, ares->error);
6737 switch (ares->type) {
6738 case LDB_REPLY_ENTRY:
6739 ar->search_msg = talloc_steal(ar, ares->message);
6742 case LDB_REPLY_REFERRAL:
6743 /* we ignore referrals */
6746 case LDB_REPLY_DONE:
6747 ret = replmd_replicated_uptodate_modify(ar);
6748 if (ret != LDB_SUCCESS) {
6749 return ldb_module_done(ar->req, NULL, NULL, ret);
6758 static int replmd_replicated_uptodate_vector(struct replmd_replicated_request *ar)
6760 struct ldb_context *ldb = ldb_module_get_ctx(ar->module);
6761 struct replmd_private *replmd_private =
6762 talloc_get_type_abort(ldb_module_get_private(ar->module),
6763 struct replmd_private);
6765 static const char *attrs[] = {
6766 "replUpToDateVector",
6771 struct ldb_request *search_req;
6773 ar->search_msg = NULL;
6776 * Let the caller know that we did an originating updates
6778 ar->objs->originating_updates = replmd_private->originating_updates;
6780 ret = ldb_build_search_req(&search_req,
6783 ar->objs->partition_dn,
6789 replmd_replicated_uptodate_search_callback,
6791 LDB_REQ_SET_LOCATION(search_req);
6792 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
6794 return ldb_next_request(ar->module, search_req);
6799 static int replmd_extended_replicated_objects(struct ldb_module *module, struct ldb_request *req)
6801 struct ldb_context *ldb;
6802 struct dsdb_extended_replicated_objects *objs;
6803 struct replmd_replicated_request *ar;
6804 struct ldb_control **ctrls;
6807 ldb = ldb_module_get_ctx(module);
6809 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_extended_replicated_objects\n");
6811 objs = talloc_get_type(req->op.extended.data, struct dsdb_extended_replicated_objects);
6813 ldb_debug(ldb, LDB_DEBUG_FATAL, "replmd_extended_replicated_objects: invalid extended data\n");
6814 return LDB_ERR_PROTOCOL_ERROR;
6817 if (objs->version != DSDB_EXTENDED_REPLICATED_OBJECTS_VERSION) {
6818 ldb_debug(ldb, LDB_DEBUG_FATAL, "replmd_extended_replicated_objects: extended data invalid version [%u != %u]\n",
6819 objs->version, DSDB_EXTENDED_REPLICATED_OBJECTS_VERSION);
6820 return LDB_ERR_PROTOCOL_ERROR;
6823 ar = replmd_ctx_init(module, req);
6825 return LDB_ERR_OPERATIONS_ERROR;
6827 /* Set the flags to have the replmd_op_callback run over the full set of objects */
6828 ar->apply_mode = true;
6830 ar->schema = dsdb_get_schema(ldb, ar);
6832 ldb_debug_set(ldb, LDB_DEBUG_FATAL, "replmd_ctx_init: no loaded schema found\n");
6834 DEBUG(0,(__location__ ": %s\n", ldb_errstring(ldb)));
6835 return LDB_ERR_CONSTRAINT_VIOLATION;
6838 ctrls = req->controls;
6840 if (req->controls) {
6841 req->controls = talloc_memdup(ar, req->controls,
6842 talloc_get_size(req->controls));
6843 if (!req->controls) return replmd_replicated_request_werror(ar, WERR_NOT_ENOUGH_MEMORY);
6846 ret = ldb_request_add_control(req, DSDB_CONTROL_REPLICATED_UPDATE_OID, false, NULL);
6847 if (ret != LDB_SUCCESS) {
6851 /* If this change contained linked attributes in the body
6852 * (rather than in the links section) we need to update
6853 * backlinks in linked_attributes */
6854 ret = ldb_request_add_control(req, DSDB_CONTROL_APPLY_LINKS, false, NULL);
6855 if (ret != LDB_SUCCESS) {
6859 ar->controls = req->controls;
6860 req->controls = ctrls;
6862 return replmd_replicated_apply_next(ar);
6866 * Checks how to handle an missing target - either we need to fail the
6867 * replication and retry with GET_TGT, ignore the link and continue, or try to
6868 * add a partial link to an unknown target.
6870 static int replmd_allow_missing_target(struct ldb_module *module,
6871 TALLOC_CTX *mem_ctx,
6872 struct ldb_dn *target_dn,
6873 struct ldb_dn *source_dn,
6876 uint32_t dsdb_repl_flags,
6878 const char * missing_str)
6880 struct ldb_context *ldb = ldb_module_get_ctx(module);
6884 * we may not be able to resolve link targets properly when
6885 * dealing with subsets of objects, e.g. the source is a
6886 * critical object and the target isn't
6889 * When we implement Trusted Domains we need to consider
6890 * whether they get treated as an incomplete replica here or not
6892 if (dsdb_repl_flags & DSDB_REPL_FLAG_OBJECT_SUBSET) {
6895 * Ignore the link. We don't increase the highwater-mark in
6896 * the object subset cases, so subsequent replications should
6897 * resolve any missing links
6899 DEBUG(2, ("%s target %s linked from %s\n", missing_str,
6900 ldb_dn_get_linearized(target_dn),
6901 ldb_dn_get_linearized(source_dn)));
6902 *ignore_link = true;
6906 if (dsdb_repl_flags & DSDB_REPL_FLAG_TARGETS_UPTODATE) {
6909 * target should already be up-to-date so there's no point in
6910 * retrying. This could be due to bad timing, or if a target
6911 * on a one-way link was deleted. We ignore the link rather
6912 * than failing the replication cycle completely
6914 *ignore_link = true;
6915 DBG_WARNING("%s is %s but up to date. Ignoring link from %s\n",
6916 ldb_dn_get_linearized(target_dn), missing_str,
6917 ldb_dn_get_linearized(source_dn));
6921 is_in_same_nc = dsdb_objects_have_same_nc(ldb,
6925 if (is_in_same_nc) {
6926 /* fail the replication and retry with GET_TGT */
6927 ldb_asprintf_errstring(ldb, "%s target %s GUID %s linked from %s\n",
6929 ldb_dn_get_linearized(target_dn),
6930 GUID_string(mem_ctx, guid),
6931 ldb_dn_get_linearized(source_dn));
6932 return LDB_ERR_NO_SUCH_OBJECT;
6936 * The target of the cross-partition link is missing. Continue
6937 * and try to at least add the forward-link. This isn't great,
6938 * but a partial link can be fixed by dbcheck, so it's better
6939 * than dropping the link completely.
6941 *ignore_link = false;
6943 if (is_obj_commit) {
6946 * Only log this when we're actually committing the objects.
6947 * This avoids spurious logs, i.e. if we're just verifying the
6948 * received link during a join.
6950 DBG_WARNING("%s cross-partition target %s linked from %s\n",
6951 missing_str, ldb_dn_get_linearized(target_dn),
6952 ldb_dn_get_linearized(source_dn));
6959 * Checks that the target object for a linked attribute exists.
6960 * @param guid returns the target object's GUID (is returned)if it exists)
6961 * @param ignore_link set to true if the linked attribute should be ignored
6962 * (i.e. the target doesn't exist, but that it's OK to skip the link)
6964 static int replmd_check_target_exists(struct ldb_module *module,
6965 struct dsdb_dn *dsdb_dn,
6966 struct la_entry *la_entry,
6967 struct ldb_dn *source_dn,
6972 struct drsuapi_DsReplicaLinkedAttribute *la = la_entry->la;
6973 struct ldb_context *ldb = ldb_module_get_ctx(module);
6974 struct ldb_result *target_res;
6975 TALLOC_CTX *tmp_ctx = talloc_new(la_entry);
6976 const char *attrs[] = { "isDeleted", "isRecycled", NULL };
6979 enum deletion_state target_deletion_state = OBJECT_REMOVED;
6980 bool active = (la->flags & DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE) ? true : false;
6982 *ignore_link = false;
6983 ntstatus = dsdb_get_extended_dn_guid(dsdb_dn->dn, guid, "GUID");
6985 if (!NT_STATUS_IS_OK(ntstatus) && !active) {
6988 * This strange behaviour (allowing a NULL/missing
6989 * GUID) originally comes from:
6991 * commit e3054ce0fe0f8f62d2f5b2a77893e7a1479128bd
6992 * Author: Andrew Tridgell <tridge@samba.org>
6993 * Date: Mon Dec 21 21:21:55 2009 +1100
6995 * s4-drs: cope better with NULL GUIDS from DRS
6997 * It is valid to get a NULL GUID over DRS for a deleted forward link. We
6998 * need to match by DN if possible when seeing if we should update an
7001 * Pair-Programmed-With: Andrew Bartlett <abartlet@samba.org>
7003 ret = dsdb_module_search_dn(module, tmp_ctx, &target_res,
7005 DSDB_FLAG_NEXT_MODULE |
7006 DSDB_SEARCH_SHOW_RECYCLED |
7007 DSDB_SEARCH_SEARCH_ALL_PARTITIONS |
7008 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT,
7010 } else if (!NT_STATUS_IS_OK(ntstatus)) {
7011 ldb_asprintf_errstring(ldb, "Failed to find GUID in linked attribute 0x%x blob for %s from %s",
7013 ldb_dn_get_linearized(dsdb_dn->dn),
7014 ldb_dn_get_linearized(source_dn));
7015 talloc_free(tmp_ctx);
7016 return LDB_ERR_OPERATIONS_ERROR;
7018 ret = dsdb_module_search(module, tmp_ctx, &target_res,
7019 NULL, LDB_SCOPE_SUBTREE,
7021 DSDB_FLAG_NEXT_MODULE |
7022 DSDB_SEARCH_SHOW_RECYCLED |
7023 DSDB_SEARCH_SEARCH_ALL_PARTITIONS |
7024 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT,
7027 GUID_string(tmp_ctx, guid));
7030 if (ret != LDB_SUCCESS) {
7031 ldb_asprintf_errstring(ldb, "Failed to re-resolve GUID %s: %s\n",
7032 GUID_string(tmp_ctx, guid),
7033 ldb_errstring(ldb));
7034 talloc_free(tmp_ctx);
7038 if (target_res->count == 0) {
7041 * target object is unknown. Check whether to ignore the link,
7042 * fail the replication, or add a partial link
7044 ret = replmd_allow_missing_target(module, tmp_ctx, dsdb_dn->dn,
7045 source_dn, is_obj_commit, guid,
7046 la_entry->dsdb_repl_flags,
7047 ignore_link, "Unknown");
7049 } else if (target_res->count != 1) {
7050 ldb_asprintf_errstring(ldb, "More than one object found matching objectGUID %s\n",
7051 GUID_string(tmp_ctx, guid));
7052 ret = LDB_ERR_OPERATIONS_ERROR;
7054 struct ldb_message *target_msg = target_res->msgs[0];
7056 dsdb_dn->dn = talloc_steal(dsdb_dn, target_msg->dn);
7058 /* Get the object's state (i.e. Not Deleted, Tombstone, etc) */
7059 replmd_deletion_state(module, target_msg,
7060 &target_deletion_state, NULL);
7063 * Check for deleted objects as per MS-DRSR 4.1.10.6.14
7064 * ProcessLinkValue(). Link updates should not be sent for
7065 * recycled and tombstone objects (deleting the links should
7066 * happen when we delete the object). This probably means our
7067 * copy of the target object isn't up to date.
7069 if (target_deletion_state >= OBJECT_RECYCLED) {
7072 * target object is deleted. Check whether to ignore the
7073 * link, fail the replication, or add a partial link
7075 ret = replmd_allow_missing_target(module, tmp_ctx,
7076 dsdb_dn->dn, source_dn,
7077 is_obj_commit, guid,
7078 la_entry->dsdb_repl_flags,
7079 ignore_link, "Deleted");
7083 talloc_free(tmp_ctx);
7088 * Extracts the key details about the source/target object for a
7089 * linked-attribute entry.
7090 * This returns the following details:
7091 * @param ret_attr the schema details for the linked attribute
7092 * @param source_msg the search result for the source object
7093 * @param target_dsdb_dn the unpacked DN info for the target object
7095 static int replmd_extract_la_entry_details(struct ldb_module *module,
7096 struct la_entry *la_entry,
7097 TALLOC_CTX *mem_ctx,
7098 const struct dsdb_attribute **ret_attr,
7099 struct ldb_message **source_msg,
7100 struct dsdb_dn **target_dsdb_dn)
7102 struct drsuapi_DsReplicaLinkedAttribute *la = la_entry->la;
7103 struct ldb_context *ldb = ldb_module_get_ctx(module);
7104 const struct dsdb_schema *schema = dsdb_get_schema(ldb, mem_ctx);
7106 const struct dsdb_attribute *attr;
7108 struct ldb_result *res;
7109 const char *attrs[4];
7112 linked_attributes[0]:
7113 &objs->linked_attributes[i]: struct drsuapi_DsReplicaLinkedAttribute
7115 identifier: struct drsuapi_DsReplicaObjectIdentifier
7116 __ndr_size : 0x0000003a (58)
7117 __ndr_size_sid : 0x00000000 (0)
7118 guid : 8e95b6a9-13dd-4158-89db-3220a5be5cc7
7120 __ndr_size_dn : 0x00000000 (0)
7122 attid : DRSUAPI_ATTID_member (0x1F)
7123 value: struct drsuapi_DsAttributeValue
7124 __ndr_size : 0x0000007e (126)
7126 blob : DATA_BLOB length=126
7127 flags : 0x00000001 (1)
7128 1: DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE
7129 originating_add_time : Wed Sep 2 22:20:01 2009 EST
7130 meta_data: struct drsuapi_DsReplicaMetaData
7131 version : 0x00000015 (21)
7132 originating_change_time : Wed Sep 2 23:39:07 2009 EST
7133 originating_invocation_id: 794640f3-18cf-40ee-a211-a93992b67a64
7134 originating_usn : 0x000000000001e19c (123292)
7136 (for cases where the link is to a normal DN)
7137 &target: struct drsuapi_DsReplicaObjectIdentifier3
7138 __ndr_size : 0x0000007e (126)
7139 __ndr_size_sid : 0x0000001c (28)
7140 guid : 7639e594-db75-4086-b0d4-67890ae46031
7141 sid : S-1-5-21-2848215498-2472035911-1947525656-19924
7142 __ndr_size_dn : 0x00000022 (34)
7143 dn : 'CN=UOne,OU=TestOU,DC=vsofs8,DC=com'
7146 /* find the attribute being modified */
7147 attr = dsdb_attribute_by_attributeID_id(schema, la->attid);
7149 struct GUID_txt_buf guid_str;
7150 ldb_asprintf_errstring(ldb, "Unable to find attributeID 0x%x for link on <GUID=%s>",
7152 GUID_buf_string(&la->identifier->guid,
7154 return LDB_ERR_OPERATIONS_ERROR;
7157 attrs[0] = attr->lDAPDisplayName;
7158 attrs[1] = "isDeleted";
7159 attrs[2] = "isRecycled";
7163 * get the existing message from the db for the object with
7164 * this GUID, returning attribute being modified. We will then
7165 * use this msg as the basis for a modify call
7167 ret = dsdb_module_search(module, mem_ctx, &res, NULL, LDB_SCOPE_SUBTREE, attrs,
7168 DSDB_FLAG_NEXT_MODULE |
7169 DSDB_SEARCH_SEARCH_ALL_PARTITIONS |
7170 DSDB_SEARCH_SHOW_RECYCLED |
7171 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT |
7172 DSDB_SEARCH_REVEAL_INTERNALS,
7174 "objectGUID=%s", GUID_string(mem_ctx, &la->identifier->guid));
7175 if (ret != LDB_SUCCESS) {
7178 if (res->count != 1) {
7179 ldb_asprintf_errstring(ldb, "DRS linked attribute for GUID %s - DN not found",
7180 GUID_string(mem_ctx, &la->identifier->guid));
7181 return LDB_ERR_NO_SUCH_OBJECT;
7184 *source_msg = res->msgs[0];
7186 /* the value blob for the attribute holds the target object DN */
7187 status = dsdb_dn_la_from_blob(ldb, attr, schema, mem_ctx, la->value.blob, target_dsdb_dn);
7188 if (!W_ERROR_IS_OK(status)) {
7189 ldb_asprintf_errstring(ldb, "Failed to parsed linked attribute blob for %s on %s - %s\n",
7190 attr->lDAPDisplayName,
7191 ldb_dn_get_linearized(res->msgs[0]->dn),
7192 win_errstr(status));
7193 return LDB_ERR_OPERATIONS_ERROR;
7202 * Verifies the source and target objects are known for a linked attribute
7204 static int replmd_verify_linked_attribute(struct replmd_replicated_request *ar,
7205 struct la_entry *la)
7207 int ret = LDB_SUCCESS;
7208 TALLOC_CTX *tmp_ctx = talloc_new(la);
7209 struct ldb_module *module = ar->module;
7210 struct ldb_message *src_msg;
7211 const struct dsdb_attribute *attr;
7212 struct dsdb_dn *tgt_dsdb_dn;
7213 struct GUID guid = GUID_zero();
7216 ret = replmd_extract_la_entry_details(module, la, tmp_ctx, &attr,
7217 &src_msg, &tgt_dsdb_dn);
7220 * When we fail to find the source object, the error code we pass
7221 * back here is really important. It flags back to the callers to
7222 * retry this request with DRSUAPI_DRS_GET_ANC. This case should
7223 * never happen if we're replicating from a Samba DC, but it is
7224 * needed to talk to a Windows DC
7226 if (ret == LDB_ERR_NO_SUCH_OBJECT) {
7227 ret = replmd_replicated_request_werror(ar, WERR_DS_DRA_MISSING_PARENT);
7230 if (ret != LDB_SUCCESS) {
7231 talloc_free(tmp_ctx);
7236 * We can skip the target object checks if we're only syncing critical
7237 * objects, or we know the target is up-to-date. If either case, we
7238 * still continue even if the target doesn't exist
7240 if ((la->dsdb_repl_flags & (DSDB_REPL_FLAG_OBJECT_SUBSET |
7241 DSDB_REPL_FLAG_TARGETS_UPTODATE)) == 0) {
7243 ret = replmd_check_target_exists(module, tgt_dsdb_dn, la,
7244 src_msg->dn, false, &guid,
7249 * When we fail to find the target object, the error code we pass
7250 * back here is really important. It flags back to the callers to
7251 * retry this request with DRSUAPI_DRS_GET_TGT
7253 if (ret == LDB_ERR_NO_SUCH_OBJECT) {
7254 ret = replmd_replicated_request_werror(ar, WERR_DS_DRA_RECYCLED_TARGET);
7257 talloc_free(tmp_ctx);
7262 * Finds the current active Parsed-DN value for a single-valued linked
7263 * attribute, if one exists.
7264 * @param ret_pdn assigned the active Parsed-DN, or NULL if none was found
7265 * @returns LDB_SUCCESS (regardless of whether a match was found), unless
7268 static int replmd_get_active_singleval_link(struct ldb_module *module,
7269 TALLOC_CTX *mem_ctx,
7270 struct parsed_dn pdn_list[],
7272 const struct dsdb_attribute *attr,
7273 struct parsed_dn **ret_pdn)
7279 if (!(attr->ldb_schema_attribute->flags & LDB_ATTR_FLAG_SINGLE_VALUE)) {
7281 /* nothing to do for multi-valued linked attributes */
7285 for (i = 0; i < count; i++) {
7286 int ret = LDB_SUCCESS;
7287 struct parsed_dn *pdn = &pdn_list[i];
7289 /* skip any inactive links */
7290 if (dsdb_dn_is_deleted_val(pdn->v)) {
7294 /* we've found an active value for this attribute */
7297 if (pdn->dsdb_dn == NULL) {
7298 struct ldb_context *ldb = ldb_module_get_ctx(module);
7300 ret = really_parse_trusted_dn(mem_ctx, ldb, pdn,
7301 attr->syntax->ldap_oid);
7307 /* no active link found */
7312 * @returns true if the replication linked attribute info is newer than we
7313 * already have in our DB
7314 * @param pdn the existing linked attribute info in our DB
7315 * @param la the new linked attribute info received during replication
7317 static bool replmd_link_update_is_newer(struct parsed_dn *pdn,
7318 struct drsuapi_DsReplicaLinkedAttribute *la)
7320 /* see if this update is newer than what we have already */
7321 struct GUID invocation_id = GUID_zero();
7322 uint32_t version = 0;
7323 NTTIME change_time = 0;
7327 /* no existing info so update is newer */
7331 dsdb_get_extended_dn_guid(pdn->dsdb_dn->dn, &invocation_id, "RMD_INVOCID");
7332 dsdb_get_extended_dn_uint32(pdn->dsdb_dn->dn, &version, "RMD_VERSION");
7333 dsdb_get_extended_dn_nttime(pdn->dsdb_dn->dn, &change_time, "RMD_CHANGETIME");
7335 return replmd_update_is_newer(&invocation_id,
7336 &la->meta_data.originating_invocation_id,
7338 la->meta_data.version,
7340 la->meta_data.originating_change_time);
7344 * Marks an existing linked attribute value as deleted in the DB
7345 * @param pdn the parsed-DN of the target-value to delete
7347 static int replmd_delete_link_value(struct ldb_module *module,
7348 struct replmd_private *replmd_private,
7349 TALLOC_CTX *mem_ctx,
7350 struct ldb_dn *src_obj_dn,
7351 const struct dsdb_schema *schema,
7352 const struct dsdb_attribute *attr,
7355 struct GUID *target_guid,
7356 struct dsdb_dn *target_dsdb_dn,
7357 struct ldb_val *output_val)
7359 struct ldb_context *ldb = ldb_module_get_ctx(module);
7362 const struct GUID *invocation_id = NULL;
7366 unix_to_nt_time(&now, t);
7368 invocation_id = samdb_ntds_invocation_id(ldb);
7369 if (invocation_id == NULL) {
7370 return LDB_ERR_OPERATIONS_ERROR;
7373 /* if the existing link is active, remove its backlink */
7376 ret = replmd_add_backlink(module, replmd_private, schema,
7377 src_obj_dn, target_guid, false,
7379 if (ret != LDB_SUCCESS) {
7384 /* mark the existing value as deleted */
7385 ret = replmd_update_la_val(mem_ctx, output_val, target_dsdb_dn,
7386 target_dsdb_dn, invocation_id, seq_num,
7387 seq_num, now, true);
7392 * Checks for a conflict in single-valued link attributes, and tries to
7393 * resolve the problem if possible.
7395 * Single-valued links should only ever have one active value. If we already
7396 * have an active link value, and during replication we receive an active link
7397 * value for a different target DN, then we need to resolve this inconsistency
7398 * and determine which value should be active. If the received info is better/
7399 * newer than the existing link attribute, then we need to set our existing
7400 * link as deleted. If the received info is worse/older, then we should continue
7401 * to add it, but set it as an inactive link.
7403 * Note that this is a corner-case that is unlikely to happen (but if it does
7404 * happen, we don't want it to break replication completely).
7406 * @param pdn_being_modified the parsed DN corresponding to the received link
7407 * target (note this is NULL if the link does not already exist in our DB)
7408 * @param pdn_list all the source object's Parsed-DNs for this attribute, i.e.
7409 * any existing active or inactive values for the attribute in our DB.
7410 * @param dsdb_dn the target DN for the received link attribute
7411 * @param add_as_inactive gets set to true if the received link is worse than
7412 * the existing link - it should still be added, but as an inactive link.
7414 static int replmd_check_singleval_la_conflict(struct ldb_module *module,
7415 struct replmd_private *replmd_private,
7416 TALLOC_CTX *mem_ctx,
7417 struct ldb_dn *src_obj_dn,
7418 struct drsuapi_DsReplicaLinkedAttribute *la,
7419 struct dsdb_dn *dsdb_dn,
7420 struct parsed_dn *pdn_being_modified,
7421 struct parsed_dn *pdn_list,
7422 struct ldb_message_element *old_el,
7423 const struct dsdb_schema *schema,
7424 const struct dsdb_attribute *attr,
7426 bool *add_as_inactive)
7428 struct parsed_dn *active_pdn = NULL;
7429 bool update_is_newer = false;
7433 * check if there's a conflict for single-valued links, i.e. an active
7434 * linked attribute already exists, but it has a different target value
7436 ret = replmd_get_active_singleval_link(module, mem_ctx, pdn_list,
7437 old_el->num_values, attr,
7440 if (ret != LDB_SUCCESS) {
7445 * If no active value exists (or the received info is for the currently
7446 * active value), then no conflict exists
7448 if (active_pdn == NULL || active_pdn == pdn_being_modified) {
7452 DBG_WARNING("Link conflict for %s attribute on %s\n",
7453 attr->lDAPDisplayName, ldb_dn_get_linearized(src_obj_dn));
7455 /* Work out how to resolve the conflict based on which info is better */
7456 update_is_newer = replmd_link_update_is_newer(active_pdn, la);
7458 if (update_is_newer) {
7459 DBG_WARNING("Using received value %s, over existing target %s\n",
7460 ldb_dn_get_linearized(dsdb_dn->dn),
7461 ldb_dn_get_linearized(active_pdn->dsdb_dn->dn));
7464 * Delete our existing active link. The received info will then
7465 * be added (through normal link processing) as the active value
7467 ret = replmd_delete_link_value(module, replmd_private, old_el,
7468 src_obj_dn, schema, attr,
7469 seq_num, true, &active_pdn->guid,
7470 active_pdn->dsdb_dn,
7473 if (ret != LDB_SUCCESS) {
7477 DBG_WARNING("Using existing target %s, over received value %s\n",
7478 ldb_dn_get_linearized(active_pdn->dsdb_dn->dn),
7479 ldb_dn_get_linearized(dsdb_dn->dn));
7482 * we want to keep our existing active link and add the
7483 * received link as inactive
7485 *add_as_inactive = true;
7492 process one linked attribute structure
7494 static int replmd_process_linked_attribute(struct ldb_module *module,
7495 struct replmd_private *replmd_private,
7496 struct la_entry *la_entry,
7497 struct ldb_request *parent)
7499 struct drsuapi_DsReplicaLinkedAttribute *la = la_entry->la;
7500 struct ldb_context *ldb = ldb_module_get_ctx(module);
7501 struct ldb_message *msg;
7502 TALLOC_CTX *tmp_ctx = talloc_new(la_entry);
7503 const struct dsdb_schema *schema = dsdb_get_schema(ldb, tmp_ctx);
7505 const struct dsdb_attribute *attr;
7506 struct dsdb_dn *dsdb_dn;
7507 uint64_t seq_num = 0;
7508 struct ldb_message_element *old_el;
7509 time_t t = time(NULL);
7510 struct parsed_dn *pdn_list, *pdn, *next;
7511 struct GUID guid = GUID_zero();
7512 bool active = (la->flags & DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE)?true:false;
7514 enum deletion_state deletion_state = OBJECT_NOT_DELETED;
7515 struct dsdb_dn *old_dsdb_dn = NULL;
7516 struct ldb_val *val_to_update = NULL;
7517 bool add_as_inactive = false;
7520 * get the attribute being modified, the search result for the source object,
7521 * and the target object's DN details
7523 ret = replmd_extract_la_entry_details(module, la_entry, tmp_ctx, &attr,
7526 if (ret != LDB_SUCCESS) {
7527 talloc_free(tmp_ctx);
7532 * Check for deleted objects per MS-DRSR 4.1.10.6.14
7533 * ProcessLinkValue, because link updates are not applied to
7534 * recycled and tombstone objects. We don't have to delete
7535 * any existing link, that should have happened when the
7536 * object deletion was replicated or initiated.
7538 replmd_deletion_state(module, msg, &deletion_state, NULL);
7540 if (deletion_state >= OBJECT_RECYCLED) {
7541 talloc_free(tmp_ctx);
7545 old_el = ldb_msg_find_element(msg, attr->lDAPDisplayName);
7546 if (old_el == NULL) {
7547 ret = ldb_msg_add_empty(msg, attr->lDAPDisplayName, LDB_FLAG_MOD_REPLACE, &old_el);
7548 if (ret != LDB_SUCCESS) {
7549 ldb_module_oom(module);
7550 talloc_free(tmp_ctx);
7551 return LDB_ERR_OPERATIONS_ERROR;
7554 old_el->flags = LDB_FLAG_MOD_REPLACE;
7557 /* parse the existing links */
7558 ret = get_parsed_dns_trusted(module, replmd_private, tmp_ctx, old_el, &pdn_list,
7559 attr->syntax->ldap_oid, parent);
7561 if (ret != LDB_SUCCESS) {
7562 talloc_free(tmp_ctx);
7566 ret = replmd_check_target_exists(module, dsdb_dn, la_entry, msg->dn,
7567 true, &guid, &ignore_link);
7569 if (ret != LDB_SUCCESS) {
7570 talloc_free(tmp_ctx);
7575 * there are some cases where the target object doesn't exist, but it's
7576 * OK to ignore the linked attribute
7579 talloc_free(tmp_ctx);
7583 /* see if this link already exists */
7584 ret = parsed_dn_find(ldb, pdn_list, old_el->num_values,
7587 dsdb_dn->extra_part, 0,
7589 attr->syntax->ldap_oid,
7591 if (ret != LDB_SUCCESS) {
7592 talloc_free(tmp_ctx);
7596 if (!replmd_link_update_is_newer(pdn, la)) {
7597 DEBUG(3,("Discarding older DRS linked attribute update to %s on %s from %s\n",
7598 old_el->name, ldb_dn_get_linearized(msg->dn),
7599 GUID_string(tmp_ctx, &la->meta_data.originating_invocation_id)));
7600 talloc_free(tmp_ctx);
7604 /* get a seq_num for this change */
7605 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &seq_num);
7606 if (ret != LDB_SUCCESS) {
7607 talloc_free(tmp_ctx);
7612 * check for single-valued link conflicts, i.e. an active linked
7613 * attribute already exists, but it has a different target value
7616 ret = replmd_check_singleval_la_conflict(module, replmd_private,
7617 tmp_ctx, msg->dn, la,
7618 dsdb_dn, pdn, pdn_list,
7619 old_el, schema, attr,
7622 if (ret != LDB_SUCCESS) {
7623 talloc_free(tmp_ctx);
7629 uint32_t rmd_flags = dsdb_dn_rmd_flags(pdn->dsdb_dn->dn);
7631 if (!(rmd_flags & DSDB_RMD_FLAG_DELETED)) {
7632 /* remove the existing backlink */
7633 ret = replmd_add_backlink(module, replmd_private,
7636 &pdn->guid, false, attr,
7638 if (ret != LDB_SUCCESS) {
7639 talloc_free(tmp_ctx);
7644 val_to_update = pdn->v;
7645 old_dsdb_dn = pdn->dsdb_dn;
7651 * We know where the new one needs to be, from the *next
7652 * pointer into pdn_list.
7655 offset = old_el->num_values;
7657 if (next->dsdb_dn == NULL) {
7658 ret = really_parse_trusted_dn(tmp_ctx, ldb, next,
7659 attr->syntax->ldap_oid);
7660 if (ret != LDB_SUCCESS) {
7664 offset = next - pdn_list;
7665 if (offset > old_el->num_values) {
7666 talloc_free(tmp_ctx);
7667 return LDB_ERR_OPERATIONS_ERROR;
7671 old_el->values = talloc_realloc(msg->elements, old_el->values,
7672 struct ldb_val, old_el->num_values+1);
7673 if (!old_el->values) {
7674 ldb_module_oom(module);
7675 return LDB_ERR_OPERATIONS_ERROR;
7678 if (offset != old_el->num_values) {
7679 memmove(&old_el->values[offset + 1], &old_el->values[offset],
7680 (old_el->num_values - offset) * sizeof(old_el->values[0]));
7683 old_el->num_values++;
7685 val_to_update = &old_el->values[offset];
7689 /* set the link attribute's value to the info that was received */
7690 ret = replmd_set_la_val(tmp_ctx, val_to_update, dsdb_dn, old_dsdb_dn,
7691 &la->meta_data.originating_invocation_id,
7692 la->meta_data.originating_usn, seq_num,
7693 la->meta_data.originating_change_time,
7694 la->meta_data.version,
7696 if (ret != LDB_SUCCESS) {
7697 talloc_free(tmp_ctx);
7701 if (add_as_inactive) {
7703 /* Set the new link as inactive/deleted to avoid conflicts */
7704 ret = replmd_delete_link_value(module, replmd_private, old_el,
7705 msg->dn, schema, attr, seq_num,
7706 false, &guid, dsdb_dn,
7709 if (ret != LDB_SUCCESS) {
7710 talloc_free(tmp_ctx);
7714 } else if (active) {
7716 /* if the new link is active, then add the new backlink */
7717 ret = replmd_add_backlink(module, replmd_private,
7722 if (ret != LDB_SUCCESS) {
7723 talloc_free(tmp_ctx);
7728 /* we only change whenChanged and uSNChanged if the seq_num
7730 ret = add_time_element(msg, "whenChanged", t);
7731 if (ret != LDB_SUCCESS) {
7732 talloc_free(tmp_ctx);
7737 ret = add_uint64_element(ldb, msg, "uSNChanged", seq_num);
7738 if (ret != LDB_SUCCESS) {
7739 talloc_free(tmp_ctx);
7744 old_el = ldb_msg_find_element(msg, attr->lDAPDisplayName);
7745 if (old_el == NULL) {
7746 talloc_free(tmp_ctx);
7747 return ldb_operr(ldb);
7750 ret = dsdb_check_single_valued_link(attr, old_el);
7751 if (ret != LDB_SUCCESS) {
7752 talloc_free(tmp_ctx);
7756 old_el->flags |= LDB_FLAG_INTERNAL_DISABLE_SINGLE_VALUE_CHECK;
7758 ret = linked_attr_modify(module, msg, parent);
7759 if (ret != LDB_SUCCESS) {
7760 ldb_debug(ldb, LDB_DEBUG_WARNING, "Failed to apply linked attribute change '%s'\n%s\n",
7762 ldb_ldif_message_redacted_string(ldb,
7764 LDB_CHANGETYPE_MODIFY,
7766 talloc_free(tmp_ctx);
7770 talloc_free(tmp_ctx);
7775 static int replmd_extended(struct ldb_module *module, struct ldb_request *req)
7777 if (strcmp(req->op.extended.oid, DSDB_EXTENDED_REPLICATED_OBJECTS_OID) == 0) {
7778 return replmd_extended_replicated_objects(module, req);
7781 return ldb_next_request(module, req);
7786 we hook into the transaction operations to allow us to
7787 perform the linked attribute updates at the end of the whole
7788 transaction. This allows a forward linked attribute to be created
7789 before the object is created. During a vampire, w2k8 sends us linked
7790 attributes before the objects they are part of.
7792 static int replmd_start_transaction(struct ldb_module *module)
7794 /* create our private structure for this transaction */
7795 struct replmd_private *replmd_private = talloc_get_type(ldb_module_get_private(module),
7796 struct replmd_private);
7797 replmd_txn_cleanup(replmd_private);
7799 /* free any leftover mod_usn records from cancelled
7801 while (replmd_private->ncs) {
7802 struct nc_entry *e = replmd_private->ncs;
7803 DLIST_REMOVE(replmd_private->ncs, e);
7807 replmd_private->originating_updates = false;
7809 return ldb_next_start_trans(module);
7813 on prepare commit we loop over our queued la_context structures and
7816 static int replmd_prepare_commit(struct ldb_module *module)
7818 struct replmd_private *replmd_private =
7819 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
7820 struct la_entry *la, *prev;
7824 * Walk the list of linked attributes from DRS replication.
7826 * We walk backwards, to do the first entry first, as we
7827 * added the entries with DLIST_ADD() which puts them at the
7830 for (la = DLIST_TAIL(replmd_private->la_list); la; la=prev) {
7831 prev = DLIST_PREV(la);
7832 DLIST_REMOVE(replmd_private->la_list, la);
7833 ret = replmd_process_linked_attribute(module, replmd_private,
7835 if (ret != LDB_SUCCESS) {
7836 replmd_txn_cleanup(replmd_private);
7841 replmd_txn_cleanup(replmd_private);
7843 /* possibly change @REPLCHANGED */
7844 ret = replmd_notify_store(module, NULL);
7845 if (ret != LDB_SUCCESS) {
7849 return ldb_next_prepare_commit(module);
7852 static int replmd_del_transaction(struct ldb_module *module)
7854 struct replmd_private *replmd_private =
7855 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
7856 replmd_txn_cleanup(replmd_private);
7858 return ldb_next_del_trans(module);
7862 static const struct ldb_module_ops ldb_repl_meta_data_module_ops = {
7863 .name = "repl_meta_data",
7864 .init_context = replmd_init,
7866 .modify = replmd_modify,
7867 .rename = replmd_rename,
7868 .del = replmd_delete,
7869 .extended = replmd_extended,
7870 .start_transaction = replmd_start_transaction,
7871 .prepare_commit = replmd_prepare_commit,
7872 .del_transaction = replmd_del_transaction,
7875 int ldb_repl_meta_data_module_init(const char *version)
7877 LDB_MODULE_CHECK_VERSION(version);
7878 return ldb_register_module(&ldb_repl_meta_data_module_ops);