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 enum urgent_situation {
131 REPL_URGENT_ON_CREATE = 1,
132 REPL_URGENT_ON_UPDATE = 2,
133 REPL_URGENT_ON_DELETE = 4
136 enum deletion_state {
137 OBJECT_NOT_DELETED=1,
144 static void replmd_deletion_state(struct ldb_module *module,
145 const struct ldb_message *msg,
146 enum deletion_state *current_state,
147 enum deletion_state *next_state)
150 bool enabled = false;
153 *current_state = OBJECT_REMOVED;
154 if (next_state != NULL) {
155 *next_state = OBJECT_REMOVED;
160 ret = dsdb_recyclebin_enabled(module, &enabled);
161 if (ret != LDB_SUCCESS) {
165 if (ldb_msg_check_string_attribute(msg, "isDeleted", "TRUE")) {
167 *current_state = OBJECT_TOMBSTONE;
168 if (next_state != NULL) {
169 *next_state = OBJECT_REMOVED;
174 if (ldb_msg_check_string_attribute(msg, "isRecycled", "TRUE")) {
175 *current_state = OBJECT_RECYCLED;
176 if (next_state != NULL) {
177 *next_state = OBJECT_REMOVED;
182 *current_state = OBJECT_DELETED;
183 if (next_state != NULL) {
184 *next_state = OBJECT_RECYCLED;
189 *current_state = OBJECT_NOT_DELETED;
190 if (next_state == NULL) {
195 *next_state = OBJECT_DELETED;
197 *next_state = OBJECT_TOMBSTONE;
201 static const struct {
202 const char *update_name;
203 enum urgent_situation repl_situation;
204 } urgent_objects[] = {
205 {"nTDSDSA", (REPL_URGENT_ON_CREATE | REPL_URGENT_ON_DELETE)},
206 {"crossRef", (REPL_URGENT_ON_CREATE | REPL_URGENT_ON_DELETE)},
207 {"attributeSchema", (REPL_URGENT_ON_CREATE | REPL_URGENT_ON_UPDATE)},
208 {"classSchema", (REPL_URGENT_ON_CREATE | REPL_URGENT_ON_UPDATE)},
209 {"secret", (REPL_URGENT_ON_CREATE | REPL_URGENT_ON_UPDATE)},
210 {"rIDManager", (REPL_URGENT_ON_CREATE | REPL_URGENT_ON_UPDATE)},
214 /* Attributes looked for when updating or deleting, to check for a urgent replication needed */
215 static const char *urgent_attrs[] = {
218 "userAccountControl",
223 static bool replmd_check_urgent_objectclass(const struct ldb_message_element *objectclass_el,
224 enum urgent_situation situation)
227 for (i=0; urgent_objects[i].update_name; i++) {
229 if ((situation & urgent_objects[i].repl_situation) == 0) {
233 for (j=0; j<objectclass_el->num_values; j++) {
234 const struct ldb_val *v = &objectclass_el->values[j];
235 if (ldb_attr_cmp((const char *)v->data, urgent_objects[i].update_name) == 0) {
243 static bool replmd_check_urgent_attribute(const struct ldb_message_element *el)
245 if (ldb_attr_in_list(urgent_attrs, el->name)) {
251 static int replmd_replicated_apply_isDeleted(struct replmd_replicated_request *ar);
254 initialise the module
255 allocate the private structure and build the list
256 of partition DNs for use by replmd_notify()
258 static int replmd_init(struct ldb_module *module)
260 struct replmd_private *replmd_private;
261 struct ldb_context *ldb = ldb_module_get_ctx(module);
262 static const char *samba_dsdb_attrs[] = { SAMBA_COMPATIBLE_FEATURES_ATTR, NULL };
263 struct ldb_dn *samba_dsdb_dn;
264 struct ldb_result *res;
266 TALLOC_CTX *frame = talloc_stackframe();
267 replmd_private = talloc_zero(module, struct replmd_private);
268 if (replmd_private == NULL) {
271 return LDB_ERR_OPERATIONS_ERROR;
273 ldb_module_set_private(module, replmd_private);
275 replmd_private->schema_dn = ldb_get_schema_basedn(ldb);
277 samba_dsdb_dn = ldb_dn_new(frame, ldb, "@SAMBA_DSDB");
278 if (!samba_dsdb_dn) {
283 ret = dsdb_module_search_dn(module, frame, &res, samba_dsdb_dn,
284 samba_dsdb_attrs, DSDB_FLAG_NEXT_MODULE, NULL);
285 if (ret == LDB_SUCCESS) {
286 replmd_private->sorted_links
287 = ldb_msg_check_string_attribute(res->msgs[0],
288 SAMBA_COMPATIBLE_FEATURES_ATTR,
289 SAMBA_SORTED_LINKS_FEATURE);
293 return ldb_next_init(module);
297 cleanup our per-transaction contexts
299 static void replmd_txn_cleanup(struct replmd_private *replmd_private)
301 talloc_free(replmd_private->la_ctx);
302 replmd_private->la_list = NULL;
303 replmd_private->la_ctx = NULL;
309 struct la_backlink *next, *prev;
310 const char *attr_name;
311 struct ldb_dn *forward_dn;
312 struct GUID target_guid;
317 a ldb_modify request operating on modules below the
320 static int linked_attr_modify(struct ldb_module *module,
321 const struct ldb_message *message,
322 struct ldb_request *parent)
324 struct ldb_request *mod_req;
326 struct ldb_context *ldb = ldb_module_get_ctx(module);
327 TALLOC_CTX *tmp_ctx = talloc_new(module);
328 struct ldb_result *res;
330 res = talloc_zero(tmp_ctx, struct ldb_result);
332 talloc_free(tmp_ctx);
333 return ldb_oom(ldb_module_get_ctx(module));
336 ret = ldb_build_mod_req(&mod_req, ldb, tmp_ctx,
340 ldb_modify_default_callback,
342 LDB_REQ_SET_LOCATION(mod_req);
343 if (ret != LDB_SUCCESS) {
344 talloc_free(tmp_ctx);
348 ret = ldb_request_add_control(mod_req, DSDB_CONTROL_REPLICATED_UPDATE_OID,
350 if (ret != LDB_SUCCESS) {
354 /* Run the new request */
355 ret = ldb_next_request(module, mod_req);
357 if (ret == LDB_SUCCESS) {
358 ret = ldb_wait(mod_req->handle, LDB_WAIT_ALL);
361 talloc_free(tmp_ctx);
366 process a backlinks we accumulated during a transaction, adding and
367 deleting the backlinks from the target objects
369 static int replmd_process_backlink(struct ldb_module *module, struct la_backlink *bl, struct ldb_request *parent)
371 struct ldb_dn *target_dn, *source_dn;
373 struct ldb_context *ldb = ldb_module_get_ctx(module);
374 struct ldb_message *msg;
375 TALLOC_CTX *frame = talloc_stackframe();
381 - construct ldb_message
382 - either an add or a delete
384 ret = dsdb_module_dn_by_guid(module, frame, &bl->target_guid, &target_dn, parent);
385 if (ret != LDB_SUCCESS) {
386 struct GUID_txt_buf guid_str;
387 DBG_WARNING("Failed to find target DN for linked attribute with GUID %s\n",
388 GUID_buf_string(&bl->target_guid, &guid_str));
389 DBG_WARNING("Please run 'samba-tool dbcheck' to resolve any missing backlinks.\n");
394 msg = ldb_msg_new(frame);
396 ldb_module_oom(module);
398 return LDB_ERR_OPERATIONS_ERROR;
401 source_dn = ldb_dn_copy(frame, bl->forward_dn);
403 ldb_module_oom(module);
405 return LDB_ERR_OPERATIONS_ERROR;
407 /* Filter down to the attributes we want in the backlink */
408 const char *accept[] = { "GUID", "SID", NULL };
409 ldb_dn_extended_filter(source_dn, accept);
412 /* construct a ldb_message for adding/deleting the backlink */
414 dn_string = ldb_dn_get_extended_linearized(frame, bl->forward_dn, 1);
416 ldb_module_oom(module);
418 return LDB_ERR_OPERATIONS_ERROR;
420 ret = ldb_msg_add_steal_string(msg, bl->attr_name, dn_string);
421 if (ret != LDB_SUCCESS) {
425 msg->elements[0].flags = bl->active?LDB_FLAG_MOD_ADD:LDB_FLAG_MOD_DELETE;
427 /* a backlink should never be single valued. Unfortunately the
428 exchange schema has a attribute
429 msExchBridgeheadedLocalConnectorsDNBL which is single
430 valued and a backlink. We need to cope with that by
431 ignoring the single value flag */
432 msg->elements[0].flags |= LDB_FLAG_INTERNAL_DISABLE_SINGLE_VALUE_CHECK;
434 ret = dsdb_module_modify(module, msg, DSDB_FLAG_NEXT_MODULE, parent);
435 if (ret == LDB_ERR_NO_SUCH_ATTRIBUTE && !bl->active) {
436 /* we allow LDB_ERR_NO_SUCH_ATTRIBUTE as success to
437 cope with possible corruption where the backlink has
438 already been removed */
439 DEBUG(3,("WARNING: backlink from %s already removed from %s - %s\n",
440 ldb_dn_get_linearized(target_dn),
441 ldb_dn_get_linearized(source_dn),
442 ldb_errstring(ldb)));
444 } else if (ret != LDB_SUCCESS) {
445 ldb_asprintf_errstring(ldb, "Failed to %s backlink from %s to %s - %s",
446 bl->active?"add":"remove",
447 ldb_dn_get_linearized(source_dn),
448 ldb_dn_get_linearized(target_dn),
458 add a backlink to the list of backlinks to add/delete in the prepare
461 forward_dn is stolen onto the defereed context
463 static int replmd_defer_add_backlink(struct ldb_module *module,
464 struct replmd_private *replmd_private,
465 const struct dsdb_schema *schema,
466 struct replmd_replicated_request *ac,
467 struct ldb_dn *forward_dn,
468 struct GUID *target_guid, bool active,
469 const struct dsdb_attribute *schema_attr,
470 struct ldb_request *parent)
472 const struct dsdb_attribute *target_attr;
473 struct la_backlink *bl;
475 bl = talloc(ac, struct la_backlink);
477 ldb_module_oom(module);
478 return LDB_ERR_OPERATIONS_ERROR;
481 target_attr = dsdb_attribute_by_linkID(schema, schema_attr->linkID ^ 1);
484 * windows 2003 has a broken schema where the
485 * definition of msDS-IsDomainFor is missing (which is
486 * supposed to be the backlink of the
487 * msDS-HasDomainNCs attribute
492 bl->attr_name = target_attr->lDAPDisplayName;
493 bl->forward_dn = talloc_steal(bl, forward_dn);
494 bl->target_guid = *target_guid;
497 DLIST_ADD(ac->la_backlinks, bl);
503 add a backlink to the list of backlinks to add/delete in the prepare
506 static int replmd_add_backlink(struct ldb_module *module,
507 struct replmd_private *replmd_private,
508 const struct dsdb_schema *schema,
509 struct ldb_dn *forward_dn,
510 struct GUID *target_guid, bool active,
511 const struct dsdb_attribute *schema_attr,
512 struct ldb_request *parent)
514 const struct dsdb_attribute *target_attr;
515 struct la_backlink bl;
518 target_attr = dsdb_attribute_by_linkID(schema, schema_attr->linkID ^ 1);
521 * windows 2003 has a broken schema where the
522 * definition of msDS-IsDomainFor is missing (which is
523 * supposed to be the backlink of the
524 * msDS-HasDomainNCs attribute
529 bl.attr_name = target_attr->lDAPDisplayName;
530 bl.forward_dn = forward_dn;
531 bl.target_guid = *target_guid;
534 ret = replmd_process_backlink(module, &bl, parent);
540 * Callback for most write operations in this module:
542 * notify the repl task that a object has changed. The notifies are
543 * gathered up in the replmd_private structure then written to the
544 * @REPLCHANGED object in each partition during the prepare_commit
546 static int replmd_op_callback(struct ldb_request *req, struct ldb_reply *ares)
549 struct replmd_replicated_request *ac =
550 talloc_get_type_abort(req->context, struct replmd_replicated_request);
551 struct replmd_private *replmd_private =
552 talloc_get_type_abort(ldb_module_get_private(ac->module), struct replmd_private);
553 struct nc_entry *modified_partition;
554 struct ldb_control *partition_ctrl;
555 const struct dsdb_control_current_partition *partition;
557 struct ldb_control **controls;
559 partition_ctrl = ldb_reply_get_control(ares, DSDB_CONTROL_CURRENT_PARTITION_OID);
561 controls = ares->controls;
562 if (ldb_request_get_control(ac->req,
563 DSDB_CONTROL_CURRENT_PARTITION_OID) == NULL) {
565 * Remove the current partition control from what we pass up
566 * the chain if it hasn't been requested manually.
568 controls = ldb_controls_except_specified(ares->controls, ares,
572 if (ares->error != LDB_SUCCESS) {
573 struct GUID_txt_buf guid_txt;
574 struct ldb_message *msg = NULL;
577 if (ac->apply_mode == false) {
578 DBG_NOTICE("Originating update failure. Error is: %s\n",
579 ldb_strerror(ares->error));
580 return ldb_module_done(ac->req, controls,
581 ares->response, ares->error);
584 msg = ac->objs->objects[ac->index_current].msg;
586 * Set at DBG_NOTICE as once these start to happe, they
587 * will happen a lot until resolved, due to repeated
588 * replication. The caller will probably print the
589 * ldb error string anyway.
591 DBG_NOTICE("DRS replication apply failure for %s. Error is: %s\n",
592 ldb_dn_get_linearized(msg->dn),
593 ldb_strerror(ares->error));
595 s = ldb_ldif_message_redacted_string(ldb_module_get_ctx(ac->module),
600 DBG_INFO("Failing DRS %s replication message was %s:\n%s\n",
601 ac->search_msg == NULL ? "ADD" : "MODIFY",
602 GUID_buf_string(&ac->objs->objects[ac->index_current].object_guid,
606 return ldb_module_done(ac->req, controls,
607 ares->response, ares->error);
610 if (ares->type != LDB_REPLY_DONE) {
611 ldb_set_errstring(ldb_module_get_ctx(ac->module), "Invalid reply type for notify\n!");
612 return ldb_module_done(ac->req, NULL,
613 NULL, LDB_ERR_OPERATIONS_ERROR);
616 if (ac->apply_mode == false) {
617 struct la_backlink *bl;
619 * process our backlink list after an replmd_add(),
620 * creating and deleting backlinks as necessary (this
621 * code is sync). The other cases are handled inline
624 for (bl=ac->la_backlinks; bl; bl=bl->next) {
625 ret = replmd_process_backlink(ac->module, bl, ac->req);
626 if (ret != LDB_SUCCESS) {
627 return ldb_module_done(ac->req, NULL,
633 if (!partition_ctrl) {
634 ldb_set_errstring(ldb_module_get_ctx(ac->module),"No partition control on reply");
635 return ldb_module_done(ac->req, NULL,
636 NULL, LDB_ERR_OPERATIONS_ERROR);
639 partition = talloc_get_type_abort(partition_ctrl->data,
640 struct dsdb_control_current_partition);
642 if (ac->seq_num > 0) {
643 for (modified_partition = replmd_private->ncs; modified_partition;
644 modified_partition = modified_partition->next) {
645 if (ldb_dn_compare(modified_partition->dn, partition->dn) == 0) {
650 if (modified_partition == NULL) {
651 modified_partition = talloc_zero(replmd_private, struct nc_entry);
652 if (!modified_partition) {
653 ldb_oom(ldb_module_get_ctx(ac->module));
654 return ldb_module_done(ac->req, NULL,
655 NULL, LDB_ERR_OPERATIONS_ERROR);
657 modified_partition->dn = ldb_dn_copy(modified_partition, partition->dn);
658 if (!modified_partition->dn) {
659 ldb_oom(ldb_module_get_ctx(ac->module));
660 return ldb_module_done(ac->req, NULL,
661 NULL, LDB_ERR_OPERATIONS_ERROR);
663 DLIST_ADD(replmd_private->ncs, modified_partition);
666 if (ac->seq_num > modified_partition->mod_usn) {
667 modified_partition->mod_usn = ac->seq_num;
669 modified_partition->mod_usn_urgent = ac->seq_num;
672 if (!ac->apply_mode) {
673 replmd_private->originating_updates = true;
677 if (ac->apply_mode) {
678 ret = replmd_replicated_apply_isDeleted(ac);
679 if (ret != LDB_SUCCESS) {
680 return ldb_module_done(ac->req, NULL, NULL, ret);
684 /* free the partition control container here, for the
685 * common path. Other cases will have it cleaned up
686 * eventually with the ares */
687 talloc_free(partition_ctrl);
688 return ldb_module_done(ac->req, controls,
689 ares->response, LDB_SUCCESS);
695 * update a @REPLCHANGED record in each partition if there have been
696 * any writes of replicated data in the partition
698 static int replmd_notify_store(struct ldb_module *module, struct ldb_request *parent)
700 struct replmd_private *replmd_private =
701 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
703 while (replmd_private->ncs) {
705 struct nc_entry *modified_partition = replmd_private->ncs;
707 ret = dsdb_module_save_partition_usn(module, modified_partition->dn,
708 modified_partition->mod_usn,
709 modified_partition->mod_usn_urgent, parent);
710 if (ret != LDB_SUCCESS) {
711 DEBUG(0,(__location__ ": Failed to save partition uSN for %s\n",
712 ldb_dn_get_linearized(modified_partition->dn)));
716 if (ldb_dn_compare(modified_partition->dn,
717 replmd_private->schema_dn) == 0) {
718 struct ldb_result *ext_res;
719 ret = dsdb_module_extended(module,
720 replmd_private->schema_dn,
722 DSDB_EXTENDED_SCHEMA_UPDATE_NOW_OID,
724 DSDB_FLAG_NEXT_MODULE,
726 if (ret != LDB_SUCCESS) {
729 talloc_free(ext_res);
732 DLIST_REMOVE(replmd_private->ncs, modified_partition);
733 talloc_free(modified_partition);
741 created a replmd_replicated_request context
743 static struct replmd_replicated_request *replmd_ctx_init(struct ldb_module *module,
744 struct ldb_request *req)
746 struct ldb_context *ldb;
747 struct replmd_replicated_request *ac;
748 const struct GUID *our_invocation_id;
750 ldb = ldb_module_get_ctx(module);
752 ac = talloc_zero(req, struct replmd_replicated_request);
761 ac->schema = dsdb_get_schema(ldb, ac);
763 ldb_debug_set(ldb, LDB_DEBUG_FATAL,
764 "replmd_modify: no dsdb_schema loaded");
765 DEBUG(0,(__location__ ": %s\n", ldb_errstring(ldb)));
770 /* get our invocationId */
771 our_invocation_id = samdb_ntds_invocation_id(ldb);
772 if (!our_invocation_id) {
773 ldb_debug_set(ldb, LDB_DEBUG_FATAL,
774 "replmd_add: unable to find invocationId\n");
778 ac->our_invocation_id = *our_invocation_id;
784 add a time element to a record
786 static int add_time_element(struct ldb_message *msg, const char *attr, time_t t)
788 struct ldb_message_element *el;
792 if (ldb_msg_find_element(msg, attr) != NULL) {
796 s = ldb_timestring(msg, t);
798 return LDB_ERR_OPERATIONS_ERROR;
801 ret = ldb_msg_add_string(msg, attr, s);
802 if (ret != LDB_SUCCESS) {
806 el = ldb_msg_find_element(msg, attr);
807 /* always set as replace. This works because on add ops, the flag
809 el->flags = LDB_FLAG_MOD_REPLACE;
815 add a uint64_t element to a record
817 static int add_uint64_element(struct ldb_context *ldb, struct ldb_message *msg,
818 const char *attr, uint64_t v)
820 struct ldb_message_element *el;
823 if (ldb_msg_find_element(msg, attr) != NULL) {
827 ret = samdb_msg_add_uint64(ldb, msg, msg, attr, v);
828 if (ret != LDB_SUCCESS) {
832 el = ldb_msg_find_element(msg, attr);
833 /* always set as replace. This works because on add ops, the flag
835 el->flags = LDB_FLAG_MOD_REPLACE;
840 static int replmd_replPropertyMetaData1_attid_sort(const struct replPropertyMetaData1 *m1,
841 const struct replPropertyMetaData1 *m2,
842 const uint32_t *rdn_attid)
845 * This assignment seems inoccous, but it is critical for the
846 * system, as we need to do the comparisons as a unsigned
847 * quantity, not signed (enums are signed integers)
849 uint32_t attid_1 = m1->attid;
850 uint32_t attid_2 = m2->attid;
852 if (attid_1 == attid_2) {
857 * See above regarding this being an unsigned comparison.
858 * Otherwise when the high bit is set on non-standard
859 * attributes, they would end up first, before objectClass
862 return attid_1 > attid_2 ? 1 : -1;
865 static int replmd_replPropertyMetaDataCtr1_verify(struct ldb_context *ldb,
866 struct replPropertyMetaDataCtr1 *ctr1,
869 if (ctr1->count == 0) {
870 ldb_debug_set(ldb, LDB_DEBUG_FATAL,
871 "No elements found in replPropertyMetaData for %s!\n",
872 ldb_dn_get_linearized(dn));
873 return LDB_ERR_CONSTRAINT_VIOLATION;
876 /* the objectClass attribute is value 0x00000000, so must be first */
877 if (ctr1->array[0].attid != DRSUAPI_ATTID_objectClass) {
878 ldb_debug_set(ldb, LDB_DEBUG_FATAL,
879 "No objectClass found in replPropertyMetaData for %s!\n",
880 ldb_dn_get_linearized(dn));
881 return LDB_ERR_OBJECT_CLASS_VIOLATION;
887 static int replmd_replPropertyMetaDataCtr1_sort_and_verify(struct ldb_context *ldb,
888 struct replPropertyMetaDataCtr1 *ctr1,
891 /* Note this is O(n^2) for the almost-sorted case, which this is */
892 LDB_TYPESAFE_QSORT(ctr1->array, ctr1->count, NULL,
893 replmd_replPropertyMetaData1_attid_sort);
894 return replmd_replPropertyMetaDataCtr1_verify(ldb, ctr1, dn);
897 static int replmd_ldb_message_element_attid_sort(const struct ldb_message_element *e1,
898 const struct ldb_message_element *e2,
899 const struct dsdb_schema *schema)
901 const struct dsdb_attribute *a1;
902 const struct dsdb_attribute *a2;
905 * TODO: make this faster by caching the dsdb_attribute pointer
906 * on the ldb_messag_element
909 a1 = dsdb_attribute_by_lDAPDisplayName(schema, e1->name);
910 a2 = dsdb_attribute_by_lDAPDisplayName(schema, e2->name);
913 * TODO: remove this check, we should rely on e1 and e2 having valid attribute names
917 return strcasecmp(e1->name, e2->name);
919 if (a1->attributeID_id == a2->attributeID_id) {
922 return a1->attributeID_id > a2->attributeID_id ? 1 : -1;
925 static void replmd_ldb_message_sort(struct ldb_message *msg,
926 const struct dsdb_schema *schema)
928 LDB_TYPESAFE_QSORT(msg->elements, msg->num_elements, schema, replmd_ldb_message_element_attid_sort);
931 static int replmd_build_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct dsdb_dn *dsdb_dn,
932 const struct GUID *invocation_id,
933 uint64_t local_usn, NTTIME nttime);
935 static int parsed_dn_compare(struct parsed_dn *pdn1, struct parsed_dn *pdn2);
937 static int get_parsed_dns(struct ldb_module *module, TALLOC_CTX *mem_ctx,
938 struct ldb_message_element *el, struct parsed_dn **pdn,
939 const char *ldap_oid, struct ldb_request *parent);
942 fix up linked attributes in replmd_add.
943 This involves setting up the right meta-data in extended DN
944 components, and creating backlinks to the object
946 static int replmd_add_fix_la(struct ldb_module *module, TALLOC_CTX *mem_ctx,
947 struct replmd_private *replmd_private,
948 struct ldb_message_element *el,
949 struct replmd_replicated_request *ac,
951 struct ldb_dn *forward_dn,
952 const struct dsdb_attribute *sa,
953 struct ldb_request *parent)
956 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
957 struct ldb_context *ldb = ldb_module_get_ctx(module);
958 struct parsed_dn *pdn;
959 /* We will take a reference to the schema in replmd_add_backlink */
960 const struct dsdb_schema *schema = dsdb_get_schema(ldb, NULL);
961 struct ldb_val *new_values = NULL;
964 if (dsdb_check_single_valued_link(sa, el) == LDB_SUCCESS) {
965 el->flags |= LDB_FLAG_INTERNAL_DISABLE_SINGLE_VALUE_CHECK;
967 ldb_asprintf_errstring(ldb,
968 "Attribute %s is single valued but "
969 "more than one value has been supplied",
971 talloc_free(tmp_ctx);
972 return LDB_ERR_CONSTRAINT_VIOLATION;
975 ret = get_parsed_dns(module, tmp_ctx, el, &pdn,
976 sa->syntax->ldap_oid, parent);
977 if (ret != LDB_SUCCESS) {
978 talloc_free(tmp_ctx);
982 new_values = talloc_array(tmp_ctx, struct ldb_val, el->num_values);
983 if (new_values == NULL) {
984 ldb_module_oom(module);
985 talloc_free(tmp_ctx);
986 return LDB_ERR_OPERATIONS_ERROR;
989 for (i = 0; i < el->num_values; i++) {
990 struct parsed_dn *p = &pdn[i];
991 if (i > 0 && parsed_dn_compare(p, &pdn[i - 1]) == 0) {
992 ldb_asprintf_errstring(ldb,
993 "Linked attribute %s has "
994 "multiple identical values", el->name);
995 talloc_free(tmp_ctx);
996 if (ldb_attr_cmp(el->name, "member") == 0) {
997 return LDB_ERR_ENTRY_ALREADY_EXISTS;
999 return LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS;
1002 ret = replmd_build_la_val(el->values, p->v, p->dsdb_dn,
1003 &ac->our_invocation_id,
1005 if (ret != LDB_SUCCESS) {
1006 talloc_free(tmp_ctx);
1010 ret = replmd_defer_add_backlink(module, replmd_private,
1012 forward_dn, &p->guid, true, sa,
1014 if (ret != LDB_SUCCESS) {
1015 talloc_free(tmp_ctx);
1019 new_values[i] = *p->v;
1021 el->values = talloc_steal(mem_ctx, new_values);
1023 talloc_free(tmp_ctx);
1027 static int replmd_add_make_extended_dn(struct ldb_request *req,
1028 const DATA_BLOB *guid_blob,
1029 struct ldb_dn **_extended_dn)
1032 const DATA_BLOB *sid_blob;
1033 /* Calculate an extended DN for any linked attributes */
1034 struct ldb_dn *extended_dn = ldb_dn_copy(req, req->op.add.message->dn);
1036 return LDB_ERR_OPERATIONS_ERROR;
1038 ret = ldb_dn_set_extended_component(extended_dn, "GUID", guid_blob);
1039 if (ret != LDB_SUCCESS) {
1043 sid_blob = ldb_msg_find_ldb_val(req->op.add.message, "objectSID");
1044 if (sid_blob != NULL) {
1045 ret = ldb_dn_set_extended_component(extended_dn, "SID", sid_blob);
1046 if (ret != LDB_SUCCESS) {
1050 *_extended_dn = extended_dn;
1055 intercept add requests
1057 static int replmd_add(struct ldb_module *module, struct ldb_request *req)
1059 struct ldb_context *ldb;
1060 struct ldb_control *control;
1061 struct replmd_replicated_request *ac;
1062 enum ndr_err_code ndr_err;
1063 struct ldb_request *down_req;
1064 struct ldb_message *msg;
1065 const DATA_BLOB *guid_blob;
1066 DATA_BLOB guid_blob_stack;
1068 uint8_t guid_data[16];
1069 struct replPropertyMetaDataBlob nmd;
1070 struct ldb_val nmd_value;
1071 struct ldb_dn *extended_dn = NULL;
1074 * The use of a time_t here seems odd, but as the NTTIME
1075 * elements are actually declared as NTTIME_1sec in the IDL,
1076 * getting a higher resolution timestamp is not required.
1078 time_t t = time(NULL);
1083 unsigned int functional_level;
1085 bool allow_add_guid = false;
1086 bool remove_current_guid = false;
1087 bool is_urgent = false;
1088 bool is_schema_nc = false;
1089 struct ldb_message_element *objectclass_el;
1090 struct replmd_private *replmd_private =
1091 talloc_get_type_abort(ldb_module_get_private(module), struct replmd_private);
1093 /* check if there's a show relax control (used by provision to say 'I know what I'm doing') */
1094 control = ldb_request_get_control(req, LDB_CONTROL_RELAX_OID);
1096 allow_add_guid = true;
1099 /* do not manipulate our control entries */
1100 if (ldb_dn_is_special(req->op.add.message->dn)) {
1101 return ldb_next_request(module, req);
1104 ldb = ldb_module_get_ctx(module);
1106 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_add\n");
1108 guid_blob = ldb_msg_find_ldb_val(req->op.add.message, "objectGUID");
1109 if (guid_blob != NULL) {
1110 if (!allow_add_guid) {
1111 ldb_set_errstring(ldb,
1112 "replmd_add: it's not allowed to add an object with objectGUID!");
1113 return LDB_ERR_UNWILLING_TO_PERFORM;
1115 NTSTATUS status = GUID_from_data_blob(guid_blob,&guid);
1116 if (!NT_STATUS_IS_OK(status)) {
1117 ldb_set_errstring(ldb,
1118 "replmd_add: Unable to parse the 'objectGUID' as a GUID!");
1119 return LDB_ERR_UNWILLING_TO_PERFORM;
1121 /* we remove this attribute as it can be a string and
1122 * will not be treated correctly and then we will re-add
1123 * it later on in the good format */
1124 remove_current_guid = true;
1128 guid = GUID_random();
1130 guid_blob_stack = data_blob_const(guid_data, sizeof(guid_data));
1132 /* This can't fail */
1133 ndr_push_struct_into_fixed_blob(&guid_blob_stack, &guid,
1134 (ndr_push_flags_fn_t)ndr_push_GUID);
1135 guid_blob = &guid_blob_stack;
1138 ac = replmd_ctx_init(module, req);
1140 return ldb_module_oom(module);
1143 functional_level = dsdb_functional_level(ldb);
1145 /* Get a sequence number from the backend */
1146 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &ac->seq_num);
1147 if (ret != LDB_SUCCESS) {
1152 /* we have to copy the message as the caller might have it as a const */
1153 msg = ldb_msg_copy_shallow(ac, req->op.add.message);
1157 return LDB_ERR_OPERATIONS_ERROR;
1160 /* generated times */
1161 unix_to_nt_time(&now, t);
1162 time_str = ldb_timestring(msg, t);
1166 return LDB_ERR_OPERATIONS_ERROR;
1168 if (remove_current_guid) {
1169 ldb_msg_remove_attr(msg,"objectGUID");
1173 * remove autogenerated attributes
1175 ldb_msg_remove_attr(msg, "whenCreated");
1176 ldb_msg_remove_attr(msg, "whenChanged");
1177 ldb_msg_remove_attr(msg, "uSNCreated");
1178 ldb_msg_remove_attr(msg, "uSNChanged");
1179 ldb_msg_remove_attr(msg, "replPropertyMetaData");
1182 * readd replicated attributes
1184 ret = ldb_msg_add_string(msg, "whenCreated", time_str);
1185 if (ret != LDB_SUCCESS) {
1191 /* build the replication meta_data */
1194 nmd.ctr.ctr1.count = msg->num_elements;
1195 nmd.ctr.ctr1.array = talloc_array(msg,
1196 struct replPropertyMetaData1,
1197 nmd.ctr.ctr1.count);
1198 if (!nmd.ctr.ctr1.array) {
1201 return LDB_ERR_OPERATIONS_ERROR;
1204 is_schema_nc = ldb_dn_compare_base(replmd_private->schema_dn, msg->dn) == 0;
1206 for (i=0; i < msg->num_elements;) {
1207 struct ldb_message_element *e = &msg->elements[i];
1208 struct replPropertyMetaData1 *m = &nmd.ctr.ctr1.array[ni];
1209 const struct dsdb_attribute *sa;
1211 if (e->name[0] == '@') {
1216 sa = dsdb_attribute_by_lDAPDisplayName(ac->schema, e->name);
1218 ldb_debug_set(ldb, LDB_DEBUG_ERROR,
1219 "replmd_add: attribute '%s' not defined in schema\n",
1222 return LDB_ERR_NO_SUCH_ATTRIBUTE;
1225 if ((sa->systemFlags & DS_FLAG_ATTR_NOT_REPLICATED) || (sa->systemFlags & DS_FLAG_ATTR_IS_CONSTRUCTED)) {
1226 /* if the attribute is not replicated (0x00000001)
1227 * or constructed (0x00000004) it has no metadata
1233 if (sa->linkID != 0 && functional_level > DS_DOMAIN_FUNCTION_2000) {
1234 if (extended_dn == NULL) {
1235 ret = replmd_add_make_extended_dn(req,
1238 if (ret != LDB_SUCCESS) {
1245 * Prepare the context for the backlinks and
1246 * create metadata for the forward links. The
1247 * backlinks are created in
1248 * replmd_op_callback() after the successful
1249 * ADD of the object.
1251 ret = replmd_add_fix_la(module, msg->elements,
1256 if (ret != LDB_SUCCESS) {
1260 /* linked attributes are not stored in
1261 replPropertyMetaData in FL above w2k */
1266 m->attid = dsdb_attribute_get_attid(sa, is_schema_nc);
1268 if (m->attid == DRSUAPI_ATTID_isDeleted) {
1269 const struct ldb_val *rdn_val = ldb_dn_get_rdn_val(msg->dn);
1272 if (rdn_val == NULL) {
1275 return LDB_ERR_OPERATIONS_ERROR;
1278 rdn = (const char*)rdn_val->data;
1279 if (strcmp(rdn, "Deleted Objects") == 0) {
1281 * Set the originating_change_time to 29/12/9999 at 23:59:59
1282 * as specified in MS-ADTS 7.1.1.4.2 Deleted Objects Container
1284 m->originating_change_time = DELETED_OBJECT_CONTAINER_CHANGE_TIME;
1286 m->originating_change_time = now;
1289 m->originating_change_time = now;
1291 m->originating_invocation_id = ac->our_invocation_id;
1292 m->originating_usn = ac->seq_num;
1293 m->local_usn = ac->seq_num;
1296 if (!(e->flags & DSDB_FLAG_INTERNAL_FORCE_META_DATA)) {
1301 e->flags &= ~DSDB_FLAG_INTERNAL_FORCE_META_DATA;
1303 if (e->num_values != 0) {
1308 ldb_msg_remove_element(msg, e);
1311 /* fix meta data count */
1312 nmd.ctr.ctr1.count = ni;
1315 * sort meta data array
1317 ret = replmd_replPropertyMetaDataCtr1_sort_and_verify(ldb, &nmd.ctr.ctr1, msg->dn);
1318 if (ret != LDB_SUCCESS) {
1319 ldb_asprintf_errstring(ldb, "%s: error during direct ADD: %s", __func__, ldb_errstring(ldb));
1324 /* generated NDR encoded values */
1325 ndr_err = ndr_push_struct_blob(&nmd_value, msg,
1327 (ndr_push_flags_fn_t)ndr_push_replPropertyMetaDataBlob);
1328 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1331 return LDB_ERR_OPERATIONS_ERROR;
1335 * add the autogenerated values
1337 ret = dsdb_msg_add_guid(msg, &guid, "objectGUID");
1338 if (ret != LDB_SUCCESS) {
1343 ret = ldb_msg_add_string(msg, "whenChanged", time_str);
1344 if (ret != LDB_SUCCESS) {
1349 ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNCreated", ac->seq_num);
1350 if (ret != LDB_SUCCESS) {
1355 ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNChanged", ac->seq_num);
1356 if (ret != LDB_SUCCESS) {
1361 ret = ldb_msg_add_value(msg, "replPropertyMetaData", &nmd_value, NULL);
1362 if (ret != LDB_SUCCESS) {
1369 * sort the attributes by attid before storing the object
1371 replmd_ldb_message_sort(msg, ac->schema);
1374 * Assert that we do have an objectClass
1376 objectclass_el = ldb_msg_find_element(msg, "objectClass");
1377 if (objectclass_el == NULL) {
1378 ldb_asprintf_errstring(ldb, __location__
1379 ": objectClass missing on %s\n",
1380 ldb_dn_get_linearized(msg->dn));
1382 return LDB_ERR_OBJECT_CLASS_VIOLATION;
1384 is_urgent = replmd_check_urgent_objectclass(objectclass_el,
1385 REPL_URGENT_ON_CREATE);
1387 ac->is_urgent = is_urgent;
1388 ret = ldb_build_add_req(&down_req, ldb, ac,
1391 ac, replmd_op_callback,
1394 LDB_REQ_SET_LOCATION(down_req);
1395 if (ret != LDB_SUCCESS) {
1400 /* current partition control is needed by "replmd_op_callback" */
1401 if (ldb_request_get_control(req, DSDB_CONTROL_CURRENT_PARTITION_OID) == NULL) {
1402 ret = ldb_request_add_control(down_req,
1403 DSDB_CONTROL_CURRENT_PARTITION_OID,
1405 if (ret != LDB_SUCCESS) {
1411 if (functional_level == DS_DOMAIN_FUNCTION_2000) {
1412 ret = ldb_request_add_control(down_req, DSDB_CONTROL_APPLY_LINKS, false, NULL);
1413 if (ret != LDB_SUCCESS) {
1419 /* mark the control done */
1421 control->critical = 0;
1423 /* go on with the call chain */
1424 return ldb_next_request(module, down_req);
1429 * update the replPropertyMetaData for one element
1431 static int replmd_update_rpmd_element(struct ldb_context *ldb,
1432 struct ldb_message *msg,
1433 struct ldb_message_element *el,
1434 struct ldb_message_element *old_el,
1435 struct replPropertyMetaDataBlob *omd,
1436 const struct dsdb_schema *schema,
1438 const struct GUID *our_invocation_id,
1441 bool is_forced_rodc,
1442 struct ldb_request *req)
1445 const struct dsdb_attribute *a;
1446 struct replPropertyMetaData1 *md1;
1447 bool may_skip = false;
1450 a = dsdb_attribute_by_lDAPDisplayName(schema, el->name);
1452 if (ldb_request_get_control(req, LDB_CONTROL_RELAX_OID)) {
1453 /* allow this to make it possible for dbcheck
1454 to remove bad attributes */
1458 DEBUG(0,(__location__ ": Unable to find attribute %s in schema\n",
1460 return LDB_ERR_OPERATIONS_ERROR;
1463 attid = dsdb_attribute_get_attid(a, is_schema_nc);
1465 if ((a->systemFlags & DS_FLAG_ATTR_NOT_REPLICATED) || (a->systemFlags & DS_FLAG_ATTR_IS_CONSTRUCTED)) {
1470 * if the attribute's value haven't changed, and this isn't
1471 * just a delete of everything then return LDB_SUCCESS Unless
1472 * we have the provision control or if the attribute is
1473 * interSiteTopologyGenerator as this page explain:
1474 * http://support.microsoft.com/kb/224815 this attribute is
1475 * periodicaly written by the DC responsible for the intersite
1476 * generation in a given site
1478 * Unchanged could be deleting or replacing an already-gone
1479 * thing with an unconstrained delete/empty replace or a
1480 * replace with the same value, but not an add with the same
1481 * value because that could be about adding a duplicate (which
1482 * is for someone else to error out on).
1484 if (old_el != NULL && ldb_msg_element_equal_ordered(el, old_el)) {
1485 if (LDB_FLAG_MOD_TYPE(el->flags) == LDB_FLAG_MOD_REPLACE) {
1488 } else if (old_el == NULL && el->num_values == 0) {
1489 if (LDB_FLAG_MOD_TYPE(el->flags) == LDB_FLAG_MOD_REPLACE) {
1491 } else if (LDB_FLAG_MOD_TYPE(el->flags) == LDB_FLAG_MOD_DELETE) {
1494 } else if (a->linkID != 0 && LDB_FLAG_MOD_TYPE(el->flags) == LDB_FLAG_MOD_DELETE &&
1495 ldb_request_get_control(req, DSDB_CONTROL_REPLMD_VANISH_LINKS) != NULL) {
1497 * We intentionally skip the version bump when attempting to
1500 * The control is set by dbcheck and expunge-tombstones which
1501 * both attempt to be non-replicating. Otherwise, making an
1502 * alteration to the replication state would trigger a
1503 * broadcast of all expunged objects.
1508 if (el->flags & DSDB_FLAG_INTERNAL_FORCE_META_DATA) {
1510 el->flags &= ~DSDB_FLAG_INTERNAL_FORCE_META_DATA;
1514 if (strcmp(el->name, "interSiteTopologyGenerator") != 0 &&
1515 !ldb_request_get_control(req, LDB_CONTROL_PROVISION_OID)) {
1517 * allow this to make it possible for dbcheck
1518 * to rebuild broken metadata
1524 for (i=0; i<omd->ctr.ctr1.count; i++) {
1526 * First check if we find it under the msDS-IntID,
1527 * then check if we find it under the OID and
1530 * This allows the administrator to simply re-write
1531 * the attributes and so restore replication, which is
1532 * likely what they will try to do.
1534 if (attid == omd->ctr.ctr1.array[i].attid) {
1538 if (a->attributeID_id == omd->ctr.ctr1.array[i].attid) {
1543 if (a->linkID != 0 && dsdb_functional_level(ldb) > DS_DOMAIN_FUNCTION_2000) {
1544 /* linked attributes are not stored in
1545 replPropertyMetaData in FL above w2k, but we do
1546 raise the seqnum for the object */
1547 if (*seq_num == 0 &&
1548 ldb_sequence_number(ldb, LDB_SEQ_NEXT, seq_num) != LDB_SUCCESS) {
1549 return LDB_ERR_OPERATIONS_ERROR;
1554 if (i == omd->ctr.ctr1.count) {
1555 /* we need to add a new one */
1556 omd->ctr.ctr1.array = talloc_realloc(msg, omd->ctr.ctr1.array,
1557 struct replPropertyMetaData1, omd->ctr.ctr1.count+1);
1558 if (omd->ctr.ctr1.array == NULL) {
1560 return LDB_ERR_OPERATIONS_ERROR;
1562 omd->ctr.ctr1.count++;
1563 ZERO_STRUCT(omd->ctr.ctr1.array[i]);
1566 /* Get a new sequence number from the backend. We only do this
1567 * if we have a change that requires a new
1568 * replPropertyMetaData element
1570 if (*seq_num == 0) {
1571 int ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, seq_num);
1572 if (ret != LDB_SUCCESS) {
1573 return LDB_ERR_OPERATIONS_ERROR;
1577 md1 = &omd->ctr.ctr1.array[i];
1581 if (md1->attid == DRSUAPI_ATTID_isDeleted) {
1582 const struct ldb_val *rdn_val = ldb_dn_get_rdn_val(msg->dn);
1585 if (rdn_val == NULL) {
1587 return LDB_ERR_OPERATIONS_ERROR;
1590 rdn = (const char*)rdn_val->data;
1591 if (strcmp(rdn, "Deleted Objects") == 0) {
1593 * Set the originating_change_time to 29/12/9999 at 23:59:59
1594 * as specified in MS-ADTS 7.1.1.4.2 Deleted Objects Container
1596 md1->originating_change_time = DELETED_OBJECT_CONTAINER_CHANGE_TIME;
1598 md1->originating_change_time = now;
1601 md1->originating_change_time = now;
1603 md1->originating_invocation_id = *our_invocation_id;
1604 md1->originating_usn = *seq_num;
1605 md1->local_usn = *seq_num;
1607 if (is_forced_rodc) {
1608 /* Force version to 0 to be overriden later via replication */
1616 * Bump the replPropertyMetaData version on an attribute, and if it
1617 * has changed (or forced by leaving rdn_old NULL), update the value
1620 * This is important, as calling a modify operation may not change the
1621 * version number if the values appear unchanged, but a rename between
1622 * parents bumps this value.
1625 static int replmd_update_rpmd_rdn_attr(struct ldb_context *ldb,
1626 struct ldb_message *msg,
1627 const struct ldb_val *rdn_new,
1628 const struct ldb_val *rdn_old,
1629 struct replPropertyMetaDataBlob *omd,
1630 struct replmd_replicated_request *ar,
1633 bool is_forced_rodc)
1635 const char *rdn_name = ldb_dn_get_rdn_name(msg->dn);
1636 const struct dsdb_attribute *rdn_attr =
1637 dsdb_attribute_by_lDAPDisplayName(ar->schema, rdn_name);
1638 const char *attr_name = rdn_attr != NULL ?
1639 rdn_attr->lDAPDisplayName :
1641 struct ldb_message_element new_el = {
1642 .flags = LDB_FLAG_MOD_REPLACE,
1645 .values = discard_const_p(struct ldb_val, rdn_new)
1647 struct ldb_message_element old_el = {
1648 .flags = LDB_FLAG_MOD_REPLACE,
1650 .num_values = rdn_old ? 1 : 0,
1651 .values = discard_const_p(struct ldb_val, rdn_old)
1654 if (ldb_msg_element_equal_ordered(&new_el, &old_el) == false) {
1655 int ret = ldb_msg_add(msg, &new_el, LDB_FLAG_MOD_REPLACE);
1656 if (ret != LDB_SUCCESS) {
1657 return ldb_oom(ldb);
1661 return replmd_update_rpmd_element(ldb, msg, &new_el, NULL,
1662 omd, ar->schema, &ar->seq_num,
1663 &ar->our_invocation_id,
1664 now, is_schema_nc, is_forced_rodc,
1669 static uint64_t find_max_local_usn(struct replPropertyMetaDataBlob omd)
1671 uint32_t count = omd.ctr.ctr1.count;
1674 for (i=0; i < count; i++) {
1675 struct replPropertyMetaData1 m = omd.ctr.ctr1.array[i];
1676 if (max < m.local_usn) {
1684 * update the replPropertyMetaData object each time we modify an
1685 * object. This is needed for DRS replication, as the merge on the
1686 * client is based on this object
1688 static int replmd_update_rpmd(struct ldb_module *module,
1689 const struct dsdb_schema *schema,
1690 struct ldb_request *req,
1691 const char * const *rename_attrs,
1692 struct ldb_message *msg, uint64_t *seq_num,
1693 time_t t, bool is_schema_nc,
1694 bool *is_urgent, bool *rodc)
1696 const struct ldb_val *omd_value;
1697 enum ndr_err_code ndr_err;
1698 struct replPropertyMetaDataBlob omd;
1701 const struct GUID *our_invocation_id;
1703 const char * const *attrs = NULL;
1704 const char * const attrs2[] = { "uSNChanged", "objectClass", "instanceType", NULL };
1705 struct ldb_result *res;
1706 struct ldb_context *ldb;
1707 struct ldb_message_element *objectclass_el;
1708 enum urgent_situation situation;
1709 bool rmd_is_provided;
1710 bool rmd_is_just_resorted = false;
1711 const char *not_rename_attrs[4 + msg->num_elements];
1712 bool is_forced_rodc = false;
1715 attrs = rename_attrs;
1717 for (i = 0; i < msg->num_elements; i++) {
1718 not_rename_attrs[i] = msg->elements[i].name;
1720 not_rename_attrs[i] = "replPropertyMetaData";
1721 not_rename_attrs[i+1] = "objectClass";
1722 not_rename_attrs[i+2] = "instanceType";
1723 not_rename_attrs[i+3] = NULL;
1724 attrs = not_rename_attrs;
1727 ldb = ldb_module_get_ctx(module);
1729 ret = samdb_rodc(ldb, rodc);
1730 if (ret != LDB_SUCCESS) {
1731 DEBUG(4, (__location__ ": unable to tell if we are an RODC\n"));
1736 ldb_request_get_control(req, DSDB_CONTROL_FORCE_RODC_LOCAL_CHANGE)) {
1737 is_forced_rodc = true;
1740 our_invocation_id = samdb_ntds_invocation_id(ldb);
1741 if (!our_invocation_id) {
1742 /* this happens during an initial vampire while
1743 updating the schema */
1744 DEBUG(5,("No invocationID - skipping replPropertyMetaData update\n"));
1748 unix_to_nt_time(&now, t);
1750 if (ldb_request_get_control(req, DSDB_CONTROL_CHANGEREPLMETADATA_OID)) {
1751 rmd_is_provided = true;
1752 if (ldb_request_get_control(req, DSDB_CONTROL_CHANGEREPLMETADATA_RESORT_OID)) {
1753 rmd_is_just_resorted = true;
1756 rmd_is_provided = false;
1759 /* if isDeleted is present and is TRUE, then we consider we are deleting,
1760 * otherwise we consider we are updating */
1761 if (ldb_msg_check_string_attribute(msg, "isDeleted", "TRUE")) {
1762 situation = REPL_URGENT_ON_DELETE;
1763 } else if (rename_attrs) {
1764 situation = REPL_URGENT_ON_CREATE | REPL_URGENT_ON_DELETE;
1766 situation = REPL_URGENT_ON_UPDATE;
1769 if (rmd_is_provided) {
1770 /* In this case the change_replmetadata control was supplied */
1771 /* We check that it's the only attribute that is provided
1772 * (it's a rare case so it's better to keep the code simplier)
1773 * We also check that the highest local_usn is bigger or the same as
1776 if( msg->num_elements != 1 ||
1777 strncmp(msg->elements[0].name,
1778 "replPropertyMetaData", 20) ) {
1779 DEBUG(0,(__location__ ": changereplmetada control called without "\
1780 "a specified replPropertyMetaData attribute or with others\n"));
1781 return LDB_ERR_OPERATIONS_ERROR;
1783 if (situation != REPL_URGENT_ON_UPDATE) {
1784 DEBUG(0,(__location__ ": changereplmetada control can't be called when deleting an object\n"));
1785 return LDB_ERR_OPERATIONS_ERROR;
1787 omd_value = ldb_msg_find_ldb_val(msg, "replPropertyMetaData");
1789 DEBUG(0,(__location__ ": replPropertyMetaData was not specified for Object %s\n",
1790 ldb_dn_get_linearized(msg->dn)));
1791 return LDB_ERR_OPERATIONS_ERROR;
1793 ndr_err = ndr_pull_struct_blob(omd_value, msg, &omd,
1794 (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
1795 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1796 DEBUG(0,(__location__ ": Failed to parse replPropertyMetaData for %s\n",
1797 ldb_dn_get_linearized(msg->dn)));
1798 return LDB_ERR_OPERATIONS_ERROR;
1801 ret = dsdb_module_search_dn(module, msg, &res, msg->dn, attrs2,
1802 DSDB_FLAG_NEXT_MODULE |
1803 DSDB_SEARCH_SHOW_RECYCLED |
1804 DSDB_SEARCH_SHOW_EXTENDED_DN |
1805 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT |
1806 DSDB_SEARCH_REVEAL_INTERNALS, req);
1808 if (ret != LDB_SUCCESS) {
1812 if (rmd_is_just_resorted == false) {
1813 *seq_num = find_max_local_usn(omd);
1815 db_seq = ldb_msg_find_attr_as_uint64(res->msgs[0], "uSNChanged", 0);
1818 * The test here now allows for a new
1819 * replPropertyMetaData with no change, if was
1820 * just dbcheck re-sorting the values.
1822 if (*seq_num <= db_seq) {
1823 DEBUG(0,(__location__ ": changereplmetada control provided but max(local_usn)" \
1824 " is less than uSNChanged (max = %lld uSNChanged = %lld)\n",
1825 (long long)*seq_num, (long long)db_seq));
1826 return LDB_ERR_OPERATIONS_ERROR;
1831 /* search for the existing replPropertyMetaDataBlob. We need
1832 * to use REVEAL and ask for DNs in storage format to support
1833 * the check for values being the same in
1834 * replmd_update_rpmd_element()
1836 ret = dsdb_module_search_dn(module, msg, &res, msg->dn, attrs,
1837 DSDB_FLAG_NEXT_MODULE |
1838 DSDB_SEARCH_SHOW_RECYCLED |
1839 DSDB_SEARCH_SHOW_EXTENDED_DN |
1840 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT |
1841 DSDB_SEARCH_REVEAL_INTERNALS, req);
1842 if (ret != LDB_SUCCESS) {
1846 omd_value = ldb_msg_find_ldb_val(res->msgs[0], "replPropertyMetaData");
1848 DEBUG(0,(__location__ ": Object %s does not have a replPropertyMetaData attribute\n",
1849 ldb_dn_get_linearized(msg->dn)));
1850 return LDB_ERR_OPERATIONS_ERROR;
1853 ndr_err = ndr_pull_struct_blob(omd_value, msg, &omd,
1854 (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
1855 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1856 DEBUG(0,(__location__ ": Failed to parse replPropertyMetaData for %s\n",
1857 ldb_dn_get_linearized(msg->dn)));
1858 return LDB_ERR_OPERATIONS_ERROR;
1861 if (omd.version != 1) {
1862 DEBUG(0,(__location__ ": bad version %u in replPropertyMetaData for %s\n",
1863 omd.version, ldb_dn_get_linearized(msg->dn)));
1864 return LDB_ERR_OPERATIONS_ERROR;
1867 for (i=0; i<msg->num_elements;) {
1868 struct ldb_message_element *el = &msg->elements[i];
1869 struct ldb_message_element *old_el;
1871 old_el = ldb_msg_find_element(res->msgs[0], el->name);
1872 ret = replmd_update_rpmd_element(ldb, msg, el, old_el,
1873 &omd, schema, seq_num,
1878 if (ret != LDB_SUCCESS) {
1882 if (!*is_urgent && (situation == REPL_URGENT_ON_UPDATE)) {
1883 *is_urgent = replmd_check_urgent_attribute(el);
1886 if (!(el->flags & DSDB_FLAG_INTERNAL_FORCE_META_DATA)) {
1891 el->flags &= ~DSDB_FLAG_INTERNAL_FORCE_META_DATA;
1893 if (el->num_values != 0) {
1898 ldb_msg_remove_element(msg, el);
1903 * Assert that we have an objectClass attribute - this is major
1904 * corruption if we don't have this!
1906 objectclass_el = ldb_msg_find_element(res->msgs[0], "objectClass");
1907 if (objectclass_el != NULL) {
1909 * Now check if this objectClass means we need to do urgent replication
1911 if (!*is_urgent && replmd_check_urgent_objectclass(objectclass_el,
1915 } else if (!ldb_request_get_control(req, DSDB_CONTROL_DBCHECK)) {
1916 ldb_asprintf_errstring(ldb, __location__
1917 ": objectClass missing on %s\n",
1918 ldb_dn_get_linearized(msg->dn));
1919 return LDB_ERR_OBJECT_CLASS_VIOLATION;
1923 * replmd_update_rpmd_element has done an update if the
1926 if (*seq_num != 0 || rmd_is_just_resorted == true) {
1927 struct ldb_val *md_value;
1928 struct ldb_message_element *el;
1930 /*if we are RODC and this is a DRSR update then its ok*/
1931 if (!ldb_request_get_control(req, DSDB_CONTROL_REPLICATED_UPDATE_OID)
1932 && !ldb_request_get_control(req, DSDB_CONTROL_DBCHECK_MODIFY_RO_REPLICA)
1933 && !is_forced_rodc) {
1934 unsigned instanceType;
1937 ldb_set_errstring(ldb, "RODC modify is forbidden!");
1938 return LDB_ERR_REFERRAL;
1941 instanceType = ldb_msg_find_attr_as_uint(res->msgs[0], "instanceType", INSTANCE_TYPE_WRITE);
1942 if (!(instanceType & INSTANCE_TYPE_WRITE)) {
1943 return ldb_error(ldb, LDB_ERR_UNWILLING_TO_PERFORM,
1944 "cannot change replicated attribute on partial replica");
1948 md_value = talloc(msg, struct ldb_val);
1949 if (md_value == NULL) {
1951 return LDB_ERR_OPERATIONS_ERROR;
1954 ret = replmd_replPropertyMetaDataCtr1_sort_and_verify(ldb, &omd.ctr.ctr1, msg->dn);
1955 if (ret != LDB_SUCCESS) {
1956 ldb_asprintf_errstring(ldb, "%s: %s", __func__, ldb_errstring(ldb));
1960 ndr_err = ndr_push_struct_blob(md_value, msg, &omd,
1961 (ndr_push_flags_fn_t)ndr_push_replPropertyMetaDataBlob);
1962 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1963 DEBUG(0,(__location__ ": Failed to marshall replPropertyMetaData for %s\n",
1964 ldb_dn_get_linearized(msg->dn)));
1965 return LDB_ERR_OPERATIONS_ERROR;
1968 ret = ldb_msg_add_empty(msg, "replPropertyMetaData", LDB_FLAG_MOD_REPLACE, &el);
1969 if (ret != LDB_SUCCESS) {
1970 DEBUG(0,(__location__ ": Failed to add updated replPropertyMetaData %s\n",
1971 ldb_dn_get_linearized(msg->dn)));
1976 el->values = md_value;
1982 static int parsed_dn_compare(struct parsed_dn *pdn1, struct parsed_dn *pdn2)
1984 int ret = ndr_guid_compare(&pdn1->guid, &pdn2->guid);
1986 return data_blob_cmp(&pdn1->dsdb_dn->extra_part,
1987 &pdn2->dsdb_dn->extra_part);
1993 get a series of message element values as an array of DNs and GUIDs
1994 the result is sorted by GUID
1996 static int get_parsed_dns(struct ldb_module *module, TALLOC_CTX *mem_ctx,
1997 struct ldb_message_element *el, struct parsed_dn **pdn,
1998 const char *ldap_oid, struct ldb_request *parent)
2001 bool values_are_sorted = true;
2002 struct ldb_context *ldb = ldb_module_get_ctx(module);
2009 (*pdn) = talloc_array(mem_ctx, struct parsed_dn, el->num_values);
2011 ldb_module_oom(module);
2012 return LDB_ERR_OPERATIONS_ERROR;
2015 for (i=0; i<el->num_values; i++) {
2016 struct ldb_val *v = &el->values[i];
2019 struct parsed_dn *p;
2023 p->dsdb_dn = dsdb_dn_parse(*pdn, ldb, v, ldap_oid);
2024 if (p->dsdb_dn == NULL) {
2025 return LDB_ERR_INVALID_DN_SYNTAX;
2028 dn = p->dsdb_dn->dn;
2030 status = dsdb_get_extended_dn_guid(dn, &p->guid, "GUID");
2031 if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND) ||
2032 unlikely(GUID_all_zero(&p->guid))) {
2033 /* we got a DN without a GUID - go find the GUID */
2034 int ret = dsdb_module_guid_by_dn(module, dn, &p->guid, parent);
2035 if (ret != LDB_SUCCESS) {
2036 ldb_asprintf_errstring(ldb, "Unable to find GUID for DN %s\n",
2037 ldb_dn_get_linearized(dn));
2038 if (ret == LDB_ERR_NO_SUCH_OBJECT &&
2039 LDB_FLAG_MOD_TYPE(el->flags) == LDB_FLAG_MOD_DELETE &&
2040 ldb_attr_cmp(el->name, "member") == 0) {
2041 return LDB_ERR_UNWILLING_TO_PERFORM;
2045 ret = dsdb_set_extended_dn_guid(dn, &p->guid, "GUID");
2046 if (ret != LDB_SUCCESS) {
2049 } else if (!NT_STATUS_IS_OK(status)) {
2050 return LDB_ERR_OPERATIONS_ERROR;
2052 if (i > 0 && values_are_sorted) {
2053 int cmp = parsed_dn_compare(p, &(*pdn)[i - 1]);
2055 values_are_sorted = false;
2058 /* keep a pointer to the original ldb_val */
2061 if (! values_are_sorted) {
2062 TYPESAFE_QSORT(*pdn, el->num_values, parsed_dn_compare);
2068 * Get a series of trusted message element values. The result is sorted by
2069 * GUID, even though the GUIDs might not be known. That works because we trust
2070 * the database to give us the elements like that if the
2071 * replmd_private->sorted_links flag is set.
2073 * We also ensure that the links are in the Functional Level 2003
2074 * linked attributes format.
2076 static int get_parsed_dns_trusted(struct ldb_module *module,
2077 struct replmd_private *replmd_private,
2078 TALLOC_CTX *mem_ctx,
2079 struct ldb_message_element *el,
2080 struct parsed_dn **pdn,
2081 const char *ldap_oid,
2082 struct ldb_request *parent)
2091 if (!replmd_private->sorted_links) {
2092 /* We need to sort the list. This is the slow old path we want
2095 ret = get_parsed_dns(module, mem_ctx, el, pdn, ldap_oid,
2097 if (ret != LDB_SUCCESS) {
2101 /* Here we get a list of 'struct parsed_dns' without the parsing */
2102 *pdn = talloc_zero_array(mem_ctx, struct parsed_dn,
2105 ldb_module_oom(module);
2106 return LDB_ERR_OPERATIONS_ERROR;
2109 for (i = 0; i < el->num_values; i++) {
2110 (*pdn)[i].v = &el->values[i];
2115 * This upgrades links to FL2003 style, and sorts the result
2116 * if that was needed.
2118 * TODO: Add a database feature that asserts we have no FL2000
2119 * style links to avoid this check or add a feature that
2120 * uses a similar check to find sorted/unsorted links
2121 * for an on-the-fly upgrade.
2124 ret = replmd_check_upgrade_links(ldb_module_get_ctx(module),
2125 *pdn, el->num_values,
2128 if (ret != LDB_SUCCESS) {
2136 Return LDB_SUCCESS if a parsed_dn list contains no duplicate values,
2137 otherwise an error code. For compatibility the error code differs depending
2138 on whether or not the attribute is "member".
2140 As always, the parsed_dn list is assumed to be sorted.
2142 static int check_parsed_dn_duplicates(struct ldb_module *module,
2143 struct ldb_message_element *el,
2144 struct parsed_dn *pdn)
2147 struct ldb_context *ldb = ldb_module_get_ctx(module);
2149 for (i = 1; i < el->num_values; i++) {
2150 struct parsed_dn *p = &pdn[i];
2151 if (parsed_dn_compare(p, &pdn[i - 1]) == 0) {
2152 ldb_asprintf_errstring(ldb,
2153 "Linked attribute %s has "
2154 "multiple identical values",
2156 if (ldb_attr_cmp(el->name, "member") == 0) {
2157 return LDB_ERR_ENTRY_ALREADY_EXISTS;
2159 return LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS;
2167 build a new extended DN, including all meta data fields
2169 RMD_FLAGS = DSDB_RMD_FLAG_* bits
2170 RMD_ADDTIME = originating_add_time
2171 RMD_INVOCID = originating_invocation_id
2172 RMD_CHANGETIME = originating_change_time
2173 RMD_ORIGINATING_USN = originating_usn
2174 RMD_LOCAL_USN = local_usn
2175 RMD_VERSION = version
2177 static int replmd_build_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v,
2178 struct dsdb_dn *dsdb_dn,
2179 const struct GUID *invocation_id,
2180 uint64_t local_usn, NTTIME nttime)
2182 return replmd_set_la_val(mem_ctx, v, dsdb_dn, NULL, invocation_id,
2183 local_usn, local_usn, nttime,
2184 RMD_VERSION_INITIAL, false);
2187 static int replmd_update_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct dsdb_dn *dsdb_dn,
2188 struct dsdb_dn *old_dsdb_dn, const struct GUID *invocation_id,
2189 uint64_t seq_num, uint64_t local_usn, NTTIME nttime,
2193 check if any links need upgrading from w2k format
2195 static int replmd_check_upgrade_links(struct ldb_context *ldb,
2196 struct parsed_dn *dns, uint32_t count,
2197 struct ldb_message_element *el,
2198 const char *ldap_oid)
2201 const struct GUID *invocation_id = NULL;
2202 for (i=0; i<count; i++) {
2206 if (dns[i].dsdb_dn == NULL) {
2207 ret = really_parse_trusted_dn(dns, ldb, &dns[i],
2209 if (ret != LDB_SUCCESS) {
2210 return LDB_ERR_INVALID_DN_SYNTAX;
2214 status = dsdb_get_extended_dn_uint32(dns[i].dsdb_dn->dn,
2215 &version, "RMD_VERSION");
2216 if (!NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
2218 * We optimistically assume they are all the same; if
2219 * the first one is fixed, they are all fixed.
2221 * If the first one was *not* fixed and we find a
2222 * later one that is, that is an occasion to shout
2228 DEBUG(0, ("Mixed w2k and fixed format "
2229 "linked attributes\n"));
2233 if (invocation_id == NULL) {
2234 invocation_id = samdb_ntds_invocation_id(ldb);
2235 if (invocation_id == NULL) {
2236 return LDB_ERR_OPERATIONS_ERROR;
2241 /* it's an old one that needs upgrading */
2242 ret = replmd_update_la_val(el->values, dns[i].v,
2243 dns[i].dsdb_dn, dns[i].dsdb_dn,
2244 invocation_id, 1, 1, 0, false);
2245 if (ret != LDB_SUCCESS) {
2251 * This sort() is critical for the operation of
2252 * get_parsed_dns_trusted() because callers of this function
2253 * expect a sorted list, and FL2000 style links are not
2254 * sorted. In particular, as well as the upgrade case,
2255 * get_parsed_dns_trusted() is called from
2256 * replmd_delete_remove_link() even in FL2000 mode
2258 * We do not normally pay the cost of the qsort() due to the
2259 * early return in the RMD_VERSION found case.
2261 TYPESAFE_QSORT(dns, count, parsed_dn_compare);
2266 Sets the value for a linked attribute, including all meta data fields
2268 see replmd_build_la_val for value names
2270 static int replmd_set_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct dsdb_dn *dsdb_dn,
2271 struct dsdb_dn *old_dsdb_dn, const struct GUID *invocation_id,
2272 uint64_t usn, uint64_t local_usn, NTTIME nttime,
2273 uint32_t version, bool deleted)
2275 struct ldb_dn *dn = dsdb_dn->dn;
2276 const char *tstring, *usn_string, *flags_string;
2277 struct ldb_val tval;
2279 struct ldb_val usnv, local_usnv;
2280 struct ldb_val vers, flagsv;
2281 const struct ldb_val *old_addtime = NULL;
2284 const char *dnstring;
2286 uint32_t rmd_flags = deleted?DSDB_RMD_FLAG_DELETED:0;
2288 tstring = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)nttime);
2290 return LDB_ERR_OPERATIONS_ERROR;
2292 tval = data_blob_string_const(tstring);
2294 usn_string = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)usn);
2296 return LDB_ERR_OPERATIONS_ERROR;
2298 usnv = data_blob_string_const(usn_string);
2300 usn_string = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)local_usn);
2302 return LDB_ERR_OPERATIONS_ERROR;
2304 local_usnv = data_blob_string_const(usn_string);
2306 status = GUID_to_ndr_blob(invocation_id, dn, &iid);
2307 if (!NT_STATUS_IS_OK(status)) {
2308 return LDB_ERR_OPERATIONS_ERROR;
2311 flags_string = talloc_asprintf(mem_ctx, "%u", rmd_flags);
2312 if (!flags_string) {
2313 return LDB_ERR_OPERATIONS_ERROR;
2315 flagsv = data_blob_string_const(flags_string);
2317 ret = ldb_dn_set_extended_component(dn, "RMD_FLAGS", &flagsv);
2318 if (ret != LDB_SUCCESS) return ret;
2320 /* get the ADDTIME from the original */
2321 if (old_dsdb_dn != NULL) {
2322 old_addtime = ldb_dn_get_extended_component(old_dsdb_dn->dn,
2325 if (old_addtime == NULL) {
2326 old_addtime = &tval;
2328 if (dsdb_dn != old_dsdb_dn ||
2329 ldb_dn_get_extended_component(dn, "RMD_ADDTIME") == NULL) {
2330 ret = ldb_dn_set_extended_component(dn, "RMD_ADDTIME", old_addtime);
2331 if (ret != LDB_SUCCESS) return ret;
2334 /* use our invocation id */
2335 ret = ldb_dn_set_extended_component(dn, "RMD_INVOCID", &iid);
2336 if (ret != LDB_SUCCESS) return ret;
2338 /* changetime is the current time */
2339 ret = ldb_dn_set_extended_component(dn, "RMD_CHANGETIME", &tval);
2340 if (ret != LDB_SUCCESS) return ret;
2342 /* update the USN */
2343 ret = ldb_dn_set_extended_component(dn, "RMD_ORIGINATING_USN", &usnv);
2344 if (ret != LDB_SUCCESS) return ret;
2346 ret = ldb_dn_set_extended_component(dn, "RMD_LOCAL_USN", &local_usnv);
2347 if (ret != LDB_SUCCESS) return ret;
2349 vstring = talloc_asprintf(mem_ctx, "%lu", (unsigned long)version);
2350 vers = data_blob_string_const(vstring);
2351 ret = ldb_dn_set_extended_component(dn, "RMD_VERSION", &vers);
2352 if (ret != LDB_SUCCESS) return ret;
2354 dnstring = dsdb_dn_get_extended_linearized(mem_ctx, dsdb_dn, 1);
2355 if (dnstring == NULL) {
2356 return LDB_ERR_OPERATIONS_ERROR;
2358 *v = data_blob_string_const(dnstring);
2364 * Updates the value for a linked attribute, including all meta data fields
2366 static int replmd_update_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct dsdb_dn *dsdb_dn,
2367 struct dsdb_dn *old_dsdb_dn, const struct GUID *invocation_id,
2368 uint64_t usn, uint64_t local_usn, NTTIME nttime,
2371 uint32_t old_version;
2372 uint32_t version = RMD_VERSION_INITIAL;
2376 * We're updating the linked attribute locally, so increase the version
2377 * by 1 so that other DCs will see the change when it gets replicated out
2379 status = dsdb_get_extended_dn_uint32(old_dsdb_dn->dn, &old_version,
2382 if (NT_STATUS_IS_OK(status)) {
2383 version = old_version + 1;
2386 return replmd_set_la_val(mem_ctx, v, dsdb_dn, old_dsdb_dn, invocation_id,
2387 usn, local_usn, nttime, version, deleted);
2391 handle adding a linked attribute
2393 static int replmd_modify_la_add(struct ldb_module *module,
2394 struct replmd_private *replmd_private,
2395 const struct dsdb_schema *schema,
2396 struct ldb_message *msg,
2397 struct ldb_message_element *el,
2398 struct ldb_message_element *old_el,
2399 const struct dsdb_attribute *schema_attr,
2402 struct ldb_dn *msg_dn,
2403 struct ldb_request *parent)
2406 struct parsed_dn *dns, *old_dns;
2407 TALLOC_CTX *tmp_ctx = talloc_new(msg);
2409 struct ldb_val *new_values = NULL;
2410 unsigned old_num_values = old_el ? old_el->num_values : 0;
2411 unsigned num_values = 0;
2412 unsigned max_num_values;
2413 const struct GUID *invocation_id;
2414 struct ldb_context *ldb = ldb_module_get_ctx(module);
2416 unix_to_nt_time(&now, t);
2418 invocation_id = samdb_ntds_invocation_id(ldb);
2419 if (!invocation_id) {
2420 talloc_free(tmp_ctx);
2421 return LDB_ERR_OPERATIONS_ERROR;
2424 /* get the DNs to be added, fully parsed.
2426 * We need full parsing because they came off the wire and we don't
2427 * trust them, besides which we need their details to know where to put
2430 ret = get_parsed_dns(module, tmp_ctx, el, &dns,
2431 schema_attr->syntax->ldap_oid, parent);
2432 if (ret != LDB_SUCCESS) {
2433 talloc_free(tmp_ctx);
2437 /* get the existing DNs, lazily parsed */
2438 ret = get_parsed_dns_trusted(module, replmd_private,
2439 tmp_ctx, old_el, &old_dns,
2440 schema_attr->syntax->ldap_oid, parent);
2442 if (ret != LDB_SUCCESS) {
2443 talloc_free(tmp_ctx);
2447 max_num_values = old_num_values + el->num_values;
2448 if (max_num_values < old_num_values) {
2449 DEBUG(0, ("we seem to have overflow in replmd_modify_la_add. "
2450 "old values: %u, new values: %u, sum: %u",
2451 old_num_values, el->num_values, max_num_values));
2452 talloc_free(tmp_ctx);
2453 return LDB_ERR_OPERATIONS_ERROR;
2456 new_values = talloc_zero_array(tmp_ctx, struct ldb_val, max_num_values);
2458 if (new_values == NULL) {
2459 ldb_module_oom(module);
2460 talloc_free(tmp_ctx);
2461 return LDB_ERR_OPERATIONS_ERROR;
2465 * For each new value, find where it would go in the list. If there is
2466 * a matching GUID there, we update the existing value; otherwise we
2470 for (i = 0; i < el->num_values; i++) {
2471 struct parsed_dn *exact;
2472 struct parsed_dn *next;
2474 int err = parsed_dn_find(ldb, old_dns, old_num_values,
2477 dns[i].dsdb_dn->extra_part, 0,
2479 schema_attr->syntax->ldap_oid,
2481 if (err != LDB_SUCCESS) {
2482 talloc_free(tmp_ctx);
2486 if (exact != NULL) {
2488 * We are trying to add one that exists, which is only
2489 * allowed if it was previously deleted.
2491 * When we do undelete a link we change it in place.
2492 * It will be copied across into the right spot in due
2496 rmd_flags = dsdb_dn_rmd_flags(exact->dsdb_dn->dn);
2498 if (!(rmd_flags & DSDB_RMD_FLAG_DELETED)) {
2499 struct GUID_txt_buf guid_str;
2500 ldb_asprintf_errstring(ldb,
2501 "Attribute %s already "
2502 "exists for target GUID %s",
2504 GUID_buf_string(&exact->guid,
2506 talloc_free(tmp_ctx);
2507 /* error codes for 'member' need to be
2509 if (ldb_attr_cmp(el->name, "member") == 0) {
2510 return LDB_ERR_ENTRY_ALREADY_EXISTS;
2512 return LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS;
2516 ret = replmd_update_la_val(new_values, exact->v,
2519 invocation_id, seq_num,
2520 seq_num, now, false);
2521 if (ret != LDB_SUCCESS) {
2522 talloc_free(tmp_ctx);
2526 ret = replmd_add_backlink(module, replmd_private,
2533 if (ret != LDB_SUCCESS) {
2534 talloc_free(tmp_ctx);
2540 * Here we don't have an exact match.
2542 * If next is NULL, this one goes beyond the end of the
2543 * existing list, so we need to add all of those ones first.
2545 * If next is not NULL, we need to add all the ones before
2549 offset = old_num_values;
2551 /* next should have been parsed, but let's make sure */
2552 if (next->dsdb_dn == NULL) {
2553 ret = really_parse_trusted_dn(tmp_ctx, ldb, next,
2554 schema_attr->syntax->ldap_oid);
2555 if (ret != LDB_SUCCESS) {
2559 offset = MIN(next - old_dns, old_num_values);
2562 /* put all the old ones before next on the list */
2563 for (; j < offset; j++) {
2564 new_values[num_values] = *old_dns[j].v;
2568 ret = replmd_add_backlink(module, replmd_private,
2573 /* Make the new linked attribute ldb_val. */
2574 ret = replmd_build_la_val(new_values, &new_values[num_values],
2575 dns[i].dsdb_dn, invocation_id,
2577 if (ret != LDB_SUCCESS) {
2578 talloc_free(tmp_ctx);
2582 if (ret != LDB_SUCCESS) {
2583 talloc_free(tmp_ctx);
2587 /* copy the rest of the old ones (if any) */
2588 for (; j < old_num_values; j++) {
2589 new_values[num_values] = *old_dns[j].v;
2593 talloc_steal(msg->elements, new_values);
2594 if (old_el != NULL) {
2595 talloc_steal(msg->elements, old_el->values);
2597 el->values = new_values;
2598 el->num_values = num_values;
2600 talloc_free(tmp_ctx);
2602 /* we now tell the backend to replace all existing values
2603 with the one we have constructed */
2604 el->flags = LDB_FLAG_MOD_REPLACE;
2611 handle deleting all active linked attributes
2613 static int replmd_modify_la_delete(struct ldb_module *module,
2614 struct replmd_private *replmd_private,
2615 const struct dsdb_schema *schema,
2616 struct ldb_message *msg,
2617 struct ldb_message_element *el,
2618 struct ldb_message_element *old_el,
2619 const struct dsdb_attribute *schema_attr,
2622 struct ldb_dn *msg_dn,
2623 struct ldb_request *parent)
2626 struct parsed_dn *dns, *old_dns;
2627 TALLOC_CTX *tmp_ctx = NULL;
2629 struct ldb_context *ldb = ldb_module_get_ctx(module);
2630 struct ldb_control *vanish_links_ctrl = NULL;
2631 bool vanish_links = false;
2632 unsigned int num_to_delete = el->num_values;
2634 const struct GUID *invocation_id;
2637 unix_to_nt_time(&now, t);
2639 invocation_id = samdb_ntds_invocation_id(ldb);
2640 if (!invocation_id) {
2641 return LDB_ERR_OPERATIONS_ERROR;
2644 if (old_el == NULL || old_el->num_values == 0) {
2645 /* there is nothing to delete... */
2646 if (num_to_delete == 0) {
2647 /* and we're deleting nothing, so that's OK */
2650 return LDB_ERR_NO_SUCH_ATTRIBUTE;
2653 tmp_ctx = talloc_new(msg);
2654 if (tmp_ctx == NULL) {
2655 return LDB_ERR_OPERATIONS_ERROR;
2658 ret = get_parsed_dns(module, tmp_ctx, el, &dns,
2659 schema_attr->syntax->ldap_oid, parent);
2660 if (ret != LDB_SUCCESS) {
2661 talloc_free(tmp_ctx);
2665 ret = get_parsed_dns_trusted(module, replmd_private,
2666 tmp_ctx, old_el, &old_dns,
2667 schema_attr->syntax->ldap_oid, parent);
2669 if (ret != LDB_SUCCESS) {
2670 talloc_free(tmp_ctx);
2675 vanish_links_ctrl = ldb_request_get_control(parent, DSDB_CONTROL_REPLMD_VANISH_LINKS);
2676 if (vanish_links_ctrl) {
2677 vanish_links = true;
2678 vanish_links_ctrl->critical = false;
2682 /* we empty out el->values here to avoid damage if we return early. */
2687 * If vanish links is set, we are actually removing members of
2688 * old_el->values; otherwise we are just marking them deleted.
2690 * There is a special case when no values are given: we remove them
2691 * all. When we have the vanish_links control we just have to remove
2692 * the backlinks and change our element to replace the existing values
2693 * with the empty list.
2696 if (num_to_delete == 0) {
2697 for (i = 0; i < old_el->num_values; i++) {
2698 struct parsed_dn *p = &old_dns[i];
2699 if (p->dsdb_dn == NULL) {
2700 ret = really_parse_trusted_dn(tmp_ctx, ldb, p,
2701 schema_attr->syntax->ldap_oid);
2702 if (ret != LDB_SUCCESS) {
2706 ret = replmd_add_backlink(module, replmd_private,
2707 schema, msg_dn, &p->guid,
2710 if (ret != LDB_SUCCESS) {
2711 talloc_free(tmp_ctx);
2718 rmd_flags = dsdb_dn_rmd_flags(p->dsdb_dn->dn);
2719 if (rmd_flags & DSDB_RMD_FLAG_DELETED) {
2723 ret = replmd_update_la_val(old_el->values, p->v,
2724 p->dsdb_dn, p->dsdb_dn,
2725 invocation_id, seq_num,
2726 seq_num, now, true);
2727 if (ret != LDB_SUCCESS) {
2728 talloc_free(tmp_ctx);
2734 el->flags = LDB_FLAG_MOD_REPLACE;
2735 talloc_free(tmp_ctx);
2741 for (i = 0; i < num_to_delete; i++) {
2742 struct parsed_dn *p = &dns[i];
2743 struct parsed_dn *exact = NULL;
2744 struct parsed_dn *next = NULL;
2745 ret = parsed_dn_find(ldb, old_dns, old_el->num_values,
2748 p->dsdb_dn->extra_part, 0,
2750 schema_attr->syntax->ldap_oid,
2752 if (ret != LDB_SUCCESS) {
2753 talloc_free(tmp_ctx);
2756 if (exact == NULL) {
2757 struct GUID_txt_buf buf;
2758 ldb_asprintf_errstring(ldb, "Attribute %s doesn't "
2759 "exist for target GUID %s",
2761 GUID_buf_string(&p->guid, &buf));
2762 if (ldb_attr_cmp(el->name, "member") == 0) {
2763 talloc_free(tmp_ctx);
2764 return LDB_ERR_UNWILLING_TO_PERFORM;
2766 talloc_free(tmp_ctx);
2767 return LDB_ERR_NO_SUCH_ATTRIBUTE;
2772 if (CHECK_DEBUGLVL(5)) {
2773 rmd_flags = dsdb_dn_rmd_flags(exact->dsdb_dn->dn);
2774 if ((rmd_flags & DSDB_RMD_FLAG_DELETED)) {
2775 struct GUID_txt_buf buf;
2776 const char *guid_str = \
2777 GUID_buf_string(&p->guid, &buf);
2778 DEBUG(5, ("Deleting deleted linked "
2779 "attribute %s to %s, because "
2780 "vanish_links control is set\n",
2781 el->name, guid_str));
2785 /* remove the backlink */
2786 ret = replmd_add_backlink(module,
2793 if (ret != LDB_SUCCESS) {
2794 talloc_free(tmp_ctx);
2798 /* We flag the deletion and tidy it up later. */
2803 rmd_flags = dsdb_dn_rmd_flags(exact->dsdb_dn->dn);
2805 if (rmd_flags & DSDB_RMD_FLAG_DELETED) {
2806 struct GUID_txt_buf buf;
2807 const char *guid_str = GUID_buf_string(&p->guid, &buf);
2808 ldb_asprintf_errstring(ldb, "Attribute %s already "
2809 "deleted for target GUID %s",
2810 el->name, guid_str);
2811 if (ldb_attr_cmp(el->name, "member") == 0) {
2812 talloc_free(tmp_ctx);
2813 return LDB_ERR_UNWILLING_TO_PERFORM;
2815 talloc_free(tmp_ctx);
2816 return LDB_ERR_NO_SUCH_ATTRIBUTE;
2820 ret = replmd_update_la_val(old_el->values, exact->v,
2821 exact->dsdb_dn, exact->dsdb_dn,
2822 invocation_id, seq_num, seq_num,
2824 if (ret != LDB_SUCCESS) {
2825 talloc_free(tmp_ctx);
2828 ret = replmd_add_backlink(module, replmd_private,
2833 if (ret != LDB_SUCCESS) {
2834 talloc_free(tmp_ctx);
2841 for (i = 0; i < old_el->num_values; i++) {
2842 if (old_dns[i].v != NULL) {
2843 old_el->values[j] = *old_dns[i].v;
2847 old_el->num_values = j;
2850 el->values = talloc_steal(msg->elements, old_el->values);
2851 el->num_values = old_el->num_values;
2853 talloc_free(tmp_ctx);
2855 /* we now tell the backend to replace all existing values
2856 with the one we have constructed */
2857 el->flags = LDB_FLAG_MOD_REPLACE;
2863 handle replacing a linked attribute
2865 static int replmd_modify_la_replace(struct ldb_module *module,
2866 struct replmd_private *replmd_private,
2867 const struct dsdb_schema *schema,
2868 struct ldb_message *msg,
2869 struct ldb_message_element *el,
2870 struct ldb_message_element *old_el,
2871 const struct dsdb_attribute *schema_attr,
2874 struct ldb_dn *msg_dn,
2875 struct ldb_request *parent)
2877 unsigned int i, old_i, new_i;
2878 struct parsed_dn *dns, *old_dns;
2879 TALLOC_CTX *tmp_ctx = talloc_new(msg);
2881 const struct GUID *invocation_id;
2882 struct ldb_context *ldb = ldb_module_get_ctx(module);
2883 struct ldb_val *new_values = NULL;
2884 const char *ldap_oid = schema_attr->syntax->ldap_oid;
2885 unsigned int old_num_values;
2886 unsigned int repl_num_values;
2887 unsigned int max_num_values;
2890 unix_to_nt_time(&now, t);
2892 invocation_id = samdb_ntds_invocation_id(ldb);
2893 if (!invocation_id) {
2894 return LDB_ERR_OPERATIONS_ERROR;
2898 * The replace operation is unlike the replace and delete cases in that
2899 * we need to look at every existing link to see whether it is being
2900 * retained or deleted. In other words, we can't avoid parsing the GUIDs.
2902 * As we are trying to combine two sorted lists, the algorithm we use
2903 * is akin to the merge phase of a merge sort. We interleave the two
2904 * lists, doing different things depending on which side the current
2907 * There are three main cases, with some sub-cases.
2909 * - a DN is in the old list but not the new one. It needs to be
2910 * marked as deleted (but left in the list).
2911 * - maybe it is already deleted, and we have less to do.
2913 * - a DN is in both lists. The old data gets replaced by the new,
2914 * and the list doesn't grow. The old link may have been marked as
2915 * deleted, in which case we undelete it.
2917 * - a DN is in the new list only. We add it in the right place.
2920 old_num_values = old_el ? old_el->num_values : 0;
2921 repl_num_values = el->num_values;
2922 max_num_values = old_num_values + repl_num_values;
2924 if (max_num_values == 0) {
2925 /* There is nothing to do! */
2929 ret = get_parsed_dns(module, tmp_ctx, el, &dns, ldap_oid, parent);
2930 if (ret != LDB_SUCCESS) {
2931 talloc_free(tmp_ctx);
2935 ret = check_parsed_dn_duplicates(module, el, dns);
2936 if (ret != LDB_SUCCESS) {
2937 talloc_free(tmp_ctx);
2941 ret = get_parsed_dns(module, tmp_ctx, old_el, &old_dns,
2943 if (ret != LDB_SUCCESS) {
2944 talloc_free(tmp_ctx);
2948 ret = replmd_check_upgrade_links(ldb, old_dns, old_num_values,
2950 if (ret != LDB_SUCCESS) {
2951 talloc_free(tmp_ctx);
2955 new_values = talloc_array(tmp_ctx, struct ldb_val, max_num_values);
2956 if (new_values == NULL) {
2957 ldb_module_oom(module);
2958 talloc_free(tmp_ctx);
2959 return LDB_ERR_OPERATIONS_ERROR;
2964 for (i = 0; i < max_num_values; i++) {
2966 struct parsed_dn *old_p, *new_p;
2967 if (old_i < old_num_values && new_i < repl_num_values) {
2968 old_p = &old_dns[old_i];
2969 new_p = &dns[new_i];
2970 cmp = parsed_dn_compare(old_p, new_p);
2971 } else if (old_i < old_num_values) {
2972 /* the new list is empty, read the old list */
2973 old_p = &old_dns[old_i];
2976 } else if (new_i < repl_num_values) {
2977 /* the old list is empty, read new list */
2979 new_p = &dns[new_i];
2987 * An old ones that come before the next replacement
2988 * (if any). We mark it as deleted and add it to the
2991 uint32_t rmd_flags = dsdb_dn_rmd_flags(old_p->dsdb_dn->dn);
2992 if ((rmd_flags & DSDB_RMD_FLAG_DELETED) == 0) {
2993 ret = replmd_update_la_val(new_values, old_p->v,
2999 if (ret != LDB_SUCCESS) {
3000 talloc_free(tmp_ctx);
3004 ret = replmd_add_backlink(module, replmd_private,
3007 &old_p->guid, false,
3010 if (ret != LDB_SUCCESS) {
3011 talloc_free(tmp_ctx);
3015 new_values[i] = *old_p->v;
3017 } else if (cmp == 0) {
3019 * We are overwriting one. If it was previously
3020 * deleted, we need to add a backlink.
3022 * Note that if any RMD_FLAGs in an extended new DN
3027 ret = replmd_update_la_val(new_values, old_p->v,
3033 if (ret != LDB_SUCCESS) {
3034 talloc_free(tmp_ctx);
3038 rmd_flags = dsdb_dn_rmd_flags(old_p->dsdb_dn->dn);
3039 if ((rmd_flags & DSDB_RMD_FLAG_DELETED) != 0) {
3040 ret = replmd_add_backlink(module, replmd_private,
3046 if (ret != LDB_SUCCESS) {
3047 talloc_free(tmp_ctx);
3052 new_values[i] = *old_p->v;
3057 * Replacements that don't match an existing one. We
3058 * just add them to the final list.
3060 ret = replmd_build_la_val(new_values,
3065 if (ret != LDB_SUCCESS) {
3066 talloc_free(tmp_ctx);
3069 ret = replmd_add_backlink(module, replmd_private,
3075 if (ret != LDB_SUCCESS) {
3076 talloc_free(tmp_ctx);
3079 new_values[i] = *new_p->v;
3083 if (old_el != NULL) {
3084 talloc_steal(msg->elements, old_el->values);
3086 el->values = talloc_steal(msg->elements, new_values);
3088 talloc_free(tmp_ctx);
3090 el->flags = LDB_FLAG_MOD_REPLACE;
3097 handle linked attributes in modify requests
3099 static int replmd_modify_handle_linked_attribs(struct ldb_module *module,
3100 struct replmd_private *replmd_private,
3101 struct ldb_message *msg,
3102 uint64_t seq_num, time_t t,
3103 struct ldb_request *parent)
3105 struct ldb_result *res;
3108 struct ldb_context *ldb = ldb_module_get_ctx(module);
3109 struct ldb_message *old_msg;
3111 const struct dsdb_schema *schema;
3113 if (dsdb_functional_level(ldb) == DS_DOMAIN_FUNCTION_2000) {
3115 * Nothing special is required for modifying or vanishing links
3116 * in fl2000 since they are just strings in a multi-valued
3119 struct ldb_control *ctrl = ldb_request_get_control(parent,
3120 DSDB_CONTROL_REPLMD_VANISH_LINKS);
3122 ctrl->critical = false;
3130 * We should restrict this to the intersection of the list of
3131 * linked attributes in the schema and the list of attributes
3134 * This will help performance a little, as otherwise we have
3135 * to allocate the entire object value-by-value.
3137 ret = dsdb_module_search_dn(module, msg, &res, msg->dn, NULL,
3138 DSDB_FLAG_NEXT_MODULE |
3139 DSDB_SEARCH_SHOW_RECYCLED |
3140 DSDB_SEARCH_REVEAL_INTERNALS |
3141 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT,
3143 if (ret != LDB_SUCCESS) {
3146 schema = dsdb_get_schema(ldb, res);
3148 return LDB_ERR_OPERATIONS_ERROR;
3151 old_msg = res->msgs[0];
3153 for (i=0; i<msg->num_elements; i++) {
3154 struct ldb_message_element *el = &msg->elements[i];
3155 struct ldb_message_element *old_el, *new_el;
3156 unsigned int mod_type = LDB_FLAG_MOD_TYPE(el->flags);
3157 const struct dsdb_attribute *schema_attr
3158 = dsdb_attribute_by_lDAPDisplayName(schema, el->name);
3160 ldb_asprintf_errstring(ldb,
3161 "%s: attribute %s is not a valid attribute in schema",
3162 __FUNCTION__, el->name);
3163 return LDB_ERR_OBJECT_CLASS_VIOLATION;
3165 if (schema_attr->linkID == 0) {
3168 if ((schema_attr->linkID & 1) == 1) {
3169 if (parent && ldb_request_get_control(parent, DSDB_CONTROL_DBCHECK)) {
3172 /* Odd is for the target. Illegal to modify */
3173 ldb_asprintf_errstring(ldb,
3174 "attribute %s must not be modified directly, it is a linked attribute", el->name);
3175 return LDB_ERR_UNWILLING_TO_PERFORM;
3177 old_el = ldb_msg_find_element(old_msg, el->name);
3179 case LDB_FLAG_MOD_REPLACE:
3180 ret = replmd_modify_la_replace(module, replmd_private,
3181 schema, msg, el, old_el,
3182 schema_attr, seq_num, t,
3186 case LDB_FLAG_MOD_DELETE:
3187 ret = replmd_modify_la_delete(module, replmd_private,
3188 schema, msg, el, old_el,
3189 schema_attr, seq_num, t,
3193 case LDB_FLAG_MOD_ADD:
3194 ret = replmd_modify_la_add(module, replmd_private,
3195 schema, msg, el, old_el,
3196 schema_attr, seq_num, t,
3201 ldb_asprintf_errstring(ldb,
3202 "invalid flags 0x%x for %s linked attribute",
3203 el->flags, el->name);
3204 return LDB_ERR_UNWILLING_TO_PERFORM;
3206 if (dsdb_check_single_valued_link(schema_attr, el) != LDB_SUCCESS) {
3207 ldb_asprintf_errstring(ldb,
3208 "Attribute %s is single valued but more than one value has been supplied",
3210 /* Return codes as found on Windows 2012r2 */
3211 if (mod_type == LDB_FLAG_MOD_REPLACE) {
3212 return LDB_ERR_CONSTRAINT_VIOLATION;
3214 return LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS;
3217 el->flags |= LDB_FLAG_INTERNAL_DISABLE_SINGLE_VALUE_CHECK;
3220 if (ret != LDB_SUCCESS) {
3224 ldb_msg_remove_attr(old_msg, el->name);
3226 ldb_msg_add_empty(old_msg, el->name, 0, &new_el);
3227 new_el->num_values = el->num_values;
3228 new_el->values = talloc_steal(msg->elements, el->values);
3230 /* TODO: this relises a bit too heavily on the exact
3231 behaviour of ldb_msg_find_element and
3232 ldb_msg_remove_element */
3233 old_el = ldb_msg_find_element(msg, el->name);
3235 ldb_msg_remove_element(msg, old_el);
3245 static int send_rodc_referral(struct ldb_request *req,
3246 struct ldb_context *ldb,
3249 char *referral = NULL;
3250 struct loadparm_context *lp_ctx = NULL;
3251 struct ldb_dn *fsmo_role_dn = NULL;
3252 struct ldb_dn *role_owner_dn = NULL;
3253 const char *domain = NULL;
3256 lp_ctx = talloc_get_type(ldb_get_opaque(ldb, "loadparm"),
3257 struct loadparm_context);
3259 werr = dsdb_get_fsmo_role_info(req, ldb, DREPL_PDC_MASTER,
3260 &fsmo_role_dn, &role_owner_dn);
3262 if (W_ERROR_IS_OK(werr)) {
3263 struct ldb_dn *server_dn = ldb_dn_copy(req, role_owner_dn);
3264 if (server_dn != NULL) {
3265 ldb_dn_remove_child_components(server_dn, 1);
3266 domain = samdb_dn_to_dnshostname(ldb, req,
3271 if (domain == NULL) {
3272 domain = lpcfg_dnsdomain(lp_ctx);
3275 referral = talloc_asprintf(req, "ldap://%s/%s",
3277 ldb_dn_get_linearized(dn));
3278 if (referral == NULL) {
3280 return LDB_ERR_OPERATIONS_ERROR;
3283 return ldb_module_send_referral(req, referral);
3287 static int replmd_modify(struct ldb_module *module, struct ldb_request *req)
3289 struct ldb_context *ldb;
3290 struct replmd_replicated_request *ac;
3291 struct ldb_request *down_req;
3292 struct ldb_message *msg;
3293 time_t t = time(NULL);
3295 bool is_urgent = false, rodc = false;
3296 bool is_schema_nc = false;
3297 unsigned int functional_level;
3298 const struct ldb_message_element *guid_el = NULL;
3299 struct ldb_control *sd_propagation_control;
3300 struct replmd_private *replmd_private =
3301 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
3303 /* do not manipulate our control entries */
3304 if (ldb_dn_is_special(req->op.mod.message->dn)) {
3305 return ldb_next_request(module, req);
3308 sd_propagation_control = ldb_request_get_control(req,
3309 DSDB_CONTROL_SEC_DESC_PROPAGATION_OID);
3310 if (sd_propagation_control != NULL) {
3311 if (req->op.mod.message->num_elements != 1) {
3312 return ldb_module_operr(module);
3314 ret = strcmp(req->op.mod.message->elements[0].name,
3315 "nTSecurityDescriptor");
3317 return ldb_module_operr(module);
3320 return ldb_next_request(module, req);
3323 ldb = ldb_module_get_ctx(module);
3325 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_modify\n");
3327 guid_el = ldb_msg_find_element(req->op.mod.message, "objectGUID");
3328 if (guid_el != NULL) {
3329 ldb_set_errstring(ldb,
3330 "replmd_modify: it's not allowed to change the objectGUID!");
3331 return LDB_ERR_CONSTRAINT_VIOLATION;
3334 ac = replmd_ctx_init(module, req);
3336 return ldb_module_oom(module);
3339 functional_level = dsdb_functional_level(ldb);
3341 /* we have to copy the message as the caller might have it as a const */
3342 msg = ldb_msg_copy_shallow(ac, req->op.mod.message);
3346 return LDB_ERR_OPERATIONS_ERROR;
3349 ldb_msg_remove_attr(msg, "whenChanged");
3350 ldb_msg_remove_attr(msg, "uSNChanged");
3352 is_schema_nc = ldb_dn_compare_base(replmd_private->schema_dn, msg->dn) == 0;
3354 ret = replmd_update_rpmd(module, ac->schema, req, NULL,
3355 msg, &ac->seq_num, t, is_schema_nc,
3357 if (rodc && (ret == LDB_ERR_REFERRAL)) {
3358 ret = send_rodc_referral(req, ldb, msg->dn);
3364 if (ret != LDB_SUCCESS) {
3369 ret = replmd_modify_handle_linked_attribs(module, replmd_private,
3370 msg, ac->seq_num, t, req);
3371 if (ret != LDB_SUCCESS) {
3377 * - replace the old object with the newly constructed one
3380 ac->is_urgent = is_urgent;
3382 ret = ldb_build_mod_req(&down_req, ldb, ac,
3385 ac, replmd_op_callback,
3387 LDB_REQ_SET_LOCATION(down_req);
3388 if (ret != LDB_SUCCESS) {
3393 /* current partition control is needed by "replmd_op_callback" */
3394 if (ldb_request_get_control(req, DSDB_CONTROL_CURRENT_PARTITION_OID) == NULL) {
3395 ret = ldb_request_add_control(down_req,
3396 DSDB_CONTROL_CURRENT_PARTITION_OID,
3398 if (ret != LDB_SUCCESS) {
3404 /* If we are in functional level 2000, then
3405 * replmd_modify_handle_linked_attribs will have done
3407 if (functional_level == DS_DOMAIN_FUNCTION_2000) {
3408 ret = ldb_request_add_control(down_req, DSDB_CONTROL_APPLY_LINKS, false, NULL);
3409 if (ret != LDB_SUCCESS) {
3415 talloc_steal(down_req, msg);
3417 /* we only change whenChanged and uSNChanged if the seq_num
3419 if (ac->seq_num != 0) {
3420 ret = add_time_element(msg, "whenChanged", t);
3421 if (ret != LDB_SUCCESS) {
3427 ret = add_uint64_element(ldb, msg, "uSNChanged", ac->seq_num);
3428 if (ret != LDB_SUCCESS) {
3435 /* go on with the call chain */
3436 return ldb_next_request(module, down_req);
3439 static int replmd_rename_callback(struct ldb_request *req, struct ldb_reply *ares);
3442 handle a rename request
3444 On a rename we need to do an extra ldb_modify which sets the
3445 whenChanged and uSNChanged attributes. We do this in a callback after the success.
3447 static int replmd_rename(struct ldb_module *module, struct ldb_request *req)
3449 struct ldb_context *ldb;
3450 struct replmd_replicated_request *ac;
3452 struct ldb_request *down_req;
3454 /* do not manipulate our control entries */
3455 if (ldb_dn_is_special(req->op.mod.message->dn)) {
3456 return ldb_next_request(module, req);
3459 ldb = ldb_module_get_ctx(module);
3461 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_rename\n");
3463 ac = replmd_ctx_init(module, req);
3465 return ldb_module_oom(module);
3468 ret = ldb_build_rename_req(&down_req, ldb, ac,
3469 ac->req->op.rename.olddn,
3470 ac->req->op.rename.newdn,
3472 ac, replmd_rename_callback,
3474 LDB_REQ_SET_LOCATION(down_req);
3475 if (ret != LDB_SUCCESS) {
3480 /* go on with the call chain */
3481 return ldb_next_request(module, down_req);
3484 /* After the rename is compleated, update the whenchanged etc */
3485 static int replmd_rename_callback(struct ldb_request *req, struct ldb_reply *ares)
3487 struct ldb_context *ldb;
3488 struct ldb_request *down_req;
3489 struct ldb_message *msg;
3490 const struct dsdb_attribute *rdn_attr;
3491 const char *rdn_name;
3492 const struct ldb_val *rdn_val;
3493 const char *attrs[5] = { NULL, };
3494 time_t t = time(NULL);
3496 bool is_urgent = false, rodc = false;
3498 struct replmd_replicated_request *ac =
3499 talloc_get_type(req->context, struct replmd_replicated_request);
3500 struct replmd_private *replmd_private =
3501 talloc_get_type(ldb_module_get_private(ac->module),
3502 struct replmd_private);
3504 ldb = ldb_module_get_ctx(ac->module);
3506 if (ares->error != LDB_SUCCESS) {
3507 return ldb_module_done(ac->req, ares->controls,
3508 ares->response, ares->error);
3511 if (ares->type != LDB_REPLY_DONE) {
3512 ldb_set_errstring(ldb,
3513 "invalid ldb_reply_type in callback");
3515 return ldb_module_done(ac->req, NULL, NULL,
3516 LDB_ERR_OPERATIONS_ERROR);
3520 * - replace the old object with the newly constructed one
3523 msg = ldb_msg_new(ac);
3526 return LDB_ERR_OPERATIONS_ERROR;
3529 msg->dn = ac->req->op.rename.newdn;
3531 is_schema_nc = ldb_dn_compare_base(replmd_private->schema_dn, msg->dn) == 0;
3533 rdn_name = ldb_dn_get_rdn_name(msg->dn);
3534 if (rdn_name == NULL) {
3536 return ldb_module_done(ac->req, NULL, NULL,
3540 /* normalize the rdn attribute name */
3541 rdn_attr = dsdb_attribute_by_lDAPDisplayName(ac->schema, rdn_name);
3542 if (rdn_attr == NULL) {
3544 return ldb_module_done(ac->req, NULL, NULL,
3547 rdn_name = rdn_attr->lDAPDisplayName;
3549 rdn_val = ldb_dn_get_rdn_val(msg->dn);
3550 if (rdn_val == NULL) {
3552 return ldb_module_done(ac->req, NULL, NULL,
3556 if (ldb_msg_add_empty(msg, rdn_name, LDB_FLAG_MOD_REPLACE, NULL) != 0) {
3558 return ldb_module_done(ac->req, NULL, NULL,
3561 if (ldb_msg_add_value(msg, rdn_name, rdn_val, NULL) != 0) {
3563 return ldb_module_done(ac->req, NULL, NULL,
3566 if (ldb_msg_add_empty(msg, "name", LDB_FLAG_MOD_REPLACE, NULL) != 0) {
3568 return ldb_module_done(ac->req, NULL, NULL,
3571 if (ldb_msg_add_value(msg, "name", rdn_val, NULL) != 0) {
3573 return ldb_module_done(ac->req, NULL, NULL,
3578 * here we let replmd_update_rpmd() only search for
3579 * the existing "replPropertyMetaData" and rdn_name attributes.
3581 * We do not want the existing "name" attribute as
3582 * the "name" attribute needs to get the version
3583 * updated on rename even if the rdn value hasn't changed.
3585 * This is the diff of the meta data, for a moved user
3586 * on a w2k8r2 server:
3589 * -dn: CN=sdf df,CN=Users,DC=bla,DC=base
3590 * +dn: CN=sdf df,OU=TestOU,DC=bla,DC=base
3591 * replPropertyMetaData: NDR: struct replPropertyMetaDataBlob
3592 * version : 0x00000001 (1)
3593 * reserved : 0x00000000 (0)
3594 * @@ -66,11 +66,11 @@ replPropertyMetaData: NDR: struct re
3595 * local_usn : 0x00000000000037a5 (14245)
3596 * array: struct replPropertyMetaData1
3597 * attid : DRSUAPI_ATTID_name (0x90001)
3598 * - version : 0x00000001 (1)
3599 * - originating_change_time : Wed Feb 9 17:20:49 2011 CET
3600 * + version : 0x00000002 (2)
3601 * + originating_change_time : Wed Apr 6 15:21:01 2011 CEST
3602 * originating_invocation_id: 0d36ca05-5507-4e62-aca3-354bab0d39e1
3603 * - originating_usn : 0x00000000000037a5 (14245)
3604 * - local_usn : 0x00000000000037a5 (14245)
3605 * + originating_usn : 0x0000000000003834 (14388)
3606 * + local_usn : 0x0000000000003834 (14388)
3607 * array: struct replPropertyMetaData1
3608 * attid : DRSUAPI_ATTID_userAccountControl (0x90008)
3609 * version : 0x00000004 (4)
3611 attrs[0] = "replPropertyMetaData";
3612 attrs[1] = "objectClass";
3613 attrs[2] = "instanceType";
3614 attrs[3] = rdn_name;
3617 ret = replmd_update_rpmd(ac->module, ac->schema, req, attrs,
3618 msg, &ac->seq_num, t,
3619 is_schema_nc, &is_urgent, &rodc);
3620 if (rodc && (ret == LDB_ERR_REFERRAL)) {
3621 ret = send_rodc_referral(req, ldb, ac->req->op.rename.olddn);
3623 return ldb_module_done(req, NULL, NULL, ret);
3626 if (ret != LDB_SUCCESS) {
3628 return ldb_module_done(ac->req, NULL, NULL, ret);
3631 if (ac->seq_num == 0) {
3633 return ldb_module_done(ac->req, NULL, NULL,
3635 "internal error seq_num == 0"));
3637 ac->is_urgent = is_urgent;
3639 ret = ldb_build_mod_req(&down_req, ldb, ac,
3642 ac, replmd_op_callback,
3644 LDB_REQ_SET_LOCATION(down_req);
3645 if (ret != LDB_SUCCESS) {
3650 /* current partition control is needed by "replmd_op_callback" */
3651 if (ldb_request_get_control(req, DSDB_CONTROL_CURRENT_PARTITION_OID) == NULL) {
3652 ret = ldb_request_add_control(down_req,
3653 DSDB_CONTROL_CURRENT_PARTITION_OID,
3655 if (ret != LDB_SUCCESS) {
3661 talloc_steal(down_req, msg);
3663 ret = add_time_element(msg, "whenChanged", t);
3664 if (ret != LDB_SUCCESS) {
3670 ret = add_uint64_element(ldb, msg, "uSNChanged", ac->seq_num);
3671 if (ret != LDB_SUCCESS) {
3677 /* go on with the call chain - do the modify after the rename */
3678 return ldb_next_request(ac->module, down_req);
3682 * remove links from objects that point at this object when an object
3683 * is deleted. We remove it from the NEXT module per MS-DRSR 5.160
3684 * RemoveObj which states that link removal due to the object being
3685 * deleted is NOT an originating update - they just go away!
3688 static int replmd_delete_remove_link(struct ldb_module *module,
3689 const struct dsdb_schema *schema,
3690 struct replmd_private *replmd_private,
3693 struct ldb_message_element *el,
3694 const struct dsdb_attribute *sa,
3695 struct ldb_request *parent)
3698 TALLOC_CTX *tmp_ctx = talloc_new(module);
3699 struct ldb_context *ldb = ldb_module_get_ctx(module);
3701 for (i=0; i<el->num_values; i++) {
3702 struct dsdb_dn *dsdb_dn;
3704 struct ldb_message *msg;
3705 const struct dsdb_attribute *target_attr;
3706 struct ldb_message_element *el2;
3708 struct ldb_val dn_val;
3709 uint32_t dsdb_flags = 0;
3710 const char *attrs[] = { NULL, NULL };
3711 struct ldb_result *link_res;
3712 struct ldb_message *link_msg;
3713 struct ldb_message_element *link_el;
3714 struct parsed_dn *link_dns;
3715 struct parsed_dn *p = NULL, *unused = NULL;
3717 if (dsdb_dn_is_deleted_val(&el->values[i])) {
3721 dsdb_dn = dsdb_dn_parse(tmp_ctx, ldb, &el->values[i], sa->syntax->ldap_oid);
3723 talloc_free(tmp_ctx);
3724 return LDB_ERR_OPERATIONS_ERROR;
3727 /* remove the link */
3728 msg = ldb_msg_new(tmp_ctx);
3730 ldb_module_oom(module);
3731 talloc_free(tmp_ctx);
3732 return LDB_ERR_OPERATIONS_ERROR;
3736 msg->dn = dsdb_dn->dn;
3738 target_attr = dsdb_attribute_by_linkID(schema, sa->linkID ^ 1);
3739 if (target_attr == NULL) {
3742 attrs[0] = target_attr->lDAPDisplayName;
3744 ret = ldb_msg_add_empty(msg, target_attr->lDAPDisplayName,
3745 LDB_FLAG_MOD_DELETE, &el2);
3746 if (ret != LDB_SUCCESS) {
3747 ldb_module_oom(module);
3748 talloc_free(tmp_ctx);
3749 return LDB_ERR_OPERATIONS_ERROR;
3752 ret = dsdb_module_search_dn(module, tmp_ctx, &link_res,
3754 DSDB_FLAG_NEXT_MODULE |
3755 DSDB_SEARCH_SHOW_EXTENDED_DN,
3758 if (ret != LDB_SUCCESS) {
3759 talloc_free(tmp_ctx);
3763 link_msg = link_res->msgs[0];
3764 link_el = ldb_msg_find_element(link_msg,
3765 target_attr->lDAPDisplayName);
3766 if (link_el == NULL) {
3767 talloc_free(tmp_ctx);
3768 return LDB_ERR_NO_SUCH_ATTRIBUTE;
3772 * This call 'upgrades' the links in link_dns, but we
3773 * do not commit the result back into the database, so
3774 * this is safe to call in FL2000 or on databases that
3775 * have been run at that level in the past.
3777 ret = get_parsed_dns_trusted(module, replmd_private, tmp_ctx,
3779 target_attr->syntax->ldap_oid, parent);
3780 if (ret != LDB_SUCCESS) {
3781 talloc_free(tmp_ctx);
3785 ret = parsed_dn_find(ldb, link_dns, link_el->num_values,
3789 target_attr->syntax->ldap_oid, false);
3790 if (ret != LDB_SUCCESS) {
3791 talloc_free(tmp_ctx);
3796 ldb_asprintf_errstring(ldb_module_get_ctx(module),
3797 "Failed to find forward link on %s "
3798 "as %s to remove backlink %s on %s",
3799 ldb_dn_get_linearized(msg->dn),
3800 target_attr->lDAPDisplayName,
3801 sa->lDAPDisplayName,
3802 ldb_dn_get_linearized(dn));
3803 talloc_free(tmp_ctx);
3804 return LDB_ERR_NO_SUCH_ATTRIBUTE;
3808 /* This needs to get the Binary DN, by first searching */
3809 dn_str = dsdb_dn_get_linearized(tmp_ctx,
3812 dn_val = data_blob_string_const(dn_str);
3813 el2->values = &dn_val;
3814 el2->num_values = 1;
3817 * Ensure that we tell the modification to vanish any linked
3818 * attributes (not simply mark them as isDeleted = TRUE)
3820 dsdb_flags |= DSDB_REPLMD_VANISH_LINKS;
3822 ret = dsdb_module_modify(module, msg, dsdb_flags|DSDB_FLAG_OWN_MODULE, parent);
3823 if (ret != LDB_SUCCESS) {
3824 talloc_free(tmp_ctx);
3828 talloc_free(tmp_ctx);
3834 handle update of replication meta data for deletion of objects
3836 This also handles the mapping of delete to a rename operation
3837 to allow deletes to be replicated.
3839 It also handles the incoming deleted objects, to ensure they are
3840 fully deleted here. In that case re_delete is true, and we do not
3841 use this as a signal to change the deleted state, just reinforce it.
3844 static int replmd_delete_internals(struct ldb_module *module, struct ldb_request *req, bool re_delete)
3846 int ret = LDB_ERR_OTHER;
3847 bool retb, disallow_move_on_delete;
3848 struct ldb_dn *old_dn, *new_dn;
3849 const char *rdn_name;
3850 const struct ldb_val *rdn_value, *new_rdn_value;
3852 struct ldb_context *ldb = ldb_module_get_ctx(module);
3853 const struct dsdb_schema *schema;
3854 struct ldb_message *msg, *old_msg;
3855 struct ldb_message_element *el;
3856 TALLOC_CTX *tmp_ctx;
3857 struct ldb_result *res, *parent_res;
3858 static const char * const preserved_attrs[] = {
3859 /* yes, this really is a hard coded list. See MS-ADTS
3860 section 3.1.1.5.5.1.1 */
3863 "dNReferenceUpdate",
3874 "msDS-LastKnownRDN",
3880 "distinguishedName",
3884 "proxiedObjectName",
3886 "nTSecurityDescriptor",
3887 "replPropertyMetaData",
3889 "securityIdentifier",
3897 "userAccountControl",
3904 static const char * const all_attrs[] = {
3905 DSDB_SECRET_ATTRIBUTES,
3909 unsigned int i, el_count = 0;
3910 uint32_t dsdb_flags = 0;
3911 struct replmd_private *replmd_private;
3912 enum deletion_state deletion_state, next_deletion_state;
3914 if (ldb_dn_is_special(req->op.del.dn)) {
3915 return ldb_next_request(module, req);
3919 * We have to allow dbcheck to remove an object that
3920 * is beyond repair, and to do so totally. This could
3921 * mean we we can get a partial object from the other
3922 * DC, causing havoc, so dbcheck suggests
3923 * re-replication first. dbcheck sets both DBCHECK
3924 * and RELAX in this situation.
3926 if (ldb_request_get_control(req, LDB_CONTROL_RELAX_OID)
3927 && ldb_request_get_control(req, DSDB_CONTROL_DBCHECK)) {
3928 /* really, really remove it */
3929 return ldb_next_request(module, req);
3932 tmp_ctx = talloc_new(ldb);
3935 return LDB_ERR_OPERATIONS_ERROR;
3938 schema = dsdb_get_schema(ldb, tmp_ctx);
3940 talloc_free(tmp_ctx);
3941 return LDB_ERR_OPERATIONS_ERROR;
3944 old_dn = ldb_dn_copy(tmp_ctx, req->op.del.dn);
3946 /* we need the complete msg off disk, so we can work out which
3947 attributes need to be removed */
3948 ret = dsdb_module_search_dn(module, tmp_ctx, &res, old_dn, all_attrs,
3949 DSDB_FLAG_NEXT_MODULE |
3950 DSDB_SEARCH_SHOW_RECYCLED |
3951 DSDB_SEARCH_REVEAL_INTERNALS |
3952 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT, req);
3953 if (ret != LDB_SUCCESS) {
3954 ldb_asprintf_errstring(ldb_module_get_ctx(module),
3955 "repmd_delete: Failed to %s %s, because we failed to find it: %s",
3956 re_delete ? "re-delete" : "delete",
3957 ldb_dn_get_linearized(old_dn),
3958 ldb_errstring(ldb_module_get_ctx(module)));
3959 talloc_free(tmp_ctx);
3962 old_msg = res->msgs[0];
3964 replmd_deletion_state(module, old_msg,
3966 &next_deletion_state);
3968 /* This supports us noticing an incoming isDeleted and acting on it */
3970 SMB_ASSERT(deletion_state > OBJECT_NOT_DELETED);
3971 next_deletion_state = deletion_state;
3974 if (next_deletion_state == OBJECT_REMOVED) {
3976 * We have to prevent objects being deleted, even if
3977 * the administrator really wants them gone, as
3978 * without the tombstone, we can get a partial object
3979 * from the other DC, causing havoc.
3981 * The only other valid case is when the 180 day
3982 * timeout has expired, when relax is specified.
3984 if (ldb_request_get_control(req, LDB_CONTROL_RELAX_OID)) {
3985 /* it is already deleted - really remove it this time */
3986 talloc_free(tmp_ctx);
3987 return ldb_next_request(module, req);
3990 ldb_asprintf_errstring(ldb, "Refusing to delete tombstone object %s. "
3991 "This check is to prevent corruption of the replicated state.",
3992 ldb_dn_get_linearized(old_msg->dn));
3993 return LDB_ERR_UNWILLING_TO_PERFORM;
3996 rdn_name = ldb_dn_get_rdn_name(old_dn);
3997 rdn_value = ldb_dn_get_rdn_val(old_dn);
3998 if ((rdn_name == NULL) || (rdn_value == NULL)) {
3999 talloc_free(tmp_ctx);
4000 return ldb_operr(ldb);
4003 msg = ldb_msg_new(tmp_ctx);
4005 ldb_module_oom(module);
4006 talloc_free(tmp_ctx);
4007 return LDB_ERR_OPERATIONS_ERROR;
4012 /* consider the SYSTEM_FLAG_DISALLOW_MOVE_ON_DELETE flag */
4013 disallow_move_on_delete =
4014 (ldb_msg_find_attr_as_int(old_msg, "systemFlags", 0)
4015 & SYSTEM_FLAG_DISALLOW_MOVE_ON_DELETE);
4017 /* work out where we will be renaming this object to */
4018 if (!disallow_move_on_delete) {
4019 struct ldb_dn *deleted_objects_dn;
4020 ret = dsdb_get_deleted_objects_dn(ldb, tmp_ctx, old_dn,
4021 &deleted_objects_dn);
4024 * We should not move objects if we can't find the
4025 * deleted objects DN. Not moving (or otherwise
4026 * harming) the Deleted Objects DN itself is handled
4029 if (re_delete && (ret != LDB_SUCCESS)) {
4030 new_dn = ldb_dn_get_parent(tmp_ctx, old_dn);
4031 if (new_dn == NULL) {
4032 ldb_module_oom(module);
4033 talloc_free(tmp_ctx);
4034 return LDB_ERR_OPERATIONS_ERROR;
4036 } else if (ret != LDB_SUCCESS) {
4037 /* this is probably an attempted delete on a partition
4038 * that doesn't allow delete operations, such as the
4039 * schema partition */
4040 ldb_asprintf_errstring(ldb, "No Deleted Objects container for DN %s",
4041 ldb_dn_get_linearized(old_dn));
4042 talloc_free(tmp_ctx);
4043 return LDB_ERR_UNWILLING_TO_PERFORM;
4045 new_dn = deleted_objects_dn;
4048 new_dn = ldb_dn_get_parent(tmp_ctx, old_dn);
4049 if (new_dn == NULL) {
4050 ldb_module_oom(module);
4051 talloc_free(tmp_ctx);
4052 return LDB_ERR_OPERATIONS_ERROR;
4056 /* get the objects GUID from the search we just did */
4057 guid = samdb_result_guid(old_msg, "objectGUID");
4059 if (deletion_state == OBJECT_NOT_DELETED) {
4060 /* Add a formatted child */
4061 retb = ldb_dn_add_child_fmt(new_dn, "%s=%s\\0ADEL:%s",
4063 ldb_dn_escape_value(tmp_ctx, *rdn_value),
4064 GUID_string(tmp_ctx, &guid));
4066 ldb_asprintf_errstring(ldb, __location__
4067 ": Unable to add a formatted child to dn: %s",
4068 ldb_dn_get_linearized(new_dn));
4069 talloc_free(tmp_ctx);
4070 return LDB_ERR_OPERATIONS_ERROR;
4073 ret = ldb_msg_add_string(msg, "isDeleted", "TRUE");
4074 if (ret != LDB_SUCCESS) {
4075 ldb_asprintf_errstring(ldb, __location__
4076 ": Failed to add isDeleted string to the msg");
4077 talloc_free(tmp_ctx);
4080 msg->elements[el_count++].flags = LDB_FLAG_MOD_REPLACE;
4083 * No matter what has happened with other renames etc, try again to
4084 * get this to be under the deleted DN. See MS-DRSR 5.160 RemoveObj
4087 struct ldb_dn *rdn = ldb_dn_copy(tmp_ctx, old_dn);
4088 retb = ldb_dn_remove_base_components(rdn, ldb_dn_get_comp_num(rdn) - 1);
4090 ldb_asprintf_errstring(ldb, __location__
4091 ": Unable to add a prepare rdn of %s",
4092 ldb_dn_get_linearized(rdn));
4093 talloc_free(tmp_ctx);
4094 return LDB_ERR_OPERATIONS_ERROR;
4096 SMB_ASSERT(ldb_dn_get_comp_num(rdn) == 1);
4098 retb = ldb_dn_add_child(new_dn, rdn);
4100 ldb_asprintf_errstring(ldb, __location__
4101 ": Unable to add rdn %s to base dn: %s",
4102 ldb_dn_get_linearized(rdn),
4103 ldb_dn_get_linearized(new_dn));
4104 talloc_free(tmp_ctx);
4105 return LDB_ERR_OPERATIONS_ERROR;
4110 now we need to modify the object in the following ways:
4112 - add isDeleted=TRUE
4113 - update rDN and name, with new rDN
4114 - remove linked attributes
4115 - remove objectCategory and sAMAccountType
4116 - remove attribs not on the preserved list
4117 - preserved if in above list, or is rDN
4118 - remove all linked attribs from this object
4119 - remove all links from other objects to this object
4120 - add lastKnownParent
4121 - update replPropertyMetaData?
4123 see MS-ADTS "Tombstone Requirements" section 3.1.1.5.5.1.1
4126 if (deletion_state == OBJECT_NOT_DELETED) {
4127 struct ldb_dn *parent_dn = ldb_dn_get_parent(tmp_ctx, old_dn);
4128 char *parent_dn_str = NULL;
4130 /* we need the storage form of the parent GUID */
4131 ret = dsdb_module_search_dn(module, tmp_ctx, &parent_res,
4133 DSDB_FLAG_NEXT_MODULE |
4134 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT |
4135 DSDB_SEARCH_REVEAL_INTERNALS|
4136 DSDB_SEARCH_SHOW_RECYCLED, req);
4137 if (ret != LDB_SUCCESS) {
4138 ldb_asprintf_errstring(ldb_module_get_ctx(module),
4139 "repmd_delete: Failed to %s %s, "
4140 "because we failed to find it's parent (%s): %s",
4141 re_delete ? "re-delete" : "delete",
4142 ldb_dn_get_linearized(old_dn),
4143 ldb_dn_get_linearized(parent_dn),
4144 ldb_errstring(ldb_module_get_ctx(module)));
4145 talloc_free(tmp_ctx);
4150 * Now we can use the DB version,
4151 * it will have the extended DN info in it
4153 parent_dn = parent_res->msgs[0]->dn;
4154 parent_dn_str = ldb_dn_get_extended_linearized(tmp_ctx,
4157 if (parent_dn_str == NULL) {
4158 talloc_free(tmp_ctx);
4159 return ldb_module_oom(module);
4162 ret = ldb_msg_add_steal_string(msg, "lastKnownParent",
4164 if (ret != LDB_SUCCESS) {
4165 ldb_asprintf_errstring(ldb, __location__
4166 ": Failed to add lastKnownParent "
4167 "string when deleting %s",
4168 ldb_dn_get_linearized(old_dn));
4169 talloc_free(tmp_ctx);
4172 msg->elements[el_count++].flags = LDB_FLAG_MOD_REPLACE;
4174 if (next_deletion_state == OBJECT_DELETED) {
4175 ret = ldb_msg_add_value(msg, "msDS-LastKnownRDN", rdn_value, NULL);
4176 if (ret != LDB_SUCCESS) {
4177 ldb_asprintf_errstring(ldb, __location__
4178 ": Failed to add msDS-LastKnownRDN "
4179 "string when deleting %s",
4180 ldb_dn_get_linearized(old_dn));
4181 talloc_free(tmp_ctx);
4184 msg->elements[el_count++].flags = LDB_FLAG_MOD_ADD;
4188 switch (next_deletion_state) {
4190 case OBJECT_RECYCLED:
4191 case OBJECT_TOMBSTONE:
4194 * MS-ADTS 3.1.1.5.5.1.1 Tombstone Requirements
4195 * describes what must be removed from a tombstone
4198 * MS-ADTS 3.1.1.5.5.1.3 Recycled-Object Requirements
4199 * describes what must be removed from a recycled
4205 * we also mark it as recycled, meaning this object can't be
4206 * recovered (we are stripping its attributes).
4207 * This is done only if we have this schema object of course ...
4208 * This behavior is identical to the one of Windows 2008R2 which
4209 * always set the isRecycled attribute, even if the recycle-bin is
4210 * not activated and what ever the forest level is.
4212 if (dsdb_attribute_by_lDAPDisplayName(schema, "isRecycled") != NULL) {
4213 ret = ldb_msg_add_string(msg, "isRecycled", "TRUE");
4214 if (ret != LDB_SUCCESS) {
4215 DEBUG(0,(__location__ ": Failed to add isRecycled string to the msg\n"));
4216 ldb_module_oom(module);
4217 talloc_free(tmp_ctx);
4220 msg->elements[el_count++].flags = LDB_FLAG_MOD_REPLACE;
4223 replmd_private = talloc_get_type(ldb_module_get_private(module),
4224 struct replmd_private);
4225 /* work out which of the old attributes we will be removing */
4226 for (i=0; i<old_msg->num_elements; i++) {
4227 const struct dsdb_attribute *sa;
4228 el = &old_msg->elements[i];
4229 sa = dsdb_attribute_by_lDAPDisplayName(schema, el->name);
4231 talloc_free(tmp_ctx);
4232 return LDB_ERR_OPERATIONS_ERROR;
4234 if (ldb_attr_cmp(el->name, rdn_name) == 0) {
4235 /* don't remove the rDN */
4238 if (sa->linkID & 1) {
4240 we have a backlink in this object
4241 that needs to be removed. We're not
4242 allowed to remove it directly
4243 however, so we instead setup a
4244 modify to delete the corresponding
4247 ret = replmd_delete_remove_link(module, schema,
4251 if (ret != LDB_SUCCESS) {
4252 const char *old_dn_str
4253 = ldb_dn_get_linearized(old_dn);
4254 ldb_asprintf_errstring(ldb,
4256 ": Failed to remove backlink of "
4257 "%s when deleting %s: %s",
4260 ldb_errstring(ldb));
4261 talloc_free(tmp_ctx);
4262 return LDB_ERR_OPERATIONS_ERROR;
4264 /* now we continue, which means we
4265 won't remove this backlink
4269 } else if (sa->linkID == 0) {
4270 if (ldb_attr_in_list(preserved_attrs, el->name)) {
4273 if (sa->searchFlags & SEARCH_FLAG_PRESERVEONDELETE) {
4278 * Ensure that we tell the modification to vanish any linked
4279 * attributes (not simply mark them as isDeleted = TRUE)
4281 dsdb_flags |= DSDB_REPLMD_VANISH_LINKS;
4283 ret = ldb_msg_add_empty(msg, el->name, LDB_FLAG_MOD_DELETE, &el);
4284 if (ret != LDB_SUCCESS) {
4285 talloc_free(tmp_ctx);
4286 ldb_module_oom(module);
4293 case OBJECT_DELETED:
4295 * MS-ADTS 3.1.1.5.5.1.2 Deleted-Object Requirements
4296 * describes what must be removed from a deleted
4300 ret = ldb_msg_add_empty(msg, "objectCategory", LDB_FLAG_MOD_REPLACE, NULL);
4301 if (ret != LDB_SUCCESS) {
4302 talloc_free(tmp_ctx);
4303 ldb_module_oom(module);
4307 ret = ldb_msg_add_empty(msg, "sAMAccountType", LDB_FLAG_MOD_REPLACE, NULL);
4308 if (ret != LDB_SUCCESS) {
4309 talloc_free(tmp_ctx);
4310 ldb_module_oom(module);
4320 if (deletion_state == OBJECT_NOT_DELETED) {
4321 const struct dsdb_attribute *sa;
4323 /* work out what the new rdn value is, for updating the
4324 rDN and name fields */
4325 new_rdn_value = ldb_dn_get_rdn_val(new_dn);
4326 if (new_rdn_value == NULL) {
4327 talloc_free(tmp_ctx);
4328 return ldb_operr(ldb);
4331 sa = dsdb_attribute_by_lDAPDisplayName(schema, rdn_name);
4333 talloc_free(tmp_ctx);
4334 return LDB_ERR_OPERATIONS_ERROR;
4337 ret = ldb_msg_add_value(msg, sa->lDAPDisplayName, new_rdn_value,
4339 if (ret != LDB_SUCCESS) {
4340 talloc_free(tmp_ctx);
4343 el->flags = LDB_FLAG_MOD_REPLACE;
4345 el = ldb_msg_find_element(old_msg, "name");
4347 ret = ldb_msg_add_value(msg, "name", new_rdn_value, &el);
4348 if (ret != LDB_SUCCESS) {
4349 talloc_free(tmp_ctx);
4352 el->flags = LDB_FLAG_MOD_REPLACE;
4357 * TODO: Per MS-DRSR 5.160 RemoveObj we should remove links directly, not as an originating update!
4362 * No matter what has happned with other renames, try again to
4363 * get this to be under the deleted DN.
4365 if (strcmp(ldb_dn_get_linearized(old_dn), ldb_dn_get_linearized(new_dn)) != 0) {
4366 /* now rename onto the new DN */
4367 ret = dsdb_module_rename(module, old_dn, new_dn, DSDB_FLAG_NEXT_MODULE, req);
4368 if (ret != LDB_SUCCESS){
4369 DEBUG(0,(__location__ ": Failed to rename object from '%s' to '%s' - %s\n",
4370 ldb_dn_get_linearized(old_dn),
4371 ldb_dn_get_linearized(new_dn),
4372 ldb_errstring(ldb)));
4373 talloc_free(tmp_ctx);
4379 ret = dsdb_module_modify(module, msg, dsdb_flags|DSDB_FLAG_OWN_MODULE, req);
4380 if (ret != LDB_SUCCESS) {
4381 ldb_asprintf_errstring(ldb, "replmd_delete: Failed to modify object %s in delete - %s",
4382 ldb_dn_get_linearized(old_dn), ldb_errstring(ldb));
4383 talloc_free(tmp_ctx);
4387 talloc_free(tmp_ctx);
4389 return ldb_module_done(req, NULL, NULL, LDB_SUCCESS);
4392 static int replmd_delete(struct ldb_module *module, struct ldb_request *req)
4394 return replmd_delete_internals(module, req, false);
4398 static int replmd_replicated_request_error(struct replmd_replicated_request *ar, int ret)
4403 static int replmd_replicated_request_werror(struct replmd_replicated_request *ar, WERROR status)
4405 int ret = LDB_ERR_OTHER;
4406 /* TODO: do some error mapping */
4408 /* Let the caller know the full WERROR */
4409 ar->objs->error = status;
4415 static struct replPropertyMetaData1 *
4416 replmd_replPropertyMetaData1_find_attid(struct replPropertyMetaDataBlob *md_blob,
4417 enum drsuapi_DsAttributeId attid)
4420 struct replPropertyMetaDataCtr1 *rpmd_ctr = &md_blob->ctr.ctr1;
4422 for (i = 0; i < rpmd_ctr->count; i++) {
4423 if (rpmd_ctr->array[i].attid == attid) {
4424 return &rpmd_ctr->array[i];
4432 return true if an update is newer than an existing entry
4433 see section 5.11 of MS-ADTS
4435 static bool replmd_update_is_newer(const struct GUID *current_invocation_id,
4436 const struct GUID *update_invocation_id,
4437 uint32_t current_version,
4438 uint32_t update_version,
4439 NTTIME current_change_time,
4440 NTTIME update_change_time)
4442 if (update_version != current_version) {
4443 return update_version > current_version;
4445 if (update_change_time != current_change_time) {
4446 return update_change_time > current_change_time;
4448 return GUID_compare(update_invocation_id, current_invocation_id) > 0;
4451 static bool replmd_replPropertyMetaData1_is_newer(struct replPropertyMetaData1 *cur_m,
4452 struct replPropertyMetaData1 *new_m)
4454 return replmd_update_is_newer(&cur_m->originating_invocation_id,
4455 &new_m->originating_invocation_id,
4458 cur_m->originating_change_time,
4459 new_m->originating_change_time);
4462 static bool replmd_replPropertyMetaData1_new_should_be_taken(uint32_t dsdb_repl_flags,
4463 struct replPropertyMetaData1 *cur_m,
4464 struct replPropertyMetaData1 *new_m)
4469 * If the new replPropertyMetaData entry for this attribute is
4470 * not provided (this happens in the case where we look for
4471 * ATTID_name, but the name was not changed), then the local
4472 * state is clearly still current, as the remote
4473 * server didn't send it due to being older the high watermark
4476 if (new_m == NULL) {
4480 if (dsdb_repl_flags & DSDB_REPL_FLAG_PRIORITISE_INCOMING) {
4482 * if we compare equal then do an
4483 * update. This is used when a client
4484 * asks for a FULL_SYNC, and can be
4485 * used to recover a corrupt
4488 * This call is a bit tricky, what we
4489 * are doing it turning the 'is_newer'
4490 * call into a 'not is older' by
4491 * swapping cur_m and new_m, and negating the
4494 cmp = !replmd_replPropertyMetaData1_is_newer(new_m,
4497 cmp = replmd_replPropertyMetaData1_is_newer(cur_m,
4507 static struct ldb_dn *replmd_conflict_dn(TALLOC_CTX *mem_ctx, struct ldb_dn *dn, struct GUID *guid)
4509 const struct ldb_val *rdn_val;
4510 const char *rdn_name;
4511 struct ldb_dn *new_dn;
4513 rdn_val = ldb_dn_get_rdn_val(dn);
4514 rdn_name = ldb_dn_get_rdn_name(dn);
4515 if (!rdn_val || !rdn_name) {
4519 new_dn = ldb_dn_copy(mem_ctx, dn);
4524 if (!ldb_dn_remove_child_components(new_dn, 1)) {
4528 if (!ldb_dn_add_child_fmt(new_dn, "%s=%s\\0ACNF:%s",
4530 ldb_dn_escape_value(new_dn, *rdn_val),
4531 GUID_string(new_dn, guid))) {
4540 perform a modify operation which sets the rDN and name attributes to
4541 their current values. This has the effect of changing these
4542 attributes to have been last updated by the current DC. This is
4543 needed to ensure that renames performed as part of conflict
4544 resolution are propogated to other DCs
4546 static int replmd_name_modify(struct replmd_replicated_request *ar,
4547 struct ldb_request *req, struct ldb_dn *dn)
4549 struct ldb_message *msg;
4550 const char *rdn_name;
4551 const struct ldb_val *rdn_val;
4552 const struct dsdb_attribute *rdn_attr;
4555 msg = ldb_msg_new(req);
4561 rdn_name = ldb_dn_get_rdn_name(dn);
4562 if (rdn_name == NULL) {
4566 /* normalize the rdn attribute name */
4567 rdn_attr = dsdb_attribute_by_lDAPDisplayName(ar->schema, rdn_name);
4568 if (rdn_attr == NULL) {
4571 rdn_name = rdn_attr->lDAPDisplayName;
4573 rdn_val = ldb_dn_get_rdn_val(dn);
4574 if (rdn_val == NULL) {
4578 if (ldb_msg_add_empty(msg, rdn_name, LDB_FLAG_MOD_REPLACE, NULL) != 0) {
4581 if (ldb_msg_add_value(msg, rdn_name, rdn_val, NULL) != 0) {
4584 if (ldb_msg_add_empty(msg, "name", LDB_FLAG_MOD_REPLACE, NULL) != 0) {
4587 if (ldb_msg_add_value(msg, "name", rdn_val, NULL) != 0) {
4592 * We have to mark this as a replicated update otherwise
4593 * schema_data may reject a rename in the schema partition
4596 ret = dsdb_module_modify(ar->module, msg,
4597 DSDB_FLAG_OWN_MODULE|DSDB_FLAG_REPLICATED_UPDATE,
4599 if (ret != LDB_SUCCESS) {
4600 DEBUG(0,(__location__ ": Failed to modify rDN/name of DN being DRS renamed '%s' - %s",
4601 ldb_dn_get_linearized(dn),
4602 ldb_errstring(ldb_module_get_ctx(ar->module))));
4612 DEBUG(0,(__location__ ": Failed to setup modify rDN/name of DN being DRS renamed '%s'",
4613 ldb_dn_get_linearized(dn)));
4614 return LDB_ERR_OPERATIONS_ERROR;
4619 callback for conflict DN handling where we have renamed the incoming
4620 record. After renaming it, we need to ensure the change of name and
4621 rDN for the incoming record is seen as an originating update by this DC.
4623 This also handles updating lastKnownParent for entries sent to lostAndFound
4625 static int replmd_op_name_modify_callback(struct ldb_request *req, struct ldb_reply *ares)
4627 struct replmd_replicated_request *ar =
4628 talloc_get_type_abort(req->context, struct replmd_replicated_request);
4629 struct ldb_dn *conflict_dn = NULL;
4632 if (ares->error != LDB_SUCCESS) {
4633 /* call the normal callback for everything except success */
4634 return replmd_op_callback(req, ares);
4637 switch (req->operation) {
4639 conflict_dn = req->op.add.message->dn;
4642 conflict_dn = req->op.mod.message->dn;
4645 smb_panic("replmd_op_name_modify_callback called in unknown circumstances");
4648 /* perform a modify of the rDN and name of the record */
4649 ret = replmd_name_modify(ar, req, conflict_dn);
4650 if (ret != LDB_SUCCESS) {
4652 return replmd_op_callback(req, ares);
4655 if (ar->objs->objects[ar->index_current].last_known_parent) {
4656 struct ldb_message *msg = ldb_msg_new(req);
4658 ldb_module_oom(ar->module);
4659 return LDB_ERR_OPERATIONS_ERROR;
4662 msg->dn = req->op.add.message->dn;
4664 ret = ldb_msg_add_steal_string(msg, "lastKnownParent",
4665 ldb_dn_get_extended_linearized(msg, ar->objs->objects[ar->index_current].last_known_parent, 1));
4666 if (ret != LDB_SUCCESS) {
4667 DEBUG(0,(__location__ ": Failed to add lastKnownParent string to the msg\n"));
4668 ldb_module_oom(ar->module);
4671 msg->elements[0].flags = LDB_FLAG_MOD_REPLACE;
4673 ret = dsdb_module_modify(ar->module, msg, DSDB_FLAG_OWN_MODULE, req);
4674 if (ret != LDB_SUCCESS) {
4675 DEBUG(0,(__location__ ": Failed to modify lastKnownParent of lostAndFound DN '%s' - %s",
4676 ldb_dn_get_linearized(msg->dn),
4677 ldb_errstring(ldb_module_get_ctx(ar->module))));
4683 return replmd_op_callback(req, ares);
4687 callback for replmd_replicated_apply_add()
4688 This copes with the creation of conflict records in the case where
4689 the DN exists, but with a different objectGUID
4691 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))
4693 struct ldb_dn *conflict_dn;
4694 struct replmd_replicated_request *ar =
4695 talloc_get_type_abort(req->context, struct replmd_replicated_request);
4696 struct ldb_result *res;
4697 const char *attrs[] = { "replPropertyMetaData", "objectGUID", NULL };
4699 const struct ldb_val *omd_value;
4700 struct replPropertyMetaDataBlob omd, *rmd;
4701 enum ndr_err_code ndr_err;
4702 bool rename_incoming_record, rodc;
4703 struct replPropertyMetaData1 *rmd_name, *omd_name;
4704 struct ldb_message *msg;
4705 struct ldb_request *down_req = NULL;
4707 /* call the normal callback for success */
4708 if (ares->error == LDB_SUCCESS) {
4709 return callback(req, ares);
4713 * we have a conflict, and need to decide if we will keep the
4714 * new record or the old record
4717 msg = ar->objs->objects[ar->index_current].msg;
4718 conflict_dn = msg->dn;
4720 /* For failures other than conflicts, fail the whole operation here */
4721 if (ares->error != LDB_ERR_ENTRY_ALREADY_EXISTS) {
4722 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module), "Failed to locally apply remote add of %s: %s",
4723 ldb_dn_get_linearized(conflict_dn),
4724 ldb_errstring(ldb_module_get_ctx(ar->module)));
4726 return ldb_module_done(ar->req, NULL, NULL,
4727 LDB_ERR_OPERATIONS_ERROR);
4730 ret = samdb_rodc(ldb_module_get_ctx(ar->module), &rodc);
4731 if (ret != LDB_SUCCESS) {
4732 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)));
4733 return ldb_module_done(ar->req, NULL, NULL,
4734 LDB_ERR_OPERATIONS_ERROR);
4740 * We are on an RODC, or were a GC for this
4741 * partition, so we have to fail this until
4742 * someone who owns the partition sorts it
4745 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
4746 "Conflict adding object '%s' from incoming replication as we are read only for the partition. \n"
4747 " - We must fail the operation until a master for this partition resolves the conflict",
4748 ldb_dn_get_linearized(conflict_dn));
4753 * first we need the replPropertyMetaData attribute from the
4754 * local, conflicting record
4756 ret = dsdb_module_search_dn(ar->module, req, &res, conflict_dn,
4758 DSDB_FLAG_NEXT_MODULE |
4759 DSDB_SEARCH_SHOW_DELETED |
4760 DSDB_SEARCH_SHOW_RECYCLED, req);
4761 if (ret != LDB_SUCCESS) {
4762 DEBUG(0,(__location__ ": Unable to find object for conflicting record '%s'\n",
4763 ldb_dn_get_linearized(conflict_dn)));
4767 omd_value = ldb_msg_find_ldb_val(res->msgs[0], "replPropertyMetaData");
4768 if (omd_value == NULL) {
4769 DEBUG(0,(__location__ ": Unable to find replPropertyMetaData for conflicting record '%s'\n",
4770 ldb_dn_get_linearized(conflict_dn)));
4774 ndr_err = ndr_pull_struct_blob(omd_value, res->msgs[0], &omd,
4775 (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
4776 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
4777 DEBUG(0,(__location__ ": Failed to parse old replPropertyMetaData for %s\n",
4778 ldb_dn_get_linearized(conflict_dn)));
4782 rmd = ar->objs->objects[ar->index_current].meta_data;
4785 * we decide which is newer based on the RPMD on the name
4786 * attribute. See [MS-DRSR] ResolveNameConflict.
4788 * We expect omd_name to be present, as this is from a local
4789 * search, but while rmd_name should have been given to us by
4790 * the remote server, if it is missing we just prefer the
4792 * replmd_replPropertyMetaData1_new_should_be_taken()
4794 rmd_name = replmd_replPropertyMetaData1_find_attid(rmd, DRSUAPI_ATTID_name);
4795 omd_name = replmd_replPropertyMetaData1_find_attid(&omd, DRSUAPI_ATTID_name);
4797 DEBUG(0,(__location__ ": Failed to find name attribute in local LDB replPropertyMetaData for %s\n",
4798 ldb_dn_get_linearized(conflict_dn)));
4803 * Should we preserve the current record, and so rename the
4804 * incoming record to be a conflict?
4806 rename_incoming_record
4807 = !replmd_replPropertyMetaData1_new_should_be_taken(ar->objs->dsdb_repl_flags & DSDB_REPL_FLAG_PRIORITISE_INCOMING,
4808 omd_name, rmd_name);
4810 if (rename_incoming_record) {
4812 struct ldb_dn *new_dn;
4814 guid = samdb_result_guid(msg, "objectGUID");
4815 if (GUID_all_zero(&guid)) {
4816 DEBUG(0,(__location__ ": Failed to find objectGUID for conflicting incoming record %s\n",
4817 ldb_dn_get_linearized(conflict_dn)));
4820 new_dn = replmd_conflict_dn(req, conflict_dn, &guid);
4821 if (new_dn == NULL) {
4822 DEBUG(0,(__location__ ": Failed to form conflict DN for %s\n",
4823 ldb_dn_get_linearized(conflict_dn)));
4827 DEBUG(2,(__location__ ": Resolving conflict record via incoming rename '%s' -> '%s'\n",
4828 ldb_dn_get_linearized(conflict_dn), ldb_dn_get_linearized(new_dn)));
4830 /* re-submit the request, but with the new DN */
4831 callback = replmd_op_name_modify_callback;
4834 /* we are renaming the existing record */
4836 struct ldb_dn *new_dn;
4838 guid = samdb_result_guid(res->msgs[0], "objectGUID");
4839 if (GUID_all_zero(&guid)) {
4840 DEBUG(0,(__location__ ": Failed to find objectGUID for existing conflict record %s\n",
4841 ldb_dn_get_linearized(conflict_dn)));
4845 new_dn = replmd_conflict_dn(req, conflict_dn, &guid);
4846 if (new_dn == NULL) {
4847 DEBUG(0,(__location__ ": Failed to form conflict DN for %s\n",
4848 ldb_dn_get_linearized(conflict_dn)));
4852 DEBUG(2,(__location__ ": Resolving conflict record via existing-record rename '%s' -> '%s'\n",
4853 ldb_dn_get_linearized(conflict_dn), ldb_dn_get_linearized(new_dn)));
4855 ret = dsdb_module_rename(ar->module, conflict_dn, new_dn,
4856 DSDB_FLAG_OWN_MODULE, req);
4857 if (ret != LDB_SUCCESS) {
4858 DEBUG(0,(__location__ ": Failed to rename conflict dn '%s' to '%s' - %s\n",
4859 ldb_dn_get_linearized(conflict_dn),
4860 ldb_dn_get_linearized(new_dn),
4861 ldb_errstring(ldb_module_get_ctx(ar->module))));
4866 * now we need to ensure that the rename is seen as an
4867 * originating update. We do that with a modify.
4869 ret = replmd_name_modify(ar, req, new_dn);
4870 if (ret != LDB_SUCCESS) {
4874 DEBUG(2,(__location__ ": With conflicting record renamed, re-apply replicated creation of '%s'\n",
4875 ldb_dn_get_linearized(req->op.add.message->dn)));
4878 ret = ldb_build_add_req(&down_req,
4879 ldb_module_get_ctx(ar->module),
4886 if (ret != LDB_SUCCESS) {
4889 LDB_REQ_SET_LOCATION(down_req);
4891 /* current partition control needed by "repmd_op_callback" */
4892 ret = ldb_request_add_control(down_req,
4893 DSDB_CONTROL_CURRENT_PARTITION_OID,
4895 if (ret != LDB_SUCCESS) {
4896 return replmd_replicated_request_error(ar, ret);
4899 if (ar->objs->dsdb_repl_flags & DSDB_REPL_FLAG_PARTIAL_REPLICA) {
4900 /* this tells the partition module to make it a
4901 partial replica if creating an NC */
4902 ret = ldb_request_add_control(down_req,
4903 DSDB_CONTROL_PARTIAL_REPLICA,
4905 if (ret != LDB_SUCCESS) {
4906 return replmd_replicated_request_error(ar, ret);
4911 * Finally we re-run the add, otherwise the new record won't
4912 * exist, as we are here because of that exact failure!
4914 return ldb_next_request(ar->module, down_req);
4917 /* on failure make the caller get the error. This means
4918 * replication will stop with an error, but there is not much
4921 return ldb_module_done(ar->req, NULL, NULL,
4926 callback for replmd_replicated_apply_add()
4927 This copes with the creation of conflict records in the case where
4928 the DN exists, but with a different objectGUID
4930 static int replmd_op_add_callback(struct ldb_request *req, struct ldb_reply *ares)
4932 struct replmd_replicated_request *ar =
4933 talloc_get_type_abort(req->context, struct replmd_replicated_request);
4935 if (ar->objs->objects[ar->index_current].last_known_parent) {
4936 /* This is like a conflict DN, where we put the object in LostAndFound
4937 see MS-DRSR 4.1.10.6.10 FindBestParentObject */
4938 return replmd_op_possible_conflict_callback(req, ares, replmd_op_name_modify_callback);
4941 return replmd_op_possible_conflict_callback(req, ares, replmd_op_callback);
4945 this is called when a new object comes in over DRS
4947 static int replmd_replicated_apply_add(struct replmd_replicated_request *ar)
4949 struct ldb_context *ldb;
4950 struct ldb_request *change_req;
4951 enum ndr_err_code ndr_err;
4952 struct ldb_message *msg;
4953 struct replPropertyMetaDataBlob *md;
4954 struct ldb_val md_value;
4957 bool remote_isDeleted = false;
4960 time_t t = time(NULL);
4961 const struct ldb_val *rdn_val;
4962 struct replmd_private *replmd_private =
4963 talloc_get_type(ldb_module_get_private(ar->module),
4964 struct replmd_private);
4965 unix_to_nt_time(&now, t);
4967 ldb = ldb_module_get_ctx(ar->module);
4968 msg = ar->objs->objects[ar->index_current].msg;
4969 md = ar->objs->objects[ar->index_current].meta_data;
4970 is_schema_nc = ldb_dn_compare_base(replmd_private->schema_dn, msg->dn) == 0;
4972 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &ar->seq_num);
4973 if (ret != LDB_SUCCESS) {
4974 return replmd_replicated_request_error(ar, ret);
4977 ret = dsdb_msg_add_guid(msg,
4978 &ar->objs->objects[ar->index_current].object_guid,
4980 if (ret != LDB_SUCCESS) {
4981 return replmd_replicated_request_error(ar, ret);
4984 ret = ldb_msg_add_string(msg, "whenChanged", ar->objs->objects[ar->index_current].when_changed);
4985 if (ret != LDB_SUCCESS) {
4986 return replmd_replicated_request_error(ar, ret);
4989 ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNCreated", ar->seq_num);
4990 if (ret != LDB_SUCCESS) {
4991 return replmd_replicated_request_error(ar, ret);
4994 ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNChanged", ar->seq_num);
4995 if (ret != LDB_SUCCESS) {
4996 return replmd_replicated_request_error(ar, ret);
4999 /* remove any message elements that have zero values */
5000 for (i=0; i<msg->num_elements; i++) {
5001 struct ldb_message_element *el = &msg->elements[i];
5003 if (el->num_values == 0) {
5004 if (ldb_attr_cmp(msg->elements[i].name, "objectClass") == 0) {
5005 ldb_asprintf_errstring(ldb, __location__
5006 ": empty objectClass sent on %s, aborting replication\n",
5007 ldb_dn_get_linearized(msg->dn));
5008 return replmd_replicated_request_error(ar, LDB_ERR_OBJECT_CLASS_VIOLATION);
5011 DEBUG(4,(__location__ ": Removing attribute %s with num_values==0\n",
5013 memmove(el, el+1, sizeof(*el)*(msg->num_elements - (i+1)));
5014 msg->num_elements--;
5021 struct GUID_txt_buf guid_txt;
5023 char *s = ldb_ldif_message_redacted_string(ldb, ar,
5026 DEBUG(8, ("DRS replication add message of %s:\n%s\n",
5027 GUID_buf_string(&ar->objs->objects[ar->index_current].object_guid, &guid_txt),
5030 } else if (DEBUGLVL(4)) {
5031 struct GUID_txt_buf guid_txt;
5032 DEBUG(4, ("DRS replication add DN of %s is %s\n",
5033 GUID_buf_string(&ar->objs->objects[ar->index_current].object_guid, &guid_txt),
5034 ldb_dn_get_linearized(msg->dn)));
5036 remote_isDeleted = ldb_msg_find_attr_as_bool(msg,
5037 "isDeleted", false);
5040 * the meta data array is already sorted by the caller, except
5041 * for the RDN, which needs to be added.
5045 rdn_val = ldb_dn_get_rdn_val(msg->dn);
5046 ret = replmd_update_rpmd_rdn_attr(ldb, msg, rdn_val, NULL,
5047 md, ar, now, is_schema_nc,
5049 if (ret != LDB_SUCCESS) {
5050 ldb_asprintf_errstring(ldb, "%s: error during DRS repl ADD: %s", __func__, ldb_errstring(ldb));
5051 return replmd_replicated_request_error(ar, ret);
5054 ret = replmd_replPropertyMetaDataCtr1_sort_and_verify(ldb, &md->ctr.ctr1, msg->dn);
5055 if (ret != LDB_SUCCESS) {
5056 ldb_asprintf_errstring(ldb, "%s: error during DRS repl ADD: %s", __func__, ldb_errstring(ldb));
5057 return replmd_replicated_request_error(ar, ret);
5060 for (i=0; i < md->ctr.ctr1.count; i++) {
5061 md->ctr.ctr1.array[i].local_usn = ar->seq_num;
5063 ndr_err = ndr_push_struct_blob(&md_value, msg, md,
5064 (ndr_push_flags_fn_t)ndr_push_replPropertyMetaDataBlob);
5065 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
5066 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
5067 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
5069 ret = ldb_msg_add_value(msg, "replPropertyMetaData", &md_value, NULL);
5070 if (ret != LDB_SUCCESS) {
5071 return replmd_replicated_request_error(ar, ret);
5074 replmd_ldb_message_sort(msg, ar->schema);
5076 if (!remote_isDeleted) {
5077 ret = dsdb_module_schedule_sd_propagation(ar->module,
5078 ar->objs->partition_dn,
5080 if (ret != LDB_SUCCESS) {
5081 return replmd_replicated_request_error(ar, ret);
5085 ar->isDeleted = remote_isDeleted;
5087 ret = ldb_build_add_req(&change_req,
5093 replmd_op_add_callback,
5095 LDB_REQ_SET_LOCATION(change_req);
5096 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
5098 /* current partition control needed by "repmd_op_callback" */
5099 ret = ldb_request_add_control(change_req,
5100 DSDB_CONTROL_CURRENT_PARTITION_OID,
5102 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
5104 if (ar->objs->dsdb_repl_flags & DSDB_REPL_FLAG_PARTIAL_REPLICA) {
5105 /* this tells the partition module to make it a
5106 partial replica if creating an NC */
5107 ret = ldb_request_add_control(change_req,
5108 DSDB_CONTROL_PARTIAL_REPLICA,
5110 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
5113 return ldb_next_request(ar->module, change_req);
5116 static int replmd_replicated_apply_search_for_parent_callback(struct ldb_request *req,
5117 struct ldb_reply *ares)
5119 struct replmd_replicated_request *ar = talloc_get_type(req->context,
5120 struct replmd_replicated_request);
5124 return ldb_module_done(ar->req, NULL, NULL,
5125 LDB_ERR_OPERATIONS_ERROR);
5129 * The error NO_SUCH_OBJECT is not expected, unless the search
5130 * base is the partition DN, and that case doesn't happen here
5131 * because then we wouldn't get a parent_guid_value in any
5134 if (ares->error != LDB_SUCCESS) {
5135 return ldb_module_done(ar->req, ares->controls,
5136 ares->response, ares->error);
5139 switch (ares->type) {
5140 case LDB_REPLY_ENTRY:
5142 struct ldb_message *parent_msg = ares->message;
5143 struct ldb_message *msg = ar->objs->objects[ar->index_current].msg;
5144 struct ldb_dn *parent_dn;
5147 if (!ldb_msg_check_string_attribute(msg, "isDeleted", "TRUE")
5148 && ldb_msg_check_string_attribute(parent_msg, "isDeleted", "TRUE")) {
5149 /* Per MS-DRSR 4.1.10.6.10
5150 * FindBestParentObject we need to move this
5151 * new object under a deleted object to
5153 struct ldb_dn *nc_root;
5155 ret = dsdb_find_nc_root(ldb_module_get_ctx(ar->module), msg, msg->dn, &nc_root);
5156 if (ret == LDB_ERR_NO_SUCH_OBJECT) {
5157 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
5158 "No suitable NC root found for %s. "
5159 "We need to move this object because parent object %s "
5160 "is deleted, but this object is not.",
5161 ldb_dn_get_linearized(msg->dn),
5162 ldb_dn_get_linearized(parent_msg->dn));
5163 return ldb_module_done(ar->req, NULL, NULL, LDB_ERR_OPERATIONS_ERROR);
5164 } else if (ret != LDB_SUCCESS) {
5165 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
5166 "Unable to find NC root for %s: %s. "
5167 "We need to move this object because parent object %s "
5168 "is deleted, but this object is not.",
5169 ldb_dn_get_linearized(msg->dn),
5170 ldb_errstring(ldb_module_get_ctx(ar->module)),
5171 ldb_dn_get_linearized(parent_msg->dn));
5172 return ldb_module_done(ar->req, NULL, NULL, LDB_ERR_OPERATIONS_ERROR);
5175 ret = dsdb_wellknown_dn(ldb_module_get_ctx(ar->module), msg,
5177 DS_GUID_LOSTANDFOUND_CONTAINER,
5179 if (ret != LDB_SUCCESS) {
5180 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
5181 "Unable to find LostAndFound Container for %s "
5182 "in partition %s: %s. "
5183 "We need to move this object because parent object %s "
5184 "is deleted, but this object is not.",
5185 ldb_dn_get_linearized(msg->dn), ldb_dn_get_linearized(nc_root),
5186 ldb_errstring(ldb_module_get_ctx(ar->module)),
5187 ldb_dn_get_linearized(parent_msg->dn));
5188 return ldb_module_done(ar->req, NULL, NULL, LDB_ERR_OPERATIONS_ERROR);
5190 ar->objs->objects[ar->index_current].last_known_parent
5191 = talloc_steal(ar->objs->objects[ar->index_current].msg, parent_msg->dn);
5195 = talloc_steal(ar->objs->objects[ar->index_current].msg, parent_msg->dn);
5198 ar->objs->objects[ar->index_current].local_parent_dn = parent_dn;
5200 comp_num = ldb_dn_get_comp_num(msg->dn);
5202 if (!ldb_dn_remove_base_components(msg->dn, comp_num - 1)) {
5204 return ldb_module_done(ar->req, NULL, NULL, ldb_module_operr(ar->module));
5207 if (!ldb_dn_add_base(msg->dn, parent_dn)) {
5209 return ldb_module_done(ar->req, NULL, NULL, ldb_module_operr(ar->module));
5213 case LDB_REPLY_REFERRAL:
5214 /* we ignore referrals */
5217 case LDB_REPLY_DONE:
5219 if (ar->objs->objects[ar->index_current].local_parent_dn == NULL) {
5220 struct GUID_txt_buf str_buf;
5221 if (ar->search_msg != NULL) {
5222 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
5223 "No parent with GUID %s found for object locally known as %s",
5224 GUID_buf_string(ar->objs->objects[ar->index_current].parent_guid, &str_buf),
5225 ldb_dn_get_linearized(ar->search_msg->dn));
5227 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
5228 "No parent with GUID %s found for object remotely known as %s",
5229 GUID_buf_string(ar->objs->objects[ar->index_current].parent_guid, &str_buf),
5230 ldb_dn_get_linearized(ar->objs->objects[ar->index_current].msg->dn));
5234 * This error code is really important, as it
5235 * is the flag back to the callers to retry
5236 * this with DRSUAPI_DRS_GET_ANC, and so get
5237 * the parent objects before the child
5240 return ldb_module_done(ar->req, NULL, NULL,
5241 replmd_replicated_request_werror(ar, WERR_DS_DRA_MISSING_PARENT));
5244 if (ar->search_msg != NULL) {
5245 ret = replmd_replicated_apply_merge(ar);
5247 ret = replmd_replicated_apply_add(ar);
5249 if (ret != LDB_SUCCESS) {
5250 return ldb_module_done(ar->req, NULL, NULL, ret);
5259 * Look for the parent object, so we put the new object in the right
5260 * place This is akin to NameObject in MS-DRSR - this routine and the
5261 * callbacks find the right parent name, and correct name for this
5265 static int replmd_replicated_apply_search_for_parent(struct replmd_replicated_request *ar)
5267 struct ldb_context *ldb;
5271 struct ldb_request *search_req;
5272 static const char *attrs[] = {"isDeleted", NULL};
5273 struct GUID_txt_buf guid_str_buf;
5275 ldb = ldb_module_get_ctx(ar->module);
5277 if (ar->objs->objects[ar->index_current].parent_guid == NULL) {
5278 if (ar->search_msg != NULL) {
5279 return replmd_replicated_apply_merge(ar);
5281 return replmd_replicated_apply_add(ar);
5285 tmp_str = GUID_buf_string(ar->objs->objects[ar->index_current].parent_guid,
5288 filter = talloc_asprintf(ar, "(objectGUID=%s)", tmp_str);
5289 if (!filter) return replmd_replicated_request_werror(ar, WERR_NOT_ENOUGH_MEMORY);
5291 ret = ldb_build_search_req(&search_req,
5294 ar->objs->partition_dn,
5300 replmd_replicated_apply_search_for_parent_callback,
5302 LDB_REQ_SET_LOCATION(search_req);
5304 ret = dsdb_request_add_controls(search_req,
5305 DSDB_SEARCH_SHOW_RECYCLED|
5306 DSDB_SEARCH_SHOW_DELETED|
5307 DSDB_SEARCH_SHOW_EXTENDED_DN);
5308 if (ret != LDB_SUCCESS) {
5312 return ldb_next_request(ar->module, search_req);
5316 handle renames that come in over DRS replication
5318 static int replmd_replicated_handle_rename(struct replmd_replicated_request *ar,
5319 struct ldb_message *msg,
5320 struct ldb_request *parent,
5324 TALLOC_CTX *tmp_ctx = talloc_new(msg);
5325 struct ldb_result *res;
5326 struct ldb_dn *conflict_dn;
5327 const char *attrs[] = { "replPropertyMetaData", "objectGUID", NULL };
5328 const struct ldb_val *omd_value;
5329 struct replPropertyMetaDataBlob omd, *rmd;
5330 enum ndr_err_code ndr_err;
5331 bool rename_incoming_record, rodc;
5332 struct replPropertyMetaData1 *rmd_name, *omd_name;
5333 struct ldb_dn *new_dn;
5336 DEBUG(4,("replmd_replicated_request rename %s => %s\n",
5337 ldb_dn_get_linearized(ar->search_msg->dn),
5338 ldb_dn_get_linearized(msg->dn)));
5341 ret = dsdb_module_rename(ar->module, ar->search_msg->dn, msg->dn,
5342 DSDB_FLAG_NEXT_MODULE, ar->req);
5343 if (ret == LDB_SUCCESS) {
5344 talloc_free(tmp_ctx);
5349 if (ret != LDB_ERR_ENTRY_ALREADY_EXISTS) {
5350 talloc_free(tmp_ctx);
5351 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module), "Failed to locally apply remote rename from %s to %s: %s",
5352 ldb_dn_get_linearized(ar->search_msg->dn),
5353 ldb_dn_get_linearized(msg->dn),
5354 ldb_errstring(ldb_module_get_ctx(ar->module)));
5358 ret = samdb_rodc(ldb_module_get_ctx(ar->module), &rodc);
5359 if (ret != LDB_SUCCESS) {
5360 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
5361 "Failed to determine if we are an RODC when attempting to form conflict DN: %s",
5362 ldb_errstring(ldb_module_get_ctx(ar->module)));
5363 return LDB_ERR_OPERATIONS_ERROR;
5366 * we have a conflict, and need to decide if we will keep the
5367 * new record or the old record
5370 conflict_dn = msg->dn;
5374 * We are on an RODC, or were a GC for this
5375 * partition, so we have to fail this until
5376 * someone who owns the partition sorts it
5379 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
5380 "Conflict adding object '%s' from incoming replication but we are read only for the partition. \n"
5381 " - We must fail the operation until a master for this partition resolves the conflict",
5382 ldb_dn_get_linearized(conflict_dn));
5387 * first we need the replPropertyMetaData attribute from the
5390 ret = dsdb_module_search_dn(ar->module, tmp_ctx, &res, conflict_dn,
5392 DSDB_FLAG_NEXT_MODULE |
5393 DSDB_SEARCH_SHOW_DELETED |
5394 DSDB_SEARCH_SHOW_RECYCLED, ar->req);
5395 if (ret != LDB_SUCCESS) {
5396 DEBUG(0,(__location__ ": Unable to find object for conflicting record '%s'\n",
5397 ldb_dn_get_linearized(conflict_dn)));
5401 omd_value = ldb_msg_find_ldb_val(res->msgs[0], "replPropertyMetaData");
5402 if (omd_value == NULL) {
5403 DEBUG(0,(__location__ ": Unable to find replPropertyMetaData for conflicting record '%s'\n",
5404 ldb_dn_get_linearized(conflict_dn)));
5408 ndr_err = ndr_pull_struct_blob(omd_value, res->msgs[0], &omd,
5409 (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
5410 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
5411 DEBUG(0,(__location__ ": Failed to parse old replPropertyMetaData for %s\n",
5412 ldb_dn_get_linearized(conflict_dn)));
5416 rmd = ar->objs->objects[ar->index_current].meta_data;
5419 * we decide which is newer based on the RPMD on the name
5420 * attribute. See [MS-DRSR] ResolveNameConflict.
5422 * We expect omd_name to be present, as this is from a local
5423 * search, but while rmd_name should have been given to us by
5424 * the remote server, if it is missing we just prefer the
5426 * replmd_replPropertyMetaData1_new_should_be_taken()
5428 rmd_name = replmd_replPropertyMetaData1_find_attid(rmd, DRSUAPI_ATTID_name);
5429 omd_name = replmd_replPropertyMetaData1_find_attid(&omd, DRSUAPI_ATTID_name);
5431 DEBUG(0,(__location__ ": Failed to find name attribute in local LDB replPropertyMetaData for %s\n",
5432 ldb_dn_get_linearized(conflict_dn)));
5437 * Should we preserve the current record, and so rename the
5438 * incoming record to be a conflict?
5440 rename_incoming_record =
5441 !replmd_replPropertyMetaData1_new_should_be_taken(
5442 ar->objs->dsdb_repl_flags & DSDB_REPL_FLAG_PRIORITISE_INCOMING,
5443 omd_name, rmd_name);
5445 if (rename_incoming_record) {
5447 new_dn = replmd_conflict_dn(msg, msg->dn,
5448 &ar->objs->objects[ar->index_current].object_guid);
5449 if (new_dn == NULL) {
5450 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
5451 "Failed to form conflict DN for %s\n",
5452 ldb_dn_get_linearized(msg->dn));
5454 return replmd_replicated_request_werror(ar, WERR_NOT_ENOUGH_MEMORY);
5457 ret = dsdb_module_rename(ar->module, ar->search_msg->dn, new_dn,
5458 DSDB_FLAG_NEXT_MODULE, ar->req);
5459 if (ret != LDB_SUCCESS) {
5460 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
5461 "Failed to rename incoming conflicting dn '%s' (was '%s') to '%s' - %s\n",
5462 ldb_dn_get_linearized(conflict_dn),
5463 ldb_dn_get_linearized(ar->search_msg->dn),
5464 ldb_dn_get_linearized(new_dn),
5465 ldb_errstring(ldb_module_get_ctx(ar->module)));
5466 return replmd_replicated_request_werror(ar, WERR_DS_DRA_DB_ERROR);
5474 /* we are renaming the existing record */
5476 guid = samdb_result_guid(res->msgs[0], "objectGUID");
5477 if (GUID_all_zero(&guid)) {
5478 DEBUG(0,(__location__ ": Failed to find objectGUID for existing conflict record %s\n",
5479 ldb_dn_get_linearized(conflict_dn)));
5483 new_dn = replmd_conflict_dn(tmp_ctx, conflict_dn, &guid);
5484 if (new_dn == NULL) {
5485 DEBUG(0,(__location__ ": Failed to form conflict DN for %s\n",
5486 ldb_dn_get_linearized(conflict_dn)));
5490 DEBUG(2,(__location__ ": Resolving conflict record via existing-record rename '%s' -> '%s'\n",
5491 ldb_dn_get_linearized(conflict_dn), ldb_dn_get_linearized(new_dn)));
5493 ret = dsdb_module_rename(ar->module, conflict_dn, new_dn,
5494 DSDB_FLAG_OWN_MODULE, ar->req);
5495 if (ret != LDB_SUCCESS) {
5496 DEBUG(0,(__location__ ": Failed to rename conflict dn '%s' to '%s' - %s\n",
5497 ldb_dn_get_linearized(conflict_dn),
5498 ldb_dn_get_linearized(new_dn),
5499 ldb_errstring(ldb_module_get_ctx(ar->module))));
5504 * now we need to ensure that the rename is seen as an
5505 * originating update. We do that with a modify.
5507 ret = replmd_name_modify(ar, ar->req, new_dn);
5508 if (ret != LDB_SUCCESS) {
5512 DEBUG(2,(__location__ ": With conflicting record renamed, re-apply replicated rename '%s' -> '%s'\n",
5513 ldb_dn_get_linearized(ar->search_msg->dn),
5514 ldb_dn_get_linearized(msg->dn)));
5517 ret = dsdb_module_rename(ar->module, ar->search_msg->dn, msg->dn,
5518 DSDB_FLAG_NEXT_MODULE, ar->req);
5519 if (ret != LDB_SUCCESS) {
5520 DEBUG(0,(__location__ ": After conflict resolution, failed to rename dn '%s' to '%s' - %s\n",
5521 ldb_dn_get_linearized(ar->search_msg->dn),
5522 ldb_dn_get_linearized(msg->dn),
5523 ldb_errstring(ldb_module_get_ctx(ar->module))));
5529 * On failure make the caller get the error
5530 * This means replication will stop with an error,
5531 * but there is not much else we can do. In the
5532 * LDB_ERR_ENTRY_ALREADY_EXISTS case this is exactly what is
5536 talloc_free(tmp_ctx);
5541 static int replmd_replicated_apply_merge(struct replmd_replicated_request *ar)
5543 struct ldb_context *ldb;
5544 struct ldb_request *change_req;
5545 enum ndr_err_code ndr_err;
5546 struct ldb_message *msg;
5547 struct replPropertyMetaDataBlob *rmd;
5548 struct replPropertyMetaDataBlob omd;
5549 const struct ldb_val *omd_value;
5550 struct replPropertyMetaDataBlob nmd;
5551 struct ldb_val nmd_value;
5552 struct GUID remote_parent_guid;
5555 unsigned int removed_attrs = 0;
5557 int (*callback)(struct ldb_request *req, struct ldb_reply *ares) = replmd_op_callback;
5558 bool isDeleted = false;
5559 bool local_isDeleted = false;
5560 bool remote_isDeleted = false;
5561 bool take_remote_isDeleted = false;
5562 bool sd_updated = false;
5563 bool renamed = false;
5564 bool is_schema_nc = false;
5566 const struct ldb_val *old_rdn, *new_rdn;
5567 struct replmd_private *replmd_private =
5568 talloc_get_type(ldb_module_get_private(ar->module),
5569 struct replmd_private);
5571 time_t t = time(NULL);
5572 unix_to_nt_time(&now, t);
5574 ldb = ldb_module_get_ctx(ar->module);
5575 msg = ar->objs->objects[ar->index_current].msg;
5577 is_schema_nc = ldb_dn_compare_base(replmd_private->schema_dn, msg->dn) == 0;
5579 rmd = ar->objs->objects[ar->index_current].meta_data;
5583 /* find existing meta data */
5584 omd_value = ldb_msg_find_ldb_val(ar->search_msg, "replPropertyMetaData");
5586 ndr_err = ndr_pull_struct_blob(omd_value, ar, &omd,
5587 (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
5588 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
5589 nt_status = ndr_map_error2ntstatus(ndr_err);
5590 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
5593 if (omd.version != 1) {
5594 return replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
5599 struct GUID_txt_buf guid_txt;
5601 char *s = ldb_ldif_message_redacted_string(ldb, ar,
5602 LDB_CHANGETYPE_MODIFY, msg);
5603 DEBUG(8, ("Initial DRS replication modify message of %s is:\n%s\n"
5606 GUID_buf_string(&ar->objs->objects[ar->index_current].object_guid, &guid_txt),
5608 ndr_print_struct_string(s,
5609 (ndr_print_fn_t)ndr_print_replPropertyMetaDataBlob,
5610 "existing replPropertyMetaData",
5612 ndr_print_struct_string(s,
5613 (ndr_print_fn_t)ndr_print_replPropertyMetaDataBlob,
5614 "incoming replPropertyMetaData",
5617 } else if (DEBUGLVL(4)) {
5618 struct GUID_txt_buf guid_txt;
5620 DEBUG(4, ("Initial DRS replication modify DN of %s is: %s\n",
5621 GUID_buf_string(&ar->objs->objects[ar->index_current].object_guid,
5623 ldb_dn_get_linearized(msg->dn)));
5626 local_isDeleted = ldb_msg_find_attr_as_bool(ar->search_msg,
5627 "isDeleted", false);
5628 remote_isDeleted = ldb_msg_find_attr_as_bool(msg,
5629 "isDeleted", false);
5632 * Fill in the remote_parent_guid with the GUID or an all-zero
5635 if (ar->objs->objects[ar->index_current].parent_guid != NULL) {
5636 remote_parent_guid = *ar->objs->objects[ar->index_current].parent_guid;
5638 remote_parent_guid = GUID_zero();
5642 * To ensure we follow a complex rename chain around, we have
5643 * to confirm that the DN is the same (mostly to confirm the
5644 * RDN) and the parentGUID is the same.
5646 * This ensures we keep things under the correct parent, which
5647 * replmd_replicated_handle_rename() will do.
5650 if (strcmp(ldb_dn_get_linearized(msg->dn), ldb_dn_get_linearized(ar->search_msg->dn)) == 0
5651 && GUID_equal(&remote_parent_guid, &ar->local_parent_guid)) {
5655 * handle renames, even just by case that come in over
5656 * DRS. Changes in the parent DN don't hit us here,
5657 * because the search for a parent will clean up those
5660 * We also have already filtered out the case where
5661 * the peer has an older name to what we have (see
5662 * replmd_replicated_apply_search_callback())
5664 ret = replmd_replicated_handle_rename(ar, msg, ar->req, &renamed);
5667 if (ret != LDB_SUCCESS) {
5668 ldb_debug(ldb, LDB_DEBUG_FATAL,
5669 "replmd_replicated_request rename %s => %s failed - %s\n",
5670 ldb_dn_get_linearized(ar->search_msg->dn),
5671 ldb_dn_get_linearized(msg->dn),
5672 ldb_errstring(ldb));
5673 return replmd_replicated_request_werror(ar, WERR_DS_DRA_DB_ERROR);
5676 if (renamed == true) {
5678 * Set the callback to one that will fix up the name
5679 * metadata on the new conflict DN
5681 callback = replmd_op_name_modify_callback;
5686 nmd.ctr.ctr1.count = omd.ctr.ctr1.count + rmd->ctr.ctr1.count;
5687 nmd.ctr.ctr1.array = talloc_array(ar,
5688 struct replPropertyMetaData1,
5689 nmd.ctr.ctr1.count);
5690 if (!nmd.ctr.ctr1.array) return replmd_replicated_request_werror(ar, WERR_NOT_ENOUGH_MEMORY);
5692 /* first copy the old meta data */
5693 for (i=0; i < omd.ctr.ctr1.count; i++) {
5694 nmd.ctr.ctr1.array[ni] = omd.ctr.ctr1.array[i];
5699 /* now merge in the new meta data */
5700 for (i=0; i < rmd->ctr.ctr1.count; i++) {
5703 for (j=0; j < ni; j++) {
5706 if (rmd->ctr.ctr1.array[i].attid != nmd.ctr.ctr1.array[j].attid) {
5710 cmp = replmd_replPropertyMetaData1_new_should_be_taken(
5711 ar->objs->dsdb_repl_flags,
5712 &nmd.ctr.ctr1.array[j],
5713 &rmd->ctr.ctr1.array[i]);
5715 /* replace the entry */
5716 nmd.ctr.ctr1.array[j] = rmd->ctr.ctr1.array[i];
5717 if (ar->seq_num == 0) {
5718 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &ar->seq_num);
5719 if (ret != LDB_SUCCESS) {
5720 return replmd_replicated_request_error(ar, ret);
5723 nmd.ctr.ctr1.array[j].local_usn = ar->seq_num;
5724 switch (nmd.ctr.ctr1.array[j].attid) {
5725 case DRSUAPI_ATTID_ntSecurityDescriptor:
5728 case DRSUAPI_ATTID_isDeleted:
5729 take_remote_isDeleted = true;
5738 if (rmd->ctr.ctr1.array[i].attid != DRSUAPI_ATTID_instanceType) {
5739 DEBUG(3,("Discarding older DRS attribute update to %s on %s from %s\n",
5740 msg->elements[i-removed_attrs].name,
5741 ldb_dn_get_linearized(msg->dn),
5742 GUID_string(ar, &rmd->ctr.ctr1.array[i].originating_invocation_id)));
5745 /* we don't want to apply this change so remove the attribute */
5746 ldb_msg_remove_element(msg, &msg->elements[i-removed_attrs]);
5753 if (found) continue;
5755 nmd.ctr.ctr1.array[ni] = rmd->ctr.ctr1.array[i];
5756 if (ar->seq_num == 0) {
5757 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &ar->seq_num);
5758 if (ret != LDB_SUCCESS) {
5759 return replmd_replicated_request_error(ar, ret);
5762 nmd.ctr.ctr1.array[ni].local_usn = ar->seq_num;
5763 switch (nmd.ctr.ctr1.array[ni].attid) {
5764 case DRSUAPI_ATTID_ntSecurityDescriptor:
5767 case DRSUAPI_ATTID_isDeleted:
5768 take_remote_isDeleted = true;
5777 * finally correct the size of the meta_data array
5779 nmd.ctr.ctr1.count = ni;
5781 new_rdn = ldb_dn_get_rdn_val(msg->dn);
5782 old_rdn = ldb_dn_get_rdn_val(ar->search_msg->dn);
5785 ret = replmd_update_rpmd_rdn_attr(ldb, msg, new_rdn, old_rdn,
5786 &nmd, ar, now, is_schema_nc,
5788 if (ret != LDB_SUCCESS) {
5789 ldb_asprintf_errstring(ldb, "%s: error during DRS repl merge: %s", __func__, ldb_errstring(ldb));
5790 return replmd_replicated_request_error(ar, ret);
5794 * sort the new meta data array
5796 ret = replmd_replPropertyMetaDataCtr1_sort_and_verify(ldb, &nmd.ctr.ctr1, msg->dn);
5797 if (ret != LDB_SUCCESS) {
5798 ldb_asprintf_errstring(ldb, "%s: error during DRS repl merge: %s", __func__, ldb_errstring(ldb));
5803 * Work out if this object is deleted, so we can prune any extra attributes. See MS-DRSR 4.1.10.6.9
5806 * This also controls SD propagation below
5808 if (take_remote_isDeleted) {
5809 isDeleted = remote_isDeleted;
5811 isDeleted = local_isDeleted;
5814 ar->isDeleted = isDeleted;
5817 * check if some replicated attributes left, otherwise skip the ldb_modify() call
5819 if (msg->num_elements == 0) {
5820 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_replicated_apply_merge[%u]: skip replace\n",
5823 return replmd_replicated_apply_isDeleted(ar);
5826 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_replicated_apply_merge[%u]: replace %u attributes\n",
5827 ar->index_current, msg->num_elements);
5833 if (sd_updated && !isDeleted) {
5834 ret = dsdb_module_schedule_sd_propagation(ar->module,
5835 ar->objs->partition_dn,
5837 if (ret != LDB_SUCCESS) {
5838 return ldb_operr(ldb);
5842 /* create the meta data value */
5843 ndr_err = ndr_push_struct_blob(&nmd_value, msg, &nmd,
5844 (ndr_push_flags_fn_t)ndr_push_replPropertyMetaDataBlob);
5845 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
5846 nt_status = ndr_map_error2ntstatus(ndr_err);
5847 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
5851 * when we know that we'll modify the record, add the whenChanged, uSNChanged
5852 * and replPopertyMetaData attributes
5854 ret = ldb_msg_add_string(msg, "whenChanged", ar->objs->objects[ar->index_current].when_changed);
5855 if (ret != LDB_SUCCESS) {
5856 return replmd_replicated_request_error(ar, ret);
5858 ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNChanged", ar->seq_num);
5859 if (ret != LDB_SUCCESS) {
5860 return replmd_replicated_request_error(ar, ret);
5862 ret = ldb_msg_add_value(msg, "replPropertyMetaData", &nmd_value, NULL);
5863 if (ret != LDB_SUCCESS) {
5864 return replmd_replicated_request_error(ar, ret);
5867 replmd_ldb_message_sort(msg, ar->schema);
5869 /* we want to replace the old values */
5870 for (i=0; i < msg->num_elements; i++) {
5871 msg->elements[i].flags = LDB_FLAG_MOD_REPLACE;
5872 if (ldb_attr_cmp(msg->elements[i].name, "objectClass") == 0) {
5873 if (msg->elements[i].num_values == 0) {
5874 ldb_asprintf_errstring(ldb, __location__
5875 ": objectClass removed on %s, aborting replication\n",
5876 ldb_dn_get_linearized(msg->dn));
5877 return replmd_replicated_request_error(ar, LDB_ERR_OBJECT_CLASS_VIOLATION);
5883 struct GUID_txt_buf guid_txt;
5885 char *s = ldb_ldif_message_redacted_string(ldb, ar,
5886 LDB_CHANGETYPE_MODIFY,
5888 DEBUG(8, ("Final DRS replication modify message of %s:\n%s\n",
5889 GUID_buf_string(&ar->objs->objects[ar->index_current].object_guid,
5893 } else if (DEBUGLVL(4)) {
5894 struct GUID_txt_buf guid_txt;
5896 DEBUG(4, ("Final DRS replication modify DN of %s is %s\n",
5897 GUID_buf_string(&ar->objs->objects[ar->index_current].object_guid,
5899 ldb_dn_get_linearized(msg->dn)));
5902 ret = ldb_build_mod_req(&change_req,
5910 LDB_REQ_SET_LOCATION(change_req);
5911 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
5913 /* current partition control needed by "repmd_op_callback" */
5914 ret = ldb_request_add_control(change_req,
5915 DSDB_CONTROL_CURRENT_PARTITION_OID,
5917 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
5919 return ldb_next_request(ar->module, change_req);
5922 static int replmd_replicated_apply_search_callback(struct ldb_request *req,
5923 struct ldb_reply *ares)
5925 struct replmd_replicated_request *ar = talloc_get_type(req->context,
5926 struct replmd_replicated_request);
5930 return ldb_module_done(ar->req, NULL, NULL,
5931 LDB_ERR_OPERATIONS_ERROR);
5933 if (ares->error != LDB_SUCCESS &&
5934 ares->error != LDB_ERR_NO_SUCH_OBJECT) {
5935 return ldb_module_done(ar->req, ares->controls,
5936 ares->response, ares->error);
5939 switch (ares->type) {
5940 case LDB_REPLY_ENTRY:
5941 ar->search_msg = talloc_steal(ar, ares->message);
5944 case LDB_REPLY_REFERRAL:
5945 /* we ignore referrals */
5948 case LDB_REPLY_DONE:
5950 struct replPropertyMetaData1 *md_remote;
5951 struct replPropertyMetaData1 *md_local;
5953 struct replPropertyMetaDataBlob omd;
5954 const struct ldb_val *omd_value;
5955 struct replPropertyMetaDataBlob *rmd;
5956 struct ldb_message *msg;
5958 ar->objs->objects[ar->index_current].local_parent_dn = NULL;
5959 ar->objs->objects[ar->index_current].last_known_parent = NULL;
5962 * This is the ADD case, find the appropriate parent,
5963 * as this object doesn't exist locally:
5965 if (ar->search_msg == NULL) {
5966 ret = replmd_replicated_apply_search_for_parent(ar);
5967 if (ret != LDB_SUCCESS) {
5968 return ldb_module_done(ar->req, NULL, NULL, ret);
5975 * Otherwise, in the MERGE case, work out if we are
5976 * attempting a rename, and if so find the parent the
5977 * newly renamed object wants to belong under (which
5978 * may not be the parent in it's attached string DN
5980 rmd = ar->objs->objects[ar->index_current].meta_data;
5984 /* find existing meta data */
5985 omd_value = ldb_msg_find_ldb_val(ar->search_msg, "replPropertyMetaData");
5987 enum ndr_err_code ndr_err;
5988 ndr_err = ndr_pull_struct_blob(omd_value, ar, &omd,
5989 (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
5990 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
5991 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
5992 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
5995 if (omd.version != 1) {
5996 return replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
6000 ar->local_parent_guid = samdb_result_guid(ar->search_msg, "parentGUID");
6002 instanceType = ldb_msg_find_attr_as_int(ar->search_msg, "instanceType", 0);
6003 if (((instanceType & INSTANCE_TYPE_IS_NC_HEAD) == 0)
6004 && GUID_all_zero(&ar->local_parent_guid)) {
6005 DEBUG(0, ("Refusing to replicate new version of %s "
6006 "as local object has an all-zero parentGUID attribute, "
6007 "despite not being an NC root\n",
6008 ldb_dn_get_linearized(ar->search_msg->dn)));
6009 return replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
6013 * now we need to check for double renames. We could have a
6014 * local rename pending which our replication partner hasn't
6015 * received yet. We choose which one wins by looking at the
6016 * attribute stamps on the two objects, the newer one wins.
6018 * This also simply applies the correct algorithms for
6019 * determining if a change was made to name at all, or
6020 * if the object has just been renamed under the same
6023 md_remote = replmd_replPropertyMetaData1_find_attid(rmd, DRSUAPI_ATTID_name);
6024 md_local = replmd_replPropertyMetaData1_find_attid(&omd, DRSUAPI_ATTID_name);
6026 DEBUG(0,(__location__ ": Failed to find name attribute in local LDB replPropertyMetaData for %s\n",
6027 ldb_dn_get_linearized(ar->search_msg->dn)));
6028 return replmd_replicated_request_werror(ar, WERR_DS_DRA_DB_ERROR);
6032 * if there is no name attribute given then we have to assume the
6033 * object we've received has the older name
6035 if (replmd_replPropertyMetaData1_new_should_be_taken(
6036 ar->objs->dsdb_repl_flags & DSDB_REPL_FLAG_PRIORITISE_INCOMING,
6037 md_local, md_remote)) {
6038 struct GUID_txt_buf p_guid_local;
6039 struct GUID_txt_buf p_guid_remote;
6040 msg = ar->objs->objects[ar->index_current].msg;
6042 /* Merge on the existing object, with rename */
6044 DEBUG(4,(__location__ ": Looking for new parent for object %s currently under %s "
6045 "as incoming object changing to %s under %s\n",
6046 ldb_dn_get_linearized(ar->search_msg->dn),
6047 GUID_buf_string(&ar->local_parent_guid, &p_guid_local),
6048 ldb_dn_get_linearized(msg->dn),
6049 GUID_buf_string(ar->objs->objects[ar->index_current].parent_guid,
6051 ret = replmd_replicated_apply_search_for_parent(ar);
6053 struct GUID_txt_buf p_guid_local;
6054 struct GUID_txt_buf p_guid_remote;
6055 msg = ar->objs->objects[ar->index_current].msg;
6058 * Merge on the existing object, force no
6059 * rename (code below just to explain why in
6063 if (strcmp(ldb_dn_get_linearized(ar->search_msg->dn),
6064 ldb_dn_get_linearized(msg->dn)) == 0) {
6065 if (ar->objs->objects[ar->index_current].parent_guid != NULL &&
6066 GUID_equal(&ar->local_parent_guid,
6067 ar->objs->objects[ar->index_current].parent_guid)
6069 DEBUG(4,(__location__ ": Keeping object %s at under %s "
6070 "despite incoming object changing parent to %s\n",
6071 ldb_dn_get_linearized(ar->search_msg->dn),
6072 GUID_buf_string(&ar->local_parent_guid, &p_guid_local),
6073 GUID_buf_string(ar->objs->objects[ar->index_current].parent_guid,
6077 DEBUG(4,(__location__ ": Keeping object %s at under %s "
6078 " and rejecting older rename to %s under %s\n",
6079 ldb_dn_get_linearized(ar->search_msg->dn),
6080 GUID_buf_string(&ar->local_parent_guid, &p_guid_local),
6081 ldb_dn_get_linearized(msg->dn),
6082 GUID_buf_string(ar->objs->objects[ar->index_current].parent_guid,
6086 * This assignment ensures that the strcmp()
6087 * and GUID_equal() calls in
6088 * replmd_replicated_apply_merge() avoids the
6091 ar->objs->objects[ar->index_current].parent_guid =
6092 &ar->local_parent_guid;
6094 msg->dn = ar->search_msg->dn;
6095 ret = replmd_replicated_apply_merge(ar);
6097 if (ret != LDB_SUCCESS) {
6098 return ldb_module_done(ar->req, NULL, NULL, ret);
6108 * Stores the linked attributes received in the replication chunk - these get
6109 * applied at the end of the transaction. We also check that each linked
6110 * attribute is valid, i.e. source and target objects are known.
6112 static int replmd_store_linked_attributes(struct replmd_replicated_request *ar)
6114 int ret = LDB_SUCCESS;
6116 struct ldb_module *module = ar->module;
6117 struct replmd_private *replmd_private =
6118 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
6119 struct ldb_context *ldb;
6121 ldb = ldb_module_get_ctx(module);
6123 DEBUG(4,("linked_attributes_count=%u\n", ar->objs->linked_attributes_count));
6125 /* save away the linked attributes for the end of the transaction */
6126 for (i = 0; i < ar->objs->linked_attributes_count; i++) {
6127 struct la_entry *la_entry;
6129 if (replmd_private->la_ctx == NULL) {
6130 replmd_private->la_ctx = talloc_new(replmd_private);
6132 la_entry = talloc(replmd_private->la_ctx, struct la_entry);
6133 if (la_entry == NULL) {
6135 return LDB_ERR_OPERATIONS_ERROR;
6137 la_entry->la = talloc(la_entry, struct drsuapi_DsReplicaLinkedAttribute);
6138 if (la_entry->la == NULL) {
6139 talloc_free(la_entry);
6141 return LDB_ERR_OPERATIONS_ERROR;
6143 *la_entry->la = ar->objs->linked_attributes[i];
6144 la_entry->dsdb_repl_flags = ar->objs->dsdb_repl_flags;
6146 /* we need to steal the non-scalars so they stay
6147 around until the end of the transaction */
6148 talloc_steal(la_entry->la, la_entry->la->identifier);
6149 talloc_steal(la_entry->la, la_entry->la->value.blob);
6151 ret = replmd_verify_linked_attribute(ar, la_entry);
6153 if (ret != LDB_SUCCESS) {
6157 DLIST_ADD(replmd_private->la_list, la_entry);
6163 static int replmd_replicated_uptodate_vector(struct replmd_replicated_request *ar);
6165 static int replmd_replicated_apply_next(struct replmd_replicated_request *ar)
6167 struct ldb_context *ldb;
6171 struct ldb_request *search_req;
6172 static const char *attrs[] = { "repsFrom", "replUpToDateVector",
6173 "parentGUID", "instanceType",
6174 "replPropertyMetaData", "nTSecurityDescriptor",
6175 "isDeleted", NULL };
6176 struct GUID_txt_buf guid_str_buf;
6178 if (ar->index_current >= ar->objs->num_objects) {
6181 * Now that we've applied all the objects, check the new linked
6182 * attributes and store them (we apply them in .prepare_commit)
6184 ret = replmd_store_linked_attributes(ar);
6186 if (ret != LDB_SUCCESS) {
6190 /* done applying objects, move on to the next stage */
6191 return replmd_replicated_uptodate_vector(ar);
6194 ldb = ldb_module_get_ctx(ar->module);
6195 ar->search_msg = NULL;
6196 ar->isDeleted = false;
6198 tmp_str = GUID_buf_string(&ar->objs->objects[ar->index_current].object_guid,
6201 filter = talloc_asprintf(ar, "(objectGUID=%s)", tmp_str);
6202 if (!filter) return replmd_replicated_request_werror(ar, WERR_NOT_ENOUGH_MEMORY);
6204 ret = ldb_build_search_req(&search_req,
6207 ar->objs->partition_dn,
6213 replmd_replicated_apply_search_callback,
6215 LDB_REQ_SET_LOCATION(search_req);
6217 ret = dsdb_request_add_controls(search_req, DSDB_SEARCH_SHOW_RECYCLED);
6219 if (ret != LDB_SUCCESS) {
6223 return ldb_next_request(ar->module, search_req);
6227 * This is essentially a wrapper for replmd_replicated_apply_next()
6229 * This is needed to ensure that both codepaths call this handler.
6231 static int replmd_replicated_apply_isDeleted(struct replmd_replicated_request *ar)
6233 struct ldb_dn *deleted_objects_dn;
6234 struct ldb_message *msg = ar->objs->objects[ar->index_current].msg;
6235 int ret = dsdb_get_deleted_objects_dn(ldb_module_get_ctx(ar->module), msg, msg->dn,
6236 &deleted_objects_dn);
6237 if (ar->isDeleted && (ret != LDB_SUCCESS || ldb_dn_compare(msg->dn, deleted_objects_dn) != 0)) {
6239 * Do a delete here again, so that if there is
6240 * anything local that conflicts with this
6241 * object being deleted, it is removed. This
6242 * includes links. See MS-DRSR 4.1.10.6.9
6245 * If the object is already deleted, and there
6246 * is no more work required, it doesn't do
6250 /* This has been updated to point to the DN we eventually did the modify on */
6252 struct ldb_request *del_req;
6253 struct ldb_result *res;
6255 TALLOC_CTX *tmp_ctx = talloc_new(ar);
6257 ret = ldb_oom(ldb_module_get_ctx(ar->module));
6261 res = talloc_zero(tmp_ctx, struct ldb_result);
6263 ret = ldb_oom(ldb_module_get_ctx(ar->module));
6264 talloc_free(tmp_ctx);
6268 /* Build a delete request, which hopefully will artually turn into nothing */
6269 ret = ldb_build_del_req(&del_req, ldb_module_get_ctx(ar->module), tmp_ctx,
6273 ldb_modify_default_callback,
6275 LDB_REQ_SET_LOCATION(del_req);
6276 if (ret != LDB_SUCCESS) {
6277 talloc_free(tmp_ctx);
6282 * This is the guts of the call, call back
6283 * into our delete code, but setting the
6284 * re_delete flag so we delete anything that
6285 * shouldn't be there on a deleted or recycled
6288 ret = replmd_delete_internals(ar->module, del_req, true);
6289 if (ret == LDB_SUCCESS) {
6290 ret = ldb_wait(del_req->handle, LDB_WAIT_ALL);
6293 talloc_free(tmp_ctx);
6294 if (ret != LDB_SUCCESS) {
6299 ar->index_current++;
6300 return replmd_replicated_apply_next(ar);
6303 static int replmd_replicated_uptodate_modify_callback(struct ldb_request *req,
6304 struct ldb_reply *ares)
6306 struct ldb_context *ldb;
6307 struct replmd_replicated_request *ar = talloc_get_type(req->context,
6308 struct replmd_replicated_request);
6309 ldb = ldb_module_get_ctx(ar->module);
6312 return ldb_module_done(ar->req, NULL, NULL,
6313 LDB_ERR_OPERATIONS_ERROR);
6315 if (ares->error != LDB_SUCCESS) {
6316 return ldb_module_done(ar->req, ares->controls,
6317 ares->response, ares->error);
6320 if (ares->type != LDB_REPLY_DONE) {
6321 ldb_asprintf_errstring(ldb, "Invalid LDB reply type %d", ares->type);
6322 return ldb_module_done(ar->req, NULL, NULL,
6323 LDB_ERR_OPERATIONS_ERROR);
6328 return ldb_module_done(ar->req, NULL, NULL, LDB_SUCCESS);
6331 static int replmd_replicated_uptodate_modify(struct replmd_replicated_request *ar)
6333 struct ldb_context *ldb;
6334 struct ldb_request *change_req;
6335 enum ndr_err_code ndr_err;
6336 struct ldb_message *msg;
6337 struct replUpToDateVectorBlob ouv;
6338 const struct ldb_val *ouv_value;
6339 const struct drsuapi_DsReplicaCursor2CtrEx *ruv;
6340 struct replUpToDateVectorBlob nuv;
6341 struct ldb_val nuv_value;
6342 struct ldb_message_element *nuv_el = NULL;
6343 struct ldb_message_element *orf_el = NULL;
6344 struct repsFromToBlob nrf;
6345 struct ldb_val *nrf_value = NULL;
6346 struct ldb_message_element *nrf_el = NULL;
6350 time_t t = time(NULL);
6353 uint32_t instanceType;
6355 ldb = ldb_module_get_ctx(ar->module);
6356 ruv = ar->objs->uptodateness_vector;
6362 unix_to_nt_time(&now, t);
6364 if (ar->search_msg == NULL) {
6365 /* this happens for a REPL_OBJ call where we are
6366 creating the target object by replicating it. The
6367 subdomain join code does this for the partition DN
6369 DEBUG(4,(__location__ ": Skipping UDV and repsFrom update as no target DN\n"));
6370 return ldb_module_done(ar->req, NULL, NULL, LDB_SUCCESS);
6373 instanceType = ldb_msg_find_attr_as_uint(ar->search_msg, "instanceType", 0);
6374 if (! (instanceType & INSTANCE_TYPE_IS_NC_HEAD)) {
6375 DEBUG(4,(__location__ ": Skipping UDV and repsFrom update as not NC root: %s\n",
6376 ldb_dn_get_linearized(ar->search_msg->dn)));
6377 return ldb_module_done(ar->req, NULL, NULL, LDB_SUCCESS);
6381 * first create the new replUpToDateVector
6383 ouv_value = ldb_msg_find_ldb_val(ar->search_msg, "replUpToDateVector");
6385 ndr_err = ndr_pull_struct_blob(ouv_value, ar, &ouv,
6386 (ndr_pull_flags_fn_t)ndr_pull_replUpToDateVectorBlob);
6387 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
6388 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
6389 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
6392 if (ouv.version != 2) {
6393 return replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
6398 * the new uptodateness vector will at least
6399 * contain 1 entry, one for the source_dsa
6401 * plus optional values from our old vector and the one from the source_dsa
6403 nuv.ctr.ctr2.count = ouv.ctr.ctr2.count;
6404 if (ruv) nuv.ctr.ctr2.count += ruv->count;
6405 nuv.ctr.ctr2.cursors = talloc_array(ar,
6406 struct drsuapi_DsReplicaCursor2,
6407 nuv.ctr.ctr2.count);
6408 if (!nuv.ctr.ctr2.cursors) return replmd_replicated_request_werror(ar, WERR_NOT_ENOUGH_MEMORY);
6410 /* first copy the old vector */
6411 for (i=0; i < ouv.ctr.ctr2.count; i++) {
6412 nuv.ctr.ctr2.cursors[ni] = ouv.ctr.ctr2.cursors[i];
6416 /* merge in the source_dsa vector is available */
6417 for (i=0; (ruv && i < ruv->count); i++) {
6420 if (GUID_equal(&ruv->cursors[i].source_dsa_invocation_id,
6421 &ar->our_invocation_id)) {
6425 for (j=0; j < ni; j++) {
6426 if (!GUID_equal(&ruv->cursors[i].source_dsa_invocation_id,
6427 &nuv.ctr.ctr2.cursors[j].source_dsa_invocation_id)) {
6433 if (ruv->cursors[i].highest_usn > nuv.ctr.ctr2.cursors[j].highest_usn) {
6434 nuv.ctr.ctr2.cursors[j] = ruv->cursors[i];
6439 if (found) continue;
6441 /* if it's not there yet, add it */
6442 nuv.ctr.ctr2.cursors[ni] = ruv->cursors[i];
6447 * finally correct the size of the cursors array
6449 nuv.ctr.ctr2.count = ni;
6454 TYPESAFE_QSORT(nuv.ctr.ctr2.cursors, nuv.ctr.ctr2.count, drsuapi_DsReplicaCursor2_compare);
6457 * create the change ldb_message
6459 msg = ldb_msg_new(ar);
6460 if (!msg) return replmd_replicated_request_werror(ar, WERR_NOT_ENOUGH_MEMORY);
6461 msg->dn = ar->search_msg->dn;
6463 ndr_err = ndr_push_struct_blob(&nuv_value, msg, &nuv,
6464 (ndr_push_flags_fn_t)ndr_push_replUpToDateVectorBlob);
6465 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
6466 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
6467 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
6469 ret = ldb_msg_add_value(msg, "replUpToDateVector", &nuv_value, &nuv_el);
6470 if (ret != LDB_SUCCESS) {
6471 return replmd_replicated_request_error(ar, ret);
6473 nuv_el->flags = LDB_FLAG_MOD_REPLACE;
6476 * now create the new repsFrom value from the given repsFromTo1 structure
6480 nrf.ctr.ctr1 = *ar->objs->source_dsa;
6481 nrf.ctr.ctr1.last_attempt = now;
6482 nrf.ctr.ctr1.last_success = now;
6483 nrf.ctr.ctr1.result_last_attempt = WERR_OK;
6486 * first see if we already have a repsFrom value for the current source dsa
6487 * if so we'll later replace this value
6489 orf_el = ldb_msg_find_element(ar->search_msg, "repsFrom");
6491 for (i=0; i < orf_el->num_values; i++) {
6492 struct repsFromToBlob *trf;
6494 trf = talloc(ar, struct repsFromToBlob);
6495 if (!trf) return replmd_replicated_request_werror(ar, WERR_NOT_ENOUGH_MEMORY);
6497 ndr_err = ndr_pull_struct_blob(&orf_el->values[i], trf, trf,
6498 (ndr_pull_flags_fn_t)ndr_pull_repsFromToBlob);
6499 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
6500 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
6501 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
6504 if (trf->version != 1) {
6505 return replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
6509 * we compare the source dsa objectGUID not the invocation_id
6510 * because we want only one repsFrom value per source dsa
6511 * and when the invocation_id of the source dsa has changed we don't need
6512 * the old repsFrom with the old invocation_id
6514 if (!GUID_equal(&trf->ctr.ctr1.source_dsa_obj_guid,
6515 &ar->objs->source_dsa->source_dsa_obj_guid)) {
6521 nrf_value = &orf_el->values[i];
6526 * copy over all old values to the new ldb_message
6528 ret = ldb_msg_add_empty(msg, "repsFrom", 0, &nrf_el);
6529 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
6534 * if we haven't found an old repsFrom value for the current source dsa
6535 * we'll add a new value
6538 struct ldb_val zero_value;
6539 ZERO_STRUCT(zero_value);
6540 ret = ldb_msg_add_value(msg, "repsFrom", &zero_value, &nrf_el);
6541 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
6543 nrf_value = &nrf_el->values[nrf_el->num_values - 1];
6546 /* we now fill the value which is already attached to ldb_message */
6547 ndr_err = ndr_push_struct_blob(nrf_value, msg,
6549 (ndr_push_flags_fn_t)ndr_push_repsFromToBlob);
6550 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
6551 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
6552 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
6556 * the ldb_message_element for the attribute, has all the old values and the new one
6557 * so we'll replace the whole attribute with all values
6559 nrf_el->flags = LDB_FLAG_MOD_REPLACE;
6561 if (CHECK_DEBUGLVL(4)) {
6562 char *s = ldb_ldif_message_redacted_string(ldb, ar,
6563 LDB_CHANGETYPE_MODIFY,
6565 DEBUG(4, ("DRS replication uptodate modify message:\n%s\n", s));
6569 /* prepare the ldb_modify() request */
6570 ret = ldb_build_mod_req(&change_req,
6576 replmd_replicated_uptodate_modify_callback,
6578 LDB_REQ_SET_LOCATION(change_req);
6579 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
6581 return ldb_next_request(ar->module, change_req);
6584 static int replmd_replicated_uptodate_search_callback(struct ldb_request *req,
6585 struct ldb_reply *ares)
6587 struct replmd_replicated_request *ar = talloc_get_type(req->context,
6588 struct replmd_replicated_request);
6592 return ldb_module_done(ar->req, NULL, NULL,
6593 LDB_ERR_OPERATIONS_ERROR);
6595 if (ares->error != LDB_SUCCESS &&
6596 ares->error != LDB_ERR_NO_SUCH_OBJECT) {
6597 return ldb_module_done(ar->req, ares->controls,
6598 ares->response, ares->error);
6601 switch (ares->type) {
6602 case LDB_REPLY_ENTRY:
6603 ar->search_msg = talloc_steal(ar, ares->message);
6606 case LDB_REPLY_REFERRAL:
6607 /* we ignore referrals */
6610 case LDB_REPLY_DONE:
6611 ret = replmd_replicated_uptodate_modify(ar);
6612 if (ret != LDB_SUCCESS) {
6613 return ldb_module_done(ar->req, NULL, NULL, ret);
6622 static int replmd_replicated_uptodate_vector(struct replmd_replicated_request *ar)
6624 struct ldb_context *ldb = ldb_module_get_ctx(ar->module);
6625 struct replmd_private *replmd_private =
6626 talloc_get_type_abort(ldb_module_get_private(ar->module),
6627 struct replmd_private);
6629 static const char *attrs[] = {
6630 "replUpToDateVector",
6635 struct ldb_request *search_req;
6637 ar->search_msg = NULL;
6640 * Let the caller know that we did an originating updates
6642 ar->objs->originating_updates = replmd_private->originating_updates;
6644 ret = ldb_build_search_req(&search_req,
6647 ar->objs->partition_dn,
6653 replmd_replicated_uptodate_search_callback,
6655 LDB_REQ_SET_LOCATION(search_req);
6656 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
6658 return ldb_next_request(ar->module, search_req);
6663 static int replmd_extended_replicated_objects(struct ldb_module *module, struct ldb_request *req)
6665 struct ldb_context *ldb;
6666 struct dsdb_extended_replicated_objects *objs;
6667 struct replmd_replicated_request *ar;
6668 struct ldb_control **ctrls;
6671 ldb = ldb_module_get_ctx(module);
6673 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_extended_replicated_objects\n");
6675 objs = talloc_get_type(req->op.extended.data, struct dsdb_extended_replicated_objects);
6677 ldb_debug(ldb, LDB_DEBUG_FATAL, "replmd_extended_replicated_objects: invalid extended data\n");
6678 return LDB_ERR_PROTOCOL_ERROR;
6681 if (objs->version != DSDB_EXTENDED_REPLICATED_OBJECTS_VERSION) {
6682 ldb_debug(ldb, LDB_DEBUG_FATAL, "replmd_extended_replicated_objects: extended data invalid version [%u != %u]\n",
6683 objs->version, DSDB_EXTENDED_REPLICATED_OBJECTS_VERSION);
6684 return LDB_ERR_PROTOCOL_ERROR;
6687 ar = replmd_ctx_init(module, req);
6689 return LDB_ERR_OPERATIONS_ERROR;
6691 /* Set the flags to have the replmd_op_callback run over the full set of objects */
6692 ar->apply_mode = true;
6694 ar->schema = dsdb_get_schema(ldb, ar);
6696 ldb_debug_set(ldb, LDB_DEBUG_FATAL, "replmd_ctx_init: no loaded schema found\n");
6698 DEBUG(0,(__location__ ": %s\n", ldb_errstring(ldb)));
6699 return LDB_ERR_CONSTRAINT_VIOLATION;
6702 ctrls = req->controls;
6704 if (req->controls) {
6705 req->controls = talloc_memdup(ar, req->controls,
6706 talloc_get_size(req->controls));
6707 if (!req->controls) return replmd_replicated_request_werror(ar, WERR_NOT_ENOUGH_MEMORY);
6710 ret = ldb_request_add_control(req, DSDB_CONTROL_REPLICATED_UPDATE_OID, false, NULL);
6711 if (ret != LDB_SUCCESS) {
6715 /* If this change contained linked attributes in the body
6716 * (rather than in the links section) we need to update
6717 * backlinks in linked_attributes */
6718 ret = ldb_request_add_control(req, DSDB_CONTROL_APPLY_LINKS, false, NULL);
6719 if (ret != LDB_SUCCESS) {
6723 ar->controls = req->controls;
6724 req->controls = ctrls;
6726 return replmd_replicated_apply_next(ar);
6730 * Checks how to handle an missing target - either we need to fail the
6731 * replication and retry with GET_TGT, ignore the link and continue, or try to
6732 * add a partial link to an unknown target.
6734 static int replmd_allow_missing_target(struct ldb_module *module,
6735 TALLOC_CTX *mem_ctx,
6736 struct ldb_dn *target_dn,
6737 struct ldb_dn *source_dn,
6740 uint32_t dsdb_repl_flags,
6742 const char * missing_str)
6744 struct ldb_context *ldb = ldb_module_get_ctx(module);
6748 * we may not be able to resolve link targets properly when
6749 * dealing with subsets of objects, e.g. the source is a
6750 * critical object and the target isn't
6753 * When we implement Trusted Domains we need to consider
6754 * whether they get treated as an incomplete replica here or not
6756 if (dsdb_repl_flags & DSDB_REPL_FLAG_OBJECT_SUBSET) {
6759 * Ignore the link. We don't increase the highwater-mark in
6760 * the object subset cases, so subsequent replications should
6761 * resolve any missing links
6763 DEBUG(2, ("%s target %s linked from %s\n", missing_str,
6764 ldb_dn_get_linearized(target_dn),
6765 ldb_dn_get_linearized(source_dn)));
6766 *ignore_link = true;
6770 if (dsdb_repl_flags & DSDB_REPL_FLAG_TARGETS_UPTODATE) {
6773 * target should already be up-to-date so there's no point in
6774 * retrying. This could be due to bad timing, or if a target
6775 * on a one-way link was deleted. We ignore the link rather
6776 * than failing the replication cycle completely
6778 *ignore_link = true;
6779 DBG_WARNING("%s is %s but up to date. Ignoring link from %s\n",
6780 ldb_dn_get_linearized(target_dn), missing_str,
6781 ldb_dn_get_linearized(source_dn));
6785 is_in_same_nc = dsdb_objects_have_same_nc(ldb,
6789 if (is_in_same_nc) {
6790 /* fail the replication and retry with GET_TGT */
6791 ldb_asprintf_errstring(ldb, "%s target %s GUID %s linked from %s\n",
6793 ldb_dn_get_linearized(target_dn),
6794 GUID_string(mem_ctx, guid),
6795 ldb_dn_get_linearized(source_dn));
6796 return LDB_ERR_NO_SUCH_OBJECT;
6800 * The target of the cross-partition link is missing. Continue
6801 * and try to at least add the forward-link. This isn't great,
6802 * but a partial link can be fixed by dbcheck, so it's better
6803 * than dropping the link completely.
6805 *ignore_link = false;
6807 if (is_obj_commit) {
6810 * Only log this when we're actually committing the objects.
6811 * This avoids spurious logs, i.e. if we're just verifying the
6812 * received link during a join.
6814 DBG_WARNING("%s cross-partition target %s linked from %s\n",
6815 missing_str, ldb_dn_get_linearized(target_dn),
6816 ldb_dn_get_linearized(source_dn));
6823 * Checks that the target object for a linked attribute exists.
6824 * @param guid returns the target object's GUID (is returned)if it exists)
6825 * @param ignore_link set to true if the linked attribute should be ignored
6826 * (i.e. the target doesn't exist, but that it's OK to skip the link)
6828 static int replmd_check_target_exists(struct ldb_module *module,
6829 struct dsdb_dn *dsdb_dn,
6830 struct la_entry *la_entry,
6831 struct ldb_dn *source_dn,
6836 struct drsuapi_DsReplicaLinkedAttribute *la = la_entry->la;
6837 struct ldb_context *ldb = ldb_module_get_ctx(module);
6838 struct ldb_result *target_res;
6839 TALLOC_CTX *tmp_ctx = talloc_new(la_entry);
6840 const char *attrs[] = { "isDeleted", "isRecycled", NULL };
6843 enum deletion_state target_deletion_state = OBJECT_REMOVED;
6844 bool active = (la->flags & DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE) ? true : false;
6846 *ignore_link = false;
6847 ntstatus = dsdb_get_extended_dn_guid(dsdb_dn->dn, guid, "GUID");
6849 if (!NT_STATUS_IS_OK(ntstatus) && !active) {
6852 * This strange behaviour (allowing a NULL/missing
6853 * GUID) originally comes from:
6855 * commit e3054ce0fe0f8f62d2f5b2a77893e7a1479128bd
6856 * Author: Andrew Tridgell <tridge@samba.org>
6857 * Date: Mon Dec 21 21:21:55 2009 +1100
6859 * s4-drs: cope better with NULL GUIDS from DRS
6861 * It is valid to get a NULL GUID over DRS for a deleted forward link. We
6862 * need to match by DN if possible when seeing if we should update an
6865 * Pair-Programmed-With: Andrew Bartlett <abartlet@samba.org>
6867 ret = dsdb_module_search_dn(module, tmp_ctx, &target_res,
6869 DSDB_FLAG_NEXT_MODULE |
6870 DSDB_SEARCH_SHOW_RECYCLED |
6871 DSDB_SEARCH_SEARCH_ALL_PARTITIONS |
6872 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT,
6874 } else if (!NT_STATUS_IS_OK(ntstatus)) {
6875 ldb_asprintf_errstring(ldb, "Failed to find GUID in linked attribute 0x%x blob for %s from %s",
6877 ldb_dn_get_linearized(dsdb_dn->dn),
6878 ldb_dn_get_linearized(source_dn));
6879 talloc_free(tmp_ctx);
6880 return LDB_ERR_OPERATIONS_ERROR;
6882 ret = dsdb_module_search(module, tmp_ctx, &target_res,
6883 NULL, LDB_SCOPE_SUBTREE,
6885 DSDB_FLAG_NEXT_MODULE |
6886 DSDB_SEARCH_SHOW_RECYCLED |
6887 DSDB_SEARCH_SEARCH_ALL_PARTITIONS |
6888 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT,
6891 GUID_string(tmp_ctx, guid));
6894 if (ret != LDB_SUCCESS) {
6895 ldb_asprintf_errstring(ldb, "Failed to re-resolve GUID %s: %s\n",
6896 GUID_string(tmp_ctx, guid),
6897 ldb_errstring(ldb));
6898 talloc_free(tmp_ctx);
6902 if (target_res->count == 0) {
6905 * target object is unknown. Check whether to ignore the link,
6906 * fail the replication, or add a partial link
6908 ret = replmd_allow_missing_target(module, tmp_ctx, dsdb_dn->dn,
6909 source_dn, is_obj_commit, guid,
6910 la_entry->dsdb_repl_flags,
6911 ignore_link, "Unknown");
6913 } else if (target_res->count != 1) {
6914 ldb_asprintf_errstring(ldb, "More than one object found matching objectGUID %s\n",
6915 GUID_string(tmp_ctx, guid));
6916 ret = LDB_ERR_OPERATIONS_ERROR;
6918 struct ldb_message *target_msg = target_res->msgs[0];
6920 dsdb_dn->dn = talloc_steal(dsdb_dn, target_msg->dn);
6922 /* Get the object's state (i.e. Not Deleted, Tombstone, etc) */
6923 replmd_deletion_state(module, target_msg,
6924 &target_deletion_state, NULL);
6927 * Check for deleted objects as per MS-DRSR 4.1.10.6.14
6928 * ProcessLinkValue(). Link updates should not be sent for
6929 * recycled and tombstone objects (deleting the links should
6930 * happen when we delete the object). This probably means our
6931 * copy of the target object isn't up to date.
6933 if (target_deletion_state >= OBJECT_RECYCLED) {
6936 * target object is deleted. Check whether to ignore the
6937 * link, fail the replication, or add a partial link
6939 ret = replmd_allow_missing_target(module, tmp_ctx,
6940 dsdb_dn->dn, source_dn,
6941 is_obj_commit, guid,
6942 la_entry->dsdb_repl_flags,
6943 ignore_link, "Deleted");
6947 talloc_free(tmp_ctx);
6952 * Extracts the key details about the source/target object for a
6953 * linked-attribute entry.
6954 * This returns the following details:
6955 * @param ret_attr the schema details for the linked attribute
6956 * @param source_msg the search result for the source object
6957 * @param target_dsdb_dn the unpacked DN info for the target object
6959 static int replmd_extract_la_entry_details(struct ldb_module *module,
6960 struct la_entry *la_entry,
6961 TALLOC_CTX *mem_ctx,
6962 const struct dsdb_attribute **ret_attr,
6963 struct ldb_message **source_msg,
6964 struct dsdb_dn **target_dsdb_dn)
6966 struct drsuapi_DsReplicaLinkedAttribute *la = la_entry->la;
6967 struct ldb_context *ldb = ldb_module_get_ctx(module);
6968 const struct dsdb_schema *schema = dsdb_get_schema(ldb, mem_ctx);
6970 const struct dsdb_attribute *attr;
6972 struct ldb_result *res;
6973 const char *attrs[4];
6976 linked_attributes[0]:
6977 &objs->linked_attributes[i]: struct drsuapi_DsReplicaLinkedAttribute
6979 identifier: struct drsuapi_DsReplicaObjectIdentifier
6980 __ndr_size : 0x0000003a (58)
6981 __ndr_size_sid : 0x00000000 (0)
6982 guid : 8e95b6a9-13dd-4158-89db-3220a5be5cc7
6984 __ndr_size_dn : 0x00000000 (0)
6986 attid : DRSUAPI_ATTID_member (0x1F)
6987 value: struct drsuapi_DsAttributeValue
6988 __ndr_size : 0x0000007e (126)
6990 blob : DATA_BLOB length=126
6991 flags : 0x00000001 (1)
6992 1: DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE
6993 originating_add_time : Wed Sep 2 22:20:01 2009 EST
6994 meta_data: struct drsuapi_DsReplicaMetaData
6995 version : 0x00000015 (21)
6996 originating_change_time : Wed Sep 2 23:39:07 2009 EST
6997 originating_invocation_id: 794640f3-18cf-40ee-a211-a93992b67a64
6998 originating_usn : 0x000000000001e19c (123292)
7000 (for cases where the link is to a normal DN)
7001 &target: struct drsuapi_DsReplicaObjectIdentifier3
7002 __ndr_size : 0x0000007e (126)
7003 __ndr_size_sid : 0x0000001c (28)
7004 guid : 7639e594-db75-4086-b0d4-67890ae46031
7005 sid : S-1-5-21-2848215498-2472035911-1947525656-19924
7006 __ndr_size_dn : 0x00000022 (34)
7007 dn : 'CN=UOne,OU=TestOU,DC=vsofs8,DC=com'
7010 /* find the attribute being modified */
7011 attr = dsdb_attribute_by_attributeID_id(schema, la->attid);
7013 struct GUID_txt_buf guid_str;
7014 ldb_asprintf_errstring(ldb, "Unable to find attributeID 0x%x for link on <GUID=%s>",
7016 GUID_buf_string(&la->identifier->guid,
7018 return LDB_ERR_OPERATIONS_ERROR;
7021 attrs[0] = attr->lDAPDisplayName;
7022 attrs[1] = "isDeleted";
7023 attrs[2] = "isRecycled";
7027 * get the existing message from the db for the object with
7028 * this GUID, returning attribute being modified. We will then
7029 * use this msg as the basis for a modify call
7031 ret = dsdb_module_search(module, mem_ctx, &res, NULL, LDB_SCOPE_SUBTREE, attrs,
7032 DSDB_FLAG_NEXT_MODULE |
7033 DSDB_SEARCH_SEARCH_ALL_PARTITIONS |
7034 DSDB_SEARCH_SHOW_RECYCLED |
7035 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT |
7036 DSDB_SEARCH_REVEAL_INTERNALS,
7038 "objectGUID=%s", GUID_string(mem_ctx, &la->identifier->guid));
7039 if (ret != LDB_SUCCESS) {
7042 if (res->count != 1) {
7043 ldb_asprintf_errstring(ldb, "DRS linked attribute for GUID %s - DN not found",
7044 GUID_string(mem_ctx, &la->identifier->guid));
7045 return LDB_ERR_NO_SUCH_OBJECT;
7048 *source_msg = res->msgs[0];
7050 /* the value blob for the attribute holds the target object DN */
7051 status = dsdb_dn_la_from_blob(ldb, attr, schema, mem_ctx, la->value.blob, target_dsdb_dn);
7052 if (!W_ERROR_IS_OK(status)) {
7053 ldb_asprintf_errstring(ldb, "Failed to parsed linked attribute blob for %s on %s - %s\n",
7054 attr->lDAPDisplayName,
7055 ldb_dn_get_linearized(res->msgs[0]->dn),
7056 win_errstr(status));
7057 return LDB_ERR_OPERATIONS_ERROR;
7066 * Verifies the source and target objects are known for a linked attribute
7068 static int replmd_verify_linked_attribute(struct replmd_replicated_request *ar,
7069 struct la_entry *la)
7071 int ret = LDB_SUCCESS;
7072 TALLOC_CTX *tmp_ctx = talloc_new(la);
7073 struct ldb_module *module = ar->module;
7074 struct ldb_message *src_msg;
7075 const struct dsdb_attribute *attr;
7076 struct dsdb_dn *tgt_dsdb_dn;
7077 struct GUID guid = GUID_zero();
7080 ret = replmd_extract_la_entry_details(module, la, tmp_ctx, &attr,
7081 &src_msg, &tgt_dsdb_dn);
7084 * When we fail to find the source object, the error code we pass
7085 * back here is really important. It flags back to the callers to
7086 * retry this request with DRSUAPI_DRS_GET_ANC. This case should
7087 * never happen if we're replicating from a Samba DC, but it is
7088 * needed to talk to a Windows DC
7090 if (ret == LDB_ERR_NO_SUCH_OBJECT) {
7091 ret = replmd_replicated_request_werror(ar, WERR_DS_DRA_MISSING_PARENT);
7094 if (ret != LDB_SUCCESS) {
7095 talloc_free(tmp_ctx);
7100 * We can skip the target object checks if we're only syncing critical
7101 * objects, or we know the target is up-to-date. If either case, we
7102 * still continue even if the target doesn't exist
7104 if ((la->dsdb_repl_flags & (DSDB_REPL_FLAG_OBJECT_SUBSET |
7105 DSDB_REPL_FLAG_TARGETS_UPTODATE)) == 0) {
7107 ret = replmd_check_target_exists(module, tgt_dsdb_dn, la,
7108 src_msg->dn, false, &guid,
7113 * When we fail to find the target object, the error code we pass
7114 * back here is really important. It flags back to the callers to
7115 * retry this request with DRSUAPI_DRS_GET_TGT
7117 if (ret == LDB_ERR_NO_SUCH_OBJECT) {
7118 ret = replmd_replicated_request_werror(ar, WERR_DS_DRA_RECYCLED_TARGET);
7121 talloc_free(tmp_ctx);
7126 * Finds the current active Parsed-DN value for a single-valued linked
7127 * attribute, if one exists.
7128 * @param ret_pdn assigned the active Parsed-DN, or NULL if none was found
7129 * @returns LDB_SUCCESS (regardless of whether a match was found), unless
7132 static int replmd_get_active_singleval_link(struct ldb_module *module,
7133 TALLOC_CTX *mem_ctx,
7134 struct parsed_dn pdn_list[],
7136 const struct dsdb_attribute *attr,
7137 struct parsed_dn **ret_pdn)
7143 if (!(attr->ldb_schema_attribute->flags & LDB_ATTR_FLAG_SINGLE_VALUE)) {
7145 /* nothing to do for multi-valued linked attributes */
7149 for (i = 0; i < count; i++) {
7150 int ret = LDB_SUCCESS;
7151 struct parsed_dn *pdn = &pdn_list[i];
7153 /* skip any inactive links */
7154 if (dsdb_dn_is_deleted_val(pdn->v)) {
7158 /* we've found an active value for this attribute */
7161 if (pdn->dsdb_dn == NULL) {
7162 struct ldb_context *ldb = ldb_module_get_ctx(module);
7164 ret = really_parse_trusted_dn(mem_ctx, ldb, pdn,
7165 attr->syntax->ldap_oid);
7171 /* no active link found */
7176 * @returns true if the replication linked attribute info is newer than we
7177 * already have in our DB
7178 * @param pdn the existing linked attribute info in our DB
7179 * @param la the new linked attribute info received during replication
7181 static bool replmd_link_update_is_newer(struct parsed_dn *pdn,
7182 struct drsuapi_DsReplicaLinkedAttribute *la)
7184 /* see if this update is newer than what we have already */
7185 struct GUID invocation_id = GUID_zero();
7186 uint32_t version = 0;
7187 NTTIME change_time = 0;
7191 /* no existing info so update is newer */
7195 dsdb_get_extended_dn_guid(pdn->dsdb_dn->dn, &invocation_id, "RMD_INVOCID");
7196 dsdb_get_extended_dn_uint32(pdn->dsdb_dn->dn, &version, "RMD_VERSION");
7197 dsdb_get_extended_dn_nttime(pdn->dsdb_dn->dn, &change_time, "RMD_CHANGETIME");
7199 return replmd_update_is_newer(&invocation_id,
7200 &la->meta_data.originating_invocation_id,
7202 la->meta_data.version,
7204 la->meta_data.originating_change_time);
7208 * Marks an existing linked attribute value as deleted in the DB
7209 * @param pdn the parsed-DN of the target-value to delete
7211 static int replmd_delete_link_value(struct ldb_module *module,
7212 struct replmd_private *replmd_private,
7213 TALLOC_CTX *mem_ctx,
7214 struct ldb_dn *src_obj_dn,
7215 const struct dsdb_schema *schema,
7216 const struct dsdb_attribute *attr,
7219 struct GUID *target_guid,
7220 struct dsdb_dn *target_dsdb_dn,
7221 struct ldb_val *output_val)
7223 struct ldb_context *ldb = ldb_module_get_ctx(module);
7226 const struct GUID *invocation_id = NULL;
7230 unix_to_nt_time(&now, t);
7232 invocation_id = samdb_ntds_invocation_id(ldb);
7233 if (invocation_id == NULL) {
7234 return LDB_ERR_OPERATIONS_ERROR;
7237 /* if the existing link is active, remove its backlink */
7240 ret = replmd_add_backlink(module, replmd_private, schema,
7241 src_obj_dn, target_guid, false,
7243 if (ret != LDB_SUCCESS) {
7248 /* mark the existing value as deleted */
7249 ret = replmd_update_la_val(mem_ctx, output_val, target_dsdb_dn,
7250 target_dsdb_dn, invocation_id, seq_num,
7251 seq_num, now, true);
7256 * Checks for a conflict in single-valued link attributes, and tries to
7257 * resolve the problem if possible.
7259 * Single-valued links should only ever have one active value. If we already
7260 * have an active link value, and during replication we receive an active link
7261 * value for a different target DN, then we need to resolve this inconsistency
7262 * and determine which value should be active. If the received info is better/
7263 * newer than the existing link attribute, then we need to set our existing
7264 * link as deleted. If the received info is worse/older, then we should continue
7265 * to add it, but set it as an inactive link.
7267 * Note that this is a corner-case that is unlikely to happen (but if it does
7268 * happen, we don't want it to break replication completely).
7270 * @param pdn_being_modified the parsed DN corresponding to the received link
7271 * target (note this is NULL if the link does not already exist in our DB)
7272 * @param pdn_list all the source object's Parsed-DNs for this attribute, i.e.
7273 * any existing active or inactive values for the attribute in our DB.
7274 * @param dsdb_dn the target DN for the received link attribute
7275 * @param add_as_inactive gets set to true if the received link is worse than
7276 * the existing link - it should still be added, but as an inactive link.
7278 static int replmd_check_singleval_la_conflict(struct ldb_module *module,
7279 struct replmd_private *replmd_private,
7280 TALLOC_CTX *mem_ctx,
7281 struct ldb_dn *src_obj_dn,
7282 struct drsuapi_DsReplicaLinkedAttribute *la,
7283 struct dsdb_dn *dsdb_dn,
7284 struct parsed_dn *pdn_being_modified,
7285 struct parsed_dn *pdn_list,
7286 struct ldb_message_element *old_el,
7287 const struct dsdb_schema *schema,
7288 const struct dsdb_attribute *attr,
7290 bool *add_as_inactive)
7292 struct parsed_dn *active_pdn = NULL;
7293 bool update_is_newer = false;
7297 * check if there's a conflict for single-valued links, i.e. an active
7298 * linked attribute already exists, but it has a different target value
7300 ret = replmd_get_active_singleval_link(module, mem_ctx, pdn_list,
7301 old_el->num_values, attr,
7304 if (ret != LDB_SUCCESS) {
7309 * If no active value exists (or the received info is for the currently
7310 * active value), then no conflict exists
7312 if (active_pdn == NULL || active_pdn == pdn_being_modified) {
7316 DBG_WARNING("Link conflict for %s attribute on %s\n",
7317 attr->lDAPDisplayName, ldb_dn_get_linearized(src_obj_dn));
7319 /* Work out how to resolve the conflict based on which info is better */
7320 update_is_newer = replmd_link_update_is_newer(active_pdn, la);
7322 if (update_is_newer) {
7323 DBG_WARNING("Using received value %s, over existing target %s\n",
7324 ldb_dn_get_linearized(dsdb_dn->dn),
7325 ldb_dn_get_linearized(active_pdn->dsdb_dn->dn));
7328 * Delete our existing active link. The received info will then
7329 * be added (through normal link processing) as the active value
7331 ret = replmd_delete_link_value(module, replmd_private, old_el,
7332 src_obj_dn, schema, attr,
7333 seq_num, true, &active_pdn->guid,
7334 active_pdn->dsdb_dn,
7337 if (ret != LDB_SUCCESS) {
7341 DBG_WARNING("Using existing target %s, over received value %s\n",
7342 ldb_dn_get_linearized(active_pdn->dsdb_dn->dn),
7343 ldb_dn_get_linearized(dsdb_dn->dn));
7346 * we want to keep our existing active link and add the
7347 * received link as inactive
7349 *add_as_inactive = true;
7356 process one linked attribute structure
7358 static int replmd_process_linked_attribute(struct ldb_module *module,
7359 struct replmd_private *replmd_private,
7360 struct la_entry *la_entry,
7361 struct ldb_request *parent)
7363 struct drsuapi_DsReplicaLinkedAttribute *la = la_entry->la;
7364 struct ldb_context *ldb = ldb_module_get_ctx(module);
7365 struct ldb_message *msg;
7366 TALLOC_CTX *tmp_ctx = talloc_new(la_entry);
7367 const struct dsdb_schema *schema = dsdb_get_schema(ldb, tmp_ctx);
7369 const struct dsdb_attribute *attr;
7370 struct dsdb_dn *dsdb_dn;
7371 uint64_t seq_num = 0;
7372 struct ldb_message_element *old_el;
7373 time_t t = time(NULL);
7374 struct parsed_dn *pdn_list, *pdn, *next;
7375 struct GUID guid = GUID_zero();
7376 bool active = (la->flags & DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE)?true:false;
7378 enum deletion_state deletion_state = OBJECT_NOT_DELETED;
7379 struct dsdb_dn *old_dsdb_dn = NULL;
7380 struct ldb_val *val_to_update = NULL;
7381 bool add_as_inactive = false;
7384 * get the attribute being modified, the search result for the source object,
7385 * and the target object's DN details
7387 ret = replmd_extract_la_entry_details(module, la_entry, tmp_ctx, &attr,
7390 if (ret != LDB_SUCCESS) {
7391 talloc_free(tmp_ctx);
7396 * Check for deleted objects per MS-DRSR 4.1.10.6.14
7397 * ProcessLinkValue, because link updates are not applied to
7398 * recycled and tombstone objects. We don't have to delete
7399 * any existing link, that should have happened when the
7400 * object deletion was replicated or initiated.
7402 replmd_deletion_state(module, msg, &deletion_state, NULL);
7404 if (deletion_state >= OBJECT_RECYCLED) {
7405 talloc_free(tmp_ctx);
7409 old_el = ldb_msg_find_element(msg, attr->lDAPDisplayName);
7410 if (old_el == NULL) {
7411 ret = ldb_msg_add_empty(msg, attr->lDAPDisplayName, LDB_FLAG_MOD_REPLACE, &old_el);
7412 if (ret != LDB_SUCCESS) {
7413 ldb_module_oom(module);
7414 talloc_free(tmp_ctx);
7415 return LDB_ERR_OPERATIONS_ERROR;
7418 old_el->flags = LDB_FLAG_MOD_REPLACE;
7421 /* parse the existing links */
7422 ret = get_parsed_dns_trusted(module, replmd_private, tmp_ctx, old_el, &pdn_list,
7423 attr->syntax->ldap_oid, parent);
7425 if (ret != LDB_SUCCESS) {
7426 talloc_free(tmp_ctx);
7430 ret = replmd_check_target_exists(module, dsdb_dn, la_entry, msg->dn,
7431 true, &guid, &ignore_link);
7433 if (ret != LDB_SUCCESS) {
7434 talloc_free(tmp_ctx);
7439 * there are some cases where the target object doesn't exist, but it's
7440 * OK to ignore the linked attribute
7443 talloc_free(tmp_ctx);
7447 /* see if this link already exists */
7448 ret = parsed_dn_find(ldb, pdn_list, old_el->num_values,
7451 dsdb_dn->extra_part, 0,
7453 attr->syntax->ldap_oid,
7455 if (ret != LDB_SUCCESS) {
7456 talloc_free(tmp_ctx);
7460 if (!replmd_link_update_is_newer(pdn, la)) {
7461 DEBUG(3,("Discarding older DRS linked attribute update to %s on %s from %s\n",
7462 old_el->name, ldb_dn_get_linearized(msg->dn),
7463 GUID_string(tmp_ctx, &la->meta_data.originating_invocation_id)));
7464 talloc_free(tmp_ctx);
7468 /* get a seq_num for this change */
7469 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &seq_num);
7470 if (ret != LDB_SUCCESS) {
7471 talloc_free(tmp_ctx);
7476 * check for single-valued link conflicts, i.e. an active linked
7477 * attribute already exists, but it has a different target value
7480 ret = replmd_check_singleval_la_conflict(module, replmd_private,
7481 tmp_ctx, msg->dn, la,
7482 dsdb_dn, pdn, pdn_list,
7483 old_el, schema, attr,
7486 if (ret != LDB_SUCCESS) {
7487 talloc_free(tmp_ctx);
7493 uint32_t rmd_flags = dsdb_dn_rmd_flags(pdn->dsdb_dn->dn);
7495 if (!(rmd_flags & DSDB_RMD_FLAG_DELETED)) {
7496 /* remove the existing backlink */
7497 ret = replmd_add_backlink(module, replmd_private,
7500 &pdn->guid, false, attr,
7502 if (ret != LDB_SUCCESS) {
7503 talloc_free(tmp_ctx);
7508 val_to_update = pdn->v;
7509 old_dsdb_dn = pdn->dsdb_dn;
7515 * We know where the new one needs to be, from the *next
7516 * pointer into pdn_list.
7519 offset = old_el->num_values;
7521 if (next->dsdb_dn == NULL) {
7522 ret = really_parse_trusted_dn(tmp_ctx, ldb, next,
7523 attr->syntax->ldap_oid);
7524 if (ret != LDB_SUCCESS) {
7528 offset = next - pdn_list;
7529 if (offset > old_el->num_values) {
7530 talloc_free(tmp_ctx);
7531 return LDB_ERR_OPERATIONS_ERROR;
7535 old_el->values = talloc_realloc(msg->elements, old_el->values,
7536 struct ldb_val, old_el->num_values+1);
7537 if (!old_el->values) {
7538 ldb_module_oom(module);
7539 return LDB_ERR_OPERATIONS_ERROR;
7542 if (offset != old_el->num_values) {
7543 memmove(&old_el->values[offset + 1], &old_el->values[offset],
7544 (old_el->num_values - offset) * sizeof(old_el->values[0]));
7547 old_el->num_values++;
7549 val_to_update = &old_el->values[offset];
7553 /* set the link attribute's value to the info that was received */
7554 ret = replmd_set_la_val(tmp_ctx, val_to_update, dsdb_dn, old_dsdb_dn,
7555 &la->meta_data.originating_invocation_id,
7556 la->meta_data.originating_usn, seq_num,
7557 la->meta_data.originating_change_time,
7558 la->meta_data.version,
7560 if (ret != LDB_SUCCESS) {
7561 talloc_free(tmp_ctx);
7565 if (add_as_inactive) {
7567 /* Set the new link as inactive/deleted to avoid conflicts */
7568 ret = replmd_delete_link_value(module, replmd_private, old_el,
7569 msg->dn, schema, attr, seq_num,
7570 false, &guid, dsdb_dn,
7573 if (ret != LDB_SUCCESS) {
7574 talloc_free(tmp_ctx);
7578 } else if (active) {
7580 /* if the new link is active, then add the new backlink */
7581 ret = replmd_add_backlink(module, replmd_private,
7586 if (ret != LDB_SUCCESS) {
7587 talloc_free(tmp_ctx);
7592 /* we only change whenChanged and uSNChanged if the seq_num
7594 ret = add_time_element(msg, "whenChanged", t);
7595 if (ret != LDB_SUCCESS) {
7596 talloc_free(tmp_ctx);
7601 ret = add_uint64_element(ldb, msg, "uSNChanged", seq_num);
7602 if (ret != LDB_SUCCESS) {
7603 talloc_free(tmp_ctx);
7608 old_el = ldb_msg_find_element(msg, attr->lDAPDisplayName);
7609 if (old_el == NULL) {
7610 talloc_free(tmp_ctx);
7611 return ldb_operr(ldb);
7614 ret = dsdb_check_single_valued_link(attr, old_el);
7615 if (ret != LDB_SUCCESS) {
7616 talloc_free(tmp_ctx);
7620 old_el->flags |= LDB_FLAG_INTERNAL_DISABLE_SINGLE_VALUE_CHECK;
7622 ret = linked_attr_modify(module, msg, parent);
7623 if (ret != LDB_SUCCESS) {
7624 ldb_debug(ldb, LDB_DEBUG_WARNING, "Failed to apply linked attribute change '%s'\n%s\n",
7626 ldb_ldif_message_redacted_string(ldb,
7628 LDB_CHANGETYPE_MODIFY,
7630 talloc_free(tmp_ctx);
7634 talloc_free(tmp_ctx);
7639 static int replmd_extended(struct ldb_module *module, struct ldb_request *req)
7641 if (strcmp(req->op.extended.oid, DSDB_EXTENDED_REPLICATED_OBJECTS_OID) == 0) {
7642 return replmd_extended_replicated_objects(module, req);
7645 return ldb_next_request(module, req);
7650 we hook into the transaction operations to allow us to
7651 perform the linked attribute updates at the end of the whole
7652 transaction. This allows a forward linked attribute to be created
7653 before the object is created. During a vampire, w2k8 sends us linked
7654 attributes before the objects they are part of.
7656 static int replmd_start_transaction(struct ldb_module *module)
7658 /* create our private structure for this transaction */
7659 struct replmd_private *replmd_private = talloc_get_type(ldb_module_get_private(module),
7660 struct replmd_private);
7661 replmd_txn_cleanup(replmd_private);
7663 /* free any leftover mod_usn records from cancelled
7665 while (replmd_private->ncs) {
7666 struct nc_entry *e = replmd_private->ncs;
7667 DLIST_REMOVE(replmd_private->ncs, e);
7671 replmd_private->originating_updates = false;
7673 return ldb_next_start_trans(module);
7677 on prepare commit we loop over our queued la_context structures and
7680 static int replmd_prepare_commit(struct ldb_module *module)
7682 struct replmd_private *replmd_private =
7683 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
7684 struct la_entry *la, *prev;
7688 * Walk the list of linked attributes from DRS replication.
7690 * We walk backwards, to do the first entry first, as we
7691 * added the entries with DLIST_ADD() which puts them at the
7694 for (la = DLIST_TAIL(replmd_private->la_list); la; la=prev) {
7695 prev = DLIST_PREV(la);
7696 DLIST_REMOVE(replmd_private->la_list, la);
7697 ret = replmd_process_linked_attribute(module, replmd_private,
7699 if (ret != LDB_SUCCESS) {
7700 replmd_txn_cleanup(replmd_private);
7705 replmd_txn_cleanup(replmd_private);
7707 /* possibly change @REPLCHANGED */
7708 ret = replmd_notify_store(module, NULL);
7709 if (ret != LDB_SUCCESS) {
7713 return ldb_next_prepare_commit(module);
7716 static int replmd_del_transaction(struct ldb_module *module)
7718 struct replmd_private *replmd_private =
7719 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
7720 replmd_txn_cleanup(replmd_private);
7722 return ldb_next_del_trans(module);
7726 static const struct ldb_module_ops ldb_repl_meta_data_module_ops = {
7727 .name = "repl_meta_data",
7728 .init_context = replmd_init,
7730 .modify = replmd_modify,
7731 .rename = replmd_rename,
7732 .del = replmd_delete,
7733 .extended = replmd_extended,
7734 .start_transaction = replmd_start_transaction,
7735 .prepare_commit = replmd_prepare_commit,
7736 .del_transaction = replmd_del_transaction,
7739 int ldb_repl_meta_data_module_init(const char *version)
7741 LDB_MODULE_CHECK_VERSION(version);
7742 return ldb_register_module(&ldb_repl_meta_data_module_ops);