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;
119 static int replmd_replicated_apply_merge(struct replmd_replicated_request *ar);
120 static int replmd_delete_internals(struct ldb_module *module, struct ldb_request *req, bool re_delete);
121 static int replmd_check_upgrade_links(struct ldb_context *ldb,
122 struct parsed_dn *dns, uint32_t count,
123 struct ldb_message_element *el,
124 const char *ldap_oid);
125 static int replmd_verify_linked_attribute(struct replmd_replicated_request *ar,
126 struct la_entry *la);
127 static int replmd_set_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct dsdb_dn *dsdb_dn,
128 struct dsdb_dn *old_dsdb_dn, const struct GUID *invocation_id,
129 uint64_t usn, uint64_t local_usn, NTTIME nttime,
130 uint32_t version, bool deleted);
132 static int replmd_make_deleted_child_dn(TALLOC_CTX *tmp_ctx,
133 struct ldb_context *ldb,
135 const char *rdn_name,
136 const struct ldb_val *rdn_value,
139 enum urgent_situation {
140 REPL_URGENT_ON_CREATE = 1,
141 REPL_URGENT_ON_UPDATE = 2,
142 REPL_URGENT_ON_DELETE = 4
145 enum deletion_state {
146 OBJECT_NOT_DELETED=1,
153 static void replmd_deletion_state(struct ldb_module *module,
154 const struct ldb_message *msg,
155 enum deletion_state *current_state,
156 enum deletion_state *next_state)
159 bool enabled = false;
162 *current_state = OBJECT_REMOVED;
163 if (next_state != NULL) {
164 *next_state = OBJECT_REMOVED;
169 ret = dsdb_recyclebin_enabled(module, &enabled);
170 if (ret != LDB_SUCCESS) {
174 if (ldb_msg_check_string_attribute(msg, "isDeleted", "TRUE")) {
176 *current_state = OBJECT_TOMBSTONE;
177 if (next_state != NULL) {
178 *next_state = OBJECT_REMOVED;
183 if (ldb_msg_check_string_attribute(msg, "isRecycled", "TRUE")) {
184 *current_state = OBJECT_RECYCLED;
185 if (next_state != NULL) {
186 *next_state = OBJECT_REMOVED;
191 *current_state = OBJECT_DELETED;
192 if (next_state != NULL) {
193 *next_state = OBJECT_RECYCLED;
198 *current_state = OBJECT_NOT_DELETED;
199 if (next_state == NULL) {
204 *next_state = OBJECT_DELETED;
206 *next_state = OBJECT_TOMBSTONE;
210 static const struct {
211 const char *update_name;
212 enum urgent_situation repl_situation;
213 } urgent_objects[] = {
214 {"nTDSDSA", (REPL_URGENT_ON_CREATE | REPL_URGENT_ON_DELETE)},
215 {"crossRef", (REPL_URGENT_ON_CREATE | REPL_URGENT_ON_DELETE)},
216 {"attributeSchema", (REPL_URGENT_ON_CREATE | REPL_URGENT_ON_UPDATE)},
217 {"classSchema", (REPL_URGENT_ON_CREATE | REPL_URGENT_ON_UPDATE)},
218 {"secret", (REPL_URGENT_ON_CREATE | REPL_URGENT_ON_UPDATE)},
219 {"rIDManager", (REPL_URGENT_ON_CREATE | REPL_URGENT_ON_UPDATE)},
223 /* Attributes looked for when updating or deleting, to check for a urgent replication needed */
224 static const char *urgent_attrs[] = {
227 "userAccountControl",
232 static bool replmd_check_urgent_objectclass(const struct ldb_message_element *objectclass_el,
233 enum urgent_situation situation)
236 for (i=0; urgent_objects[i].update_name; i++) {
238 if ((situation & urgent_objects[i].repl_situation) == 0) {
242 for (j=0; j<objectclass_el->num_values; j++) {
243 const struct ldb_val *v = &objectclass_el->values[j];
244 if (ldb_attr_cmp((const char *)v->data, urgent_objects[i].update_name) == 0) {
252 static bool replmd_check_urgent_attribute(const struct ldb_message_element *el)
254 if (ldb_attr_in_list(urgent_attrs, el->name)) {
260 static int replmd_replicated_apply_isDeleted(struct replmd_replicated_request *ar);
263 initialise the module
264 allocate the private structure and build the list
265 of partition DNs for use by replmd_notify()
267 static int replmd_init(struct ldb_module *module)
269 struct replmd_private *replmd_private;
270 struct ldb_context *ldb = ldb_module_get_ctx(module);
271 static const char *samba_dsdb_attrs[] = { SAMBA_COMPATIBLE_FEATURES_ATTR, NULL };
272 struct ldb_dn *samba_dsdb_dn;
273 struct ldb_result *res;
275 TALLOC_CTX *frame = talloc_stackframe();
276 replmd_private = talloc_zero(module, struct replmd_private);
277 if (replmd_private == NULL) {
280 return LDB_ERR_OPERATIONS_ERROR;
282 ldb_module_set_private(module, replmd_private);
284 replmd_private->schema_dn = ldb_get_schema_basedn(ldb);
286 samba_dsdb_dn = ldb_dn_new(frame, ldb, "@SAMBA_DSDB");
287 if (!samba_dsdb_dn) {
292 ret = dsdb_module_search_dn(module, frame, &res, samba_dsdb_dn,
293 samba_dsdb_attrs, DSDB_FLAG_NEXT_MODULE, NULL);
294 if (ret == LDB_SUCCESS) {
295 replmd_private->sorted_links
296 = ldb_msg_check_string_attribute(res->msgs[0],
297 SAMBA_COMPATIBLE_FEATURES_ATTR,
298 SAMBA_SORTED_LINKS_FEATURE);
302 return ldb_next_init(module);
306 cleanup our per-transaction contexts
308 static void replmd_txn_cleanup(struct replmd_private *replmd_private)
310 talloc_free(replmd_private->la_ctx);
311 replmd_private->la_list = NULL;
312 replmd_private->la_ctx = NULL;
318 struct la_backlink *next, *prev;
319 const char *attr_name;
320 struct ldb_dn *forward_dn;
321 struct GUID target_guid;
326 a ldb_modify request operating on modules below the
329 static int linked_attr_modify(struct ldb_module *module,
330 const struct ldb_message *message,
331 struct ldb_request *parent)
333 struct ldb_request *mod_req;
335 struct ldb_context *ldb = ldb_module_get_ctx(module);
336 TALLOC_CTX *tmp_ctx = talloc_new(module);
337 struct ldb_result *res;
339 res = talloc_zero(tmp_ctx, struct ldb_result);
341 talloc_free(tmp_ctx);
342 return ldb_oom(ldb_module_get_ctx(module));
345 ret = ldb_build_mod_req(&mod_req, ldb, tmp_ctx,
349 ldb_modify_default_callback,
351 LDB_REQ_SET_LOCATION(mod_req);
352 if (ret != LDB_SUCCESS) {
353 talloc_free(tmp_ctx);
357 ret = ldb_request_add_control(mod_req, DSDB_CONTROL_REPLICATED_UPDATE_OID,
359 if (ret != LDB_SUCCESS) {
363 /* Run the new request */
364 ret = ldb_next_request(module, mod_req);
366 if (ret == LDB_SUCCESS) {
367 ret = ldb_wait(mod_req->handle, LDB_WAIT_ALL);
370 talloc_free(tmp_ctx);
375 process a backlinks we accumulated during a transaction, adding and
376 deleting the backlinks from the target objects
378 static int replmd_process_backlink(struct ldb_module *module, struct la_backlink *bl, struct ldb_request *parent)
380 struct ldb_dn *target_dn, *source_dn;
382 struct ldb_context *ldb = ldb_module_get_ctx(module);
383 struct ldb_message *msg;
384 TALLOC_CTX *frame = talloc_stackframe();
390 - construct ldb_message
391 - either an add or a delete
393 ret = dsdb_module_dn_by_guid(module, frame, &bl->target_guid, &target_dn, parent);
394 if (ret != LDB_SUCCESS) {
395 struct GUID_txt_buf guid_str;
396 DBG_WARNING("Failed to find target DN for linked attribute with GUID %s\n",
397 GUID_buf_string(&bl->target_guid, &guid_str));
398 DBG_WARNING("Please run 'samba-tool dbcheck' to resolve any missing backlinks.\n");
403 msg = ldb_msg_new(frame);
405 ldb_module_oom(module);
407 return LDB_ERR_OPERATIONS_ERROR;
410 source_dn = ldb_dn_copy(frame, bl->forward_dn);
412 ldb_module_oom(module);
414 return LDB_ERR_OPERATIONS_ERROR;
416 /* Filter down to the attributes we want in the backlink */
417 const char *accept[] = { "GUID", "SID", NULL };
418 ldb_dn_extended_filter(source_dn, accept);
421 /* construct a ldb_message for adding/deleting the backlink */
423 dn_string = ldb_dn_get_extended_linearized(frame, bl->forward_dn, 1);
425 ldb_module_oom(module);
427 return LDB_ERR_OPERATIONS_ERROR;
429 ret = ldb_msg_add_steal_string(msg, bl->attr_name, dn_string);
430 if (ret != LDB_SUCCESS) {
434 msg->elements[0].flags = bl->active?LDB_FLAG_MOD_ADD:LDB_FLAG_MOD_DELETE;
436 /* a backlink should never be single valued. Unfortunately the
437 exchange schema has a attribute
438 msExchBridgeheadedLocalConnectorsDNBL which is single
439 valued and a backlink. We need to cope with that by
440 ignoring the single value flag */
441 msg->elements[0].flags |= LDB_FLAG_INTERNAL_DISABLE_SINGLE_VALUE_CHECK;
443 ret = dsdb_module_modify(module, msg, DSDB_FLAG_NEXT_MODULE, parent);
444 if (ret == LDB_ERR_NO_SUCH_ATTRIBUTE && !bl->active) {
445 /* we allow LDB_ERR_NO_SUCH_ATTRIBUTE as success to
446 cope with possible corruption where the backlink has
447 already been removed */
448 DEBUG(3,("WARNING: backlink from %s already removed from %s - %s\n",
449 ldb_dn_get_linearized(target_dn),
450 ldb_dn_get_linearized(source_dn),
451 ldb_errstring(ldb)));
453 } else if (ret != LDB_SUCCESS) {
454 ldb_asprintf_errstring(ldb, "Failed to %s backlink from %s to %s - %s",
455 bl->active?"add":"remove",
456 ldb_dn_get_linearized(source_dn),
457 ldb_dn_get_linearized(target_dn),
467 add a backlink to the list of backlinks to add/delete in the prepare
470 forward_dn is stolen onto the defereed context
472 static int replmd_defer_add_backlink(struct ldb_module *module,
473 struct replmd_private *replmd_private,
474 const struct dsdb_schema *schema,
475 struct replmd_replicated_request *ac,
476 struct ldb_dn *forward_dn,
477 struct GUID *target_guid, bool active,
478 const struct dsdb_attribute *schema_attr,
479 struct ldb_request *parent)
481 const struct dsdb_attribute *target_attr;
482 struct la_backlink *bl;
484 bl = talloc(ac, struct la_backlink);
486 ldb_module_oom(module);
487 return LDB_ERR_OPERATIONS_ERROR;
490 target_attr = dsdb_attribute_by_linkID(schema, schema_attr->linkID ^ 1);
493 * windows 2003 has a broken schema where the
494 * definition of msDS-IsDomainFor is missing (which is
495 * supposed to be the backlink of the
496 * msDS-HasDomainNCs attribute
501 bl->attr_name = target_attr->lDAPDisplayName;
502 bl->forward_dn = talloc_steal(bl, forward_dn);
503 bl->target_guid = *target_guid;
506 DLIST_ADD(ac->la_backlinks, bl);
512 add a backlink to the list of backlinks to add/delete in the prepare
515 static int replmd_add_backlink(struct ldb_module *module,
516 struct replmd_private *replmd_private,
517 const struct dsdb_schema *schema,
518 struct ldb_dn *forward_dn,
519 struct GUID *target_guid, bool active,
520 const struct dsdb_attribute *schema_attr,
521 struct ldb_request *parent)
523 const struct dsdb_attribute *target_attr;
524 struct la_backlink bl;
527 target_attr = dsdb_attribute_by_linkID(schema, schema_attr->linkID ^ 1);
530 * windows 2003 has a broken schema where the
531 * definition of msDS-IsDomainFor is missing (which is
532 * supposed to be the backlink of the
533 * msDS-HasDomainNCs attribute
538 bl.attr_name = target_attr->lDAPDisplayName;
539 bl.forward_dn = forward_dn;
540 bl.target_guid = *target_guid;
543 ret = replmd_process_backlink(module, &bl, parent);
549 * Callback for most write operations in this module:
551 * notify the repl task that a object has changed. The notifies are
552 * gathered up in the replmd_private structure then written to the
553 * @REPLCHANGED object in each partition during the prepare_commit
555 static int replmd_op_callback(struct ldb_request *req, struct ldb_reply *ares)
558 struct replmd_replicated_request *ac =
559 talloc_get_type_abort(req->context, struct replmd_replicated_request);
560 struct replmd_private *replmd_private =
561 talloc_get_type_abort(ldb_module_get_private(ac->module), struct replmd_private);
562 struct nc_entry *modified_partition;
563 struct ldb_control *partition_ctrl;
564 const struct dsdb_control_current_partition *partition;
566 struct ldb_control **controls;
568 partition_ctrl = ldb_reply_get_control(ares, DSDB_CONTROL_CURRENT_PARTITION_OID);
570 controls = ares->controls;
571 if (ldb_request_get_control(ac->req,
572 DSDB_CONTROL_CURRENT_PARTITION_OID) == NULL) {
574 * Remove the current partition control from what we pass up
575 * the chain if it hasn't been requested manually.
577 controls = ldb_controls_except_specified(ares->controls, ares,
581 if (ares->error != LDB_SUCCESS) {
582 struct GUID_txt_buf guid_txt;
583 struct ldb_message *msg = NULL;
586 if (ac->apply_mode == false) {
587 DBG_NOTICE("Originating update failure. Error is: %s\n",
588 ldb_strerror(ares->error));
589 return ldb_module_done(ac->req, controls,
590 ares->response, ares->error);
593 msg = ac->objs->objects[ac->index_current].msg;
595 * Set at DBG_NOTICE as once these start to happe, they
596 * will happen a lot until resolved, due to repeated
597 * replication. The caller will probably print the
598 * ldb error string anyway.
600 DBG_NOTICE("DRS replication apply failure for %s. Error is: %s\n",
601 ldb_dn_get_linearized(msg->dn),
602 ldb_strerror(ares->error));
604 s = ldb_ldif_message_redacted_string(ldb_module_get_ctx(ac->module),
609 DBG_INFO("Failing DRS %s replication message was %s:\n%s\n",
610 ac->search_msg == NULL ? "ADD" : "MODIFY",
611 GUID_buf_string(&ac->objs->objects[ac->index_current].object_guid,
615 return ldb_module_done(ac->req, controls,
616 ares->response, ares->error);
619 if (ares->type != LDB_REPLY_DONE) {
620 ldb_set_errstring(ldb_module_get_ctx(ac->module), "Invalid reply type for notify\n!");
621 return ldb_module_done(ac->req, NULL,
622 NULL, LDB_ERR_OPERATIONS_ERROR);
625 if (ac->apply_mode == false) {
626 struct la_backlink *bl;
628 * process our backlink list after an replmd_add(),
629 * creating and deleting backlinks as necessary (this
630 * code is sync). The other cases are handled inline
633 for (bl=ac->la_backlinks; bl; bl=bl->next) {
634 ret = replmd_process_backlink(ac->module, bl, ac->req);
635 if (ret != LDB_SUCCESS) {
636 return ldb_module_done(ac->req, NULL,
642 if (!partition_ctrl) {
643 ldb_set_errstring(ldb_module_get_ctx(ac->module),"No partition control on reply");
644 return ldb_module_done(ac->req, NULL,
645 NULL, LDB_ERR_OPERATIONS_ERROR);
648 partition = talloc_get_type_abort(partition_ctrl->data,
649 struct dsdb_control_current_partition);
651 if (ac->seq_num > 0) {
652 for (modified_partition = replmd_private->ncs; modified_partition;
653 modified_partition = modified_partition->next) {
654 if (ldb_dn_compare(modified_partition->dn, partition->dn) == 0) {
659 if (modified_partition == NULL) {
660 modified_partition = talloc_zero(replmd_private, struct nc_entry);
661 if (!modified_partition) {
662 ldb_oom(ldb_module_get_ctx(ac->module));
663 return ldb_module_done(ac->req, NULL,
664 NULL, LDB_ERR_OPERATIONS_ERROR);
666 modified_partition->dn = ldb_dn_copy(modified_partition, partition->dn);
667 if (!modified_partition->dn) {
668 ldb_oom(ldb_module_get_ctx(ac->module));
669 return ldb_module_done(ac->req, NULL,
670 NULL, LDB_ERR_OPERATIONS_ERROR);
672 DLIST_ADD(replmd_private->ncs, modified_partition);
675 if (ac->seq_num > modified_partition->mod_usn) {
676 modified_partition->mod_usn = ac->seq_num;
678 modified_partition->mod_usn_urgent = ac->seq_num;
681 if (!ac->apply_mode) {
682 replmd_private->originating_updates = true;
686 if (ac->apply_mode) {
687 ret = replmd_replicated_apply_isDeleted(ac);
688 if (ret != LDB_SUCCESS) {
689 return ldb_module_done(ac->req, NULL, NULL, ret);
693 /* free the partition control container here, for the
694 * common path. Other cases will have it cleaned up
695 * eventually with the ares */
696 talloc_free(partition_ctrl);
697 return ldb_module_done(ac->req, controls,
698 ares->response, LDB_SUCCESS);
704 * update a @REPLCHANGED record in each partition if there have been
705 * any writes of replicated data in the partition
707 static int replmd_notify_store(struct ldb_module *module, struct ldb_request *parent)
709 struct replmd_private *replmd_private =
710 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
712 while (replmd_private->ncs) {
714 struct nc_entry *modified_partition = replmd_private->ncs;
716 ret = dsdb_module_save_partition_usn(module, modified_partition->dn,
717 modified_partition->mod_usn,
718 modified_partition->mod_usn_urgent, parent);
719 if (ret != LDB_SUCCESS) {
720 DEBUG(0,(__location__ ": Failed to save partition uSN for %s\n",
721 ldb_dn_get_linearized(modified_partition->dn)));
725 if (ldb_dn_compare(modified_partition->dn,
726 replmd_private->schema_dn) == 0) {
727 struct ldb_result *ext_res;
728 ret = dsdb_module_extended(module,
729 replmd_private->schema_dn,
731 DSDB_EXTENDED_SCHEMA_UPDATE_NOW_OID,
733 DSDB_FLAG_NEXT_MODULE,
735 if (ret != LDB_SUCCESS) {
738 talloc_free(ext_res);
741 DLIST_REMOVE(replmd_private->ncs, modified_partition);
742 talloc_free(modified_partition);
750 created a replmd_replicated_request context
752 static struct replmd_replicated_request *replmd_ctx_init(struct ldb_module *module,
753 struct ldb_request *req)
755 struct ldb_context *ldb;
756 struct replmd_replicated_request *ac;
757 const struct GUID *our_invocation_id;
759 ldb = ldb_module_get_ctx(module);
761 ac = talloc_zero(req, struct replmd_replicated_request);
770 ac->schema = dsdb_get_schema(ldb, ac);
772 ldb_debug_set(ldb, LDB_DEBUG_FATAL,
773 "replmd_modify: no dsdb_schema loaded");
774 DEBUG(0,(__location__ ": %s\n", ldb_errstring(ldb)));
779 /* get our invocationId */
780 our_invocation_id = samdb_ntds_invocation_id(ldb);
781 if (!our_invocation_id) {
782 ldb_debug_set(ldb, LDB_DEBUG_FATAL,
783 "replmd_add: unable to find invocationId\n");
787 ac->our_invocation_id = *our_invocation_id;
793 add a time element to a record
795 static int add_time_element(struct ldb_message *msg, const char *attr, time_t t)
797 struct ldb_message_element *el;
801 if (ldb_msg_find_element(msg, attr) != NULL) {
805 s = ldb_timestring(msg, t);
807 return LDB_ERR_OPERATIONS_ERROR;
810 ret = ldb_msg_add_string(msg, attr, s);
811 if (ret != LDB_SUCCESS) {
815 el = ldb_msg_find_element(msg, attr);
816 /* always set as replace. This works because on add ops, the flag
818 el->flags = LDB_FLAG_MOD_REPLACE;
824 add a uint64_t element to a record
826 static int add_uint64_element(struct ldb_context *ldb, struct ldb_message *msg,
827 const char *attr, uint64_t v)
829 struct ldb_message_element *el;
832 if (ldb_msg_find_element(msg, attr) != NULL) {
836 ret = samdb_msg_add_uint64(ldb, msg, msg, attr, v);
837 if (ret != LDB_SUCCESS) {
841 el = ldb_msg_find_element(msg, attr);
842 /* always set as replace. This works because on add ops, the flag
844 el->flags = LDB_FLAG_MOD_REPLACE;
849 static int replmd_replPropertyMetaData1_attid_sort(const struct replPropertyMetaData1 *m1,
850 const struct replPropertyMetaData1 *m2,
851 const uint32_t *rdn_attid)
854 * This assignment seems inoccous, but it is critical for the
855 * system, as we need to do the comparisons as a unsigned
856 * quantity, not signed (enums are signed integers)
858 uint32_t attid_1 = m1->attid;
859 uint32_t attid_2 = m2->attid;
861 if (attid_1 == attid_2) {
866 * See above regarding this being an unsigned comparison.
867 * Otherwise when the high bit is set on non-standard
868 * attributes, they would end up first, before objectClass
871 return attid_1 > attid_2 ? 1 : -1;
874 static int replmd_replPropertyMetaDataCtr1_verify(struct ldb_context *ldb,
875 struct replPropertyMetaDataCtr1 *ctr1,
878 if (ctr1->count == 0) {
879 ldb_debug_set(ldb, LDB_DEBUG_FATAL,
880 "No elements found in replPropertyMetaData for %s!\n",
881 ldb_dn_get_linearized(dn));
882 return LDB_ERR_CONSTRAINT_VIOLATION;
885 /* the objectClass attribute is value 0x00000000, so must be first */
886 if (ctr1->array[0].attid != DRSUAPI_ATTID_objectClass) {
887 ldb_debug_set(ldb, LDB_DEBUG_FATAL,
888 "No objectClass found in replPropertyMetaData for %s!\n",
889 ldb_dn_get_linearized(dn));
890 return LDB_ERR_OBJECT_CLASS_VIOLATION;
896 static int replmd_replPropertyMetaDataCtr1_sort_and_verify(struct ldb_context *ldb,
897 struct replPropertyMetaDataCtr1 *ctr1,
900 /* Note this is O(n^2) for the almost-sorted case, which this is */
901 LDB_TYPESAFE_QSORT(ctr1->array, ctr1->count, NULL,
902 replmd_replPropertyMetaData1_attid_sort);
903 return replmd_replPropertyMetaDataCtr1_verify(ldb, ctr1, dn);
906 static int replmd_ldb_message_element_attid_sort(const struct ldb_message_element *e1,
907 const struct ldb_message_element *e2,
908 const struct dsdb_schema *schema)
910 const struct dsdb_attribute *a1;
911 const struct dsdb_attribute *a2;
914 * TODO: make this faster by caching the dsdb_attribute pointer
915 * on the ldb_messag_element
918 a1 = dsdb_attribute_by_lDAPDisplayName(schema, e1->name);
919 a2 = dsdb_attribute_by_lDAPDisplayName(schema, e2->name);
922 * TODO: remove this check, we should rely on e1 and e2 having valid attribute names
926 return strcasecmp(e1->name, e2->name);
928 if (a1->attributeID_id == a2->attributeID_id) {
931 return a1->attributeID_id > a2->attributeID_id ? 1 : -1;
934 static void replmd_ldb_message_sort(struct ldb_message *msg,
935 const struct dsdb_schema *schema)
937 LDB_TYPESAFE_QSORT(msg->elements, msg->num_elements, schema, replmd_ldb_message_element_attid_sort);
940 static int replmd_build_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct dsdb_dn *dsdb_dn,
941 const struct GUID *invocation_id,
942 uint64_t local_usn, NTTIME nttime);
944 static int parsed_dn_compare(struct parsed_dn *pdn1, struct parsed_dn *pdn2);
946 static int get_parsed_dns(struct ldb_module *module, TALLOC_CTX *mem_ctx,
947 struct ldb_message_element *el, struct parsed_dn **pdn,
948 const char *ldap_oid, struct ldb_request *parent);
950 static int check_parsed_dn_duplicates(struct ldb_module *module,
951 struct ldb_message_element *el,
952 struct parsed_dn *pdn);
955 fix up linked attributes in replmd_add.
956 This involves setting up the right meta-data in extended DN
957 components, and creating backlinks to the object
959 static int replmd_add_fix_la(struct ldb_module *module, TALLOC_CTX *mem_ctx,
960 struct replmd_private *replmd_private,
961 struct ldb_message_element *el,
962 struct replmd_replicated_request *ac,
964 struct ldb_dn *forward_dn,
965 const struct dsdb_attribute *sa,
966 struct ldb_request *parent)
969 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
970 struct ldb_context *ldb = ldb_module_get_ctx(module);
971 struct parsed_dn *pdn;
972 /* We will take a reference to the schema in replmd_add_backlink */
973 const struct dsdb_schema *schema = dsdb_get_schema(ldb, NULL);
974 struct ldb_val *new_values = NULL;
977 if (dsdb_check_single_valued_link(sa, el) == LDB_SUCCESS) {
978 el->flags |= LDB_FLAG_INTERNAL_DISABLE_SINGLE_VALUE_CHECK;
980 ldb_asprintf_errstring(ldb,
981 "Attribute %s is single valued but "
982 "more than one value has been supplied",
984 talloc_free(tmp_ctx);
985 return LDB_ERR_CONSTRAINT_VIOLATION;
988 ret = get_parsed_dns(module, tmp_ctx, el, &pdn,
989 sa->syntax->ldap_oid, parent);
990 if (ret != LDB_SUCCESS) {
991 talloc_free(tmp_ctx);
995 ret = check_parsed_dn_duplicates(module, el, pdn);
996 if (ret != LDB_SUCCESS) {
997 talloc_free(tmp_ctx);
1001 new_values = talloc_array(tmp_ctx, struct ldb_val, el->num_values);
1002 if (new_values == NULL) {
1003 ldb_module_oom(module);
1004 talloc_free(tmp_ctx);
1005 return LDB_ERR_OPERATIONS_ERROR;
1008 for (i = 0; i < el->num_values; i++) {
1009 struct parsed_dn *p = &pdn[i];
1010 ret = replmd_build_la_val(el->values, p->v, p->dsdb_dn,
1011 &ac->our_invocation_id,
1013 if (ret != LDB_SUCCESS) {
1014 talloc_free(tmp_ctx);
1018 ret = replmd_defer_add_backlink(module, replmd_private,
1020 forward_dn, &p->guid, true, sa,
1022 if (ret != LDB_SUCCESS) {
1023 talloc_free(tmp_ctx);
1027 new_values[i] = *p->v;
1029 el->values = talloc_steal(mem_ctx, new_values);
1031 talloc_free(tmp_ctx);
1035 static int replmd_add_make_extended_dn(struct ldb_request *req,
1036 const DATA_BLOB *guid_blob,
1037 struct ldb_dn **_extended_dn)
1040 const DATA_BLOB *sid_blob;
1041 /* Calculate an extended DN for any linked attributes */
1042 struct ldb_dn *extended_dn = ldb_dn_copy(req, req->op.add.message->dn);
1044 return LDB_ERR_OPERATIONS_ERROR;
1046 ret = ldb_dn_set_extended_component(extended_dn, "GUID", guid_blob);
1047 if (ret != LDB_SUCCESS) {
1051 sid_blob = ldb_msg_find_ldb_val(req->op.add.message, "objectSID");
1052 if (sid_blob != NULL) {
1053 ret = ldb_dn_set_extended_component(extended_dn, "SID", sid_blob);
1054 if (ret != LDB_SUCCESS) {
1058 *_extended_dn = extended_dn;
1063 intercept add requests
1065 static int replmd_add(struct ldb_module *module, struct ldb_request *req)
1067 struct ldb_context *ldb;
1068 struct ldb_control *control;
1069 struct replmd_replicated_request *ac;
1070 enum ndr_err_code ndr_err;
1071 struct ldb_request *down_req;
1072 struct ldb_message *msg;
1073 const DATA_BLOB *guid_blob;
1074 DATA_BLOB guid_blob_stack;
1076 uint8_t guid_data[16];
1077 struct replPropertyMetaDataBlob nmd;
1078 struct ldb_val nmd_value;
1079 struct ldb_dn *extended_dn = NULL;
1082 * The use of a time_t here seems odd, but as the NTTIME
1083 * elements are actually declared as NTTIME_1sec in the IDL,
1084 * getting a higher resolution timestamp is not required.
1086 time_t t = time(NULL);
1091 unsigned int functional_level;
1093 bool allow_add_guid = false;
1094 bool remove_current_guid = false;
1095 bool is_urgent = false;
1096 bool is_schema_nc = false;
1097 struct ldb_message_element *objectclass_el;
1098 struct replmd_private *replmd_private =
1099 talloc_get_type_abort(ldb_module_get_private(module), struct replmd_private);
1101 /* check if there's a show relax control (used by provision to say 'I know what I'm doing') */
1102 control = ldb_request_get_control(req, LDB_CONTROL_RELAX_OID);
1104 allow_add_guid = true;
1107 /* do not manipulate our control entries */
1108 if (ldb_dn_is_special(req->op.add.message->dn)) {
1109 return ldb_next_request(module, req);
1112 ldb = ldb_module_get_ctx(module);
1114 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_add\n");
1116 guid_blob = ldb_msg_find_ldb_val(req->op.add.message, "objectGUID");
1117 if (guid_blob != NULL) {
1118 if (!allow_add_guid) {
1119 ldb_set_errstring(ldb,
1120 "replmd_add: it's not allowed to add an object with objectGUID!");
1121 return LDB_ERR_UNWILLING_TO_PERFORM;
1123 NTSTATUS status = GUID_from_data_blob(guid_blob,&guid);
1124 if (!NT_STATUS_IS_OK(status)) {
1125 ldb_set_errstring(ldb,
1126 "replmd_add: Unable to parse the 'objectGUID' as a GUID!");
1127 return LDB_ERR_UNWILLING_TO_PERFORM;
1129 /* we remove this attribute as it can be a string and
1130 * will not be treated correctly and then we will re-add
1131 * it later on in the good format */
1132 remove_current_guid = true;
1136 guid = GUID_random();
1138 guid_blob_stack = data_blob_const(guid_data, sizeof(guid_data));
1140 /* This can't fail */
1141 ndr_push_struct_into_fixed_blob(&guid_blob_stack, &guid,
1142 (ndr_push_flags_fn_t)ndr_push_GUID);
1143 guid_blob = &guid_blob_stack;
1146 ac = replmd_ctx_init(module, req);
1148 return ldb_module_oom(module);
1151 functional_level = dsdb_functional_level(ldb);
1153 /* Get a sequence number from the backend */
1154 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &ac->seq_num);
1155 if (ret != LDB_SUCCESS) {
1160 /* we have to copy the message as the caller might have it as a const */
1161 msg = ldb_msg_copy_shallow(ac, req->op.add.message);
1165 return LDB_ERR_OPERATIONS_ERROR;
1168 /* generated times */
1169 unix_to_nt_time(&now, t);
1170 time_str = ldb_timestring(msg, t);
1174 return LDB_ERR_OPERATIONS_ERROR;
1176 if (remove_current_guid) {
1177 ldb_msg_remove_attr(msg,"objectGUID");
1181 * remove autogenerated attributes
1183 ldb_msg_remove_attr(msg, "whenCreated");
1184 ldb_msg_remove_attr(msg, "whenChanged");
1185 ldb_msg_remove_attr(msg, "uSNCreated");
1186 ldb_msg_remove_attr(msg, "uSNChanged");
1187 ldb_msg_remove_attr(msg, "replPropertyMetaData");
1190 * readd replicated attributes
1192 ret = ldb_msg_add_string(msg, "whenCreated", time_str);
1193 if (ret != LDB_SUCCESS) {
1199 /* build the replication meta_data */
1202 nmd.ctr.ctr1.count = msg->num_elements;
1203 nmd.ctr.ctr1.array = talloc_array(msg,
1204 struct replPropertyMetaData1,
1205 nmd.ctr.ctr1.count);
1206 if (!nmd.ctr.ctr1.array) {
1209 return LDB_ERR_OPERATIONS_ERROR;
1212 is_schema_nc = ldb_dn_compare_base(replmd_private->schema_dn, msg->dn) == 0;
1214 for (i=0; i < msg->num_elements;) {
1215 struct ldb_message_element *e = &msg->elements[i];
1216 struct replPropertyMetaData1 *m = &nmd.ctr.ctr1.array[ni];
1217 const struct dsdb_attribute *sa;
1219 if (e->name[0] == '@') {
1224 sa = dsdb_attribute_by_lDAPDisplayName(ac->schema, e->name);
1226 ldb_debug_set(ldb, LDB_DEBUG_ERROR,
1227 "replmd_add: attribute '%s' not defined in schema\n",
1230 return LDB_ERR_NO_SUCH_ATTRIBUTE;
1233 if ((sa->systemFlags & DS_FLAG_ATTR_NOT_REPLICATED) || (sa->systemFlags & DS_FLAG_ATTR_IS_CONSTRUCTED)) {
1234 /* if the attribute is not replicated (0x00000001)
1235 * or constructed (0x00000004) it has no metadata
1241 if (sa->linkID != 0 && functional_level > DS_DOMAIN_FUNCTION_2000) {
1242 if (extended_dn == NULL) {
1243 ret = replmd_add_make_extended_dn(req,
1246 if (ret != LDB_SUCCESS) {
1253 * Prepare the context for the backlinks and
1254 * create metadata for the forward links. The
1255 * backlinks are created in
1256 * replmd_op_callback() after the successful
1257 * ADD of the object.
1259 ret = replmd_add_fix_la(module, msg->elements,
1264 if (ret != LDB_SUCCESS) {
1268 /* linked attributes are not stored in
1269 replPropertyMetaData in FL above w2k */
1274 m->attid = dsdb_attribute_get_attid(sa, is_schema_nc);
1276 if (m->attid == DRSUAPI_ATTID_isDeleted) {
1277 const struct ldb_val *rdn_val = ldb_dn_get_rdn_val(msg->dn);
1280 if (rdn_val == NULL) {
1283 return LDB_ERR_OPERATIONS_ERROR;
1286 rdn = (const char*)rdn_val->data;
1287 if (strcmp(rdn, "Deleted Objects") == 0) {
1289 * Set the originating_change_time to 29/12/9999 at 23:59:59
1290 * as specified in MS-ADTS 7.1.1.4.2 Deleted Objects Container
1292 m->originating_change_time = DELETED_OBJECT_CONTAINER_CHANGE_TIME;
1294 m->originating_change_time = now;
1297 m->originating_change_time = now;
1299 m->originating_invocation_id = ac->our_invocation_id;
1300 m->originating_usn = ac->seq_num;
1301 m->local_usn = ac->seq_num;
1304 if (!(e->flags & DSDB_FLAG_INTERNAL_FORCE_META_DATA)) {
1309 e->flags &= ~DSDB_FLAG_INTERNAL_FORCE_META_DATA;
1311 if (e->num_values != 0) {
1316 ldb_msg_remove_element(msg, e);
1319 /* fix meta data count */
1320 nmd.ctr.ctr1.count = ni;
1323 * sort meta data array
1325 ret = replmd_replPropertyMetaDataCtr1_sort_and_verify(ldb, &nmd.ctr.ctr1, msg->dn);
1326 if (ret != LDB_SUCCESS) {
1327 ldb_asprintf_errstring(ldb, "%s: error during direct ADD: %s", __func__, ldb_errstring(ldb));
1332 /* generated NDR encoded values */
1333 ndr_err = ndr_push_struct_blob(&nmd_value, msg,
1335 (ndr_push_flags_fn_t)ndr_push_replPropertyMetaDataBlob);
1336 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1339 return LDB_ERR_OPERATIONS_ERROR;
1343 * add the autogenerated values
1345 ret = dsdb_msg_add_guid(msg, &guid, "objectGUID");
1346 if (ret != LDB_SUCCESS) {
1351 ret = ldb_msg_add_string(msg, "whenChanged", time_str);
1352 if (ret != LDB_SUCCESS) {
1357 ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNCreated", ac->seq_num);
1358 if (ret != LDB_SUCCESS) {
1363 ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNChanged", ac->seq_num);
1364 if (ret != LDB_SUCCESS) {
1369 ret = ldb_msg_add_value(msg, "replPropertyMetaData", &nmd_value, NULL);
1370 if (ret != LDB_SUCCESS) {
1377 * sort the attributes by attid before storing the object
1379 replmd_ldb_message_sort(msg, ac->schema);
1382 * Assert that we do have an objectClass
1384 objectclass_el = ldb_msg_find_element(msg, "objectClass");
1385 if (objectclass_el == NULL) {
1386 ldb_asprintf_errstring(ldb, __location__
1387 ": objectClass missing on %s\n",
1388 ldb_dn_get_linearized(msg->dn));
1390 return LDB_ERR_OBJECT_CLASS_VIOLATION;
1392 is_urgent = replmd_check_urgent_objectclass(objectclass_el,
1393 REPL_URGENT_ON_CREATE);
1395 ac->is_urgent = is_urgent;
1396 ret = ldb_build_add_req(&down_req, ldb, ac,
1399 ac, replmd_op_callback,
1402 LDB_REQ_SET_LOCATION(down_req);
1403 if (ret != LDB_SUCCESS) {
1408 /* current partition control is needed by "replmd_op_callback" */
1409 if (ldb_request_get_control(req, DSDB_CONTROL_CURRENT_PARTITION_OID) == NULL) {
1410 ret = ldb_request_add_control(down_req,
1411 DSDB_CONTROL_CURRENT_PARTITION_OID,
1413 if (ret != LDB_SUCCESS) {
1419 if (functional_level == DS_DOMAIN_FUNCTION_2000) {
1420 ret = ldb_request_add_control(down_req, DSDB_CONTROL_APPLY_LINKS, false, NULL);
1421 if (ret != LDB_SUCCESS) {
1427 /* mark the control done */
1429 control->critical = 0;
1431 /* go on with the call chain */
1432 return ldb_next_request(module, down_req);
1437 * update the replPropertyMetaData for one element
1439 static int replmd_update_rpmd_element(struct ldb_context *ldb,
1440 struct ldb_message *msg,
1441 struct ldb_message_element *el,
1442 struct ldb_message_element *old_el,
1443 struct replPropertyMetaDataBlob *omd,
1444 const struct dsdb_schema *schema,
1446 const struct GUID *our_invocation_id,
1449 bool is_forced_rodc,
1450 struct ldb_request *req)
1453 const struct dsdb_attribute *a;
1454 struct replPropertyMetaData1 *md1;
1455 bool may_skip = false;
1458 a = dsdb_attribute_by_lDAPDisplayName(schema, el->name);
1460 if (ldb_request_get_control(req, LDB_CONTROL_RELAX_OID)) {
1461 /* allow this to make it possible for dbcheck
1462 to remove bad attributes */
1466 DEBUG(0,(__location__ ": Unable to find attribute %s in schema\n",
1468 return LDB_ERR_OPERATIONS_ERROR;
1471 attid = dsdb_attribute_get_attid(a, is_schema_nc);
1473 if ((a->systemFlags & DS_FLAG_ATTR_NOT_REPLICATED) || (a->systemFlags & DS_FLAG_ATTR_IS_CONSTRUCTED)) {
1478 * if the attribute's value haven't changed, and this isn't
1479 * just a delete of everything then return LDB_SUCCESS Unless
1480 * we have the provision control or if the attribute is
1481 * interSiteTopologyGenerator as this page explain:
1482 * http://support.microsoft.com/kb/224815 this attribute is
1483 * periodicaly written by the DC responsible for the intersite
1484 * generation in a given site
1486 * Unchanged could be deleting or replacing an already-gone
1487 * thing with an unconstrained delete/empty replace or a
1488 * replace with the same value, but not an add with the same
1489 * value because that could be about adding a duplicate (which
1490 * is for someone else to error out on).
1492 if (old_el != NULL && ldb_msg_element_equal_ordered(el, old_el)) {
1493 if (LDB_FLAG_MOD_TYPE(el->flags) == LDB_FLAG_MOD_REPLACE) {
1496 } else if (old_el == NULL && el->num_values == 0) {
1497 if (LDB_FLAG_MOD_TYPE(el->flags) == LDB_FLAG_MOD_REPLACE) {
1499 } else if (LDB_FLAG_MOD_TYPE(el->flags) == LDB_FLAG_MOD_DELETE) {
1502 } else if (a->linkID != 0 && LDB_FLAG_MOD_TYPE(el->flags) == LDB_FLAG_MOD_DELETE &&
1503 ldb_request_get_control(req, DSDB_CONTROL_REPLMD_VANISH_LINKS) != NULL) {
1505 * We intentionally skip the version bump when attempting to
1508 * The control is set by dbcheck and expunge-tombstones which
1509 * both attempt to be non-replicating. Otherwise, making an
1510 * alteration to the replication state would trigger a
1511 * broadcast of all expunged objects.
1516 if (el->flags & DSDB_FLAG_INTERNAL_FORCE_META_DATA) {
1518 el->flags &= ~DSDB_FLAG_INTERNAL_FORCE_META_DATA;
1522 if (strcmp(el->name, "interSiteTopologyGenerator") != 0 &&
1523 !ldb_request_get_control(req, LDB_CONTROL_PROVISION_OID)) {
1525 * allow this to make it possible for dbcheck
1526 * to rebuild broken metadata
1532 for (i=0; i<omd->ctr.ctr1.count; i++) {
1534 * First check if we find it under the msDS-IntID,
1535 * then check if we find it under the OID and
1538 * This allows the administrator to simply re-write
1539 * the attributes and so restore replication, which is
1540 * likely what they will try to do.
1542 if (attid == omd->ctr.ctr1.array[i].attid) {
1546 if (a->attributeID_id == omd->ctr.ctr1.array[i].attid) {
1551 if (a->linkID != 0 && dsdb_functional_level(ldb) > DS_DOMAIN_FUNCTION_2000) {
1552 /* linked attributes are not stored in
1553 replPropertyMetaData in FL above w2k, but we do
1554 raise the seqnum for the object */
1555 if (*seq_num == 0 &&
1556 ldb_sequence_number(ldb, LDB_SEQ_NEXT, seq_num) != LDB_SUCCESS) {
1557 return LDB_ERR_OPERATIONS_ERROR;
1562 if (i == omd->ctr.ctr1.count) {
1563 /* we need to add a new one */
1564 omd->ctr.ctr1.array = talloc_realloc(msg, omd->ctr.ctr1.array,
1565 struct replPropertyMetaData1, omd->ctr.ctr1.count+1);
1566 if (omd->ctr.ctr1.array == NULL) {
1568 return LDB_ERR_OPERATIONS_ERROR;
1570 omd->ctr.ctr1.count++;
1571 ZERO_STRUCT(omd->ctr.ctr1.array[i]);
1574 /* Get a new sequence number from the backend. We only do this
1575 * if we have a change that requires a new
1576 * replPropertyMetaData element
1578 if (*seq_num == 0) {
1579 int ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, seq_num);
1580 if (ret != LDB_SUCCESS) {
1581 return LDB_ERR_OPERATIONS_ERROR;
1585 md1 = &omd->ctr.ctr1.array[i];
1589 if (md1->attid == DRSUAPI_ATTID_isDeleted) {
1590 const struct ldb_val *rdn_val = ldb_dn_get_rdn_val(msg->dn);
1593 if (rdn_val == NULL) {
1595 return LDB_ERR_OPERATIONS_ERROR;
1598 rdn = (const char*)rdn_val->data;
1599 if (strcmp(rdn, "Deleted Objects") == 0) {
1601 * Set the originating_change_time to 29/12/9999 at 23:59:59
1602 * as specified in MS-ADTS 7.1.1.4.2 Deleted Objects Container
1604 md1->originating_change_time = DELETED_OBJECT_CONTAINER_CHANGE_TIME;
1606 md1->originating_change_time = now;
1609 md1->originating_change_time = now;
1611 md1->originating_invocation_id = *our_invocation_id;
1612 md1->originating_usn = *seq_num;
1613 md1->local_usn = *seq_num;
1615 if (is_forced_rodc) {
1616 /* Force version to 0 to be overriden later via replication */
1624 * Bump the replPropertyMetaData version on an attribute, and if it
1625 * has changed (or forced by leaving rdn_old NULL), update the value
1628 * This is important, as calling a modify operation may not change the
1629 * version number if the values appear unchanged, but a rename between
1630 * parents bumps this value.
1633 static int replmd_update_rpmd_rdn_attr(struct ldb_context *ldb,
1634 struct ldb_message *msg,
1635 const struct ldb_val *rdn_new,
1636 const struct ldb_val *rdn_old,
1637 struct replPropertyMetaDataBlob *omd,
1638 struct replmd_replicated_request *ar,
1641 bool is_forced_rodc)
1643 const char *rdn_name = ldb_dn_get_rdn_name(msg->dn);
1644 const struct dsdb_attribute *rdn_attr =
1645 dsdb_attribute_by_lDAPDisplayName(ar->schema, rdn_name);
1646 const char *attr_name = rdn_attr != NULL ?
1647 rdn_attr->lDAPDisplayName :
1649 struct ldb_message_element new_el = {
1650 .flags = LDB_FLAG_MOD_REPLACE,
1653 .values = discard_const_p(struct ldb_val, rdn_new)
1655 struct ldb_message_element old_el = {
1656 .flags = LDB_FLAG_MOD_REPLACE,
1658 .num_values = rdn_old ? 1 : 0,
1659 .values = discard_const_p(struct ldb_val, rdn_old)
1662 if (ldb_msg_element_equal_ordered(&new_el, &old_el) == false) {
1663 int ret = ldb_msg_add(msg, &new_el, LDB_FLAG_MOD_REPLACE);
1664 if (ret != LDB_SUCCESS) {
1665 return ldb_oom(ldb);
1669 return replmd_update_rpmd_element(ldb, msg, &new_el, NULL,
1670 omd, ar->schema, &ar->seq_num,
1671 &ar->our_invocation_id,
1672 now, is_schema_nc, is_forced_rodc,
1677 static uint64_t find_max_local_usn(struct replPropertyMetaDataBlob omd)
1679 uint32_t count = omd.ctr.ctr1.count;
1682 for (i=0; i < count; i++) {
1683 struct replPropertyMetaData1 m = omd.ctr.ctr1.array[i];
1684 if (max < m.local_usn) {
1692 * update the replPropertyMetaData object each time we modify an
1693 * object. This is needed for DRS replication, as the merge on the
1694 * client is based on this object
1696 static int replmd_update_rpmd(struct ldb_module *module,
1697 const struct dsdb_schema *schema,
1698 struct ldb_request *req,
1699 const char * const *rename_attrs,
1700 struct ldb_message *msg, uint64_t *seq_num,
1701 time_t t, bool is_schema_nc,
1702 bool *is_urgent, bool *rodc)
1704 const struct ldb_val *omd_value;
1705 enum ndr_err_code ndr_err;
1706 struct replPropertyMetaDataBlob omd;
1709 const struct GUID *our_invocation_id;
1711 const char * const *attrs = NULL;
1712 const char * const attrs2[] = { "uSNChanged", "objectClass", "instanceType", NULL };
1713 struct ldb_result *res;
1714 struct ldb_context *ldb;
1715 struct ldb_message_element *objectclass_el;
1716 enum urgent_situation situation;
1717 bool rmd_is_provided;
1718 bool rmd_is_just_resorted = false;
1719 const char *not_rename_attrs[4 + msg->num_elements];
1720 bool is_forced_rodc = false;
1723 attrs = rename_attrs;
1725 for (i = 0; i < msg->num_elements; i++) {
1726 not_rename_attrs[i] = msg->elements[i].name;
1728 not_rename_attrs[i] = "replPropertyMetaData";
1729 not_rename_attrs[i+1] = "objectClass";
1730 not_rename_attrs[i+2] = "instanceType";
1731 not_rename_attrs[i+3] = NULL;
1732 attrs = not_rename_attrs;
1735 ldb = ldb_module_get_ctx(module);
1737 ret = samdb_rodc(ldb, rodc);
1738 if (ret != LDB_SUCCESS) {
1739 DEBUG(4, (__location__ ": unable to tell if we are an RODC\n"));
1744 ldb_request_get_control(req, DSDB_CONTROL_FORCE_RODC_LOCAL_CHANGE)) {
1745 is_forced_rodc = true;
1748 our_invocation_id = samdb_ntds_invocation_id(ldb);
1749 if (!our_invocation_id) {
1750 /* this happens during an initial vampire while
1751 updating the schema */
1752 DEBUG(5,("No invocationID - skipping replPropertyMetaData update\n"));
1756 unix_to_nt_time(&now, t);
1758 if (ldb_request_get_control(req, DSDB_CONTROL_CHANGEREPLMETADATA_OID)) {
1759 rmd_is_provided = true;
1760 if (ldb_request_get_control(req, DSDB_CONTROL_CHANGEREPLMETADATA_RESORT_OID)) {
1761 rmd_is_just_resorted = true;
1764 rmd_is_provided = false;
1767 /* if isDeleted is present and is TRUE, then we consider we are deleting,
1768 * otherwise we consider we are updating */
1769 if (ldb_msg_check_string_attribute(msg, "isDeleted", "TRUE")) {
1770 situation = REPL_URGENT_ON_DELETE;
1771 } else if (rename_attrs) {
1772 situation = REPL_URGENT_ON_CREATE | REPL_URGENT_ON_DELETE;
1774 situation = REPL_URGENT_ON_UPDATE;
1777 if (rmd_is_provided) {
1778 /* In this case the change_replmetadata control was supplied */
1779 /* We check that it's the only attribute that is provided
1780 * (it's a rare case so it's better to keep the code simplier)
1781 * We also check that the highest local_usn is bigger or the same as
1784 if( msg->num_elements != 1 ||
1785 strncmp(msg->elements[0].name,
1786 "replPropertyMetaData", 20) ) {
1787 DEBUG(0,(__location__ ": changereplmetada control called without "\
1788 "a specified replPropertyMetaData attribute or with others\n"));
1789 return LDB_ERR_OPERATIONS_ERROR;
1791 if (situation != REPL_URGENT_ON_UPDATE) {
1792 DEBUG(0,(__location__ ": changereplmetada control can't be called when deleting an object\n"));
1793 return LDB_ERR_OPERATIONS_ERROR;
1795 omd_value = ldb_msg_find_ldb_val(msg, "replPropertyMetaData");
1797 DEBUG(0,(__location__ ": replPropertyMetaData was not specified for Object %s\n",
1798 ldb_dn_get_linearized(msg->dn)));
1799 return LDB_ERR_OPERATIONS_ERROR;
1801 ndr_err = ndr_pull_struct_blob(omd_value, msg, &omd,
1802 (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
1803 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1804 DEBUG(0,(__location__ ": Failed to parse replPropertyMetaData for %s\n",
1805 ldb_dn_get_linearized(msg->dn)));
1806 return LDB_ERR_OPERATIONS_ERROR;
1809 ret = dsdb_module_search_dn(module, msg, &res, msg->dn, attrs2,
1810 DSDB_FLAG_NEXT_MODULE |
1811 DSDB_SEARCH_SHOW_RECYCLED |
1812 DSDB_SEARCH_SHOW_EXTENDED_DN |
1813 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT |
1814 DSDB_SEARCH_REVEAL_INTERNALS, req);
1816 if (ret != LDB_SUCCESS) {
1820 if (rmd_is_just_resorted == false) {
1821 *seq_num = find_max_local_usn(omd);
1823 db_seq = ldb_msg_find_attr_as_uint64(res->msgs[0], "uSNChanged", 0);
1826 * The test here now allows for a new
1827 * replPropertyMetaData with no change, if was
1828 * just dbcheck re-sorting the values.
1830 if (*seq_num <= db_seq) {
1831 DEBUG(0,(__location__ ": changereplmetada control provided but max(local_usn)" \
1832 " is less than uSNChanged (max = %lld uSNChanged = %lld)\n",
1833 (long long)*seq_num, (long long)db_seq));
1834 return LDB_ERR_OPERATIONS_ERROR;
1839 /* search for the existing replPropertyMetaDataBlob. We need
1840 * to use REVEAL and ask for DNs in storage format to support
1841 * the check for values being the same in
1842 * replmd_update_rpmd_element()
1844 ret = dsdb_module_search_dn(module, msg, &res, msg->dn, attrs,
1845 DSDB_FLAG_NEXT_MODULE |
1846 DSDB_SEARCH_SHOW_RECYCLED |
1847 DSDB_SEARCH_SHOW_EXTENDED_DN |
1848 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT |
1849 DSDB_SEARCH_REVEAL_INTERNALS, req);
1850 if (ret != LDB_SUCCESS) {
1854 omd_value = ldb_msg_find_ldb_val(res->msgs[0], "replPropertyMetaData");
1856 DEBUG(0,(__location__ ": Object %s does not have a replPropertyMetaData attribute\n",
1857 ldb_dn_get_linearized(msg->dn)));
1858 return LDB_ERR_OPERATIONS_ERROR;
1861 ndr_err = ndr_pull_struct_blob(omd_value, msg, &omd,
1862 (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
1863 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1864 DEBUG(0,(__location__ ": Failed to parse replPropertyMetaData for %s\n",
1865 ldb_dn_get_linearized(msg->dn)));
1866 return LDB_ERR_OPERATIONS_ERROR;
1869 if (omd.version != 1) {
1870 DEBUG(0,(__location__ ": bad version %u in replPropertyMetaData for %s\n",
1871 omd.version, ldb_dn_get_linearized(msg->dn)));
1872 return LDB_ERR_OPERATIONS_ERROR;
1875 for (i=0; i<msg->num_elements;) {
1876 struct ldb_message_element *el = &msg->elements[i];
1877 struct ldb_message_element *old_el;
1879 old_el = ldb_msg_find_element(res->msgs[0], el->name);
1880 ret = replmd_update_rpmd_element(ldb, msg, el, old_el,
1881 &omd, schema, seq_num,
1886 if (ret != LDB_SUCCESS) {
1890 if (!*is_urgent && (situation == REPL_URGENT_ON_UPDATE)) {
1891 *is_urgent = replmd_check_urgent_attribute(el);
1894 if (!(el->flags & DSDB_FLAG_INTERNAL_FORCE_META_DATA)) {
1899 el->flags &= ~DSDB_FLAG_INTERNAL_FORCE_META_DATA;
1901 if (el->num_values != 0) {
1906 ldb_msg_remove_element(msg, el);
1911 * Assert that we have an objectClass attribute - this is major
1912 * corruption if we don't have this!
1914 objectclass_el = ldb_msg_find_element(res->msgs[0], "objectClass");
1915 if (objectclass_el != NULL) {
1917 * Now check if this objectClass means we need to do urgent replication
1919 if (!*is_urgent && replmd_check_urgent_objectclass(objectclass_el,
1923 } else if (!ldb_request_get_control(req, DSDB_CONTROL_DBCHECK)) {
1924 ldb_asprintf_errstring(ldb, __location__
1925 ": objectClass missing on %s\n",
1926 ldb_dn_get_linearized(msg->dn));
1927 return LDB_ERR_OBJECT_CLASS_VIOLATION;
1931 * replmd_update_rpmd_element has done an update if the
1934 if (*seq_num != 0 || rmd_is_just_resorted == true) {
1935 struct ldb_val *md_value;
1936 struct ldb_message_element *el;
1938 /*if we are RODC and this is a DRSR update then its ok*/
1939 if (!ldb_request_get_control(req, DSDB_CONTROL_REPLICATED_UPDATE_OID)
1940 && !ldb_request_get_control(req, DSDB_CONTROL_DBCHECK_MODIFY_RO_REPLICA)
1941 && !is_forced_rodc) {
1942 unsigned instanceType;
1945 ldb_set_errstring(ldb, "RODC modify is forbidden!");
1946 return LDB_ERR_REFERRAL;
1949 instanceType = ldb_msg_find_attr_as_uint(res->msgs[0], "instanceType", INSTANCE_TYPE_WRITE);
1950 if (!(instanceType & INSTANCE_TYPE_WRITE)) {
1951 return ldb_error(ldb, LDB_ERR_UNWILLING_TO_PERFORM,
1952 "cannot change replicated attribute on partial replica");
1956 md_value = talloc(msg, struct ldb_val);
1957 if (md_value == NULL) {
1959 return LDB_ERR_OPERATIONS_ERROR;
1962 ret = replmd_replPropertyMetaDataCtr1_sort_and_verify(ldb, &omd.ctr.ctr1, msg->dn);
1963 if (ret != LDB_SUCCESS) {
1964 ldb_asprintf_errstring(ldb, "%s: %s", __func__, ldb_errstring(ldb));
1968 ndr_err = ndr_push_struct_blob(md_value, msg, &omd,
1969 (ndr_push_flags_fn_t)ndr_push_replPropertyMetaDataBlob);
1970 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1971 DEBUG(0,(__location__ ": Failed to marshall replPropertyMetaData for %s\n",
1972 ldb_dn_get_linearized(msg->dn)));
1973 return LDB_ERR_OPERATIONS_ERROR;
1976 ret = ldb_msg_add_empty(msg, "replPropertyMetaData", LDB_FLAG_MOD_REPLACE, &el);
1977 if (ret != LDB_SUCCESS) {
1978 DEBUG(0,(__location__ ": Failed to add updated replPropertyMetaData %s\n",
1979 ldb_dn_get_linearized(msg->dn)));
1984 el->values = md_value;
1990 static int parsed_dn_compare(struct parsed_dn *pdn1, struct parsed_dn *pdn2)
1992 int ret = ndr_guid_compare(&pdn1->guid, &pdn2->guid);
1994 return data_blob_cmp(&pdn1->dsdb_dn->extra_part,
1995 &pdn2->dsdb_dn->extra_part);
2001 get a series of message element values as an array of DNs and GUIDs
2002 the result is sorted by GUID
2004 static int get_parsed_dns(struct ldb_module *module, TALLOC_CTX *mem_ctx,
2005 struct ldb_message_element *el, struct parsed_dn **pdn,
2006 const char *ldap_oid, struct ldb_request *parent)
2009 bool values_are_sorted = true;
2010 struct ldb_context *ldb = ldb_module_get_ctx(module);
2017 (*pdn) = talloc_array(mem_ctx, struct parsed_dn, el->num_values);
2019 ldb_module_oom(module);
2020 return LDB_ERR_OPERATIONS_ERROR;
2023 for (i=0; i<el->num_values; i++) {
2024 struct ldb_val *v = &el->values[i];
2027 struct parsed_dn *p;
2031 p->dsdb_dn = dsdb_dn_parse(*pdn, ldb, v, ldap_oid);
2032 if (p->dsdb_dn == NULL) {
2033 return LDB_ERR_INVALID_DN_SYNTAX;
2036 dn = p->dsdb_dn->dn;
2038 status = dsdb_get_extended_dn_guid(dn, &p->guid, "GUID");
2039 if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND) ||
2040 unlikely(GUID_all_zero(&p->guid))) {
2041 /* we got a DN without a GUID - go find the GUID */
2042 int ret = dsdb_module_guid_by_dn(module, dn, &p->guid, parent);
2043 if (ret != LDB_SUCCESS) {
2044 char *dn_str = NULL;
2045 dn_str = ldb_dn_get_extended_linearized(mem_ctx,
2047 ldb_asprintf_errstring(ldb,
2048 "Unable to find GUID for DN %s\n",
2050 if (ret == LDB_ERR_NO_SUCH_OBJECT &&
2051 LDB_FLAG_MOD_TYPE(el->flags) == LDB_FLAG_MOD_DELETE &&
2052 ldb_attr_cmp(el->name, "member") == 0) {
2053 return LDB_ERR_UNWILLING_TO_PERFORM;
2057 ret = dsdb_set_extended_dn_guid(dn, &p->guid, "GUID");
2058 if (ret != LDB_SUCCESS) {
2061 } else if (!NT_STATUS_IS_OK(status)) {
2062 return LDB_ERR_OPERATIONS_ERROR;
2064 if (i > 0 && values_are_sorted) {
2065 int cmp = parsed_dn_compare(p, &(*pdn)[i - 1]);
2067 values_are_sorted = false;
2070 /* keep a pointer to the original ldb_val */
2073 if (! values_are_sorted) {
2074 TYPESAFE_QSORT(*pdn, el->num_values, parsed_dn_compare);
2080 * Get a series of trusted message element values. The result is sorted by
2081 * GUID, even though the GUIDs might not be known. That works because we trust
2082 * the database to give us the elements like that if the
2083 * replmd_private->sorted_links flag is set.
2085 * We also ensure that the links are in the Functional Level 2003
2086 * linked attributes format.
2088 static int get_parsed_dns_trusted(struct ldb_module *module,
2089 struct replmd_private *replmd_private,
2090 TALLOC_CTX *mem_ctx,
2091 struct ldb_message_element *el,
2092 struct parsed_dn **pdn,
2093 const char *ldap_oid,
2094 struct ldb_request *parent)
2103 if (!replmd_private->sorted_links) {
2104 /* We need to sort the list. This is the slow old path we want
2107 ret = get_parsed_dns(module, mem_ctx, el, pdn, ldap_oid,
2109 if (ret != LDB_SUCCESS) {
2113 /* Here we get a list of 'struct parsed_dns' without the parsing */
2114 *pdn = talloc_zero_array(mem_ctx, struct parsed_dn,
2117 ldb_module_oom(module);
2118 return LDB_ERR_OPERATIONS_ERROR;
2121 for (i = 0; i < el->num_values; i++) {
2122 (*pdn)[i].v = &el->values[i];
2127 * This upgrades links to FL2003 style, and sorts the result
2128 * if that was needed.
2130 * TODO: Add a database feature that asserts we have no FL2000
2131 * style links to avoid this check or add a feature that
2132 * uses a similar check to find sorted/unsorted links
2133 * for an on-the-fly upgrade.
2136 ret = replmd_check_upgrade_links(ldb_module_get_ctx(module),
2137 *pdn, el->num_values,
2140 if (ret != LDB_SUCCESS) {
2148 Return LDB_SUCCESS if a parsed_dn list contains no duplicate values,
2149 otherwise an error code. For compatibility the error code differs depending
2150 on whether or not the attribute is "member".
2152 As always, the parsed_dn list is assumed to be sorted.
2154 static int check_parsed_dn_duplicates(struct ldb_module *module,
2155 struct ldb_message_element *el,
2156 struct parsed_dn *pdn)
2159 struct ldb_context *ldb = ldb_module_get_ctx(module);
2161 for (i = 1; i < el->num_values; i++) {
2162 struct parsed_dn *p = &pdn[i];
2163 if (parsed_dn_compare(p, &pdn[i - 1]) == 0) {
2164 ldb_asprintf_errstring(ldb,
2165 "Linked attribute %s has "
2166 "multiple identical values",
2168 if (ldb_attr_cmp(el->name, "member") == 0) {
2169 return LDB_ERR_ENTRY_ALREADY_EXISTS;
2171 return LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS;
2179 build a new extended DN, including all meta data fields
2181 RMD_FLAGS = DSDB_RMD_FLAG_* bits
2182 RMD_ADDTIME = originating_add_time
2183 RMD_INVOCID = originating_invocation_id
2184 RMD_CHANGETIME = originating_change_time
2185 RMD_ORIGINATING_USN = originating_usn
2186 RMD_LOCAL_USN = local_usn
2187 RMD_VERSION = version
2189 static int replmd_build_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v,
2190 struct dsdb_dn *dsdb_dn,
2191 const struct GUID *invocation_id,
2192 uint64_t local_usn, NTTIME nttime)
2194 return replmd_set_la_val(mem_ctx, v, dsdb_dn, NULL, invocation_id,
2195 local_usn, local_usn, nttime,
2196 RMD_VERSION_INITIAL, false);
2199 static int replmd_update_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct dsdb_dn *dsdb_dn,
2200 struct dsdb_dn *old_dsdb_dn, const struct GUID *invocation_id,
2201 uint64_t seq_num, uint64_t local_usn, NTTIME nttime,
2205 check if any links need upgrading from w2k format
2207 static int replmd_check_upgrade_links(struct ldb_context *ldb,
2208 struct parsed_dn *dns, uint32_t count,
2209 struct ldb_message_element *el,
2210 const char *ldap_oid)
2213 const struct GUID *invocation_id = NULL;
2214 for (i=0; i<count; i++) {
2218 if (dns[i].dsdb_dn == NULL) {
2219 ret = really_parse_trusted_dn(dns, ldb, &dns[i],
2221 if (ret != LDB_SUCCESS) {
2222 return LDB_ERR_INVALID_DN_SYNTAX;
2226 status = dsdb_get_extended_dn_uint32(dns[i].dsdb_dn->dn,
2227 &version, "RMD_VERSION");
2228 if (!NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
2230 * We optimistically assume they are all the same; if
2231 * the first one is fixed, they are all fixed.
2233 * If the first one was *not* fixed and we find a
2234 * later one that is, that is an occasion to shout
2240 DEBUG(0, ("Mixed w2k and fixed format "
2241 "linked attributes\n"));
2245 if (invocation_id == NULL) {
2246 invocation_id = samdb_ntds_invocation_id(ldb);
2247 if (invocation_id == NULL) {
2248 return LDB_ERR_OPERATIONS_ERROR;
2253 /* it's an old one that needs upgrading */
2254 ret = replmd_update_la_val(el->values, dns[i].v,
2255 dns[i].dsdb_dn, dns[i].dsdb_dn,
2256 invocation_id, 1, 1, 0, false);
2257 if (ret != LDB_SUCCESS) {
2263 * This sort() is critical for the operation of
2264 * get_parsed_dns_trusted() because callers of this function
2265 * expect a sorted list, and FL2000 style links are not
2266 * sorted. In particular, as well as the upgrade case,
2267 * get_parsed_dns_trusted() is called from
2268 * replmd_delete_remove_link() even in FL2000 mode
2270 * We do not normally pay the cost of the qsort() due to the
2271 * early return in the RMD_VERSION found case.
2273 TYPESAFE_QSORT(dns, count, parsed_dn_compare);
2278 Sets the value for a linked attribute, including all meta data fields
2280 see replmd_build_la_val for value names
2282 static int replmd_set_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct dsdb_dn *dsdb_dn,
2283 struct dsdb_dn *old_dsdb_dn, const struct GUID *invocation_id,
2284 uint64_t usn, uint64_t local_usn, NTTIME nttime,
2285 uint32_t version, bool deleted)
2287 struct ldb_dn *dn = dsdb_dn->dn;
2288 const char *tstring, *usn_string, *flags_string;
2289 struct ldb_val tval;
2291 struct ldb_val usnv, local_usnv;
2292 struct ldb_val vers, flagsv;
2293 const struct ldb_val *old_addtime = NULL;
2296 const char *dnstring;
2298 uint32_t rmd_flags = deleted?DSDB_RMD_FLAG_DELETED:0;
2300 tstring = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)nttime);
2302 return LDB_ERR_OPERATIONS_ERROR;
2304 tval = data_blob_string_const(tstring);
2306 usn_string = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)usn);
2308 return LDB_ERR_OPERATIONS_ERROR;
2310 usnv = data_blob_string_const(usn_string);
2312 usn_string = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)local_usn);
2314 return LDB_ERR_OPERATIONS_ERROR;
2316 local_usnv = data_blob_string_const(usn_string);
2318 status = GUID_to_ndr_blob(invocation_id, dn, &iid);
2319 if (!NT_STATUS_IS_OK(status)) {
2320 return LDB_ERR_OPERATIONS_ERROR;
2323 flags_string = talloc_asprintf(mem_ctx, "%u", rmd_flags);
2324 if (!flags_string) {
2325 return LDB_ERR_OPERATIONS_ERROR;
2327 flagsv = data_blob_string_const(flags_string);
2329 ret = ldb_dn_set_extended_component(dn, "RMD_FLAGS", &flagsv);
2330 if (ret != LDB_SUCCESS) return ret;
2332 /* get the ADDTIME from the original */
2333 if (old_dsdb_dn != NULL) {
2334 old_addtime = ldb_dn_get_extended_component(old_dsdb_dn->dn,
2337 if (old_addtime == NULL) {
2338 old_addtime = &tval;
2340 if (dsdb_dn != old_dsdb_dn ||
2341 ldb_dn_get_extended_component(dn, "RMD_ADDTIME") == NULL) {
2342 ret = ldb_dn_set_extended_component(dn, "RMD_ADDTIME", old_addtime);
2343 if (ret != LDB_SUCCESS) return ret;
2346 /* use our invocation id */
2347 ret = ldb_dn_set_extended_component(dn, "RMD_INVOCID", &iid);
2348 if (ret != LDB_SUCCESS) return ret;
2350 /* changetime is the current time */
2351 ret = ldb_dn_set_extended_component(dn, "RMD_CHANGETIME", &tval);
2352 if (ret != LDB_SUCCESS) return ret;
2354 /* update the USN */
2355 ret = ldb_dn_set_extended_component(dn, "RMD_ORIGINATING_USN", &usnv);
2356 if (ret != LDB_SUCCESS) return ret;
2358 ret = ldb_dn_set_extended_component(dn, "RMD_LOCAL_USN", &local_usnv);
2359 if (ret != LDB_SUCCESS) return ret;
2361 vstring = talloc_asprintf(mem_ctx, "%lu", (unsigned long)version);
2362 vers = data_blob_string_const(vstring);
2363 ret = ldb_dn_set_extended_component(dn, "RMD_VERSION", &vers);
2364 if (ret != LDB_SUCCESS) return ret;
2366 dnstring = dsdb_dn_get_extended_linearized(mem_ctx, dsdb_dn, 1);
2367 if (dnstring == NULL) {
2368 return LDB_ERR_OPERATIONS_ERROR;
2370 *v = data_blob_string_const(dnstring);
2376 * Updates the value for a linked attribute, including all meta data fields
2378 static int replmd_update_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct dsdb_dn *dsdb_dn,
2379 struct dsdb_dn *old_dsdb_dn, const struct GUID *invocation_id,
2380 uint64_t usn, uint64_t local_usn, NTTIME nttime,
2383 uint32_t old_version;
2384 uint32_t version = RMD_VERSION_INITIAL;
2388 * We're updating the linked attribute locally, so increase the version
2389 * by 1 so that other DCs will see the change when it gets replicated out
2391 status = dsdb_get_extended_dn_uint32(old_dsdb_dn->dn, &old_version,
2394 if (NT_STATUS_IS_OK(status)) {
2395 version = old_version + 1;
2398 return replmd_set_la_val(mem_ctx, v, dsdb_dn, old_dsdb_dn, invocation_id,
2399 usn, local_usn, nttime, version, deleted);
2403 handle adding a linked attribute
2405 static int replmd_modify_la_add(struct ldb_module *module,
2406 struct replmd_private *replmd_private,
2407 struct replmd_replicated_request *ac,
2408 struct ldb_message *msg,
2409 struct ldb_message_element *el,
2410 struct ldb_message_element *old_el,
2411 const struct dsdb_attribute *schema_attr,
2413 struct ldb_dn *msg_dn,
2414 struct ldb_request *parent)
2417 struct parsed_dn *dns, *old_dns;
2418 TALLOC_CTX *tmp_ctx = talloc_new(msg);
2420 struct ldb_val *new_values = NULL;
2421 unsigned old_num_values = old_el ? old_el->num_values : 0;
2422 unsigned num_values = 0;
2423 unsigned max_num_values;
2424 struct ldb_context *ldb = ldb_module_get_ctx(module);
2426 unix_to_nt_time(&now, t);
2428 /* get the DNs to be added, fully parsed.
2430 * We need full parsing because they came off the wire and we don't
2431 * trust them, besides which we need their details to know where to put
2434 ret = get_parsed_dns(module, tmp_ctx, el, &dns,
2435 schema_attr->syntax->ldap_oid, parent);
2436 if (ret != LDB_SUCCESS) {
2437 talloc_free(tmp_ctx);
2441 /* get the existing DNs, lazily parsed */
2442 ret = get_parsed_dns_trusted(module, replmd_private,
2443 tmp_ctx, old_el, &old_dns,
2444 schema_attr->syntax->ldap_oid, parent);
2446 if (ret != LDB_SUCCESS) {
2447 talloc_free(tmp_ctx);
2451 max_num_values = old_num_values + el->num_values;
2452 if (max_num_values < old_num_values) {
2453 DEBUG(0, ("we seem to have overflow in replmd_modify_la_add. "
2454 "old values: %u, new values: %u, sum: %u\n",
2455 old_num_values, el->num_values, max_num_values));
2456 talloc_free(tmp_ctx);
2457 return LDB_ERR_OPERATIONS_ERROR;
2460 new_values = talloc_zero_array(tmp_ctx, struct ldb_val, max_num_values);
2462 if (new_values == NULL) {
2463 ldb_module_oom(module);
2464 talloc_free(tmp_ctx);
2465 return LDB_ERR_OPERATIONS_ERROR;
2469 * For each new value, find where it would go in the list. If there is
2470 * a matching GUID there, we update the existing value; otherwise we
2474 for (i = 0; i < el->num_values; i++) {
2475 struct parsed_dn *exact;
2476 struct parsed_dn *next;
2478 int err = parsed_dn_find(ldb, old_dns, old_num_values,
2481 dns[i].dsdb_dn->extra_part, 0,
2483 schema_attr->syntax->ldap_oid,
2485 if (err != LDB_SUCCESS) {
2486 talloc_free(tmp_ctx);
2490 if (ac->fix_link_sid) {
2491 char *fixed_dnstring = NULL;
2492 struct dom_sid tmp_sid = { 0, };
2493 DATA_BLOB sid_blob = data_blob_null;
2494 enum ndr_err_code ndr_err;
2498 if (exact == NULL) {
2499 talloc_free(tmp_ctx);
2500 return ldb_operr(ldb);
2503 if (dns[i].dsdb_dn->dn_format != DSDB_NORMAL_DN) {
2504 talloc_free(tmp_ctx);
2505 return ldb_operr(ldb);
2509 * Only "<GUID=...><SID=...>" is allowed.
2511 * We get the GUID to just to find the old
2512 * value and the SID in order to add it
2513 * to the found value.
2516 num = ldb_dn_get_comp_num(dns[i].dsdb_dn->dn);
2518 talloc_free(tmp_ctx);
2519 return ldb_operr(ldb);
2522 num = ldb_dn_get_extended_comp_num(dns[i].dsdb_dn->dn);
2524 talloc_free(tmp_ctx);
2525 return ldb_operr(ldb);
2528 status = dsdb_get_extended_dn_sid(exact->dsdb_dn->dn,
2530 if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
2531 /* this is what we expect */
2532 } else if (NT_STATUS_IS_OK(status)) {
2533 struct GUID_txt_buf guid_str;
2534 ldb_debug_set(ldb, LDB_DEBUG_FATAL,
2535 "i[%u] SID NOT MISSING... Attribute %s already "
2536 "exists for target GUID %s, SID %s, DN: %s",
2538 GUID_buf_string(&exact->guid,
2540 dom_sid_string(tmp_ctx, &tmp_sid),
2541 dsdb_dn_get_extended_linearized(tmp_ctx,
2542 exact->dsdb_dn, 1));
2543 talloc_free(tmp_ctx);
2544 return LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS;
2546 talloc_free(tmp_ctx);
2547 return ldb_operr(ldb);
2550 status = dsdb_get_extended_dn_sid(dns[i].dsdb_dn->dn,
2552 if (!NT_STATUS_IS_OK(status)) {
2553 struct GUID_txt_buf guid_str;
2554 ldb_asprintf_errstring(ldb,
2555 "NO SID PROVIDED... Attribute %s already "
2556 "exists for target GUID %s",
2558 GUID_buf_string(&exact->guid,
2560 talloc_free(tmp_ctx);
2561 return LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS;
2564 ndr_err = ndr_push_struct_blob(&sid_blob, tmp_ctx, &tmp_sid,
2565 (ndr_push_flags_fn_t)ndr_push_dom_sid);
2566 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
2567 talloc_free(tmp_ctx);
2568 return ldb_operr(ldb);
2571 ret = ldb_dn_set_extended_component(exact->dsdb_dn->dn, "SID", &sid_blob);
2572 data_blob_free(&sid_blob);
2573 if (ret != LDB_SUCCESS) {
2574 talloc_free(tmp_ctx);
2578 fixed_dnstring = dsdb_dn_get_extended_linearized(
2579 new_values, exact->dsdb_dn, 1);
2580 if (fixed_dnstring == NULL) {
2581 talloc_free(tmp_ctx);
2582 return ldb_operr(ldb);
2586 * We just replace the existing value...
2588 *exact->v = data_blob_string_const(fixed_dnstring);
2593 if (exact != NULL) {
2595 * We are trying to add one that exists, which is only
2596 * allowed if it was previously deleted.
2598 * When we do undelete a link we change it in place.
2599 * It will be copied across into the right spot in due
2603 rmd_flags = dsdb_dn_rmd_flags(exact->dsdb_dn->dn);
2605 if (!(rmd_flags & DSDB_RMD_FLAG_DELETED)) {
2606 struct GUID_txt_buf guid_str;
2607 ldb_asprintf_errstring(ldb,
2608 "Attribute %s already "
2609 "exists for target GUID %s",
2611 GUID_buf_string(&exact->guid,
2613 talloc_free(tmp_ctx);
2614 /* error codes for 'member' need to be
2616 if (ldb_attr_cmp(el->name, "member") == 0) {
2617 return LDB_ERR_ENTRY_ALREADY_EXISTS;
2619 return LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS;
2623 ret = replmd_update_la_val(new_values, exact->v,
2626 &ac->our_invocation_id,
2627 ac->seq_num, ac->seq_num,
2629 if (ret != LDB_SUCCESS) {
2630 talloc_free(tmp_ctx);
2634 ret = replmd_add_backlink(module, replmd_private,
2641 if (ret != LDB_SUCCESS) {
2642 talloc_free(tmp_ctx);
2648 * Here we don't have an exact match.
2650 * If next is NULL, this one goes beyond the end of the
2651 * existing list, so we need to add all of those ones first.
2653 * If next is not NULL, we need to add all the ones before
2657 offset = old_num_values;
2659 /* next should have been parsed, but let's make sure */
2660 if (next->dsdb_dn == NULL) {
2661 ret = really_parse_trusted_dn(tmp_ctx, ldb, next,
2662 schema_attr->syntax->ldap_oid);
2663 if (ret != LDB_SUCCESS) {
2667 offset = MIN(next - old_dns, old_num_values);
2670 /* put all the old ones before next on the list */
2671 for (; j < offset; j++) {
2672 new_values[num_values] = *old_dns[j].v;
2676 ret = replmd_add_backlink(module, replmd_private,
2681 /* Make the new linked attribute ldb_val. */
2682 ret = replmd_build_la_val(new_values, &new_values[num_values],
2683 dns[i].dsdb_dn, &ac->our_invocation_id,
2685 if (ret != LDB_SUCCESS) {
2686 talloc_free(tmp_ctx);
2690 if (ret != LDB_SUCCESS) {
2691 talloc_free(tmp_ctx);
2695 /* copy the rest of the old ones (if any) */
2696 for (; j < old_num_values; j++) {
2697 new_values[num_values] = *old_dns[j].v;
2701 talloc_steal(msg->elements, new_values);
2702 if (old_el != NULL) {
2703 talloc_steal(msg->elements, old_el->values);
2705 el->values = new_values;
2706 el->num_values = num_values;
2708 talloc_free(tmp_ctx);
2710 /* we now tell the backend to replace all existing values
2711 with the one we have constructed */
2712 el->flags = LDB_FLAG_MOD_REPLACE;
2719 handle deleting all active linked attributes
2721 static int replmd_modify_la_delete(struct ldb_module *module,
2722 struct replmd_private *replmd_private,
2723 struct replmd_replicated_request *ac,
2724 struct ldb_message *msg,
2725 struct ldb_message_element *el,
2726 struct ldb_message_element *old_el,
2727 const struct dsdb_attribute *schema_attr,
2729 struct ldb_dn *msg_dn,
2730 struct ldb_request *parent)
2733 struct parsed_dn *dns, *old_dns;
2734 TALLOC_CTX *tmp_ctx = NULL;
2736 struct ldb_context *ldb = ldb_module_get_ctx(module);
2737 struct ldb_control *vanish_links_ctrl = NULL;
2738 bool vanish_links = false;
2739 unsigned int num_to_delete = el->num_values;
2743 unix_to_nt_time(&now, t);
2745 if (old_el == NULL || old_el->num_values == 0) {
2746 /* there is nothing to delete... */
2747 if (num_to_delete == 0) {
2748 /* and we're deleting nothing, so that's OK */
2751 return LDB_ERR_NO_SUCH_ATTRIBUTE;
2754 tmp_ctx = talloc_new(msg);
2755 if (tmp_ctx == NULL) {
2756 return LDB_ERR_OPERATIONS_ERROR;
2759 ret = get_parsed_dns(module, tmp_ctx, el, &dns,
2760 schema_attr->syntax->ldap_oid, parent);
2761 if (ret != LDB_SUCCESS) {
2762 talloc_free(tmp_ctx);
2766 ret = get_parsed_dns_trusted(module, replmd_private,
2767 tmp_ctx, old_el, &old_dns,
2768 schema_attr->syntax->ldap_oid, parent);
2770 if (ret != LDB_SUCCESS) {
2771 talloc_free(tmp_ctx);
2776 vanish_links_ctrl = ldb_request_get_control(parent, DSDB_CONTROL_REPLMD_VANISH_LINKS);
2777 if (vanish_links_ctrl) {
2778 vanish_links = true;
2779 vanish_links_ctrl->critical = false;
2783 /* we empty out el->values here to avoid damage if we return early. */
2788 * If vanish links is set, we are actually removing members of
2789 * old_el->values; otherwise we are just marking them deleted.
2791 * There is a special case when no values are given: we remove them
2792 * all. When we have the vanish_links control we just have to remove
2793 * the backlinks and change our element to replace the existing values
2794 * with the empty list.
2797 if (num_to_delete == 0) {
2798 for (i = 0; i < old_el->num_values; i++) {
2799 struct parsed_dn *p = &old_dns[i];
2800 if (p->dsdb_dn == NULL) {
2801 ret = really_parse_trusted_dn(tmp_ctx, ldb, p,
2802 schema_attr->syntax->ldap_oid);
2803 if (ret != LDB_SUCCESS) {
2807 ret = replmd_add_backlink(module, replmd_private,
2808 ac->schema, msg_dn, &p->guid,
2811 if (ret != LDB_SUCCESS) {
2812 talloc_free(tmp_ctx);
2819 rmd_flags = dsdb_dn_rmd_flags(p->dsdb_dn->dn);
2820 if (rmd_flags & DSDB_RMD_FLAG_DELETED) {
2824 ret = replmd_update_la_val(old_el->values, p->v,
2825 p->dsdb_dn, p->dsdb_dn,
2826 &ac->our_invocation_id,
2827 ac->seq_num, ac->seq_num,
2829 if (ret != LDB_SUCCESS) {
2830 talloc_free(tmp_ctx);
2836 el->flags = LDB_FLAG_MOD_REPLACE;
2837 talloc_free(tmp_ctx);
2843 for (i = 0; i < num_to_delete; i++) {
2844 struct parsed_dn *p = &dns[i];
2845 struct parsed_dn *exact = NULL;
2846 struct parsed_dn *next = NULL;
2847 ret = parsed_dn_find(ldb, old_dns, old_el->num_values,
2850 p->dsdb_dn->extra_part, 0,
2852 schema_attr->syntax->ldap_oid,
2854 if (ret != LDB_SUCCESS) {
2855 talloc_free(tmp_ctx);
2858 if (exact == NULL) {
2859 struct GUID_txt_buf buf;
2860 ldb_asprintf_errstring(ldb, "Attribute %s doesn't "
2861 "exist for target GUID %s",
2863 GUID_buf_string(&p->guid, &buf));
2864 if (ldb_attr_cmp(el->name, "member") == 0) {
2865 talloc_free(tmp_ctx);
2866 return LDB_ERR_UNWILLING_TO_PERFORM;
2868 talloc_free(tmp_ctx);
2869 return LDB_ERR_NO_SUCH_ATTRIBUTE;
2874 if (CHECK_DEBUGLVL(5)) {
2875 rmd_flags = dsdb_dn_rmd_flags(exact->dsdb_dn->dn);
2876 if ((rmd_flags & DSDB_RMD_FLAG_DELETED)) {
2877 struct GUID_txt_buf buf;
2878 const char *guid_str = \
2879 GUID_buf_string(&p->guid, &buf);
2880 DEBUG(5, ("Deleting deleted linked "
2881 "attribute %s to %s, because "
2882 "vanish_links control is set\n",
2883 el->name, guid_str));
2887 /* remove the backlink */
2888 ret = replmd_add_backlink(module,
2895 if (ret != LDB_SUCCESS) {
2896 talloc_free(tmp_ctx);
2900 /* We flag the deletion and tidy it up later. */
2905 rmd_flags = dsdb_dn_rmd_flags(exact->dsdb_dn->dn);
2907 if (rmd_flags & DSDB_RMD_FLAG_DELETED) {
2908 struct GUID_txt_buf buf;
2909 const char *guid_str = GUID_buf_string(&p->guid, &buf);
2910 ldb_asprintf_errstring(ldb, "Attribute %s already "
2911 "deleted for target GUID %s",
2912 el->name, guid_str);
2913 if (ldb_attr_cmp(el->name, "member") == 0) {
2914 talloc_free(tmp_ctx);
2915 return LDB_ERR_UNWILLING_TO_PERFORM;
2917 talloc_free(tmp_ctx);
2918 return LDB_ERR_NO_SUCH_ATTRIBUTE;
2922 ret = replmd_update_la_val(old_el->values, exact->v,
2923 exact->dsdb_dn, exact->dsdb_dn,
2924 &ac->our_invocation_id,
2925 ac->seq_num, ac->seq_num,
2927 if (ret != LDB_SUCCESS) {
2928 talloc_free(tmp_ctx);
2931 ret = replmd_add_backlink(module, replmd_private,
2936 if (ret != LDB_SUCCESS) {
2937 talloc_free(tmp_ctx);
2944 struct ldb_val *tmp_vals = NULL;
2946 tmp_vals = talloc_array(tmp_ctx, struct ldb_val,
2947 old_el->num_values);
2948 if (tmp_vals == NULL) {
2949 talloc_free(tmp_ctx);
2950 return ldb_module_oom(module);
2952 for (i = 0; i < old_el->num_values; i++) {
2953 if (old_dns[i].v == NULL) {
2956 tmp_vals[j] = *old_dns[i].v;
2959 for (i = 0; i < j; i++) {
2960 old_el->values[i] = tmp_vals[i];
2962 old_el->num_values = j;
2965 el->values = talloc_steal(msg->elements, old_el->values);
2966 el->num_values = old_el->num_values;
2968 talloc_free(tmp_ctx);
2970 /* we now tell the backend to replace all existing values
2971 with the one we have constructed */
2972 el->flags = LDB_FLAG_MOD_REPLACE;
2978 handle replacing a linked attribute
2980 static int replmd_modify_la_replace(struct ldb_module *module,
2981 struct replmd_private *replmd_private,
2982 struct replmd_replicated_request *ac,
2983 struct ldb_message *msg,
2984 struct ldb_message_element *el,
2985 struct ldb_message_element *old_el,
2986 const struct dsdb_attribute *schema_attr,
2988 struct ldb_dn *msg_dn,
2989 struct ldb_request *parent)
2991 unsigned int i, old_i, new_i;
2992 struct parsed_dn *dns, *old_dns;
2993 TALLOC_CTX *tmp_ctx = talloc_new(msg);
2995 struct ldb_context *ldb = ldb_module_get_ctx(module);
2996 struct ldb_val *new_values = NULL;
2997 const char *ldap_oid = schema_attr->syntax->ldap_oid;
2998 unsigned int old_num_values;
2999 unsigned int repl_num_values;
3000 unsigned int max_num_values;
3003 unix_to_nt_time(&now, t);
3006 * The replace operation is unlike the replace and delete cases in that
3007 * we need to look at every existing link to see whether it is being
3008 * retained or deleted. In other words, we can't avoid parsing the GUIDs.
3010 * As we are trying to combine two sorted lists, the algorithm we use
3011 * is akin to the merge phase of a merge sort. We interleave the two
3012 * lists, doing different things depending on which side the current
3015 * There are three main cases, with some sub-cases.
3017 * - a DN is in the old list but not the new one. It needs to be
3018 * marked as deleted (but left in the list).
3019 * - maybe it is already deleted, and we have less to do.
3021 * - a DN is in both lists. The old data gets replaced by the new,
3022 * and the list doesn't grow. The old link may have been marked as
3023 * deleted, in which case we undelete it.
3025 * - a DN is in the new list only. We add it in the right place.
3028 old_num_values = old_el ? old_el->num_values : 0;
3029 repl_num_values = el->num_values;
3030 max_num_values = old_num_values + repl_num_values;
3032 if (max_num_values == 0) {
3033 /* There is nothing to do! */
3037 ret = get_parsed_dns(module, tmp_ctx, el, &dns, ldap_oid, parent);
3038 if (ret != LDB_SUCCESS) {
3039 talloc_free(tmp_ctx);
3043 ret = check_parsed_dn_duplicates(module, el, dns);
3044 if (ret != LDB_SUCCESS) {
3045 talloc_free(tmp_ctx);
3049 ret = get_parsed_dns(module, tmp_ctx, old_el, &old_dns,
3051 if (ret != LDB_SUCCESS) {
3052 talloc_free(tmp_ctx);
3056 ret = replmd_check_upgrade_links(ldb, old_dns, old_num_values,
3058 if (ret != LDB_SUCCESS) {
3059 talloc_free(tmp_ctx);
3063 new_values = talloc_array(tmp_ctx, struct ldb_val, max_num_values);
3064 if (new_values == NULL) {
3065 ldb_module_oom(module);
3066 talloc_free(tmp_ctx);
3067 return LDB_ERR_OPERATIONS_ERROR;
3072 for (i = 0; i < max_num_values; i++) {
3074 struct parsed_dn *old_p, *new_p;
3075 if (old_i < old_num_values && new_i < repl_num_values) {
3076 old_p = &old_dns[old_i];
3077 new_p = &dns[new_i];
3078 cmp = parsed_dn_compare(old_p, new_p);
3079 } else if (old_i < old_num_values) {
3080 /* the new list is empty, read the old list */
3081 old_p = &old_dns[old_i];
3084 } else if (new_i < repl_num_values) {
3085 /* the old list is empty, read new list */
3087 new_p = &dns[new_i];
3095 * An old ones that come before the next replacement
3096 * (if any). We mark it as deleted and add it to the
3099 uint32_t rmd_flags = dsdb_dn_rmd_flags(old_p->dsdb_dn->dn);
3100 if ((rmd_flags & DSDB_RMD_FLAG_DELETED) == 0) {
3101 ret = replmd_update_la_val(new_values, old_p->v,
3104 &ac->our_invocation_id,
3105 ac->seq_num, ac->seq_num,
3107 if (ret != LDB_SUCCESS) {
3108 talloc_free(tmp_ctx);
3112 ret = replmd_add_backlink(module, replmd_private,
3115 &old_p->guid, false,
3118 if (ret != LDB_SUCCESS) {
3119 talloc_free(tmp_ctx);
3123 new_values[i] = *old_p->v;
3125 } else if (cmp == 0) {
3127 * We are overwriting one. If it was previously
3128 * deleted, we need to add a backlink.
3130 * Note that if any RMD_FLAGs in an extended new DN
3135 ret = replmd_update_la_val(new_values, old_p->v,
3138 &ac->our_invocation_id,
3139 ac->seq_num, ac->seq_num,
3141 if (ret != LDB_SUCCESS) {
3142 talloc_free(tmp_ctx);
3146 rmd_flags = dsdb_dn_rmd_flags(old_p->dsdb_dn->dn);
3147 if ((rmd_flags & DSDB_RMD_FLAG_DELETED) != 0) {
3148 ret = replmd_add_backlink(module, replmd_private,
3154 if (ret != LDB_SUCCESS) {
3155 talloc_free(tmp_ctx);
3160 new_values[i] = *old_p->v;
3165 * Replacements that don't match an existing one. We
3166 * just add them to the final list.
3168 ret = replmd_build_la_val(new_values,
3171 &ac->our_invocation_id,
3173 if (ret != LDB_SUCCESS) {
3174 talloc_free(tmp_ctx);
3177 ret = replmd_add_backlink(module, replmd_private,
3183 if (ret != LDB_SUCCESS) {
3184 talloc_free(tmp_ctx);
3187 new_values[i] = *new_p->v;
3191 if (old_el != NULL) {
3192 talloc_steal(msg->elements, old_el->values);
3194 el->values = talloc_steal(msg->elements, new_values);
3196 talloc_free(tmp_ctx);
3198 el->flags = LDB_FLAG_MOD_REPLACE;
3205 handle linked attributes in modify requests
3207 static int replmd_modify_handle_linked_attribs(struct ldb_module *module,
3208 struct replmd_private *replmd_private,
3209 struct replmd_replicated_request *ac,
3210 struct ldb_message *msg,
3212 struct ldb_request *parent)
3214 struct ldb_result *res;
3217 struct ldb_context *ldb = ldb_module_get_ctx(module);
3218 struct ldb_message *old_msg;
3220 if (dsdb_functional_level(ldb) == DS_DOMAIN_FUNCTION_2000) {
3222 * Nothing special is required for modifying or vanishing links
3223 * in fl2000 since they are just strings in a multi-valued
3226 struct ldb_control *ctrl = ldb_request_get_control(parent,
3227 DSDB_CONTROL_REPLMD_VANISH_LINKS);
3229 ctrl->critical = false;
3237 * We should restrict this to the intersection of the list of
3238 * linked attributes in the schema and the list of attributes
3241 * This will help performance a little, as otherwise we have
3242 * to allocate the entire object value-by-value.
3244 ret = dsdb_module_search_dn(module, msg, &res, msg->dn, NULL,
3245 DSDB_FLAG_NEXT_MODULE |
3246 DSDB_SEARCH_SHOW_RECYCLED |
3247 DSDB_SEARCH_REVEAL_INTERNALS |
3248 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT,
3250 if (ret != LDB_SUCCESS) {
3254 old_msg = res->msgs[0];
3256 for (i=0; i<msg->num_elements; i++) {
3257 struct ldb_message_element *el = &msg->elements[i];
3258 struct ldb_message_element *old_el, *new_el;
3259 unsigned int mod_type = LDB_FLAG_MOD_TYPE(el->flags);
3260 const struct dsdb_attribute *schema_attr
3261 = dsdb_attribute_by_lDAPDisplayName(ac->schema, el->name);
3263 ldb_asprintf_errstring(ldb,
3264 "%s: attribute %s is not a valid attribute in schema",
3265 __FUNCTION__, el->name);
3266 return LDB_ERR_OBJECT_CLASS_VIOLATION;
3268 if (schema_attr->linkID == 0) {
3271 if ((schema_attr->linkID & 1) == 1) {
3273 struct ldb_control *ctrl;
3275 ctrl = ldb_request_get_control(parent,
3276 DSDB_CONTROL_REPLMD_VANISH_LINKS);
3278 ctrl->critical = false;
3281 ctrl = ldb_request_get_control(parent,
3282 DSDB_CONTROL_DBCHECK);
3288 /* Odd is for the target. Illegal to modify */
3289 ldb_asprintf_errstring(ldb,
3290 "attribute %s must not be modified directly, it is a linked attribute", el->name);
3291 return LDB_ERR_UNWILLING_TO_PERFORM;
3293 old_el = ldb_msg_find_element(old_msg, el->name);
3295 case LDB_FLAG_MOD_REPLACE:
3296 ret = replmd_modify_la_replace(module, replmd_private,
3297 ac, msg, el, old_el,
3302 case LDB_FLAG_MOD_DELETE:
3303 ret = replmd_modify_la_delete(module, replmd_private,
3304 ac, msg, el, old_el,
3309 case LDB_FLAG_MOD_ADD:
3310 ret = replmd_modify_la_add(module, replmd_private,
3311 ac, msg, el, old_el,
3317 ldb_asprintf_errstring(ldb,
3318 "invalid flags 0x%x for %s linked attribute",
3319 el->flags, el->name);
3320 return LDB_ERR_UNWILLING_TO_PERFORM;
3322 if (dsdb_check_single_valued_link(schema_attr, el) != LDB_SUCCESS) {
3323 ldb_asprintf_errstring(ldb,
3324 "Attribute %s is single valued but more than one value has been supplied",
3326 /* Return codes as found on Windows 2012r2 */
3327 if (mod_type == LDB_FLAG_MOD_REPLACE) {
3328 return LDB_ERR_CONSTRAINT_VIOLATION;
3330 return LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS;
3333 el->flags |= LDB_FLAG_INTERNAL_DISABLE_SINGLE_VALUE_CHECK;
3336 if (ret != LDB_SUCCESS) {
3340 ldb_msg_remove_attr(old_msg, el->name);
3342 ldb_msg_add_empty(old_msg, el->name, 0, &new_el);
3343 new_el->num_values = el->num_values;
3344 new_el->values = talloc_steal(msg->elements, el->values);
3346 /* TODO: this relises a bit too heavily on the exact
3347 behaviour of ldb_msg_find_element and
3348 ldb_msg_remove_element */
3349 old_el = ldb_msg_find_element(msg, el->name);
3351 ldb_msg_remove_element(msg, old_el);
3361 static int send_rodc_referral(struct ldb_request *req,
3362 struct ldb_context *ldb,
3365 char *referral = NULL;
3366 struct loadparm_context *lp_ctx = NULL;
3367 struct ldb_dn *fsmo_role_dn = NULL;
3368 struct ldb_dn *role_owner_dn = NULL;
3369 const char *domain = NULL;
3372 lp_ctx = talloc_get_type(ldb_get_opaque(ldb, "loadparm"),
3373 struct loadparm_context);
3375 werr = dsdb_get_fsmo_role_info(req, ldb, DREPL_PDC_MASTER,
3376 &fsmo_role_dn, &role_owner_dn);
3378 if (W_ERROR_IS_OK(werr)) {
3379 struct ldb_dn *server_dn = ldb_dn_copy(req, role_owner_dn);
3380 if (server_dn != NULL) {
3381 ldb_dn_remove_child_components(server_dn, 1);
3382 domain = samdb_dn_to_dnshostname(ldb, req,
3387 if (domain == NULL) {
3388 domain = lpcfg_dnsdomain(lp_ctx);
3391 referral = talloc_asprintf(req, "ldap://%s/%s",
3393 ldb_dn_get_linearized(dn));
3394 if (referral == NULL) {
3396 return LDB_ERR_OPERATIONS_ERROR;
3399 return ldb_module_send_referral(req, referral);
3403 static int replmd_modify(struct ldb_module *module, struct ldb_request *req)
3405 struct ldb_context *ldb;
3406 struct replmd_replicated_request *ac;
3407 struct ldb_request *down_req;
3408 struct ldb_message *msg;
3409 time_t t = time(NULL);
3411 bool is_urgent = false, rodc = false;
3412 bool is_schema_nc = false;
3413 unsigned int functional_level;
3414 const struct ldb_message_element *guid_el = NULL;
3415 struct ldb_control *sd_propagation_control;
3416 struct ldb_control *fix_links_control = NULL;
3417 struct ldb_control *fix_dn_name_control = NULL;
3418 struct ldb_control *fix_dn_sid_control = NULL;
3419 struct replmd_private *replmd_private =
3420 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
3422 /* do not manipulate our control entries */
3423 if (ldb_dn_is_special(req->op.mod.message->dn)) {
3424 return ldb_next_request(module, req);
3427 sd_propagation_control = ldb_request_get_control(req,
3428 DSDB_CONTROL_SEC_DESC_PROPAGATION_OID);
3429 if (sd_propagation_control != NULL) {
3430 if (req->op.mod.message->num_elements != 1) {
3431 return ldb_module_operr(module);
3433 ret = strcmp(req->op.mod.message->elements[0].name,
3434 "nTSecurityDescriptor");
3436 return ldb_module_operr(module);
3439 return ldb_next_request(module, req);
3442 ldb = ldb_module_get_ctx(module);
3444 fix_links_control = ldb_request_get_control(req,
3445 DSDB_CONTROL_DBCHECK_FIX_DUPLICATE_LINKS);
3446 if (fix_links_control != NULL) {
3447 struct dsdb_schema *schema = NULL;
3448 const struct dsdb_attribute *sa = NULL;
3450 if (req->op.mod.message->num_elements != 1) {
3451 return ldb_module_operr(module);
3454 if (req->op.mod.message->elements[0].flags != LDB_FLAG_MOD_REPLACE) {
3455 return ldb_module_operr(module);
3458 schema = dsdb_get_schema(ldb, req);
3459 if (schema == NULL) {
3460 return ldb_module_operr(module);
3463 sa = dsdb_attribute_by_lDAPDisplayName(schema,
3464 req->op.mod.message->elements[0].name);
3466 return ldb_module_operr(module);
3469 if (sa->linkID == 0) {
3470 return ldb_module_operr(module);
3473 fix_links_control->critical = false;
3474 return ldb_next_request(module, req);
3477 fix_dn_name_control = ldb_request_get_control(req,
3478 DSDB_CONTROL_DBCHECK_FIX_LINK_DN_NAME);
3479 if (fix_dn_name_control != NULL) {
3480 struct dsdb_schema *schema = NULL;
3481 const struct dsdb_attribute *sa = NULL;
3483 if (req->op.mod.message->num_elements != 2) {
3484 return ldb_module_operr(module);
3487 if (req->op.mod.message->elements[0].flags != LDB_FLAG_MOD_DELETE) {
3488 return ldb_module_operr(module);
3491 if (req->op.mod.message->elements[1].flags != LDB_FLAG_MOD_ADD) {
3492 return ldb_module_operr(module);
3495 if (req->op.mod.message->elements[0].num_values != 1) {
3496 return ldb_module_operr(module);
3499 if (req->op.mod.message->elements[1].num_values != 1) {
3500 return ldb_module_operr(module);
3503 schema = dsdb_get_schema(ldb, req);
3504 if (schema == NULL) {
3505 return ldb_module_operr(module);
3508 if (ldb_attr_cmp(req->op.mod.message->elements[0].name,
3509 req->op.mod.message->elements[1].name) != 0) {
3510 return ldb_module_operr(module);
3513 sa = dsdb_attribute_by_lDAPDisplayName(schema,
3514 req->op.mod.message->elements[0].name);
3516 return ldb_module_operr(module);
3519 if (sa->dn_format == DSDB_INVALID_DN) {
3520 return ldb_module_operr(module);
3523 if (sa->linkID != 0) {
3524 return ldb_module_operr(module);
3528 * If we are run from dbcheck and we are not updating
3529 * a link (as these would need to be sorted and so
3530 * can't go via such a simple update, then do not
3531 * trigger replicated updates and a new USN from this
3532 * change, it wasn't a real change, just a new
3533 * (correct) string DN
3536 fix_dn_name_control->critical = false;
3537 return ldb_next_request(module, req);
3540 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_modify\n");
3542 guid_el = ldb_msg_find_element(req->op.mod.message, "objectGUID");
3543 if (guid_el != NULL) {
3544 ldb_set_errstring(ldb,
3545 "replmd_modify: it's not allowed to change the objectGUID!");
3546 return LDB_ERR_CONSTRAINT_VIOLATION;
3549 ac = replmd_ctx_init(module, req);
3551 return ldb_module_oom(module);
3554 functional_level = dsdb_functional_level(ldb);
3556 /* we have to copy the message as the caller might have it as a const */
3557 msg = ldb_msg_copy_shallow(ac, req->op.mod.message);
3561 return LDB_ERR_OPERATIONS_ERROR;
3564 fix_dn_sid_control = ldb_request_get_control(req,
3565 DSDB_CONTROL_DBCHECK_FIX_LINK_DN_SID);
3566 if (fix_dn_sid_control != NULL) {
3567 const struct dsdb_attribute *sa = NULL;
3569 if (msg->num_elements != 1) {
3571 return ldb_module_operr(module);
3574 if (msg->elements[0].flags != LDB_FLAG_MOD_ADD) {
3576 return ldb_module_operr(module);
3579 if (msg->elements[0].num_values != 1) {
3581 return ldb_module_operr(module);
3584 sa = dsdb_attribute_by_lDAPDisplayName(ac->schema,
3585 msg->elements[0].name);
3588 return ldb_module_operr(module);
3591 if (sa->dn_format != DSDB_NORMAL_DN) {
3593 return ldb_module_operr(module);
3596 fix_dn_sid_control->critical = false;
3597 ac->fix_link_sid = true;
3599 goto handle_linked_attribs;
3602 ldb_msg_remove_attr(msg, "whenChanged");
3603 ldb_msg_remove_attr(msg, "uSNChanged");
3605 is_schema_nc = ldb_dn_compare_base(replmd_private->schema_dn, msg->dn) == 0;
3607 ret = replmd_update_rpmd(module, ac->schema, req, NULL,
3608 msg, &ac->seq_num, t, is_schema_nc,
3610 if (rodc && (ret == LDB_ERR_REFERRAL)) {
3611 ret = send_rodc_referral(req, ldb, msg->dn);
3617 if (ret != LDB_SUCCESS) {
3622 handle_linked_attribs:
3623 ret = replmd_modify_handle_linked_attribs(module, replmd_private,
3625 if (ret != LDB_SUCCESS) {
3631 * - replace the old object with the newly constructed one
3634 ac->is_urgent = is_urgent;
3636 ret = ldb_build_mod_req(&down_req, ldb, ac,
3639 ac, replmd_op_callback,
3641 LDB_REQ_SET_LOCATION(down_req);
3642 if (ret != LDB_SUCCESS) {
3647 /* current partition control is needed by "replmd_op_callback" */
3648 if (ldb_request_get_control(req, DSDB_CONTROL_CURRENT_PARTITION_OID) == NULL) {
3649 ret = ldb_request_add_control(down_req,
3650 DSDB_CONTROL_CURRENT_PARTITION_OID,
3652 if (ret != LDB_SUCCESS) {
3658 /* If we are in functional level 2000, then
3659 * replmd_modify_handle_linked_attribs will have done
3661 if (functional_level == DS_DOMAIN_FUNCTION_2000) {
3662 ret = ldb_request_add_control(down_req, DSDB_CONTROL_APPLY_LINKS, false, NULL);
3663 if (ret != LDB_SUCCESS) {
3669 talloc_steal(down_req, msg);
3671 /* we only change whenChanged and uSNChanged if the seq_num
3673 if (ac->seq_num != 0) {
3674 ret = add_time_element(msg, "whenChanged", t);
3675 if (ret != LDB_SUCCESS) {
3681 ret = add_uint64_element(ldb, msg, "uSNChanged", ac->seq_num);
3682 if (ret != LDB_SUCCESS) {
3689 /* go on with the call chain */
3690 return ldb_next_request(module, down_req);
3693 static int replmd_rename_callback(struct ldb_request *req, struct ldb_reply *ares);
3696 handle a rename request
3698 On a rename we need to do an extra ldb_modify which sets the
3699 whenChanged and uSNChanged attributes. We do this in a callback after the success.
3701 static int replmd_rename(struct ldb_module *module, struct ldb_request *req)
3703 struct ldb_context *ldb;
3704 struct replmd_replicated_request *ac;
3706 struct ldb_request *down_req;
3708 /* do not manipulate our control entries */
3709 if (ldb_dn_is_special(req->op.mod.message->dn)) {
3710 return ldb_next_request(module, req);
3713 ldb = ldb_module_get_ctx(module);
3715 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_rename\n");
3717 ac = replmd_ctx_init(module, req);
3719 return ldb_module_oom(module);
3722 ret = ldb_build_rename_req(&down_req, ldb, ac,
3723 ac->req->op.rename.olddn,
3724 ac->req->op.rename.newdn,
3726 ac, replmd_rename_callback,
3728 LDB_REQ_SET_LOCATION(down_req);
3729 if (ret != LDB_SUCCESS) {
3734 /* go on with the call chain */
3735 return ldb_next_request(module, down_req);
3738 /* After the rename is compleated, update the whenchanged etc */
3739 static int replmd_rename_callback(struct ldb_request *req, struct ldb_reply *ares)
3741 struct ldb_context *ldb;
3742 struct ldb_request *down_req;
3743 struct ldb_message *msg;
3744 const struct dsdb_attribute *rdn_attr;
3745 const char *rdn_name;
3746 const struct ldb_val *rdn_val;
3747 const char *attrs[5] = { NULL, };
3748 time_t t = time(NULL);
3750 bool is_urgent = false, rodc = false;
3752 struct replmd_replicated_request *ac =
3753 talloc_get_type(req->context, struct replmd_replicated_request);
3754 struct replmd_private *replmd_private =
3755 talloc_get_type(ldb_module_get_private(ac->module),
3756 struct replmd_private);
3758 ldb = ldb_module_get_ctx(ac->module);
3760 if (ares->error != LDB_SUCCESS) {
3761 return ldb_module_done(ac->req, ares->controls,
3762 ares->response, ares->error);
3765 if (ares->type != LDB_REPLY_DONE) {
3766 ldb_set_errstring(ldb,
3767 "invalid ldb_reply_type in callback");
3769 return ldb_module_done(ac->req, NULL, NULL,
3770 LDB_ERR_OPERATIONS_ERROR);
3774 * - replace the old object with the newly constructed one
3777 msg = ldb_msg_new(ac);
3780 return LDB_ERR_OPERATIONS_ERROR;
3783 msg->dn = ac->req->op.rename.newdn;
3785 is_schema_nc = ldb_dn_compare_base(replmd_private->schema_dn, msg->dn) == 0;
3787 rdn_name = ldb_dn_get_rdn_name(msg->dn);
3788 if (rdn_name == NULL) {
3790 return ldb_module_done(ac->req, NULL, NULL,
3794 /* normalize the rdn attribute name */
3795 rdn_attr = dsdb_attribute_by_lDAPDisplayName(ac->schema, rdn_name);
3796 if (rdn_attr == NULL) {
3798 return ldb_module_done(ac->req, NULL, NULL,
3801 rdn_name = rdn_attr->lDAPDisplayName;
3803 rdn_val = ldb_dn_get_rdn_val(msg->dn);
3804 if (rdn_val == NULL) {
3806 return ldb_module_done(ac->req, NULL, NULL,
3810 if (ldb_msg_add_empty(msg, rdn_name, LDB_FLAG_MOD_REPLACE, NULL) != 0) {
3812 return ldb_module_done(ac->req, NULL, NULL,
3815 if (ldb_msg_add_value(msg, rdn_name, rdn_val, NULL) != 0) {
3817 return ldb_module_done(ac->req, NULL, NULL,
3820 if (ldb_msg_add_empty(msg, "name", LDB_FLAG_MOD_REPLACE, NULL) != 0) {
3822 return ldb_module_done(ac->req, NULL, NULL,
3825 if (ldb_msg_add_value(msg, "name", rdn_val, NULL) != 0) {
3827 return ldb_module_done(ac->req, NULL, NULL,
3832 * here we let replmd_update_rpmd() only search for
3833 * the existing "replPropertyMetaData" and rdn_name attributes.
3835 * We do not want the existing "name" attribute as
3836 * the "name" attribute needs to get the version
3837 * updated on rename even if the rdn value hasn't changed.
3839 * This is the diff of the meta data, for a moved user
3840 * on a w2k8r2 server:
3843 * -dn: CN=sdf df,CN=Users,DC=bla,DC=base
3844 * +dn: CN=sdf df,OU=TestOU,DC=bla,DC=base
3845 * replPropertyMetaData: NDR: struct replPropertyMetaDataBlob
3846 * version : 0x00000001 (1)
3847 * reserved : 0x00000000 (0)
3848 * @@ -66,11 +66,11 @@ replPropertyMetaData: NDR: struct re
3849 * local_usn : 0x00000000000037a5 (14245)
3850 * array: struct replPropertyMetaData1
3851 * attid : DRSUAPI_ATTID_name (0x90001)
3852 * - version : 0x00000001 (1)
3853 * - originating_change_time : Wed Feb 9 17:20:49 2011 CET
3854 * + version : 0x00000002 (2)
3855 * + originating_change_time : Wed Apr 6 15:21:01 2011 CEST
3856 * originating_invocation_id: 0d36ca05-5507-4e62-aca3-354bab0d39e1
3857 * - originating_usn : 0x00000000000037a5 (14245)
3858 * - local_usn : 0x00000000000037a5 (14245)
3859 * + originating_usn : 0x0000000000003834 (14388)
3860 * + local_usn : 0x0000000000003834 (14388)
3861 * array: struct replPropertyMetaData1
3862 * attid : DRSUAPI_ATTID_userAccountControl (0x90008)
3863 * version : 0x00000004 (4)
3865 attrs[0] = "replPropertyMetaData";
3866 attrs[1] = "objectClass";
3867 attrs[2] = "instanceType";
3868 attrs[3] = rdn_name;
3871 ret = replmd_update_rpmd(ac->module, ac->schema, req, attrs,
3872 msg, &ac->seq_num, t,
3873 is_schema_nc, &is_urgent, &rodc);
3874 if (rodc && (ret == LDB_ERR_REFERRAL)) {
3875 ret = send_rodc_referral(req, ldb, ac->req->op.rename.olddn);
3877 return ldb_module_done(req, NULL, NULL, ret);
3880 if (ret != LDB_SUCCESS) {
3882 return ldb_module_done(ac->req, NULL, NULL, ret);
3885 if (ac->seq_num == 0) {
3887 return ldb_module_done(ac->req, NULL, NULL,
3889 "internal error seq_num == 0"));
3891 ac->is_urgent = is_urgent;
3893 ret = ldb_build_mod_req(&down_req, ldb, ac,
3896 ac, replmd_op_callback,
3898 LDB_REQ_SET_LOCATION(down_req);
3899 if (ret != LDB_SUCCESS) {
3904 /* current partition control is needed by "replmd_op_callback" */
3905 if (ldb_request_get_control(req, DSDB_CONTROL_CURRENT_PARTITION_OID) == NULL) {
3906 ret = ldb_request_add_control(down_req,
3907 DSDB_CONTROL_CURRENT_PARTITION_OID,
3909 if (ret != LDB_SUCCESS) {
3915 talloc_steal(down_req, msg);
3917 ret = add_time_element(msg, "whenChanged", t);
3918 if (ret != LDB_SUCCESS) {
3924 ret = add_uint64_element(ldb, msg, "uSNChanged", ac->seq_num);
3925 if (ret != LDB_SUCCESS) {
3931 /* go on with the call chain - do the modify after the rename */
3932 return ldb_next_request(ac->module, down_req);
3936 * remove links from objects that point at this object when an object
3937 * is deleted. We remove it from the NEXT module per MS-DRSR 5.160
3938 * RemoveObj which states that link removal due to the object being
3939 * deleted is NOT an originating update - they just go away!
3942 static int replmd_delete_remove_link(struct ldb_module *module,
3943 const struct dsdb_schema *schema,
3944 struct replmd_private *replmd_private,
3947 struct ldb_message_element *el,
3948 const struct dsdb_attribute *sa,
3949 struct ldb_request *parent)
3952 TALLOC_CTX *tmp_ctx = talloc_new(module);
3953 struct ldb_context *ldb = ldb_module_get_ctx(module);
3955 for (i=0; i<el->num_values; i++) {
3956 struct dsdb_dn *dsdb_dn;
3958 struct ldb_message *msg;
3959 const struct dsdb_attribute *target_attr;
3960 struct ldb_message_element *el2;
3962 struct ldb_val dn_val;
3963 uint32_t dsdb_flags = 0;
3964 const char *attrs[] = { NULL, NULL };
3965 struct ldb_result *link_res;
3966 struct ldb_message *link_msg;
3967 struct ldb_message_element *link_el;
3968 struct parsed_dn *link_dns;
3969 struct parsed_dn *p = NULL, *unused = NULL;
3971 if (dsdb_dn_is_deleted_val(&el->values[i])) {
3975 dsdb_dn = dsdb_dn_parse(tmp_ctx, ldb, &el->values[i], sa->syntax->ldap_oid);
3977 talloc_free(tmp_ctx);
3978 return LDB_ERR_OPERATIONS_ERROR;
3981 /* remove the link */
3982 msg = ldb_msg_new(tmp_ctx);
3984 ldb_module_oom(module);
3985 talloc_free(tmp_ctx);
3986 return LDB_ERR_OPERATIONS_ERROR;
3990 msg->dn = dsdb_dn->dn;
3992 target_attr = dsdb_attribute_by_linkID(schema, sa->linkID ^ 1);
3993 if (target_attr == NULL) {
3996 attrs[0] = target_attr->lDAPDisplayName;
3998 ret = ldb_msg_add_empty(msg, target_attr->lDAPDisplayName,
3999 LDB_FLAG_MOD_DELETE, &el2);
4000 if (ret != LDB_SUCCESS) {
4001 ldb_module_oom(module);
4002 talloc_free(tmp_ctx);
4003 return LDB_ERR_OPERATIONS_ERROR;
4006 ret = dsdb_module_search_dn(module, tmp_ctx, &link_res,
4008 DSDB_FLAG_NEXT_MODULE |
4009 DSDB_SEARCH_SHOW_EXTENDED_DN |
4010 DSDB_SEARCH_SHOW_RECYCLED,
4013 if (ret != LDB_SUCCESS) {
4014 talloc_free(tmp_ctx);
4018 link_msg = link_res->msgs[0];
4019 link_el = ldb_msg_find_element(link_msg,
4020 target_attr->lDAPDisplayName);
4021 if (link_el == NULL) {
4022 talloc_free(tmp_ctx);
4023 return LDB_ERR_NO_SUCH_ATTRIBUTE;
4027 * This call 'upgrades' the links in link_dns, but we
4028 * do not commit the result back into the database, so
4029 * this is safe to call in FL2000 or on databases that
4030 * have been run at that level in the past.
4032 ret = get_parsed_dns_trusted(module, replmd_private, tmp_ctx,
4034 target_attr->syntax->ldap_oid, parent);
4035 if (ret != LDB_SUCCESS) {
4036 talloc_free(tmp_ctx);
4040 ret = parsed_dn_find(ldb, link_dns, link_el->num_values,
4044 target_attr->syntax->ldap_oid, false);
4045 if (ret != LDB_SUCCESS) {
4046 talloc_free(tmp_ctx);
4051 ldb_asprintf_errstring(ldb_module_get_ctx(module),
4052 "Failed to find forward link on %s "
4053 "as %s to remove backlink %s on %s",
4054 ldb_dn_get_linearized(msg->dn),
4055 target_attr->lDAPDisplayName,
4056 sa->lDAPDisplayName,
4057 ldb_dn_get_linearized(dn));
4058 talloc_free(tmp_ctx);
4059 return LDB_ERR_NO_SUCH_ATTRIBUTE;
4063 /* This needs to get the Binary DN, by first searching */
4064 dn_str = dsdb_dn_get_linearized(tmp_ctx,
4067 dn_val = data_blob_string_const(dn_str);
4068 el2->values = &dn_val;
4069 el2->num_values = 1;
4072 * Ensure that we tell the modification to vanish any linked
4073 * attributes (not simply mark them as isDeleted = TRUE)
4075 dsdb_flags |= DSDB_REPLMD_VANISH_LINKS;
4077 ret = dsdb_module_modify(module, msg, dsdb_flags|DSDB_FLAG_OWN_MODULE, parent);
4078 if (ret != LDB_SUCCESS) {
4079 talloc_free(tmp_ctx);
4083 talloc_free(tmp_ctx);
4089 handle update of replication meta data for deletion of objects
4091 This also handles the mapping of delete to a rename operation
4092 to allow deletes to be replicated.
4094 It also handles the incoming deleted objects, to ensure they are
4095 fully deleted here. In that case re_delete is true, and we do not
4096 use this as a signal to change the deleted state, just reinforce it.
4099 static int replmd_delete_internals(struct ldb_module *module, struct ldb_request *req, bool re_delete)
4101 int ret = LDB_ERR_OTHER;
4102 bool retb, disallow_move_on_delete;
4103 struct ldb_dn *old_dn = NULL, *new_dn = NULL;
4104 const char *rdn_name;
4105 const struct ldb_val *rdn_value, *new_rdn_value;
4107 struct ldb_context *ldb = ldb_module_get_ctx(module);
4108 const struct dsdb_schema *schema;
4109 struct ldb_message *msg, *old_msg;
4110 struct ldb_message_element *el;
4111 TALLOC_CTX *tmp_ctx;
4112 struct ldb_result *res, *parent_res;
4113 static const char * const preserved_attrs[] = {
4114 /* yes, this really is a hard coded list. See MS-ADTS
4115 section 3.1.1.5.5.1.1 */
4118 "dNReferenceUpdate",
4129 "msDS-LastKnownRDN",
4135 "distinguishedName",
4139 "proxiedObjectName",
4141 "nTSecurityDescriptor",
4142 "replPropertyMetaData",
4144 "securityIdentifier",
4152 "userAccountControl",
4159 static const char * const all_attrs[] = {
4160 DSDB_SECRET_ATTRIBUTES,
4164 static const struct ldb_val true_val = {
4165 .data = discard_const_p(uint8_t, "TRUE"),
4170 uint32_t dsdb_flags = 0;
4171 struct replmd_private *replmd_private;
4172 enum deletion_state deletion_state, next_deletion_state;
4174 if (ldb_dn_is_special(req->op.del.dn)) {
4175 return ldb_next_request(module, req);
4179 * We have to allow dbcheck to remove an object that
4180 * is beyond repair, and to do so totally. This could
4181 * mean we we can get a partial object from the other
4182 * DC, causing havoc, so dbcheck suggests
4183 * re-replication first. dbcheck sets both DBCHECK
4184 * and RELAX in this situation.
4186 if (ldb_request_get_control(req, LDB_CONTROL_RELAX_OID)
4187 && ldb_request_get_control(req, DSDB_CONTROL_DBCHECK)) {
4188 /* really, really remove it */
4189 return ldb_next_request(module, req);
4192 tmp_ctx = talloc_new(ldb);
4195 return LDB_ERR_OPERATIONS_ERROR;
4198 schema = dsdb_get_schema(ldb, tmp_ctx);
4200 talloc_free(tmp_ctx);
4201 return LDB_ERR_OPERATIONS_ERROR;
4204 old_dn = ldb_dn_copy(tmp_ctx, req->op.del.dn);
4206 /* we need the complete msg off disk, so we can work out which
4207 attributes need to be removed */
4208 ret = dsdb_module_search_dn(module, tmp_ctx, &res, old_dn, all_attrs,
4209 DSDB_FLAG_NEXT_MODULE |
4210 DSDB_SEARCH_SHOW_RECYCLED |
4211 DSDB_SEARCH_REVEAL_INTERNALS |
4212 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT, req);
4213 if (ret != LDB_SUCCESS) {
4214 ldb_asprintf_errstring(ldb_module_get_ctx(module),
4215 "repmd_delete: Failed to %s %s, because we failed to find it: %s",
4216 re_delete ? "re-delete" : "delete",
4217 ldb_dn_get_linearized(old_dn),
4218 ldb_errstring(ldb_module_get_ctx(module)));
4219 talloc_free(tmp_ctx);
4222 old_msg = res->msgs[0];
4224 replmd_deletion_state(module, old_msg,
4226 &next_deletion_state);
4228 /* This supports us noticing an incoming isDeleted and acting on it */
4230 SMB_ASSERT(deletion_state > OBJECT_NOT_DELETED);
4231 next_deletion_state = deletion_state;
4234 if (next_deletion_state == OBJECT_REMOVED) {
4236 * We have to prevent objects being deleted, even if
4237 * the administrator really wants them gone, as
4238 * without the tombstone, we can get a partial object
4239 * from the other DC, causing havoc.
4241 * The only other valid case is when the 180 day
4242 * timeout has expired, when relax is specified.
4244 if (ldb_request_get_control(req, LDB_CONTROL_RELAX_OID)) {
4245 /* it is already deleted - really remove it this time */
4246 talloc_free(tmp_ctx);
4247 return ldb_next_request(module, req);
4250 ldb_asprintf_errstring(ldb, "Refusing to delete tombstone object %s. "
4251 "This check is to prevent corruption of the replicated state.",
4252 ldb_dn_get_linearized(old_msg->dn));
4253 return LDB_ERR_UNWILLING_TO_PERFORM;
4256 rdn_name = ldb_dn_get_rdn_name(old_dn);
4257 rdn_value = ldb_dn_get_rdn_val(old_dn);
4258 if ((rdn_name == NULL) || (rdn_value == NULL)) {
4259 talloc_free(tmp_ctx);
4260 return ldb_operr(ldb);
4263 msg = ldb_msg_new(tmp_ctx);
4265 ldb_module_oom(module);
4266 talloc_free(tmp_ctx);
4267 return LDB_ERR_OPERATIONS_ERROR;
4272 /* consider the SYSTEM_FLAG_DISALLOW_MOVE_ON_DELETE flag */
4273 disallow_move_on_delete =
4274 (ldb_msg_find_attr_as_int(old_msg, "systemFlags", 0)
4275 & SYSTEM_FLAG_DISALLOW_MOVE_ON_DELETE);
4277 /* work out where we will be renaming this object to */
4278 if (!disallow_move_on_delete) {
4279 struct ldb_dn *deleted_objects_dn;
4280 ret = dsdb_get_deleted_objects_dn(ldb, tmp_ctx, old_dn,
4281 &deleted_objects_dn);
4284 * We should not move objects if we can't find the
4285 * deleted objects DN. Not moving (or otherwise
4286 * harming) the Deleted Objects DN itself is handled
4289 if (re_delete && (ret != LDB_SUCCESS)) {
4290 new_dn = ldb_dn_get_parent(tmp_ctx, old_dn);
4291 if (new_dn == NULL) {
4292 ldb_module_oom(module);
4293 talloc_free(tmp_ctx);
4294 return LDB_ERR_OPERATIONS_ERROR;
4296 } else if (ret != LDB_SUCCESS) {
4297 /* this is probably an attempted delete on a partition
4298 * that doesn't allow delete operations, such as the
4299 * schema partition */
4300 ldb_asprintf_errstring(ldb, "No Deleted Objects container for DN %s",
4301 ldb_dn_get_linearized(old_dn));
4302 talloc_free(tmp_ctx);
4303 return LDB_ERR_UNWILLING_TO_PERFORM;
4305 new_dn = deleted_objects_dn;
4308 new_dn = ldb_dn_get_parent(tmp_ctx, old_dn);
4309 if (new_dn == NULL) {
4310 ldb_module_oom(module);
4311 talloc_free(tmp_ctx);
4312 return LDB_ERR_OPERATIONS_ERROR;
4316 /* get the objects GUID from the search we just did */
4317 guid = samdb_result_guid(old_msg, "objectGUID");
4319 if (deletion_state == OBJECT_NOT_DELETED) {
4320 struct ldb_message_element *is_deleted_el;
4322 ret = replmd_make_deleted_child_dn(tmp_ctx,
4325 rdn_name, rdn_value,
4328 if (ret != LDB_SUCCESS) {
4329 talloc_free(tmp_ctx);
4333 ret = ldb_msg_add_value(msg, "isDeleted", &true_val,
4335 if (ret != LDB_SUCCESS) {
4336 ldb_asprintf_errstring(ldb, __location__
4337 ": Failed to add isDeleted string to the msg");
4338 talloc_free(tmp_ctx);
4341 is_deleted_el->flags = LDB_FLAG_MOD_REPLACE;
4344 * No matter what has happened with other renames etc, try again to
4345 * get this to be under the deleted DN. See MS-DRSR 5.160 RemoveObj
4348 struct ldb_dn *rdn = ldb_dn_copy(tmp_ctx, old_dn);
4349 retb = ldb_dn_remove_base_components(rdn, ldb_dn_get_comp_num(rdn) - 1);
4351 ldb_asprintf_errstring(ldb, __location__
4352 ": Unable to add a prepare rdn of %s",
4353 ldb_dn_get_linearized(rdn));
4354 talloc_free(tmp_ctx);
4355 return LDB_ERR_OPERATIONS_ERROR;
4357 SMB_ASSERT(ldb_dn_get_comp_num(rdn) == 1);
4359 retb = ldb_dn_add_child(new_dn, rdn);
4361 ldb_asprintf_errstring(ldb, __location__
4362 ": Unable to add rdn %s to base dn: %s",
4363 ldb_dn_get_linearized(rdn),
4364 ldb_dn_get_linearized(new_dn));
4365 talloc_free(tmp_ctx);
4366 return LDB_ERR_OPERATIONS_ERROR;
4371 now we need to modify the object in the following ways:
4373 - add isDeleted=TRUE
4374 - update rDN and name, with new rDN
4375 - remove linked attributes
4376 - remove objectCategory and sAMAccountType
4377 - remove attribs not on the preserved list
4378 - preserved if in above list, or is rDN
4379 - remove all linked attribs from this object
4380 - remove all links from other objects to this object
4381 - add lastKnownParent
4382 - update replPropertyMetaData?
4384 see MS-ADTS "Tombstone Requirements" section 3.1.1.5.5.1.1
4387 if (deletion_state == OBJECT_NOT_DELETED) {
4388 struct ldb_dn *parent_dn = ldb_dn_get_parent(tmp_ctx, old_dn);
4389 char *parent_dn_str = NULL;
4390 struct ldb_message_element *p_el;
4392 /* we need the storage form of the parent GUID */
4393 ret = dsdb_module_search_dn(module, tmp_ctx, &parent_res,
4395 DSDB_FLAG_NEXT_MODULE |
4396 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT |
4397 DSDB_SEARCH_REVEAL_INTERNALS|
4398 DSDB_SEARCH_SHOW_RECYCLED, req);
4399 if (ret != LDB_SUCCESS) {
4400 ldb_asprintf_errstring(ldb_module_get_ctx(module),
4401 "repmd_delete: Failed to %s %s, "
4402 "because we failed to find it's parent (%s): %s",
4403 re_delete ? "re-delete" : "delete",
4404 ldb_dn_get_linearized(old_dn),
4405 ldb_dn_get_linearized(parent_dn),
4406 ldb_errstring(ldb_module_get_ctx(module)));
4407 talloc_free(tmp_ctx);
4412 * Now we can use the DB version,
4413 * it will have the extended DN info in it
4415 parent_dn = parent_res->msgs[0]->dn;
4416 parent_dn_str = ldb_dn_get_extended_linearized(tmp_ctx,
4419 if (parent_dn_str == NULL) {
4420 talloc_free(tmp_ctx);
4421 return ldb_module_oom(module);
4424 ret = ldb_msg_add_steal_string(msg, "lastKnownParent",
4426 if (ret != LDB_SUCCESS) {
4427 ldb_asprintf_errstring(ldb, __location__
4428 ": Failed to add lastKnownParent "
4429 "string when deleting %s",
4430 ldb_dn_get_linearized(old_dn));
4431 talloc_free(tmp_ctx);
4434 p_el = ldb_msg_find_element(msg,
4437 talloc_free(tmp_ctx);
4438 return ldb_module_operr(module);
4440 p_el->flags = LDB_FLAG_MOD_REPLACE;
4442 if (next_deletion_state == OBJECT_DELETED) {
4443 ret = ldb_msg_add_value(msg, "msDS-LastKnownRDN", rdn_value, NULL);
4444 if (ret != LDB_SUCCESS) {
4445 ldb_asprintf_errstring(ldb, __location__
4446 ": Failed to add msDS-LastKnownRDN "
4447 "string when deleting %s",
4448 ldb_dn_get_linearized(old_dn));
4449 talloc_free(tmp_ctx);
4452 p_el = ldb_msg_find_element(msg,
4453 "msDS-LastKnownRDN");
4455 talloc_free(tmp_ctx);
4456 return ldb_module_operr(module);
4458 p_el->flags = LDB_FLAG_MOD_ADD;
4462 switch (next_deletion_state) {
4464 case OBJECT_RECYCLED:
4465 case OBJECT_TOMBSTONE:
4468 * MS-ADTS 3.1.1.5.5.1.1 Tombstone Requirements
4469 * describes what must be removed from a tombstone
4472 * MS-ADTS 3.1.1.5.5.1.3 Recycled-Object Requirements
4473 * describes what must be removed from a recycled
4479 * we also mark it as recycled, meaning this object can't be
4480 * recovered (we are stripping its attributes).
4481 * This is done only if we have this schema object of course ...
4482 * This behavior is identical to the one of Windows 2008R2 which
4483 * always set the isRecycled attribute, even if the recycle-bin is
4484 * not activated and what ever the forest level is.
4486 if (dsdb_attribute_by_lDAPDisplayName(schema, "isRecycled") != NULL) {
4487 struct ldb_message_element *is_recycled_el;
4489 ret = ldb_msg_add_value(msg, "isRecycled", &true_val,
4491 if (ret != LDB_SUCCESS) {
4492 DEBUG(0,(__location__ ": Failed to add isRecycled string to the msg\n"));
4493 ldb_module_oom(module);
4494 talloc_free(tmp_ctx);
4497 is_recycled_el->flags = LDB_FLAG_MOD_REPLACE;
4500 replmd_private = talloc_get_type(ldb_module_get_private(module),
4501 struct replmd_private);
4502 /* work out which of the old attributes we will be removing */
4503 for (i=0; i<old_msg->num_elements; i++) {
4504 const struct dsdb_attribute *sa;
4505 el = &old_msg->elements[i];
4506 sa = dsdb_attribute_by_lDAPDisplayName(schema, el->name);
4508 talloc_free(tmp_ctx);
4509 return LDB_ERR_OPERATIONS_ERROR;
4511 if (ldb_attr_cmp(el->name, rdn_name) == 0) {
4512 /* don't remove the rDN */
4516 if (sa->linkID & 1) {
4518 we have a backlink in this object
4519 that needs to be removed. We're not
4520 allowed to remove it directly
4521 however, so we instead setup a
4522 modify to delete the corresponding
4525 ret = replmd_delete_remove_link(module, schema,
4529 if (ret == LDB_SUCCESS) {
4531 * now we continue, which means we
4532 * won't remove this backlink
4538 if (ret != LDB_ERR_NO_SUCH_ATTRIBUTE) {
4539 const char *old_dn_str
4540 = ldb_dn_get_linearized(old_dn);
4541 ldb_asprintf_errstring(ldb,
4543 ": Failed to remove backlink of "
4544 "%s when deleting %s: %s",
4547 ldb_errstring(ldb));
4548 talloc_free(tmp_ctx);
4549 return LDB_ERR_OPERATIONS_ERROR;
4553 * Otherwise vanish the link, we are
4554 * out of sync and the controlling
4555 * object does not have the source
4559 dsdb_flags |= DSDB_REPLMD_VANISH_LINKS;
4561 } else if (sa->linkID == 0) {
4562 if (ldb_attr_in_list(preserved_attrs, el->name)) {
4565 if (sa->searchFlags & SEARCH_FLAG_PRESERVEONDELETE) {
4570 * Ensure that we tell the modification to vanish any linked
4571 * attributes (not simply mark them as isDeleted = TRUE)
4573 dsdb_flags |= DSDB_REPLMD_VANISH_LINKS;
4575 ret = ldb_msg_add_empty(msg, el->name, LDB_FLAG_MOD_DELETE, &el);
4576 if (ret != LDB_SUCCESS) {
4577 talloc_free(tmp_ctx);
4578 ldb_module_oom(module);
4585 case OBJECT_DELETED:
4587 * MS-ADTS 3.1.1.5.5.1.2 Deleted-Object Requirements
4588 * describes what must be removed from a deleted
4592 ret = ldb_msg_add_empty(msg, "objectCategory", LDB_FLAG_MOD_REPLACE, NULL);
4593 if (ret != LDB_SUCCESS) {
4594 talloc_free(tmp_ctx);
4595 ldb_module_oom(module);
4599 ret = ldb_msg_add_empty(msg, "sAMAccountType", LDB_FLAG_MOD_REPLACE, NULL);
4600 if (ret != LDB_SUCCESS) {
4601 talloc_free(tmp_ctx);
4602 ldb_module_oom(module);
4612 if (deletion_state == OBJECT_NOT_DELETED) {
4613 const struct dsdb_attribute *sa;
4615 /* work out what the new rdn value is, for updating the
4616 rDN and name fields */
4617 new_rdn_value = ldb_dn_get_rdn_val(new_dn);
4618 if (new_rdn_value == NULL) {
4619 talloc_free(tmp_ctx);
4620 return ldb_operr(ldb);
4623 sa = dsdb_attribute_by_lDAPDisplayName(schema, rdn_name);
4625 talloc_free(tmp_ctx);
4626 return LDB_ERR_OPERATIONS_ERROR;
4629 ret = ldb_msg_add_value(msg, sa->lDAPDisplayName, new_rdn_value,
4631 if (ret != LDB_SUCCESS) {
4632 talloc_free(tmp_ctx);
4635 el->flags = LDB_FLAG_MOD_REPLACE;
4637 el = ldb_msg_find_element(old_msg, "name");
4639 ret = ldb_msg_add_value(msg, "name", new_rdn_value, &el);
4640 if (ret != LDB_SUCCESS) {
4641 talloc_free(tmp_ctx);
4644 el->flags = LDB_FLAG_MOD_REPLACE;
4649 * TODO: Per MS-DRSR 5.160 RemoveObj we should remove links directly, not as an originating update!
4654 * No matter what has happned with other renames, try again to
4655 * get this to be under the deleted DN.
4657 if (strcmp(ldb_dn_get_linearized(old_dn), ldb_dn_get_linearized(new_dn)) != 0) {
4658 /* now rename onto the new DN */
4659 ret = dsdb_module_rename(module, old_dn, new_dn, DSDB_FLAG_NEXT_MODULE, req);
4660 if (ret != LDB_SUCCESS){
4661 DEBUG(0,(__location__ ": Failed to rename object from '%s' to '%s' - %s\n",
4662 ldb_dn_get_linearized(old_dn),
4663 ldb_dn_get_linearized(new_dn),
4664 ldb_errstring(ldb)));
4665 talloc_free(tmp_ctx);
4671 ret = dsdb_module_modify(module, msg, dsdb_flags|DSDB_FLAG_OWN_MODULE, req);
4672 if (ret != LDB_SUCCESS) {
4673 ldb_asprintf_errstring(ldb, "replmd_delete: Failed to modify object %s in delete - %s",
4674 ldb_dn_get_linearized(old_dn), ldb_errstring(ldb));
4675 talloc_free(tmp_ctx);
4679 talloc_free(tmp_ctx);
4681 return ldb_module_done(req, NULL, NULL, LDB_SUCCESS);
4684 static int replmd_delete(struct ldb_module *module, struct ldb_request *req)
4686 return replmd_delete_internals(module, req, false);
4690 static int replmd_replicated_request_error(struct replmd_replicated_request *ar, int ret)
4695 static int replmd_replicated_request_werror(struct replmd_replicated_request *ar, WERROR status)
4697 int ret = LDB_ERR_OTHER;
4698 /* TODO: do some error mapping */
4700 /* Let the caller know the full WERROR */
4701 ar->objs->error = status;
4707 static struct replPropertyMetaData1 *
4708 replmd_replPropertyMetaData1_find_attid(struct replPropertyMetaDataBlob *md_blob,
4709 enum drsuapi_DsAttributeId attid)
4712 struct replPropertyMetaDataCtr1 *rpmd_ctr = &md_blob->ctr.ctr1;
4714 for (i = 0; i < rpmd_ctr->count; i++) {
4715 if (rpmd_ctr->array[i].attid == attid) {
4716 return &rpmd_ctr->array[i];
4724 return true if an update is newer than an existing entry
4725 see section 5.11 of MS-ADTS
4727 static bool replmd_update_is_newer(const struct GUID *current_invocation_id,
4728 const struct GUID *update_invocation_id,
4729 uint32_t current_version,
4730 uint32_t update_version,
4731 NTTIME current_change_time,
4732 NTTIME update_change_time)
4734 if (update_version != current_version) {
4735 return update_version > current_version;
4737 if (update_change_time != current_change_time) {
4738 return update_change_time > current_change_time;
4740 return GUID_compare(update_invocation_id, current_invocation_id) > 0;
4743 static bool replmd_replPropertyMetaData1_is_newer(struct replPropertyMetaData1 *cur_m,
4744 struct replPropertyMetaData1 *new_m)
4746 return replmd_update_is_newer(&cur_m->originating_invocation_id,
4747 &new_m->originating_invocation_id,
4750 cur_m->originating_change_time,
4751 new_m->originating_change_time);
4754 static bool replmd_replPropertyMetaData1_new_should_be_taken(uint32_t dsdb_repl_flags,
4755 struct replPropertyMetaData1 *cur_m,
4756 struct replPropertyMetaData1 *new_m)
4761 * If the new replPropertyMetaData entry for this attribute is
4762 * not provided (this happens in the case where we look for
4763 * ATTID_name, but the name was not changed), then the local
4764 * state is clearly still current, as the remote
4765 * server didn't send it due to being older the high watermark
4768 if (new_m == NULL) {
4772 if (dsdb_repl_flags & DSDB_REPL_FLAG_PRIORITISE_INCOMING) {
4774 * if we compare equal then do an
4775 * update. This is used when a client
4776 * asks for a FULL_SYNC, and can be
4777 * used to recover a corrupt
4780 * This call is a bit tricky, what we
4781 * are doing it turning the 'is_newer'
4782 * call into a 'not is older' by
4783 * swapping cur_m and new_m, and negating the
4786 cmp = !replmd_replPropertyMetaData1_is_newer(new_m,
4789 cmp = replmd_replPropertyMetaData1_is_newer(cur_m,
4797 form a DN for a deleted (DEL:) or conflict (CNF:) DN
4799 static int replmd_make_prefix_child_dn(TALLOC_CTX *tmp_ctx,
4800 struct ldb_context *ldb,
4802 const char *four_char_prefix,
4803 const char *rdn_name,
4804 const struct ldb_val *rdn_value,
4807 struct ldb_val deleted_child_rdn_val;
4808 struct GUID_txt_buf guid_str;
4812 GUID_buf_string(&guid, &guid_str);
4814 retb = ldb_dn_add_child_fmt(dn, "X=Y");
4816 ldb_asprintf_errstring(ldb, __location__
4817 ": Unable to add a formatted child to dn: %s",
4818 ldb_dn_get_linearized(dn));
4819 return LDB_ERR_OPERATIONS_ERROR;
4823 * TODO: Per MS-ADTS 3.1.1.5.5 Delete Operation
4824 * we should truncate this value to ensure the RDN is not more than 255 chars.
4826 * However we MS-ADTS 3.1.1.5.1.2 Naming Constraints indicates that:
4828 * "Naming constraints are not enforced for replicated
4829 * updates." so this is safe and we don't have to work out not
4830 * splitting a UTF8 char right now.
4832 deleted_child_rdn_val = ldb_val_dup(tmp_ctx, rdn_value);
4835 * sizeof(guid_str.buf) will always be longer than
4836 * strlen(guid_str.buf) but we allocate using this and
4837 * waste the trailing bytes to avoid scaring folks
4838 * with memcpy() using strlen() below
4841 deleted_child_rdn_val.data
4842 = talloc_realloc(tmp_ctx, deleted_child_rdn_val.data,
4844 rdn_value->length + 5
4845 + sizeof(guid_str.buf));
4846 if (!deleted_child_rdn_val.data) {
4847 ldb_asprintf_errstring(ldb, __location__
4848 ": Unable to add a formatted child to dn: %s",
4849 ldb_dn_get_linearized(dn));
4850 return LDB_ERR_OPERATIONS_ERROR;
4853 deleted_child_rdn_val.length =
4854 rdn_value->length + 5
4855 + strlen(guid_str.buf);
4857 SMB_ASSERT(deleted_child_rdn_val.length <
4858 talloc_get_size(deleted_child_rdn_val.data));
4861 * talloc won't allocate more than 256MB so we can't
4862 * overflow but just to be sure
4864 if (deleted_child_rdn_val.length < rdn_value->length) {
4865 return LDB_ERR_OPERATIONS_ERROR;
4868 deleted_child_rdn_val.data[rdn_value->length] = 0x0a;
4869 memcpy(&deleted_child_rdn_val.data[rdn_value->length + 1],
4870 four_char_prefix, 4);
4871 memcpy(&deleted_child_rdn_val.data[rdn_value->length + 5],
4873 sizeof(guid_str.buf));
4875 /* Now set the value into the RDN, without parsing it */
4876 ret = ldb_dn_set_component(
4880 deleted_child_rdn_val);
4889 static struct ldb_dn *replmd_conflict_dn(TALLOC_CTX *mem_ctx,
4890 struct ldb_context *ldb,
4894 const struct ldb_val *rdn_val;
4895 const char *rdn_name;
4896 struct ldb_dn *new_dn;
4899 rdn_val = ldb_dn_get_rdn_val(dn);
4900 rdn_name = ldb_dn_get_rdn_name(dn);
4901 if (!rdn_val || !rdn_name) {
4905 new_dn = ldb_dn_get_parent(mem_ctx, dn);
4910 ret = replmd_make_prefix_child_dn(mem_ctx,
4916 if (ret != LDB_SUCCESS) {
4925 static int replmd_make_deleted_child_dn(TALLOC_CTX *tmp_ctx,
4926 struct ldb_context *ldb,
4928 const char *rdn_name,
4929 const struct ldb_val *rdn_value,
4932 return replmd_make_prefix_child_dn(tmp_ctx,
4942 perform a modify operation which sets the rDN and name attributes to
4943 their current values. This has the effect of changing these
4944 attributes to have been last updated by the current DC. This is
4945 needed to ensure that renames performed as part of conflict
4946 resolution are propagated to other DCs
4948 static int replmd_name_modify(struct replmd_replicated_request *ar,
4949 struct ldb_request *req, struct ldb_dn *dn)
4951 struct ldb_message *msg;
4952 const char *rdn_name;
4953 const struct ldb_val *rdn_val;
4954 const struct dsdb_attribute *rdn_attr;
4957 msg = ldb_msg_new(req);
4963 rdn_name = ldb_dn_get_rdn_name(dn);
4964 if (rdn_name == NULL) {
4968 /* normalize the rdn attribute name */
4969 rdn_attr = dsdb_attribute_by_lDAPDisplayName(ar->schema, rdn_name);
4970 if (rdn_attr == NULL) {
4973 rdn_name = rdn_attr->lDAPDisplayName;
4975 rdn_val = ldb_dn_get_rdn_val(dn);
4976 if (rdn_val == NULL) {
4980 if (ldb_msg_add_empty(msg, rdn_name, LDB_FLAG_MOD_REPLACE, NULL) != 0) {
4983 if (ldb_msg_add_value(msg, rdn_name, rdn_val, NULL) != 0) {
4986 if (ldb_msg_add_empty(msg, "name", LDB_FLAG_MOD_REPLACE, NULL) != 0) {
4989 if (ldb_msg_add_value(msg, "name", rdn_val, NULL) != 0) {
4994 * We have to mark this as a replicated update otherwise
4995 * schema_data may reject a rename in the schema partition
4998 ret = dsdb_module_modify(ar->module, msg,
4999 DSDB_FLAG_OWN_MODULE|DSDB_FLAG_REPLICATED_UPDATE,
5001 if (ret != LDB_SUCCESS) {
5002 DEBUG(0,(__location__ ": Failed to modify rDN/name of DN being DRS renamed '%s' - %s",
5003 ldb_dn_get_linearized(dn),
5004 ldb_errstring(ldb_module_get_ctx(ar->module))));
5014 DEBUG(0,(__location__ ": Failed to setup modify rDN/name of DN being DRS renamed '%s'",
5015 ldb_dn_get_linearized(dn)));
5016 return LDB_ERR_OPERATIONS_ERROR;
5021 callback for conflict DN handling where we have renamed the incoming
5022 record. After renaming it, we need to ensure the change of name and
5023 rDN for the incoming record is seen as an originating update by this DC.
5025 This also handles updating lastKnownParent for entries sent to lostAndFound
5027 static int replmd_op_name_modify_callback(struct ldb_request *req, struct ldb_reply *ares)
5029 struct replmd_replicated_request *ar =
5030 talloc_get_type_abort(req->context, struct replmd_replicated_request);
5031 struct ldb_dn *conflict_dn = NULL;
5034 if (ares->error != LDB_SUCCESS) {
5035 /* call the normal callback for everything except success */
5036 return replmd_op_callback(req, ares);
5039 switch (req->operation) {
5041 conflict_dn = req->op.add.message->dn;
5044 conflict_dn = req->op.mod.message->dn;
5047 smb_panic("replmd_op_name_modify_callback called in unknown circumstances");
5050 /* perform a modify of the rDN and name of the record */
5051 ret = replmd_name_modify(ar, req, conflict_dn);
5052 if (ret != LDB_SUCCESS) {
5054 return replmd_op_callback(req, ares);
5057 if (ar->objs->objects[ar->index_current].last_known_parent) {
5058 struct ldb_message *msg = ldb_msg_new(req);
5060 ldb_module_oom(ar->module);
5061 return LDB_ERR_OPERATIONS_ERROR;
5064 msg->dn = req->op.add.message->dn;
5066 ret = ldb_msg_add_steal_string(msg, "lastKnownParent",
5067 ldb_dn_get_extended_linearized(msg, ar->objs->objects[ar->index_current].last_known_parent, 1));
5068 if (ret != LDB_SUCCESS) {
5069 DEBUG(0,(__location__ ": Failed to add lastKnownParent string to the msg\n"));
5070 ldb_module_oom(ar->module);
5073 msg->elements[0].flags = LDB_FLAG_MOD_REPLACE;
5075 ret = dsdb_module_modify(ar->module, msg, DSDB_FLAG_OWN_MODULE, req);
5076 if (ret != LDB_SUCCESS) {
5077 DEBUG(0,(__location__ ": Failed to modify lastKnownParent of lostAndFound DN '%s' - %s",
5078 ldb_dn_get_linearized(msg->dn),
5079 ldb_errstring(ldb_module_get_ctx(ar->module))));
5085 return replmd_op_callback(req, ares);
5089 callback for replmd_replicated_apply_add()
5090 This copes with the creation of conflict records in the case where
5091 the DN exists, but with a different objectGUID
5093 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))
5095 struct ldb_dn *conflict_dn;
5096 struct replmd_replicated_request *ar =
5097 talloc_get_type_abort(req->context, struct replmd_replicated_request);
5098 struct ldb_result *res;
5099 const char *attrs[] = { "replPropertyMetaData", "objectGUID", NULL };
5101 const struct ldb_val *omd_value;
5102 struct replPropertyMetaDataBlob omd, *rmd;
5103 enum ndr_err_code ndr_err;
5104 bool rename_incoming_record, rodc;
5105 struct replPropertyMetaData1 *rmd_name, *omd_name;
5106 struct ldb_message *msg;
5107 struct ldb_request *down_req = NULL;
5109 /* call the normal callback for success */
5110 if (ares->error == LDB_SUCCESS) {
5111 return callback(req, ares);
5115 * we have a conflict, and need to decide if we will keep the
5116 * new record or the old record
5119 msg = ar->objs->objects[ar->index_current].msg;
5120 conflict_dn = msg->dn;
5122 /* For failures other than conflicts, fail the whole operation here */
5123 if (ares->error != LDB_ERR_ENTRY_ALREADY_EXISTS) {
5124 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module), "Failed to locally apply remote add of %s: %s",
5125 ldb_dn_get_linearized(conflict_dn),
5126 ldb_errstring(ldb_module_get_ctx(ar->module)));
5128 return ldb_module_done(ar->req, NULL, NULL,
5129 LDB_ERR_OPERATIONS_ERROR);
5132 ret = samdb_rodc(ldb_module_get_ctx(ar->module), &rodc);
5133 if (ret != LDB_SUCCESS) {
5134 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)));
5135 return ldb_module_done(ar->req, NULL, NULL,
5136 LDB_ERR_OPERATIONS_ERROR);
5142 * We are on an RODC, or were a GC for this
5143 * partition, so we have to fail this until
5144 * someone who owns the partition sorts it
5147 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
5148 "Conflict adding object '%s' from incoming replication as we are read only for the partition. \n"
5149 " - We must fail the operation until a master for this partition resolves the conflict",
5150 ldb_dn_get_linearized(conflict_dn));
5151 ret = LDB_ERR_OPERATIONS_ERROR;
5156 * first we need the replPropertyMetaData attribute from the
5157 * local, conflicting record
5159 ret = dsdb_module_search_dn(ar->module, req, &res, conflict_dn,
5161 DSDB_FLAG_NEXT_MODULE |
5162 DSDB_SEARCH_SHOW_DELETED |
5163 DSDB_SEARCH_SHOW_RECYCLED, req);
5164 if (ret != LDB_SUCCESS) {
5165 DEBUG(0,(__location__ ": Unable to find object for conflicting record '%s'\n",
5166 ldb_dn_get_linearized(conflict_dn)));
5170 omd_value = ldb_msg_find_ldb_val(res->msgs[0], "replPropertyMetaData");
5171 if (omd_value == NULL) {
5172 DEBUG(0,(__location__ ": Unable to find replPropertyMetaData for conflicting record '%s'\n",
5173 ldb_dn_get_linearized(conflict_dn)));
5177 ndr_err = ndr_pull_struct_blob(omd_value, res->msgs[0], &omd,
5178 (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
5179 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
5180 DEBUG(0,(__location__ ": Failed to parse old replPropertyMetaData for %s\n",
5181 ldb_dn_get_linearized(conflict_dn)));
5185 rmd = ar->objs->objects[ar->index_current].meta_data;
5188 * we decide which is newer based on the RPMD on the name
5189 * attribute. See [MS-DRSR] ResolveNameConflict.
5191 * We expect omd_name to be present, as this is from a local
5192 * search, but while rmd_name should have been given to us by
5193 * the remote server, if it is missing we just prefer the
5195 * replmd_replPropertyMetaData1_new_should_be_taken()
5197 rmd_name = replmd_replPropertyMetaData1_find_attid(rmd, DRSUAPI_ATTID_name);
5198 omd_name = replmd_replPropertyMetaData1_find_attid(&omd, DRSUAPI_ATTID_name);
5200 DEBUG(0,(__location__ ": Failed to find name attribute in local LDB replPropertyMetaData for %s\n",
5201 ldb_dn_get_linearized(conflict_dn)));
5206 * Should we preserve the current record, and so rename the
5207 * incoming record to be a conflict?
5209 rename_incoming_record
5210 = !replmd_replPropertyMetaData1_new_should_be_taken(ar->objs->dsdb_repl_flags & DSDB_REPL_FLAG_PRIORITISE_INCOMING,
5211 omd_name, rmd_name);
5213 if (rename_incoming_record) {
5215 struct ldb_dn *new_dn;
5217 guid = samdb_result_guid(msg, "objectGUID");
5218 if (GUID_all_zero(&guid)) {
5219 DEBUG(0,(__location__ ": Failed to find objectGUID for conflicting incoming record %s\n",
5220 ldb_dn_get_linearized(conflict_dn)));
5223 new_dn = replmd_conflict_dn(req,
5224 ldb_module_get_ctx(ar->module),
5225 conflict_dn, &guid);
5226 if (new_dn == NULL) {
5227 DEBUG(0,(__location__ ": Failed to form conflict DN for %s\n",
5228 ldb_dn_get_linearized(conflict_dn)));
5232 DEBUG(2,(__location__ ": Resolving conflict record via incoming rename '%s' -> '%s'\n",
5233 ldb_dn_get_linearized(conflict_dn), ldb_dn_get_linearized(new_dn)));
5235 /* re-submit the request, but with the new DN */
5236 callback = replmd_op_name_modify_callback;
5239 /* we are renaming the existing record */
5241 struct ldb_dn *new_dn;
5243 guid = samdb_result_guid(res->msgs[0], "objectGUID");
5244 if (GUID_all_zero(&guid)) {
5245 DEBUG(0,(__location__ ": Failed to find objectGUID for existing conflict record %s\n",
5246 ldb_dn_get_linearized(conflict_dn)));
5250 new_dn = replmd_conflict_dn(req,
5251 ldb_module_get_ctx(ar->module),
5252 conflict_dn, &guid);
5253 if (new_dn == NULL) {
5254 DEBUG(0,(__location__ ": Failed to form conflict DN for %s\n",
5255 ldb_dn_get_linearized(conflict_dn)));
5259 DEBUG(2,(__location__ ": Resolving conflict record via existing-record rename '%s' -> '%s'\n",
5260 ldb_dn_get_linearized(conflict_dn), ldb_dn_get_linearized(new_dn)));
5262 ret = dsdb_module_rename(ar->module, conflict_dn, new_dn,
5263 DSDB_FLAG_OWN_MODULE, req);
5264 if (ret != LDB_SUCCESS) {
5265 DEBUG(0,(__location__ ": Failed to rename conflict dn '%s' to '%s' - %s\n",
5266 ldb_dn_get_linearized(conflict_dn),
5267 ldb_dn_get_linearized(new_dn),
5268 ldb_errstring(ldb_module_get_ctx(ar->module))));
5273 * now we need to ensure that the rename is seen as an
5274 * originating update. We do that with a modify.
5276 ret = replmd_name_modify(ar, req, new_dn);
5277 if (ret != LDB_SUCCESS) {
5281 DEBUG(2,(__location__ ": With conflicting record renamed, re-apply replicated creation of '%s'\n",
5282 ldb_dn_get_linearized(req->op.add.message->dn)));
5285 ret = ldb_build_add_req(&down_req,
5286 ldb_module_get_ctx(ar->module),
5293 if (ret != LDB_SUCCESS) {
5296 LDB_REQ_SET_LOCATION(down_req);
5298 /* current partition control needed by "repmd_op_callback" */
5299 ret = ldb_request_add_control(down_req,
5300 DSDB_CONTROL_CURRENT_PARTITION_OID,
5302 if (ret != LDB_SUCCESS) {
5303 return replmd_replicated_request_error(ar, ret);
5306 if (ar->objs->dsdb_repl_flags & DSDB_REPL_FLAG_PARTIAL_REPLICA) {
5307 /* this tells the partition module to make it a
5308 partial replica if creating an NC */
5309 ret = ldb_request_add_control(down_req,
5310 DSDB_CONTROL_PARTIAL_REPLICA,
5312 if (ret != LDB_SUCCESS) {
5313 return replmd_replicated_request_error(ar, ret);
5318 * Finally we re-run the add, otherwise the new record won't
5319 * exist, as we are here because of that exact failure!
5321 return ldb_next_request(ar->module, down_req);
5324 /* on failure make the caller get the error. This means
5325 * replication will stop with an error, but there is not much
5328 if (ret == LDB_SUCCESS) {
5329 ret = LDB_ERR_OPERATIONS_ERROR;
5331 return ldb_module_done(ar->req, NULL, NULL,
5336 callback for replmd_replicated_apply_add()
5337 This copes with the creation of conflict records in the case where
5338 the DN exists, but with a different objectGUID
5340 static int replmd_op_add_callback(struct ldb_request *req, struct ldb_reply *ares)
5342 struct replmd_replicated_request *ar =
5343 talloc_get_type_abort(req->context, struct replmd_replicated_request);
5345 if (ar->objs->objects[ar->index_current].last_known_parent) {
5346 /* This is like a conflict DN, where we put the object in LostAndFound
5347 see MS-DRSR 4.1.10.6.10 FindBestParentObject */
5348 return replmd_op_possible_conflict_callback(req, ares, replmd_op_name_modify_callback);
5351 return replmd_op_possible_conflict_callback(req, ares, replmd_op_callback);
5355 this is called when a new object comes in over DRS
5357 static int replmd_replicated_apply_add(struct replmd_replicated_request *ar)
5359 struct ldb_context *ldb;
5360 struct ldb_request *change_req;
5361 enum ndr_err_code ndr_err;
5362 struct ldb_message *msg;
5363 struct replPropertyMetaDataBlob *md;
5364 struct ldb_val md_value;
5367 bool remote_isDeleted = false;
5370 time_t t = time(NULL);
5371 const struct ldb_val *rdn_val;
5372 struct replmd_private *replmd_private =
5373 talloc_get_type(ldb_module_get_private(ar->module),
5374 struct replmd_private);
5375 unix_to_nt_time(&now, t);
5377 ldb = ldb_module_get_ctx(ar->module);
5378 msg = ar->objs->objects[ar->index_current].msg;
5379 md = ar->objs->objects[ar->index_current].meta_data;
5380 is_schema_nc = ldb_dn_compare_base(replmd_private->schema_dn, msg->dn) == 0;
5382 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &ar->seq_num);
5383 if (ret != LDB_SUCCESS) {
5384 return replmd_replicated_request_error(ar, ret);
5387 ret = dsdb_msg_add_guid(msg,
5388 &ar->objs->objects[ar->index_current].object_guid,
5390 if (ret != LDB_SUCCESS) {
5391 return replmd_replicated_request_error(ar, ret);
5394 ret = ldb_msg_add_string(msg, "whenChanged", ar->objs->objects[ar->index_current].when_changed);
5395 if (ret != LDB_SUCCESS) {
5396 return replmd_replicated_request_error(ar, ret);
5399 ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNCreated", ar->seq_num);
5400 if (ret != LDB_SUCCESS) {
5401 return replmd_replicated_request_error(ar, ret);
5404 ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNChanged", ar->seq_num);
5405 if (ret != LDB_SUCCESS) {
5406 return replmd_replicated_request_error(ar, ret);
5409 /* remove any message elements that have zero values */
5410 for (i=0; i<msg->num_elements; i++) {
5411 struct ldb_message_element *el = &msg->elements[i];
5413 if (el->num_values == 0) {
5414 if (ldb_attr_cmp(msg->elements[i].name, "objectClass") == 0) {
5415 ldb_asprintf_errstring(ldb, __location__
5416 ": empty objectClass sent on %s, aborting replication\n",
5417 ldb_dn_get_linearized(msg->dn));
5418 return replmd_replicated_request_error(ar, LDB_ERR_OBJECT_CLASS_VIOLATION);
5421 DEBUG(4,(__location__ ": Removing attribute %s with num_values==0\n",
5423 memmove(el, el+1, sizeof(*el)*(msg->num_elements - (i+1)));
5424 msg->num_elements--;
5431 struct GUID_txt_buf guid_txt;
5433 char *s = ldb_ldif_message_redacted_string(ldb, ar,
5436 DEBUG(8, ("DRS replication add message of %s:\n%s\n",
5437 GUID_buf_string(&ar->objs->objects[ar->index_current].object_guid, &guid_txt),
5440 } else if (DEBUGLVL(4)) {
5441 struct GUID_txt_buf guid_txt;
5442 DEBUG(4, ("DRS replication add DN of %s is %s\n",
5443 GUID_buf_string(&ar->objs->objects[ar->index_current].object_guid, &guid_txt),
5444 ldb_dn_get_linearized(msg->dn)));
5446 remote_isDeleted = ldb_msg_find_attr_as_bool(msg,
5447 "isDeleted", false);
5450 * the meta data array is already sorted by the caller, except
5451 * for the RDN, which needs to be added.
5455 rdn_val = ldb_dn_get_rdn_val(msg->dn);
5456 ret = replmd_update_rpmd_rdn_attr(ldb, msg, rdn_val, NULL,
5457 md, ar, now, is_schema_nc,
5459 if (ret != LDB_SUCCESS) {
5460 ldb_asprintf_errstring(ldb, "%s: error during DRS repl ADD: %s", __func__, ldb_errstring(ldb));
5461 return replmd_replicated_request_error(ar, ret);
5464 ret = replmd_replPropertyMetaDataCtr1_sort_and_verify(ldb, &md->ctr.ctr1, msg->dn);
5465 if (ret != LDB_SUCCESS) {
5466 ldb_asprintf_errstring(ldb, "%s: error during DRS repl ADD: %s", __func__, ldb_errstring(ldb));
5467 return replmd_replicated_request_error(ar, ret);
5470 for (i=0; i < md->ctr.ctr1.count; i++) {
5471 md->ctr.ctr1.array[i].local_usn = ar->seq_num;
5473 ndr_err = ndr_push_struct_blob(&md_value, msg, md,
5474 (ndr_push_flags_fn_t)ndr_push_replPropertyMetaDataBlob);
5475 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
5476 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
5477 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
5479 ret = ldb_msg_add_value(msg, "replPropertyMetaData", &md_value, NULL);
5480 if (ret != LDB_SUCCESS) {
5481 return replmd_replicated_request_error(ar, ret);
5484 replmd_ldb_message_sort(msg, ar->schema);
5486 if (!remote_isDeleted) {
5487 ret = dsdb_module_schedule_sd_propagation(ar->module,
5488 ar->objs->partition_dn,
5490 if (ret != LDB_SUCCESS) {
5491 return replmd_replicated_request_error(ar, ret);
5495 ar->isDeleted = remote_isDeleted;
5497 ret = ldb_build_add_req(&change_req,
5503 replmd_op_add_callback,
5505 LDB_REQ_SET_LOCATION(change_req);
5506 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
5508 /* current partition control needed by "repmd_op_callback" */
5509 ret = ldb_request_add_control(change_req,
5510 DSDB_CONTROL_CURRENT_PARTITION_OID,
5512 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
5514 if (ar->objs->dsdb_repl_flags & DSDB_REPL_FLAG_PARTIAL_REPLICA) {
5515 /* this tells the partition module to make it a
5516 partial replica if creating an NC */
5517 ret = ldb_request_add_control(change_req,
5518 DSDB_CONTROL_PARTIAL_REPLICA,
5520 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
5523 return ldb_next_request(ar->module, change_req);
5526 static int replmd_replicated_apply_search_for_parent_callback(struct ldb_request *req,
5527 struct ldb_reply *ares)
5529 struct replmd_replicated_request *ar = talloc_get_type(req->context,
5530 struct replmd_replicated_request);
5534 return ldb_module_done(ar->req, NULL, NULL,
5535 LDB_ERR_OPERATIONS_ERROR);
5539 * The error NO_SUCH_OBJECT is not expected, unless the search
5540 * base is the partition DN, and that case doesn't happen here
5541 * because then we wouldn't get a parent_guid_value in any
5544 if (ares->error != LDB_SUCCESS) {
5545 return ldb_module_done(ar->req, ares->controls,
5546 ares->response, ares->error);
5549 switch (ares->type) {
5550 case LDB_REPLY_ENTRY:
5552 struct ldb_message *parent_msg = ares->message;
5553 struct ldb_message *msg = ar->objs->objects[ar->index_current].msg;
5554 struct ldb_dn *parent_dn = NULL;
5557 if (!ldb_msg_check_string_attribute(msg, "isDeleted", "TRUE")
5558 && ldb_msg_check_string_attribute(parent_msg, "isDeleted", "TRUE")) {
5559 /* Per MS-DRSR 4.1.10.6.10
5560 * FindBestParentObject we need to move this
5561 * new object under a deleted object to
5563 struct ldb_dn *nc_root;
5565 ret = dsdb_find_nc_root(ldb_module_get_ctx(ar->module), msg, msg->dn, &nc_root);
5566 if (ret == LDB_ERR_NO_SUCH_OBJECT) {
5567 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
5568 "No suitable NC root found for %s. "
5569 "We need to move this object because parent object %s "
5570 "is deleted, but this object is not.",
5571 ldb_dn_get_linearized(msg->dn),
5572 ldb_dn_get_linearized(parent_msg->dn));
5573 return ldb_module_done(ar->req, NULL, NULL, LDB_ERR_OPERATIONS_ERROR);
5574 } else if (ret != LDB_SUCCESS) {
5575 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
5576 "Unable to find NC root for %s: %s. "
5577 "We need to move this object because parent object %s "
5578 "is deleted, but this object is not.",
5579 ldb_dn_get_linearized(msg->dn),
5580 ldb_errstring(ldb_module_get_ctx(ar->module)),
5581 ldb_dn_get_linearized(parent_msg->dn));
5582 return ldb_module_done(ar->req, NULL, NULL, LDB_ERR_OPERATIONS_ERROR);
5585 ret = dsdb_wellknown_dn(ldb_module_get_ctx(ar->module), msg,
5587 DS_GUID_LOSTANDFOUND_CONTAINER,
5589 if (ret != LDB_SUCCESS) {
5590 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
5591 "Unable to find LostAndFound Container for %s "
5592 "in partition %s: %s. "
5593 "We need to move this object because parent object %s "
5594 "is deleted, but this object is not.",
5595 ldb_dn_get_linearized(msg->dn), ldb_dn_get_linearized(nc_root),
5596 ldb_errstring(ldb_module_get_ctx(ar->module)),
5597 ldb_dn_get_linearized(parent_msg->dn));
5598 return ldb_module_done(ar->req, NULL, NULL, LDB_ERR_OPERATIONS_ERROR);
5600 ar->objs->objects[ar->index_current].last_known_parent
5601 = talloc_steal(ar->objs->objects[ar->index_current].msg, parent_msg->dn);
5605 = talloc_steal(ar->objs->objects[ar->index_current].msg, parent_msg->dn);
5608 ar->objs->objects[ar->index_current].local_parent_dn = parent_dn;
5610 comp_num = ldb_dn_get_comp_num(msg->dn);
5612 if (!ldb_dn_remove_base_components(msg->dn, comp_num - 1)) {
5614 return ldb_module_done(ar->req, NULL, NULL, ldb_module_operr(ar->module));
5617 if (!ldb_dn_add_base(msg->dn, parent_dn)) {
5619 return ldb_module_done(ar->req, NULL, NULL, ldb_module_operr(ar->module));
5623 case LDB_REPLY_REFERRAL:
5624 /* we ignore referrals */
5627 case LDB_REPLY_DONE:
5629 if (ar->objs->objects[ar->index_current].local_parent_dn == NULL) {
5630 struct GUID_txt_buf str_buf;
5631 if (ar->search_msg != NULL) {
5632 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
5633 "No parent with GUID %s found for object locally known as %s",
5634 GUID_buf_string(ar->objs->objects[ar->index_current].parent_guid, &str_buf),
5635 ldb_dn_get_linearized(ar->search_msg->dn));
5637 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
5638 "No parent with GUID %s found for object remotely known as %s",
5639 GUID_buf_string(ar->objs->objects[ar->index_current].parent_guid, &str_buf),
5640 ldb_dn_get_linearized(ar->objs->objects[ar->index_current].msg->dn));
5644 * This error code is really important, as it
5645 * is the flag back to the callers to retry
5646 * this with DRSUAPI_DRS_GET_ANC, and so get
5647 * the parent objects before the child
5650 return ldb_module_done(ar->req, NULL, NULL,
5651 replmd_replicated_request_werror(ar, WERR_DS_DRA_MISSING_PARENT));
5654 if (ar->search_msg != NULL) {
5655 ret = replmd_replicated_apply_merge(ar);
5657 ret = replmd_replicated_apply_add(ar);
5659 if (ret != LDB_SUCCESS) {
5660 return ldb_module_done(ar->req, NULL, NULL, ret);
5669 * Look for the parent object, so we put the new object in the right
5670 * place This is akin to NameObject in MS-DRSR - this routine and the
5671 * callbacks find the right parent name, and correct name for this
5675 static int replmd_replicated_apply_search_for_parent(struct replmd_replicated_request *ar)
5677 struct ldb_context *ldb;
5681 struct ldb_request *search_req;
5682 static const char *attrs[] = {"isDeleted", NULL};
5683 struct GUID_txt_buf guid_str_buf;
5685 ldb = ldb_module_get_ctx(ar->module);
5687 if (ar->objs->objects[ar->index_current].parent_guid == NULL) {
5688 if (ar->search_msg != NULL) {
5689 return replmd_replicated_apply_merge(ar);
5691 return replmd_replicated_apply_add(ar);
5695 tmp_str = GUID_buf_string(ar->objs->objects[ar->index_current].parent_guid,
5698 filter = talloc_asprintf(ar, "(objectGUID=%s)", tmp_str);
5699 if (!filter) return replmd_replicated_request_werror(ar, WERR_NOT_ENOUGH_MEMORY);
5701 ret = ldb_build_search_req(&search_req,
5704 ar->objs->partition_dn,
5710 replmd_replicated_apply_search_for_parent_callback,
5712 LDB_REQ_SET_LOCATION(search_req);
5714 ret = dsdb_request_add_controls(search_req,
5715 DSDB_SEARCH_SHOW_RECYCLED|
5716 DSDB_SEARCH_SHOW_DELETED|
5717 DSDB_SEARCH_SHOW_EXTENDED_DN);
5718 if (ret != LDB_SUCCESS) {
5722 return ldb_next_request(ar->module, search_req);
5726 handle renames that come in over DRS replication
5728 static int replmd_replicated_handle_rename(struct replmd_replicated_request *ar,
5729 struct ldb_message *msg,
5730 struct ldb_request *parent,
5734 TALLOC_CTX *tmp_ctx = talloc_new(msg);
5735 struct ldb_result *res;
5736 struct ldb_dn *conflict_dn;
5737 const char *attrs[] = { "replPropertyMetaData", "objectGUID", NULL };
5738 const struct ldb_val *omd_value;
5739 struct replPropertyMetaDataBlob omd, *rmd;
5740 enum ndr_err_code ndr_err;
5741 bool rename_incoming_record, rodc;
5742 struct replPropertyMetaData1 *rmd_name, *omd_name;
5743 struct ldb_dn *new_dn;
5746 DEBUG(4,("replmd_replicated_request rename %s => %s\n",
5747 ldb_dn_get_linearized(ar->search_msg->dn),
5748 ldb_dn_get_linearized(msg->dn)));
5751 ret = dsdb_module_rename(ar->module, ar->search_msg->dn, msg->dn,
5752 DSDB_FLAG_NEXT_MODULE, ar->req);
5753 if (ret == LDB_SUCCESS) {
5754 talloc_free(tmp_ctx);
5759 if (ret != LDB_ERR_ENTRY_ALREADY_EXISTS) {
5760 talloc_free(tmp_ctx);
5761 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module), "Failed to locally apply remote rename from %s to %s: %s",
5762 ldb_dn_get_linearized(ar->search_msg->dn),
5763 ldb_dn_get_linearized(msg->dn),
5764 ldb_errstring(ldb_module_get_ctx(ar->module)));
5768 ret = samdb_rodc(ldb_module_get_ctx(ar->module), &rodc);
5769 if (ret != LDB_SUCCESS) {
5770 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
5771 "Failed to determine if we are an RODC when attempting to form conflict DN: %s",
5772 ldb_errstring(ldb_module_get_ctx(ar->module)));
5773 return LDB_ERR_OPERATIONS_ERROR;
5776 * we have a conflict, and need to decide if we will keep the
5777 * new record or the old record
5780 conflict_dn = msg->dn;
5784 * We are on an RODC, or were a GC for this
5785 * partition, so we have to fail this until
5786 * someone who owns the partition sorts it
5789 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
5790 "Conflict adding object '%s' from incoming replication but we are read only for the partition. \n"
5791 " - We must fail the operation until a master for this partition resolves the conflict",
5792 ldb_dn_get_linearized(conflict_dn));
5793 ret = LDB_ERR_OPERATIONS_ERROR;
5798 * first we need the replPropertyMetaData attribute from the
5801 ret = dsdb_module_search_dn(ar->module, tmp_ctx, &res, conflict_dn,
5803 DSDB_FLAG_NEXT_MODULE |
5804 DSDB_SEARCH_SHOW_DELETED |
5805 DSDB_SEARCH_SHOW_RECYCLED, ar->req);
5806 if (ret != LDB_SUCCESS) {
5807 DEBUG(0,(__location__ ": Unable to find object for conflicting record '%s'\n",
5808 ldb_dn_get_linearized(conflict_dn)));
5812 omd_value = ldb_msg_find_ldb_val(res->msgs[0], "replPropertyMetaData");
5813 if (omd_value == NULL) {
5814 DEBUG(0,(__location__ ": Unable to find replPropertyMetaData for conflicting record '%s'\n",
5815 ldb_dn_get_linearized(conflict_dn)));
5819 ndr_err = ndr_pull_struct_blob(omd_value, res->msgs[0], &omd,
5820 (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
5821 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
5822 DEBUG(0,(__location__ ": Failed to parse old replPropertyMetaData for %s\n",
5823 ldb_dn_get_linearized(conflict_dn)));
5827 rmd = ar->objs->objects[ar->index_current].meta_data;
5830 * we decide which is newer based on the RPMD on the name
5831 * attribute. See [MS-DRSR] ResolveNameConflict.
5833 * We expect omd_name to be present, as this is from a local
5834 * search, but while rmd_name should have been given to us by
5835 * the remote server, if it is missing we just prefer the
5837 * replmd_replPropertyMetaData1_new_should_be_taken()
5839 rmd_name = replmd_replPropertyMetaData1_find_attid(rmd, DRSUAPI_ATTID_name);
5840 omd_name = replmd_replPropertyMetaData1_find_attid(&omd, DRSUAPI_ATTID_name);
5842 DEBUG(0,(__location__ ": Failed to find name attribute in local LDB replPropertyMetaData for %s\n",
5843 ldb_dn_get_linearized(conflict_dn)));
5848 * Should we preserve the current record, and so rename the
5849 * incoming record to be a conflict?
5851 rename_incoming_record =
5852 !replmd_replPropertyMetaData1_new_should_be_taken(
5853 ar->objs->dsdb_repl_flags & DSDB_REPL_FLAG_PRIORITISE_INCOMING,
5854 omd_name, rmd_name);
5856 if (rename_incoming_record) {
5858 new_dn = replmd_conflict_dn(msg,
5859 ldb_module_get_ctx(ar->module),
5861 &ar->objs->objects[ar->index_current].object_guid);
5862 if (new_dn == NULL) {
5863 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
5864 "Failed to form conflict DN for %s\n",
5865 ldb_dn_get_linearized(msg->dn));
5867 return replmd_replicated_request_werror(ar, WERR_NOT_ENOUGH_MEMORY);
5870 ret = dsdb_module_rename(ar->module, ar->search_msg->dn, new_dn,
5871 DSDB_FLAG_NEXT_MODULE, ar->req);
5872 if (ret != LDB_SUCCESS) {
5873 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
5874 "Failed to rename incoming conflicting dn '%s' (was '%s') to '%s' - %s\n",
5875 ldb_dn_get_linearized(conflict_dn),
5876 ldb_dn_get_linearized(ar->search_msg->dn),
5877 ldb_dn_get_linearized(new_dn),
5878 ldb_errstring(ldb_module_get_ctx(ar->module)));
5879 return replmd_replicated_request_werror(ar, WERR_DS_DRA_DB_ERROR);
5887 /* we are renaming the existing record */
5889 guid = samdb_result_guid(res->msgs[0], "objectGUID");
5890 if (GUID_all_zero(&guid)) {
5891 DEBUG(0,(__location__ ": Failed to find objectGUID for existing conflict record %s\n",
5892 ldb_dn_get_linearized(conflict_dn)));
5896 new_dn = replmd_conflict_dn(tmp_ctx,
5897 ldb_module_get_ctx(ar->module),
5898 conflict_dn, &guid);
5899 if (new_dn == NULL) {
5900 DEBUG(0,(__location__ ": Failed to form conflict DN for %s\n",
5901 ldb_dn_get_linearized(conflict_dn)));
5905 DEBUG(2,(__location__ ": Resolving conflict record via existing-record rename '%s' -> '%s'\n",
5906 ldb_dn_get_linearized(conflict_dn), ldb_dn_get_linearized(new_dn)));
5908 ret = dsdb_module_rename(ar->module, conflict_dn, new_dn,
5909 DSDB_FLAG_OWN_MODULE, ar->req);
5910 if (ret != LDB_SUCCESS) {
5911 DEBUG(0,(__location__ ": Failed to rename conflict dn '%s' to '%s' - %s\n",
5912 ldb_dn_get_linearized(conflict_dn),
5913 ldb_dn_get_linearized(new_dn),
5914 ldb_errstring(ldb_module_get_ctx(ar->module))));
5919 * now we need to ensure that the rename is seen as an
5920 * originating update. We do that with a modify.
5922 ret = replmd_name_modify(ar, ar->req, new_dn);
5923 if (ret != LDB_SUCCESS) {
5927 DEBUG(2,(__location__ ": With conflicting record renamed, re-apply replicated rename '%s' -> '%s'\n",
5928 ldb_dn_get_linearized(ar->search_msg->dn),
5929 ldb_dn_get_linearized(msg->dn)));
5932 ret = dsdb_module_rename(ar->module, ar->search_msg->dn, msg->dn,
5933 DSDB_FLAG_NEXT_MODULE, ar->req);
5934 if (ret != LDB_SUCCESS) {
5935 DEBUG(0,(__location__ ": After conflict resolution, failed to rename dn '%s' to '%s' - %s\n",
5936 ldb_dn_get_linearized(ar->search_msg->dn),
5937 ldb_dn_get_linearized(msg->dn),
5938 ldb_errstring(ldb_module_get_ctx(ar->module))));
5942 talloc_free(tmp_ctx);
5946 * On failure make the caller get the error
5947 * This means replication will stop with an error,
5948 * but there is not much else we can do. In the
5949 * LDB_ERR_ENTRY_ALREADY_EXISTS case this is exactly what is
5952 if (ret == LDB_SUCCESS) {
5953 ret = LDB_ERR_OPERATIONS_ERROR;
5956 talloc_free(tmp_ctx);
5961 static int replmd_replicated_apply_merge(struct replmd_replicated_request *ar)
5963 struct ldb_context *ldb;
5964 struct ldb_request *change_req;
5965 enum ndr_err_code ndr_err;
5966 struct ldb_message *msg;
5967 struct replPropertyMetaDataBlob *rmd;
5968 struct replPropertyMetaDataBlob omd;
5969 const struct ldb_val *omd_value;
5970 struct replPropertyMetaDataBlob nmd;
5971 struct ldb_val nmd_value;
5972 struct GUID remote_parent_guid;
5975 unsigned int removed_attrs = 0;
5977 int (*callback)(struct ldb_request *req, struct ldb_reply *ares) = replmd_op_callback;
5978 bool isDeleted = false;
5979 bool local_isDeleted = false;
5980 bool remote_isDeleted = false;
5981 bool take_remote_isDeleted = false;
5982 bool sd_updated = false;
5983 bool renamed = false;
5984 bool is_schema_nc = false;
5986 const struct ldb_val *old_rdn, *new_rdn;
5987 struct replmd_private *replmd_private =
5988 talloc_get_type(ldb_module_get_private(ar->module),
5989 struct replmd_private);
5991 time_t t = time(NULL);
5992 unix_to_nt_time(&now, t);
5994 ldb = ldb_module_get_ctx(ar->module);
5995 msg = ar->objs->objects[ar->index_current].msg;
5997 is_schema_nc = ldb_dn_compare_base(replmd_private->schema_dn, msg->dn) == 0;
5999 rmd = ar->objs->objects[ar->index_current].meta_data;
6003 /* find existing meta data */
6004 omd_value = ldb_msg_find_ldb_val(ar->search_msg, "replPropertyMetaData");
6006 ndr_err = ndr_pull_struct_blob(omd_value, ar, &omd,
6007 (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
6008 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
6009 nt_status = ndr_map_error2ntstatus(ndr_err);
6010 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
6013 if (omd.version != 1) {
6014 return replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
6019 struct GUID_txt_buf guid_txt;
6021 char *s = ldb_ldif_message_redacted_string(ldb, ar,
6022 LDB_CHANGETYPE_MODIFY, msg);
6023 DEBUG(8, ("Initial DRS replication modify message of %s is:\n%s\n"
6026 GUID_buf_string(&ar->objs->objects[ar->index_current].object_guid, &guid_txt),
6028 ndr_print_struct_string(s,
6029 (ndr_print_fn_t)ndr_print_replPropertyMetaDataBlob,
6030 "existing replPropertyMetaData",
6032 ndr_print_struct_string(s,
6033 (ndr_print_fn_t)ndr_print_replPropertyMetaDataBlob,
6034 "incoming replPropertyMetaData",
6037 } else if (DEBUGLVL(4)) {
6038 struct GUID_txt_buf guid_txt;
6040 DEBUG(4, ("Initial DRS replication modify DN of %s is: %s\n",
6041 GUID_buf_string(&ar->objs->objects[ar->index_current].object_guid,
6043 ldb_dn_get_linearized(msg->dn)));
6046 local_isDeleted = ldb_msg_find_attr_as_bool(ar->search_msg,
6047 "isDeleted", false);
6048 remote_isDeleted = ldb_msg_find_attr_as_bool(msg,
6049 "isDeleted", false);
6052 * Fill in the remote_parent_guid with the GUID or an all-zero
6055 if (ar->objs->objects[ar->index_current].parent_guid != NULL) {
6056 remote_parent_guid = *ar->objs->objects[ar->index_current].parent_guid;
6058 remote_parent_guid = GUID_zero();
6062 * To ensure we follow a complex rename chain around, we have
6063 * to confirm that the DN is the same (mostly to confirm the
6064 * RDN) and the parentGUID is the same.
6066 * This ensures we keep things under the correct parent, which
6067 * replmd_replicated_handle_rename() will do.
6070 if (strcmp(ldb_dn_get_linearized(msg->dn), ldb_dn_get_linearized(ar->search_msg->dn)) == 0
6071 && GUID_equal(&remote_parent_guid, &ar->local_parent_guid)) {
6075 * handle renames, even just by case that come in over
6076 * DRS. Changes in the parent DN don't hit us here,
6077 * because the search for a parent will clean up those
6080 * We also have already filtered out the case where
6081 * the peer has an older name to what we have (see
6082 * replmd_replicated_apply_search_callback())
6084 ret = replmd_replicated_handle_rename(ar, msg, ar->req, &renamed);
6087 if (ret != LDB_SUCCESS) {
6088 ldb_debug(ldb, LDB_DEBUG_FATAL,
6089 "replmd_replicated_request rename %s => %s failed - %s\n",
6090 ldb_dn_get_linearized(ar->search_msg->dn),
6091 ldb_dn_get_linearized(msg->dn),
6092 ldb_errstring(ldb));
6093 return replmd_replicated_request_werror(ar, WERR_DS_DRA_DB_ERROR);
6096 if (renamed == true) {
6098 * Set the callback to one that will fix up the name
6099 * metadata on the new conflict DN
6101 callback = replmd_op_name_modify_callback;
6106 nmd.ctr.ctr1.count = omd.ctr.ctr1.count + rmd->ctr.ctr1.count;
6107 nmd.ctr.ctr1.array = talloc_array(ar,
6108 struct replPropertyMetaData1,
6109 nmd.ctr.ctr1.count);
6110 if (!nmd.ctr.ctr1.array) return replmd_replicated_request_werror(ar, WERR_NOT_ENOUGH_MEMORY);
6112 /* first copy the old meta data */
6113 for (i=0; i < omd.ctr.ctr1.count; i++) {
6114 nmd.ctr.ctr1.array[ni] = omd.ctr.ctr1.array[i];
6119 /* now merge in the new meta data */
6120 for (i=0; i < rmd->ctr.ctr1.count; i++) {
6123 for (j=0; j < ni; j++) {
6126 if (rmd->ctr.ctr1.array[i].attid != nmd.ctr.ctr1.array[j].attid) {
6130 cmp = replmd_replPropertyMetaData1_new_should_be_taken(
6131 ar->objs->dsdb_repl_flags,
6132 &nmd.ctr.ctr1.array[j],
6133 &rmd->ctr.ctr1.array[i]);
6135 /* replace the entry */
6136 nmd.ctr.ctr1.array[j] = rmd->ctr.ctr1.array[i];
6137 if (ar->seq_num == 0) {
6138 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &ar->seq_num);
6139 if (ret != LDB_SUCCESS) {
6140 return replmd_replicated_request_error(ar, ret);
6143 nmd.ctr.ctr1.array[j].local_usn = ar->seq_num;
6144 switch (nmd.ctr.ctr1.array[j].attid) {
6145 case DRSUAPI_ATTID_ntSecurityDescriptor:
6148 case DRSUAPI_ATTID_isDeleted:
6149 take_remote_isDeleted = true;
6158 if (rmd->ctr.ctr1.array[i].attid != DRSUAPI_ATTID_instanceType) {
6159 DEBUG(3,("Discarding older DRS attribute update to %s on %s from %s\n",
6160 msg->elements[i-removed_attrs].name,
6161 ldb_dn_get_linearized(msg->dn),
6162 GUID_string(ar, &rmd->ctr.ctr1.array[i].originating_invocation_id)));
6165 /* we don't want to apply this change so remove the attribute */
6166 ldb_msg_remove_element(msg, &msg->elements[i-removed_attrs]);
6173 if (found) continue;
6175 nmd.ctr.ctr1.array[ni] = rmd->ctr.ctr1.array[i];
6176 if (ar->seq_num == 0) {
6177 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &ar->seq_num);
6178 if (ret != LDB_SUCCESS) {
6179 return replmd_replicated_request_error(ar, ret);
6182 nmd.ctr.ctr1.array[ni].local_usn = ar->seq_num;
6183 switch (nmd.ctr.ctr1.array[ni].attid) {
6184 case DRSUAPI_ATTID_ntSecurityDescriptor:
6187 case DRSUAPI_ATTID_isDeleted:
6188 take_remote_isDeleted = true;
6197 * finally correct the size of the meta_data array
6199 nmd.ctr.ctr1.count = ni;
6201 new_rdn = ldb_dn_get_rdn_val(msg->dn);
6202 old_rdn = ldb_dn_get_rdn_val(ar->search_msg->dn);
6205 ret = replmd_update_rpmd_rdn_attr(ldb, msg, new_rdn, old_rdn,
6206 &nmd, ar, now, is_schema_nc,
6208 if (ret != LDB_SUCCESS) {
6209 ldb_asprintf_errstring(ldb, "%s: error during DRS repl merge: %s", __func__, ldb_errstring(ldb));
6210 return replmd_replicated_request_error(ar, ret);
6214 * sort the new meta data array
6216 ret = replmd_replPropertyMetaDataCtr1_sort_and_verify(ldb, &nmd.ctr.ctr1, msg->dn);
6217 if (ret != LDB_SUCCESS) {
6218 ldb_asprintf_errstring(ldb, "%s: error during DRS repl merge: %s", __func__, ldb_errstring(ldb));
6223 * Work out if this object is deleted, so we can prune any extra attributes. See MS-DRSR 4.1.10.6.9
6226 * This also controls SD propagation below
6228 if (take_remote_isDeleted) {
6229 isDeleted = remote_isDeleted;
6231 isDeleted = local_isDeleted;
6234 ar->isDeleted = isDeleted;
6237 * check if some replicated attributes left, otherwise skip the ldb_modify() call
6239 if (msg->num_elements == 0) {
6240 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_replicated_apply_merge[%u]: skip replace\n",
6243 return replmd_replicated_apply_isDeleted(ar);
6246 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_replicated_apply_merge[%u]: replace %u attributes\n",
6247 ar->index_current, msg->num_elements);
6253 if (sd_updated && !isDeleted) {
6254 ret = dsdb_module_schedule_sd_propagation(ar->module,
6255 ar->objs->partition_dn,
6257 if (ret != LDB_SUCCESS) {
6258 return ldb_operr(ldb);
6262 /* create the meta data value */
6263 ndr_err = ndr_push_struct_blob(&nmd_value, msg, &nmd,
6264 (ndr_push_flags_fn_t)ndr_push_replPropertyMetaDataBlob);
6265 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
6266 nt_status = ndr_map_error2ntstatus(ndr_err);
6267 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
6271 * when we know that we'll modify the record, add the whenChanged, uSNChanged
6272 * and replPopertyMetaData attributes
6274 ret = ldb_msg_add_string(msg, "whenChanged", ar->objs->objects[ar->index_current].when_changed);
6275 if (ret != LDB_SUCCESS) {
6276 return replmd_replicated_request_error(ar, ret);
6278 ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNChanged", ar->seq_num);
6279 if (ret != LDB_SUCCESS) {
6280 return replmd_replicated_request_error(ar, ret);
6282 ret = ldb_msg_add_value(msg, "replPropertyMetaData", &nmd_value, NULL);
6283 if (ret != LDB_SUCCESS) {
6284 return replmd_replicated_request_error(ar, ret);
6287 replmd_ldb_message_sort(msg, ar->schema);
6289 /* we want to replace the old values */
6290 for (i=0; i < msg->num_elements; i++) {
6291 msg->elements[i].flags = LDB_FLAG_MOD_REPLACE;
6292 if (ldb_attr_cmp(msg->elements[i].name, "objectClass") == 0) {
6293 if (msg->elements[i].num_values == 0) {
6294 ldb_asprintf_errstring(ldb, __location__
6295 ": objectClass removed on %s, aborting replication\n",
6296 ldb_dn_get_linearized(msg->dn));
6297 return replmd_replicated_request_error(ar, LDB_ERR_OBJECT_CLASS_VIOLATION);
6303 struct GUID_txt_buf guid_txt;
6305 char *s = ldb_ldif_message_redacted_string(ldb, ar,
6306 LDB_CHANGETYPE_MODIFY,
6308 DEBUG(8, ("Final DRS replication modify message of %s:\n%s\n",
6309 GUID_buf_string(&ar->objs->objects[ar->index_current].object_guid,
6313 } else if (DEBUGLVL(4)) {
6314 struct GUID_txt_buf guid_txt;
6316 DEBUG(4, ("Final DRS replication modify DN of %s is %s\n",
6317 GUID_buf_string(&ar->objs->objects[ar->index_current].object_guid,
6319 ldb_dn_get_linearized(msg->dn)));
6322 ret = ldb_build_mod_req(&change_req,
6330 LDB_REQ_SET_LOCATION(change_req);
6331 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
6333 /* current partition control needed by "repmd_op_callback" */
6334 ret = ldb_request_add_control(change_req,
6335 DSDB_CONTROL_CURRENT_PARTITION_OID,
6337 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
6339 return ldb_next_request(ar->module, change_req);
6342 static int replmd_replicated_apply_search_callback(struct ldb_request *req,
6343 struct ldb_reply *ares)
6345 struct replmd_replicated_request *ar = talloc_get_type(req->context,
6346 struct replmd_replicated_request);
6350 return ldb_module_done(ar->req, NULL, NULL,
6351 LDB_ERR_OPERATIONS_ERROR);
6353 if (ares->error != LDB_SUCCESS &&
6354 ares->error != LDB_ERR_NO_SUCH_OBJECT) {
6355 return ldb_module_done(ar->req, ares->controls,
6356 ares->response, ares->error);
6359 switch (ares->type) {
6360 case LDB_REPLY_ENTRY:
6361 ar->search_msg = talloc_steal(ar, ares->message);
6364 case LDB_REPLY_REFERRAL:
6365 /* we ignore referrals */
6368 case LDB_REPLY_DONE:
6370 struct replPropertyMetaData1 *md_remote;
6371 struct replPropertyMetaData1 *md_local;
6373 struct replPropertyMetaDataBlob omd;
6374 const struct ldb_val *omd_value;
6375 struct replPropertyMetaDataBlob *rmd;
6376 struct ldb_message *msg;
6378 ar->objs->objects[ar->index_current].local_parent_dn = NULL;
6379 ar->objs->objects[ar->index_current].last_known_parent = NULL;
6382 * This is the ADD case, find the appropriate parent,
6383 * as this object doesn't exist locally:
6385 if (ar->search_msg == NULL) {
6386 ret = replmd_replicated_apply_search_for_parent(ar);
6387 if (ret != LDB_SUCCESS) {
6388 return ldb_module_done(ar->req, NULL, NULL, ret);
6395 * Otherwise, in the MERGE case, work out if we are
6396 * attempting a rename, and if so find the parent the
6397 * newly renamed object wants to belong under (which
6398 * may not be the parent in it's attached string DN
6400 rmd = ar->objs->objects[ar->index_current].meta_data;
6404 /* find existing meta data */
6405 omd_value = ldb_msg_find_ldb_val(ar->search_msg, "replPropertyMetaData");
6407 enum ndr_err_code ndr_err;
6408 ndr_err = ndr_pull_struct_blob(omd_value, ar, &omd,
6409 (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
6410 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
6411 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
6412 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
6415 if (omd.version != 1) {
6416 return replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
6420 ar->local_parent_guid = samdb_result_guid(ar->search_msg, "parentGUID");
6422 instanceType = ldb_msg_find_attr_as_int(ar->search_msg, "instanceType", 0);
6423 if (((instanceType & INSTANCE_TYPE_IS_NC_HEAD) == 0)
6424 && GUID_all_zero(&ar->local_parent_guid)) {
6425 DEBUG(0, ("Refusing to replicate new version of %s "
6426 "as local object has an all-zero parentGUID attribute, "
6427 "despite not being an NC root\n",
6428 ldb_dn_get_linearized(ar->search_msg->dn)));
6429 return replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
6433 * now we need to check for double renames. We could have a
6434 * local rename pending which our replication partner hasn't
6435 * received yet. We choose which one wins by looking at the
6436 * attribute stamps on the two objects, the newer one wins.
6438 * This also simply applies the correct algorithms for
6439 * determining if a change was made to name at all, or
6440 * if the object has just been renamed under the same
6443 md_remote = replmd_replPropertyMetaData1_find_attid(rmd, DRSUAPI_ATTID_name);
6444 md_local = replmd_replPropertyMetaData1_find_attid(&omd, DRSUAPI_ATTID_name);
6446 DEBUG(0,(__location__ ": Failed to find name attribute in local LDB replPropertyMetaData for %s\n",
6447 ldb_dn_get_linearized(ar->search_msg->dn)));
6448 return replmd_replicated_request_werror(ar, WERR_DS_DRA_DB_ERROR);
6452 * if there is no name attribute given then we have to assume the
6453 * object we've received has the older name
6455 if (replmd_replPropertyMetaData1_new_should_be_taken(
6456 ar->objs->dsdb_repl_flags & DSDB_REPL_FLAG_PRIORITISE_INCOMING,
6457 md_local, md_remote)) {
6458 struct GUID_txt_buf p_guid_local;
6459 struct GUID_txt_buf p_guid_remote;
6460 msg = ar->objs->objects[ar->index_current].msg;
6462 /* Merge on the existing object, with rename */
6464 DEBUG(4,(__location__ ": Looking for new parent for object %s currently under %s "
6465 "as incoming object changing to %s under %s\n",
6466 ldb_dn_get_linearized(ar->search_msg->dn),
6467 GUID_buf_string(&ar->local_parent_guid, &p_guid_local),
6468 ldb_dn_get_linearized(msg->dn),
6469 GUID_buf_string(ar->objs->objects[ar->index_current].parent_guid,
6471 ret = replmd_replicated_apply_search_for_parent(ar);
6473 struct GUID_txt_buf p_guid_local;
6474 struct GUID_txt_buf p_guid_remote;
6475 msg = ar->objs->objects[ar->index_current].msg;
6478 * Merge on the existing object, force no
6479 * rename (code below just to explain why in
6483 if (strcmp(ldb_dn_get_linearized(ar->search_msg->dn),
6484 ldb_dn_get_linearized(msg->dn)) == 0) {
6485 if (ar->objs->objects[ar->index_current].parent_guid != NULL &&
6486 GUID_equal(&ar->local_parent_guid,
6487 ar->objs->objects[ar->index_current].parent_guid)
6489 DEBUG(4,(__location__ ": Keeping object %s at under %s "
6490 "despite incoming object changing parent to %s\n",
6491 ldb_dn_get_linearized(ar->search_msg->dn),
6492 GUID_buf_string(&ar->local_parent_guid, &p_guid_local),
6493 GUID_buf_string(ar->objs->objects[ar->index_current].parent_guid,
6497 DEBUG(4,(__location__ ": Keeping object %s at under %s "
6498 " and rejecting older rename to %s under %s\n",
6499 ldb_dn_get_linearized(ar->search_msg->dn),
6500 GUID_buf_string(&ar->local_parent_guid, &p_guid_local),
6501 ldb_dn_get_linearized(msg->dn),
6502 GUID_buf_string(ar->objs->objects[ar->index_current].parent_guid,
6506 * This assignment ensures that the strcmp()
6507 * and GUID_equal() calls in
6508 * replmd_replicated_apply_merge() avoids the
6511 ar->objs->objects[ar->index_current].parent_guid =
6512 &ar->local_parent_guid;
6514 msg->dn = ar->search_msg->dn;
6515 ret = replmd_replicated_apply_merge(ar);
6517 if (ret != LDB_SUCCESS) {
6518 return ldb_module_done(ar->req, NULL, NULL, ret);
6528 * Stores the linked attributes received in the replication chunk - these get
6529 * applied at the end of the transaction. We also check that each linked
6530 * attribute is valid, i.e. source and target objects are known.
6532 static int replmd_store_linked_attributes(struct replmd_replicated_request *ar)
6534 int ret = LDB_SUCCESS;
6536 struct ldb_module *module = ar->module;
6537 struct replmd_private *replmd_private =
6538 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
6539 struct ldb_context *ldb;
6541 ldb = ldb_module_get_ctx(module);
6543 DEBUG(4,("linked_attributes_count=%u\n", ar->objs->linked_attributes_count));
6545 /* save away the linked attributes for the end of the transaction */
6546 for (i = 0; i < ar->objs->linked_attributes_count; i++) {
6547 struct la_entry *la_entry;
6549 if (replmd_private->la_ctx == NULL) {
6550 replmd_private->la_ctx = talloc_new(replmd_private);
6552 la_entry = talloc(replmd_private->la_ctx, struct la_entry);
6553 if (la_entry == NULL) {
6555 return LDB_ERR_OPERATIONS_ERROR;
6557 la_entry->la = talloc(la_entry, struct drsuapi_DsReplicaLinkedAttribute);
6558 if (la_entry->la == NULL) {
6559 talloc_free(la_entry);
6561 return LDB_ERR_OPERATIONS_ERROR;
6563 *la_entry->la = ar->objs->linked_attributes[i];
6564 la_entry->dsdb_repl_flags = ar->objs->dsdb_repl_flags;
6566 /* we need to steal the non-scalars so they stay
6567 around until the end of the transaction */
6568 talloc_steal(la_entry->la, la_entry->la->identifier);
6569 talloc_steal(la_entry->la, la_entry->la->value.blob);
6571 ret = replmd_verify_linked_attribute(ar, la_entry);
6573 if (ret != LDB_SUCCESS) {
6577 DLIST_ADD(replmd_private->la_list, la_entry);
6583 static int replmd_replicated_uptodate_vector(struct replmd_replicated_request *ar);
6585 static int replmd_replicated_apply_next(struct replmd_replicated_request *ar)
6587 struct ldb_context *ldb;
6591 struct ldb_request *search_req;
6592 static const char *attrs[] = { "repsFrom", "replUpToDateVector",
6593 "parentGUID", "instanceType",
6594 "replPropertyMetaData", "nTSecurityDescriptor",
6595 "isDeleted", NULL };
6596 struct GUID_txt_buf guid_str_buf;
6598 if (ar->index_current >= ar->objs->num_objects) {
6601 * Now that we've applied all the objects, check the new linked
6602 * attributes and store them (we apply them in .prepare_commit)
6604 ret = replmd_store_linked_attributes(ar);
6606 if (ret != LDB_SUCCESS) {
6610 /* done applying objects, move on to the next stage */
6611 return replmd_replicated_uptodate_vector(ar);
6614 ldb = ldb_module_get_ctx(ar->module);
6615 ar->search_msg = NULL;
6616 ar->isDeleted = false;
6618 tmp_str = GUID_buf_string(&ar->objs->objects[ar->index_current].object_guid,
6621 filter = talloc_asprintf(ar, "(objectGUID=%s)", tmp_str);
6622 if (!filter) return replmd_replicated_request_werror(ar, WERR_NOT_ENOUGH_MEMORY);
6624 ret = ldb_build_search_req(&search_req,
6627 ar->objs->partition_dn,
6633 replmd_replicated_apply_search_callback,
6635 LDB_REQ_SET_LOCATION(search_req);
6637 ret = dsdb_request_add_controls(search_req, DSDB_SEARCH_SHOW_RECYCLED);
6639 if (ret != LDB_SUCCESS) {
6643 return ldb_next_request(ar->module, search_req);
6647 * This is essentially a wrapper for replmd_replicated_apply_next()
6649 * This is needed to ensure that both codepaths call this handler.
6651 static int replmd_replicated_apply_isDeleted(struct replmd_replicated_request *ar)
6653 struct ldb_dn *deleted_objects_dn;
6654 struct ldb_message *msg = ar->objs->objects[ar->index_current].msg;
6655 int ret = dsdb_get_deleted_objects_dn(ldb_module_get_ctx(ar->module), msg, msg->dn,
6656 &deleted_objects_dn);
6657 if (ar->isDeleted && (ret != LDB_SUCCESS || ldb_dn_compare(msg->dn, deleted_objects_dn) != 0)) {
6659 * Do a delete here again, so that if there is
6660 * anything local that conflicts with this
6661 * object being deleted, it is removed. This
6662 * includes links. See MS-DRSR 4.1.10.6.9
6665 * If the object is already deleted, and there
6666 * is no more work required, it doesn't do
6670 /* This has been updated to point to the DN we eventually did the modify on */
6672 struct ldb_request *del_req;
6673 struct ldb_result *res;
6675 TALLOC_CTX *tmp_ctx = talloc_new(ar);
6677 ret = ldb_oom(ldb_module_get_ctx(ar->module));
6681 res = talloc_zero(tmp_ctx, struct ldb_result);
6683 ret = ldb_oom(ldb_module_get_ctx(ar->module));
6684 talloc_free(tmp_ctx);
6688 /* Build a delete request, which hopefully will artually turn into nothing */
6689 ret = ldb_build_del_req(&del_req, ldb_module_get_ctx(ar->module), tmp_ctx,
6693 ldb_modify_default_callback,
6695 LDB_REQ_SET_LOCATION(del_req);
6696 if (ret != LDB_SUCCESS) {
6697 talloc_free(tmp_ctx);
6702 * This is the guts of the call, call back
6703 * into our delete code, but setting the
6704 * re_delete flag so we delete anything that
6705 * shouldn't be there on a deleted or recycled
6708 ret = replmd_delete_internals(ar->module, del_req, true);
6709 if (ret == LDB_SUCCESS) {
6710 ret = ldb_wait(del_req->handle, LDB_WAIT_ALL);
6713 talloc_free(tmp_ctx);
6714 if (ret != LDB_SUCCESS) {
6719 ar->index_current++;
6720 return replmd_replicated_apply_next(ar);
6723 static int replmd_replicated_uptodate_modify_callback(struct ldb_request *req,
6724 struct ldb_reply *ares)
6726 struct ldb_context *ldb;
6727 struct replmd_replicated_request *ar = talloc_get_type(req->context,
6728 struct replmd_replicated_request);
6729 ldb = ldb_module_get_ctx(ar->module);
6732 return ldb_module_done(ar->req, NULL, NULL,
6733 LDB_ERR_OPERATIONS_ERROR);
6735 if (ares->error != LDB_SUCCESS) {
6736 return ldb_module_done(ar->req, ares->controls,
6737 ares->response, ares->error);
6740 if (ares->type != LDB_REPLY_DONE) {
6741 ldb_asprintf_errstring(ldb, "Invalid LDB reply type %d", ares->type);
6742 return ldb_module_done(ar->req, NULL, NULL,
6743 LDB_ERR_OPERATIONS_ERROR);
6748 return ldb_module_done(ar->req, NULL, NULL, LDB_SUCCESS);
6751 static int replmd_replicated_uptodate_modify(struct replmd_replicated_request *ar)
6753 struct ldb_context *ldb;
6754 struct ldb_request *change_req;
6755 enum ndr_err_code ndr_err;
6756 struct ldb_message *msg;
6757 struct replUpToDateVectorBlob ouv;
6758 const struct ldb_val *ouv_value;
6759 const struct drsuapi_DsReplicaCursor2CtrEx *ruv;
6760 struct replUpToDateVectorBlob nuv;
6761 struct ldb_val nuv_value;
6762 struct ldb_message_element *nuv_el = NULL;
6763 struct ldb_message_element *orf_el = NULL;
6764 struct repsFromToBlob nrf;
6765 struct ldb_val *nrf_value = NULL;
6766 struct ldb_message_element *nrf_el = NULL;
6770 time_t t = time(NULL);
6773 uint32_t instanceType;
6775 ldb = ldb_module_get_ctx(ar->module);
6776 ruv = ar->objs->uptodateness_vector;
6782 unix_to_nt_time(&now, t);
6784 if (ar->search_msg == NULL) {
6785 /* this happens for a REPL_OBJ call where we are
6786 creating the target object by replicating it. The
6787 subdomain join code does this for the partition DN
6789 DEBUG(4,(__location__ ": Skipping UDV and repsFrom update as no target DN\n"));
6790 return ldb_module_done(ar->req, NULL, NULL, LDB_SUCCESS);
6793 instanceType = ldb_msg_find_attr_as_uint(ar->search_msg, "instanceType", 0);
6794 if (! (instanceType & INSTANCE_TYPE_IS_NC_HEAD)) {
6795 DEBUG(4,(__location__ ": Skipping UDV and repsFrom update as not NC root: %s\n",
6796 ldb_dn_get_linearized(ar->search_msg->dn)));
6797 return ldb_module_done(ar->req, NULL, NULL, LDB_SUCCESS);
6801 * first create the new replUpToDateVector
6803 ouv_value = ldb_msg_find_ldb_val(ar->search_msg, "replUpToDateVector");
6805 ndr_err = ndr_pull_struct_blob(ouv_value, ar, &ouv,
6806 (ndr_pull_flags_fn_t)ndr_pull_replUpToDateVectorBlob);
6807 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
6808 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
6809 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
6812 if (ouv.version != 2) {
6813 return replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
6818 * the new uptodateness vector will at least
6819 * contain 1 entry, one for the source_dsa
6821 * plus optional values from our old vector and the one from the source_dsa
6823 nuv.ctr.ctr2.count = ouv.ctr.ctr2.count;
6824 if (ruv) nuv.ctr.ctr2.count += ruv->count;
6825 nuv.ctr.ctr2.cursors = talloc_array(ar,
6826 struct drsuapi_DsReplicaCursor2,
6827 nuv.ctr.ctr2.count);
6828 if (!nuv.ctr.ctr2.cursors) return replmd_replicated_request_werror(ar, WERR_NOT_ENOUGH_MEMORY);
6830 /* first copy the old vector */
6831 for (i=0; i < ouv.ctr.ctr2.count; i++) {
6832 nuv.ctr.ctr2.cursors[ni] = ouv.ctr.ctr2.cursors[i];
6836 /* merge in the source_dsa vector is available */
6837 for (i=0; (ruv && i < ruv->count); i++) {
6840 if (GUID_equal(&ruv->cursors[i].source_dsa_invocation_id,
6841 &ar->our_invocation_id)) {
6845 for (j=0; j < ni; j++) {
6846 if (!GUID_equal(&ruv->cursors[i].source_dsa_invocation_id,
6847 &nuv.ctr.ctr2.cursors[j].source_dsa_invocation_id)) {
6853 if (ruv->cursors[i].highest_usn > nuv.ctr.ctr2.cursors[j].highest_usn) {
6854 nuv.ctr.ctr2.cursors[j] = ruv->cursors[i];
6859 if (found) continue;
6861 /* if it's not there yet, add it */
6862 nuv.ctr.ctr2.cursors[ni] = ruv->cursors[i];
6867 * finally correct the size of the cursors array
6869 nuv.ctr.ctr2.count = ni;
6874 TYPESAFE_QSORT(nuv.ctr.ctr2.cursors, nuv.ctr.ctr2.count, drsuapi_DsReplicaCursor2_compare);
6877 * create the change ldb_message
6879 msg = ldb_msg_new(ar);
6880 if (!msg) return replmd_replicated_request_werror(ar, WERR_NOT_ENOUGH_MEMORY);
6881 msg->dn = ar->search_msg->dn;
6883 ndr_err = ndr_push_struct_blob(&nuv_value, msg, &nuv,
6884 (ndr_push_flags_fn_t)ndr_push_replUpToDateVectorBlob);
6885 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
6886 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
6887 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
6889 ret = ldb_msg_add_value(msg, "replUpToDateVector", &nuv_value, &nuv_el);
6890 if (ret != LDB_SUCCESS) {
6891 return replmd_replicated_request_error(ar, ret);
6893 nuv_el->flags = LDB_FLAG_MOD_REPLACE;
6896 * now create the new repsFrom value from the given repsFromTo1 structure
6900 nrf.ctr.ctr1 = *ar->objs->source_dsa;
6901 nrf.ctr.ctr1.last_attempt = now;
6902 nrf.ctr.ctr1.last_success = now;
6903 nrf.ctr.ctr1.result_last_attempt = WERR_OK;
6906 * first see if we already have a repsFrom value for the current source dsa
6907 * if so we'll later replace this value
6909 orf_el = ldb_msg_find_element(ar->search_msg, "repsFrom");
6911 for (i=0; i < orf_el->num_values; i++) {
6912 struct repsFromToBlob *trf;
6914 trf = talloc(ar, struct repsFromToBlob);
6915 if (!trf) return replmd_replicated_request_werror(ar, WERR_NOT_ENOUGH_MEMORY);
6917 ndr_err = ndr_pull_struct_blob(&orf_el->values[i], trf, trf,
6918 (ndr_pull_flags_fn_t)ndr_pull_repsFromToBlob);
6919 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
6920 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
6921 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
6924 if (trf->version != 1) {
6925 return replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
6929 * we compare the source dsa objectGUID not the invocation_id
6930 * because we want only one repsFrom value per source dsa
6931 * and when the invocation_id of the source dsa has changed we don't need
6932 * the old repsFrom with the old invocation_id
6934 if (!GUID_equal(&trf->ctr.ctr1.source_dsa_obj_guid,
6935 &ar->objs->source_dsa->source_dsa_obj_guid)) {
6941 nrf_value = &orf_el->values[i];
6946 * copy over all old values to the new ldb_message
6948 ret = ldb_msg_add_empty(msg, "repsFrom", 0, &nrf_el);
6949 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
6954 * if we haven't found an old repsFrom value for the current source dsa
6955 * we'll add a new value
6958 struct ldb_val zero_value;
6959 ZERO_STRUCT(zero_value);
6960 ret = ldb_msg_add_value(msg, "repsFrom", &zero_value, &nrf_el);
6961 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
6963 nrf_value = &nrf_el->values[nrf_el->num_values - 1];
6966 /* we now fill the value which is already attached to ldb_message */
6967 ndr_err = ndr_push_struct_blob(nrf_value, msg,
6969 (ndr_push_flags_fn_t)ndr_push_repsFromToBlob);
6970 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
6971 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
6972 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
6976 * the ldb_message_element for the attribute, has all the old values and the new one
6977 * so we'll replace the whole attribute with all values
6979 nrf_el->flags = LDB_FLAG_MOD_REPLACE;
6981 if (CHECK_DEBUGLVL(4)) {
6982 char *s = ldb_ldif_message_redacted_string(ldb, ar,
6983 LDB_CHANGETYPE_MODIFY,
6985 DEBUG(4, ("DRS replication uptodate modify message:\n%s\n", s));
6989 /* prepare the ldb_modify() request */
6990 ret = ldb_build_mod_req(&change_req,
6996 replmd_replicated_uptodate_modify_callback,
6998 LDB_REQ_SET_LOCATION(change_req);
6999 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
7001 return ldb_next_request(ar->module, change_req);
7004 static int replmd_replicated_uptodate_search_callback(struct ldb_request *req,
7005 struct ldb_reply *ares)
7007 struct replmd_replicated_request *ar = talloc_get_type(req->context,
7008 struct replmd_replicated_request);
7012 return ldb_module_done(ar->req, NULL, NULL,
7013 LDB_ERR_OPERATIONS_ERROR);
7015 if (ares->error != LDB_SUCCESS &&
7016 ares->error != LDB_ERR_NO_SUCH_OBJECT) {
7017 return ldb_module_done(ar->req, ares->controls,
7018 ares->response, ares->error);
7021 switch (ares->type) {
7022 case LDB_REPLY_ENTRY:
7023 ar->search_msg = talloc_steal(ar, ares->message);
7026 case LDB_REPLY_REFERRAL:
7027 /* we ignore referrals */
7030 case LDB_REPLY_DONE:
7031 ret = replmd_replicated_uptodate_modify(ar);
7032 if (ret != LDB_SUCCESS) {
7033 return ldb_module_done(ar->req, NULL, NULL, ret);
7042 static int replmd_replicated_uptodate_vector(struct replmd_replicated_request *ar)
7044 struct ldb_context *ldb = ldb_module_get_ctx(ar->module);
7045 struct replmd_private *replmd_private =
7046 talloc_get_type_abort(ldb_module_get_private(ar->module),
7047 struct replmd_private);
7049 static const char *attrs[] = {
7050 "replUpToDateVector",
7055 struct ldb_request *search_req;
7057 ar->search_msg = NULL;
7060 * Let the caller know that we did an originating updates
7062 ar->objs->originating_updates = replmd_private->originating_updates;
7064 ret = ldb_build_search_req(&search_req,
7067 ar->objs->partition_dn,
7073 replmd_replicated_uptodate_search_callback,
7075 LDB_REQ_SET_LOCATION(search_req);
7076 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
7078 return ldb_next_request(ar->module, search_req);
7083 static int replmd_extended_replicated_objects(struct ldb_module *module, struct ldb_request *req)
7085 struct ldb_context *ldb;
7086 struct dsdb_extended_replicated_objects *objs;
7087 struct replmd_replicated_request *ar;
7088 struct ldb_control **ctrls;
7091 ldb = ldb_module_get_ctx(module);
7093 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_extended_replicated_objects\n");
7095 objs = talloc_get_type(req->op.extended.data, struct dsdb_extended_replicated_objects);
7097 ldb_debug(ldb, LDB_DEBUG_FATAL, "replmd_extended_replicated_objects: invalid extended data\n");
7098 return LDB_ERR_PROTOCOL_ERROR;
7101 if (objs->version != DSDB_EXTENDED_REPLICATED_OBJECTS_VERSION) {
7102 ldb_debug(ldb, LDB_DEBUG_FATAL, "replmd_extended_replicated_objects: extended data invalid version [%u != %u]\n",
7103 objs->version, DSDB_EXTENDED_REPLICATED_OBJECTS_VERSION);
7104 return LDB_ERR_PROTOCOL_ERROR;
7107 ar = replmd_ctx_init(module, req);
7109 return LDB_ERR_OPERATIONS_ERROR;
7111 /* Set the flags to have the replmd_op_callback run over the full set of objects */
7112 ar->apply_mode = true;
7114 ar->schema = dsdb_get_schema(ldb, ar);
7116 ldb_debug_set(ldb, LDB_DEBUG_FATAL, "replmd_ctx_init: no loaded schema found\n");
7118 DEBUG(0,(__location__ ": %s\n", ldb_errstring(ldb)));
7119 return LDB_ERR_CONSTRAINT_VIOLATION;
7122 ctrls = req->controls;
7124 if (req->controls) {
7125 req->controls = talloc_memdup(ar, req->controls,
7126 talloc_get_size(req->controls));
7127 if (!req->controls) return replmd_replicated_request_werror(ar, WERR_NOT_ENOUGH_MEMORY);
7130 ret = ldb_request_add_control(req, DSDB_CONTROL_REPLICATED_UPDATE_OID, false, NULL);
7131 if (ret != LDB_SUCCESS) {
7135 /* If this change contained linked attributes in the body
7136 * (rather than in the links section) we need to update
7137 * backlinks in linked_attributes */
7138 ret = ldb_request_add_control(req, DSDB_CONTROL_APPLY_LINKS, false, NULL);
7139 if (ret != LDB_SUCCESS) {
7143 ar->controls = req->controls;
7144 req->controls = ctrls;
7146 return replmd_replicated_apply_next(ar);
7150 * Checks how to handle an missing target - either we need to fail the
7151 * replication and retry with GET_TGT, ignore the link and continue, or try to
7152 * add a partial link to an unknown target.
7154 static int replmd_allow_missing_target(struct ldb_module *module,
7155 TALLOC_CTX *mem_ctx,
7156 struct ldb_dn *target_dn,
7157 struct ldb_dn *source_dn,
7160 uint32_t dsdb_repl_flags,
7162 const char * missing_str)
7164 struct ldb_context *ldb = ldb_module_get_ctx(module);
7168 * we may not be able to resolve link targets properly when
7169 * dealing with subsets of objects, e.g. the source is a
7170 * critical object and the target isn't
7173 * When we implement Trusted Domains we need to consider
7174 * whether they get treated as an incomplete replica here or not
7176 if (dsdb_repl_flags & DSDB_REPL_FLAG_OBJECT_SUBSET) {
7179 * Ignore the link. We don't increase the highwater-mark in
7180 * the object subset cases, so subsequent replications should
7181 * resolve any missing links
7183 DEBUG(2, ("%s target %s linked from %s\n", missing_str,
7184 ldb_dn_get_linearized(target_dn),
7185 ldb_dn_get_linearized(source_dn)));
7186 *ignore_link = true;
7190 if (dsdb_repl_flags & DSDB_REPL_FLAG_TARGETS_UPTODATE) {
7193 * target should already be up-to-date so there's no point in
7194 * retrying. This could be due to bad timing, or if a target
7195 * on a one-way link was deleted. We ignore the link rather
7196 * than failing the replication cycle completely
7198 *ignore_link = true;
7199 DBG_WARNING("%s is %s but up to date. Ignoring link from %s\n",
7200 ldb_dn_get_linearized(target_dn), missing_str,
7201 ldb_dn_get_linearized(source_dn));
7205 is_in_same_nc = dsdb_objects_have_same_nc(ldb,
7209 if (is_in_same_nc) {
7210 /* fail the replication and retry with GET_TGT */
7211 ldb_asprintf_errstring(ldb, "%s target %s GUID %s linked from %s\n",
7213 ldb_dn_get_linearized(target_dn),
7214 GUID_string(mem_ctx, guid),
7215 ldb_dn_get_linearized(source_dn));
7216 return LDB_ERR_NO_SUCH_OBJECT;
7220 * The target of the cross-partition link is missing. Continue
7221 * and try to at least add the forward-link. This isn't great,
7222 * but a partial link can be fixed by dbcheck, so it's better
7223 * than dropping the link completely.
7225 *ignore_link = false;
7227 if (is_obj_commit) {
7230 * Only log this when we're actually committing the objects.
7231 * This avoids spurious logs, i.e. if we're just verifying the
7232 * received link during a join.
7234 DBG_WARNING("%s cross-partition target %s linked from %s\n",
7235 missing_str, ldb_dn_get_linearized(target_dn),
7236 ldb_dn_get_linearized(source_dn));
7243 * Checks that the target object for a linked attribute exists.
7244 * @param guid returns the target object's GUID (is returned)if it exists)
7245 * @param ignore_link set to true if the linked attribute should be ignored
7246 * (i.e. the target doesn't exist, but that it's OK to skip the link)
7248 static int replmd_check_target_exists(struct ldb_module *module,
7249 struct dsdb_dn *dsdb_dn,
7250 struct la_entry *la_entry,
7251 struct ldb_dn *source_dn,
7256 struct drsuapi_DsReplicaLinkedAttribute *la = la_entry->la;
7257 struct ldb_context *ldb = ldb_module_get_ctx(module);
7258 struct ldb_result *target_res;
7259 TALLOC_CTX *tmp_ctx = talloc_new(la_entry);
7260 const char *attrs[] = { "isDeleted", "isRecycled", NULL };
7263 enum deletion_state target_deletion_state = OBJECT_REMOVED;
7264 bool active = (la->flags & DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE) ? true : false;
7266 *ignore_link = false;
7267 ntstatus = dsdb_get_extended_dn_guid(dsdb_dn->dn, guid, "GUID");
7269 if (!NT_STATUS_IS_OK(ntstatus) && !active) {
7272 * This strange behaviour (allowing a NULL/missing
7273 * GUID) originally comes from:
7275 * commit e3054ce0fe0f8f62d2f5b2a77893e7a1479128bd
7276 * Author: Andrew Tridgell <tridge@samba.org>
7277 * Date: Mon Dec 21 21:21:55 2009 +1100
7279 * s4-drs: cope better with NULL GUIDS from DRS
7281 * It is valid to get a NULL GUID over DRS for a deleted forward link. We
7282 * need to match by DN if possible when seeing if we should update an
7285 * Pair-Programmed-With: Andrew Bartlett <abartlet@samba.org>
7287 ret = dsdb_module_search_dn(module, tmp_ctx, &target_res,
7289 DSDB_FLAG_NEXT_MODULE |
7290 DSDB_SEARCH_SHOW_RECYCLED |
7291 DSDB_SEARCH_SEARCH_ALL_PARTITIONS |
7292 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT,
7294 } else if (!NT_STATUS_IS_OK(ntstatus)) {
7295 ldb_asprintf_errstring(ldb, "Failed to find GUID in linked attribute 0x%x blob for %s from %s",
7297 ldb_dn_get_linearized(dsdb_dn->dn),
7298 ldb_dn_get_linearized(source_dn));
7299 talloc_free(tmp_ctx);
7300 return LDB_ERR_OPERATIONS_ERROR;
7302 ret = dsdb_module_search(module, tmp_ctx, &target_res,
7303 NULL, LDB_SCOPE_SUBTREE,
7305 DSDB_FLAG_NEXT_MODULE |
7306 DSDB_SEARCH_SHOW_RECYCLED |
7307 DSDB_SEARCH_SEARCH_ALL_PARTITIONS |
7308 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT,
7311 GUID_string(tmp_ctx, guid));
7314 if (ret != LDB_SUCCESS) {
7315 ldb_asprintf_errstring(ldb, "Failed to re-resolve GUID %s: %s\n",
7316 GUID_string(tmp_ctx, guid),
7317 ldb_errstring(ldb));
7318 talloc_free(tmp_ctx);
7322 if (target_res->count == 0) {
7325 * target object is unknown. Check whether to ignore the link,
7326 * fail the replication, or add a partial link
7328 ret = replmd_allow_missing_target(module, tmp_ctx, dsdb_dn->dn,
7329 source_dn, is_obj_commit, guid,
7330 la_entry->dsdb_repl_flags,
7331 ignore_link, "Unknown");
7333 } else if (target_res->count != 1) {
7334 ldb_asprintf_errstring(ldb, "More than one object found matching objectGUID %s\n",
7335 GUID_string(tmp_ctx, guid));
7336 ret = LDB_ERR_OPERATIONS_ERROR;
7338 struct ldb_message *target_msg = target_res->msgs[0];
7340 dsdb_dn->dn = talloc_steal(dsdb_dn, target_msg->dn);
7342 /* Get the object's state (i.e. Not Deleted, Tombstone, etc) */
7343 replmd_deletion_state(module, target_msg,
7344 &target_deletion_state, NULL);
7347 * Check for deleted objects as per MS-DRSR 4.1.10.6.14
7348 * ProcessLinkValue(). Link updates should not be sent for
7349 * recycled and tombstone objects (deleting the links should
7350 * happen when we delete the object). This probably means our
7351 * copy of the target object isn't up to date.
7353 if (target_deletion_state >= OBJECT_RECYCLED) {
7356 * target object is deleted. Check whether to ignore the
7357 * link, fail the replication, or add a partial link
7359 ret = replmd_allow_missing_target(module, tmp_ctx,
7360 dsdb_dn->dn, source_dn,
7361 is_obj_commit, guid,
7362 la_entry->dsdb_repl_flags,
7363 ignore_link, "Deleted");
7367 talloc_free(tmp_ctx);
7372 * Extracts the key details about the source/target object for a
7373 * linked-attribute entry.
7374 * This returns the following details:
7375 * @param ret_attr the schema details for the linked attribute
7376 * @param source_msg the search result for the source object
7377 * @param target_dsdb_dn the unpacked DN info for the target object
7379 static int replmd_extract_la_entry_details(struct ldb_module *module,
7380 struct la_entry *la_entry,
7381 TALLOC_CTX *mem_ctx,
7382 const struct dsdb_attribute **ret_attr,
7383 struct ldb_message **source_msg,
7384 struct dsdb_dn **target_dsdb_dn)
7386 struct drsuapi_DsReplicaLinkedAttribute *la = la_entry->la;
7387 struct ldb_context *ldb = ldb_module_get_ctx(module);
7388 const struct dsdb_schema *schema = dsdb_get_schema(ldb, mem_ctx);
7390 const struct dsdb_attribute *attr;
7392 struct ldb_result *res;
7393 const char *attrs[4];
7396 linked_attributes[0]:
7397 &objs->linked_attributes[i]: struct drsuapi_DsReplicaLinkedAttribute
7399 identifier: struct drsuapi_DsReplicaObjectIdentifier
7400 __ndr_size : 0x0000003a (58)
7401 __ndr_size_sid : 0x00000000 (0)
7402 guid : 8e95b6a9-13dd-4158-89db-3220a5be5cc7
7404 __ndr_size_dn : 0x00000000 (0)
7406 attid : DRSUAPI_ATTID_member (0x1F)
7407 value: struct drsuapi_DsAttributeValue
7408 __ndr_size : 0x0000007e (126)
7410 blob : DATA_BLOB length=126
7411 flags : 0x00000001 (1)
7412 1: DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE
7413 originating_add_time : Wed Sep 2 22:20:01 2009 EST
7414 meta_data: struct drsuapi_DsReplicaMetaData
7415 version : 0x00000015 (21)
7416 originating_change_time : Wed Sep 2 23:39:07 2009 EST
7417 originating_invocation_id: 794640f3-18cf-40ee-a211-a93992b67a64
7418 originating_usn : 0x000000000001e19c (123292)
7420 (for cases where the link is to a normal DN)
7421 &target: struct drsuapi_DsReplicaObjectIdentifier3
7422 __ndr_size : 0x0000007e (126)
7423 __ndr_size_sid : 0x0000001c (28)
7424 guid : 7639e594-db75-4086-b0d4-67890ae46031
7425 sid : S-1-5-21-2848215498-2472035911-1947525656-19924
7426 __ndr_size_dn : 0x00000022 (34)
7427 dn : 'CN=UOne,OU=TestOU,DC=vsofs8,DC=com'
7430 /* find the attribute being modified */
7431 attr = dsdb_attribute_by_attributeID_id(schema, la->attid);
7433 struct GUID_txt_buf guid_str;
7434 ldb_asprintf_errstring(ldb, "Unable to find attributeID 0x%x for link on <GUID=%s>",
7436 GUID_buf_string(&la->identifier->guid,
7438 return LDB_ERR_OPERATIONS_ERROR;
7442 * All attributes listed here must be dealt with in some way
7443 * by replmd_process_linked_attribute() otherwise in the case
7444 * of isDeleted: FALSE the modify will fail with:
7446 * Failed to apply linked attribute change 'attribute 'isDeleted':
7447 * invalid modify flags on
7448 * 'CN=g1_1527570609273,CN=Users,DC=samba,DC=example,DC=com':
7451 * This is becaue isDeleted is a Boolean, so FALSE is a
7452 * legitimate value (set by Samba's deletetest.py)
7454 attrs[0] = attr->lDAPDisplayName;
7455 attrs[1] = "isDeleted";
7456 attrs[2] = "isRecycled";
7460 * get the existing message from the db for the object with
7461 * this GUID, returning attribute being modified. We will then
7462 * use this msg as the basis for a modify call
7464 ret = dsdb_module_search(module, mem_ctx, &res, NULL, LDB_SCOPE_SUBTREE, attrs,
7465 DSDB_FLAG_NEXT_MODULE |
7466 DSDB_SEARCH_SEARCH_ALL_PARTITIONS |
7467 DSDB_SEARCH_SHOW_RECYCLED |
7468 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT |
7469 DSDB_SEARCH_REVEAL_INTERNALS,
7471 "objectGUID=%s", GUID_string(mem_ctx, &la->identifier->guid));
7472 if (ret != LDB_SUCCESS) {
7475 if (res->count != 1) {
7476 ldb_asprintf_errstring(ldb, "DRS linked attribute for GUID %s - DN not found",
7477 GUID_string(mem_ctx, &la->identifier->guid));
7478 return LDB_ERR_NO_SUCH_OBJECT;
7481 *source_msg = res->msgs[0];
7483 /* the value blob for the attribute holds the target object DN */
7484 status = dsdb_dn_la_from_blob(ldb, attr, schema, mem_ctx, la->value.blob, target_dsdb_dn);
7485 if (!W_ERROR_IS_OK(status)) {
7486 ldb_asprintf_errstring(ldb, "Failed to parsed linked attribute blob for %s on %s - %s\n",
7487 attr->lDAPDisplayName,
7488 ldb_dn_get_linearized(res->msgs[0]->dn),
7489 win_errstr(status));
7490 return LDB_ERR_OPERATIONS_ERROR;
7499 * Verifies the source and target objects are known for a linked attribute
7501 static int replmd_verify_linked_attribute(struct replmd_replicated_request *ar,
7502 struct la_entry *la)
7504 int ret = LDB_SUCCESS;
7505 TALLOC_CTX *tmp_ctx = talloc_new(la);
7506 struct ldb_module *module = ar->module;
7507 struct ldb_message *src_msg;
7508 const struct dsdb_attribute *attr;
7509 struct dsdb_dn *tgt_dsdb_dn;
7510 struct GUID guid = GUID_zero();
7513 ret = replmd_extract_la_entry_details(module, la, tmp_ctx, &attr,
7514 &src_msg, &tgt_dsdb_dn);
7517 * When we fail to find the source object, the error code we pass
7518 * back here is really important. It flags back to the callers to
7519 * retry this request with DRSUAPI_DRS_GET_ANC. This case should
7520 * never happen if we're replicating from a Samba DC, but it is
7521 * needed to talk to a Windows DC
7523 if (ret == LDB_ERR_NO_SUCH_OBJECT) {
7524 ret = replmd_replicated_request_werror(ar, WERR_DS_DRA_MISSING_PARENT);
7527 if (ret != LDB_SUCCESS) {
7528 talloc_free(tmp_ctx);
7533 * We can skip the target object checks if we're only syncing critical
7534 * objects, or we know the target is up-to-date. If either case, we
7535 * still continue even if the target doesn't exist
7537 if ((la->dsdb_repl_flags & (DSDB_REPL_FLAG_OBJECT_SUBSET |
7538 DSDB_REPL_FLAG_TARGETS_UPTODATE)) == 0) {
7540 ret = replmd_check_target_exists(module, tgt_dsdb_dn, la,
7541 src_msg->dn, false, &guid,
7546 * When we fail to find the target object, the error code we pass
7547 * back here is really important. It flags back to the callers to
7548 * retry this request with DRSUAPI_DRS_GET_TGT
7550 if (ret == LDB_ERR_NO_SUCH_OBJECT) {
7551 ret = replmd_replicated_request_werror(ar, WERR_DS_DRA_RECYCLED_TARGET);
7554 talloc_free(tmp_ctx);
7559 * Finds the current active Parsed-DN value for a single-valued linked
7560 * attribute, if one exists.
7561 * @param ret_pdn assigned the active Parsed-DN, or NULL if none was found
7562 * @returns LDB_SUCCESS (regardless of whether a match was found), unless
7565 static int replmd_get_active_singleval_link(struct ldb_module *module,
7566 TALLOC_CTX *mem_ctx,
7567 struct parsed_dn pdn_list[],
7569 const struct dsdb_attribute *attr,
7570 struct parsed_dn **ret_pdn)
7576 if (!(attr->ldb_schema_attribute->flags & LDB_ATTR_FLAG_SINGLE_VALUE)) {
7578 /* nothing to do for multi-valued linked attributes */
7582 for (i = 0; i < count; i++) {
7583 int ret = LDB_SUCCESS;
7584 struct parsed_dn *pdn = &pdn_list[i];
7586 /* skip any inactive links */
7587 if (dsdb_dn_is_deleted_val(pdn->v)) {
7591 /* we've found an active value for this attribute */
7594 if (pdn->dsdb_dn == NULL) {
7595 struct ldb_context *ldb = ldb_module_get_ctx(module);
7597 ret = really_parse_trusted_dn(mem_ctx, ldb, pdn,
7598 attr->syntax->ldap_oid);
7604 /* no active link found */
7609 * @returns true if the replication linked attribute info is newer than we
7610 * already have in our DB
7611 * @param pdn the existing linked attribute info in our DB
7612 * @param la the new linked attribute info received during replication
7614 static bool replmd_link_update_is_newer(struct parsed_dn *pdn,
7615 struct drsuapi_DsReplicaLinkedAttribute *la)
7617 /* see if this update is newer than what we have already */
7618 struct GUID invocation_id = GUID_zero();
7619 uint32_t version = 0;
7620 NTTIME change_time = 0;
7624 /* no existing info so update is newer */
7628 dsdb_get_extended_dn_guid(pdn->dsdb_dn->dn, &invocation_id, "RMD_INVOCID");
7629 dsdb_get_extended_dn_uint32(pdn->dsdb_dn->dn, &version, "RMD_VERSION");
7630 dsdb_get_extended_dn_nttime(pdn->dsdb_dn->dn, &change_time, "RMD_CHANGETIME");
7632 return replmd_update_is_newer(&invocation_id,
7633 &la->meta_data.originating_invocation_id,
7635 la->meta_data.version,
7637 la->meta_data.originating_change_time);
7641 * Marks an existing linked attribute value as deleted in the DB
7642 * @param pdn the parsed-DN of the target-value to delete
7644 static int replmd_delete_link_value(struct ldb_module *module,
7645 struct replmd_private *replmd_private,
7646 TALLOC_CTX *mem_ctx,
7647 struct ldb_dn *src_obj_dn,
7648 const struct dsdb_schema *schema,
7649 const struct dsdb_attribute *attr,
7652 struct GUID *target_guid,
7653 struct dsdb_dn *target_dsdb_dn,
7654 struct ldb_val *output_val)
7656 struct ldb_context *ldb = ldb_module_get_ctx(module);
7659 const struct GUID *invocation_id = NULL;
7663 unix_to_nt_time(&now, t);
7665 invocation_id = samdb_ntds_invocation_id(ldb);
7666 if (invocation_id == NULL) {
7667 return LDB_ERR_OPERATIONS_ERROR;
7670 /* if the existing link is active, remove its backlink */
7673 ret = replmd_add_backlink(module, replmd_private, schema,
7674 src_obj_dn, target_guid, false,
7676 if (ret != LDB_SUCCESS) {
7681 /* mark the existing value as deleted */
7682 ret = replmd_update_la_val(mem_ctx, output_val, target_dsdb_dn,
7683 target_dsdb_dn, invocation_id, seq_num,
7684 seq_num, now, true);
7689 * Checks for a conflict in single-valued link attributes, and tries to
7690 * resolve the problem if possible.
7692 * Single-valued links should only ever have one active value. If we already
7693 * have an active link value, and during replication we receive an active link
7694 * value for a different target DN, then we need to resolve this inconsistency
7695 * and determine which value should be active. If the received info is better/
7696 * newer than the existing link attribute, then we need to set our existing
7697 * link as deleted. If the received info is worse/older, then we should continue
7698 * to add it, but set it as an inactive link.
7700 * Note that this is a corner-case that is unlikely to happen (but if it does
7701 * happen, we don't want it to break replication completely).
7703 * @param pdn_being_modified the parsed DN corresponding to the received link
7704 * target (note this is NULL if the link does not already exist in our DB)
7705 * @param pdn_list all the source object's Parsed-DNs for this attribute, i.e.
7706 * any existing active or inactive values for the attribute in our DB.
7707 * @param dsdb_dn the target DN for the received link attribute
7708 * @param add_as_inactive gets set to true if the received link is worse than
7709 * the existing link - it should still be added, but as an inactive link.
7711 static int replmd_check_singleval_la_conflict(struct ldb_module *module,
7712 struct replmd_private *replmd_private,
7713 TALLOC_CTX *mem_ctx,
7714 struct ldb_dn *src_obj_dn,
7715 struct drsuapi_DsReplicaLinkedAttribute *la,
7716 struct dsdb_dn *dsdb_dn,
7717 struct parsed_dn *pdn_being_modified,
7718 struct parsed_dn *pdn_list,
7719 struct ldb_message_element *old_el,
7720 const struct dsdb_schema *schema,
7721 const struct dsdb_attribute *attr,
7723 bool *add_as_inactive)
7725 struct parsed_dn *active_pdn = NULL;
7726 bool update_is_newer = false;
7730 * check if there's a conflict for single-valued links, i.e. an active
7731 * linked attribute already exists, but it has a different target value
7733 ret = replmd_get_active_singleval_link(module, mem_ctx, pdn_list,
7734 old_el->num_values, attr,
7737 if (ret != LDB_SUCCESS) {
7742 * If no active value exists (or the received info is for the currently
7743 * active value), then no conflict exists
7745 if (active_pdn == NULL || active_pdn == pdn_being_modified) {
7749 DBG_WARNING("Link conflict for %s attribute on %s\n",
7750 attr->lDAPDisplayName, ldb_dn_get_linearized(src_obj_dn));
7752 /* Work out how to resolve the conflict based on which info is better */
7753 update_is_newer = replmd_link_update_is_newer(active_pdn, la);
7755 if (update_is_newer) {
7756 DBG_WARNING("Using received value %s, over existing target %s\n",
7757 ldb_dn_get_linearized(dsdb_dn->dn),
7758 ldb_dn_get_linearized(active_pdn->dsdb_dn->dn));
7761 * Delete our existing active link. The received info will then
7762 * be added (through normal link processing) as the active value
7764 ret = replmd_delete_link_value(module, replmd_private, old_el,
7765 src_obj_dn, schema, attr,
7766 seq_num, true, &active_pdn->guid,
7767 active_pdn->dsdb_dn,
7770 if (ret != LDB_SUCCESS) {
7774 DBG_WARNING("Using existing target %s, over received value %s\n",
7775 ldb_dn_get_linearized(active_pdn->dsdb_dn->dn),
7776 ldb_dn_get_linearized(dsdb_dn->dn));
7779 * we want to keep our existing active link and add the
7780 * received link as inactive
7782 *add_as_inactive = true;
7789 process one linked attribute structure
7791 static int replmd_process_linked_attribute(struct ldb_module *module,
7792 struct replmd_private *replmd_private,
7793 struct la_entry *la_entry,
7794 struct ldb_request *parent)
7796 struct drsuapi_DsReplicaLinkedAttribute *la = la_entry->la;
7797 struct ldb_context *ldb = ldb_module_get_ctx(module);
7798 struct ldb_message *msg;
7799 TALLOC_CTX *tmp_ctx = talloc_new(la_entry);
7800 const struct dsdb_schema *schema = dsdb_get_schema(ldb, tmp_ctx);
7802 const struct dsdb_attribute *attr;
7803 struct dsdb_dn *dsdb_dn;
7804 uint64_t seq_num = 0;
7805 struct ldb_message_element *old_el;
7806 time_t t = time(NULL);
7807 struct parsed_dn *pdn_list, *pdn, *next;
7808 struct GUID guid = GUID_zero();
7809 bool active = (la->flags & DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE)?true:false;
7811 enum deletion_state deletion_state = OBJECT_NOT_DELETED;
7812 struct dsdb_dn *old_dsdb_dn = NULL;
7813 struct ldb_val *val_to_update = NULL;
7814 bool add_as_inactive = false;
7817 * get the attribute being modified, the search result for the source object,
7818 * and the target object's DN details
7820 ret = replmd_extract_la_entry_details(module, la_entry, tmp_ctx, &attr,
7823 if (ret != LDB_SUCCESS) {
7824 talloc_free(tmp_ctx);
7829 * Check for deleted objects per MS-DRSR 4.1.10.6.14
7830 * ProcessLinkValue, because link updates are not applied to
7831 * recycled and tombstone objects. We don't have to delete
7832 * any existing link, that should have happened when the
7833 * object deletion was replicated or initiated.
7835 * This needs isDeleted and isRecycled to be included as
7836 * attributes in the search and so in msg if set.
7838 replmd_deletion_state(module, msg, &deletion_state, NULL);
7840 if (deletion_state >= OBJECT_RECYCLED) {
7841 talloc_free(tmp_ctx);
7846 * Now that we know the deletion_state, remove the extra
7847 * attributes added for that purpose. We need to do this
7848 * otherwise in the case of isDeleted: FALSE the modify will
7851 * Failed to apply linked attribute change 'attribute 'isDeleted':
7852 * invalid modify flags on
7853 * 'CN=g1_1527570609273,CN=Users,DC=samba,DC=example,DC=com':
7856 * This is becaue isDeleted is a Boolean, so FALSE is a
7857 * legitimate value (set by Samba's deletetest.py)
7860 ldb_msg_remove_attr(msg, "isDeleted");
7861 ldb_msg_remove_attr(msg, "isRecycled");
7863 old_el = ldb_msg_find_element(msg, attr->lDAPDisplayName);
7864 if (old_el == NULL) {
7865 ret = ldb_msg_add_empty(msg, attr->lDAPDisplayName, LDB_FLAG_MOD_REPLACE, &old_el);
7866 if (ret != LDB_SUCCESS) {
7867 ldb_module_oom(module);
7868 talloc_free(tmp_ctx);
7869 return LDB_ERR_OPERATIONS_ERROR;
7872 old_el->flags = LDB_FLAG_MOD_REPLACE;
7875 /* parse the existing links */
7876 ret = get_parsed_dns_trusted(module, replmd_private, tmp_ctx, old_el, &pdn_list,
7877 attr->syntax->ldap_oid, parent);
7879 if (ret != LDB_SUCCESS) {
7880 talloc_free(tmp_ctx);
7884 ret = replmd_check_target_exists(module, dsdb_dn, la_entry, msg->dn,
7885 true, &guid, &ignore_link);
7887 if (ret != LDB_SUCCESS) {
7888 talloc_free(tmp_ctx);
7893 * there are some cases where the target object doesn't exist, but it's
7894 * OK to ignore the linked attribute
7897 talloc_free(tmp_ctx);
7901 /* see if this link already exists */
7902 ret = parsed_dn_find(ldb, pdn_list, old_el->num_values,
7905 dsdb_dn->extra_part, 0,
7907 attr->syntax->ldap_oid,
7909 if (ret != LDB_SUCCESS) {
7910 talloc_free(tmp_ctx);
7914 if (!replmd_link_update_is_newer(pdn, la)) {
7915 DEBUG(3,("Discarding older DRS linked attribute update to %s on %s from %s\n",
7916 old_el->name, ldb_dn_get_linearized(msg->dn),
7917 GUID_string(tmp_ctx, &la->meta_data.originating_invocation_id)));
7918 talloc_free(tmp_ctx);
7922 /* get a seq_num for this change */
7923 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &seq_num);
7924 if (ret != LDB_SUCCESS) {
7925 talloc_free(tmp_ctx);
7930 * check for single-valued link conflicts, i.e. an active linked
7931 * attribute already exists, but it has a different target value
7934 ret = replmd_check_singleval_la_conflict(module, replmd_private,
7935 tmp_ctx, msg->dn, la,
7936 dsdb_dn, pdn, pdn_list,
7937 old_el, schema, attr,
7940 if (ret != LDB_SUCCESS) {
7941 talloc_free(tmp_ctx);
7947 uint32_t rmd_flags = dsdb_dn_rmd_flags(pdn->dsdb_dn->dn);
7949 if (!(rmd_flags & DSDB_RMD_FLAG_DELETED)) {
7950 /* remove the existing backlink */
7951 ret = replmd_add_backlink(module, replmd_private,
7954 &pdn->guid, false, attr,
7956 if (ret != LDB_SUCCESS) {
7957 talloc_free(tmp_ctx);
7962 val_to_update = pdn->v;
7963 old_dsdb_dn = pdn->dsdb_dn;
7969 * We know where the new one needs to be, from the *next
7970 * pointer into pdn_list.
7973 offset = old_el->num_values;
7975 if (next->dsdb_dn == NULL) {
7976 ret = really_parse_trusted_dn(tmp_ctx, ldb, next,
7977 attr->syntax->ldap_oid);
7978 if (ret != LDB_SUCCESS) {
7982 offset = next - pdn_list;
7983 if (offset > old_el->num_values) {
7984 talloc_free(tmp_ctx);
7985 return LDB_ERR_OPERATIONS_ERROR;
7989 old_el->values = talloc_realloc(msg->elements, old_el->values,
7990 struct ldb_val, old_el->num_values+1);
7991 if (!old_el->values) {
7992 ldb_module_oom(module);
7993 return LDB_ERR_OPERATIONS_ERROR;
7996 if (offset != old_el->num_values) {
7997 memmove(&old_el->values[offset + 1], &old_el->values[offset],
7998 (old_el->num_values - offset) * sizeof(old_el->values[0]));
8001 old_el->num_values++;
8003 val_to_update = &old_el->values[offset];
8007 /* set the link attribute's value to the info that was received */
8008 ret = replmd_set_la_val(tmp_ctx, val_to_update, dsdb_dn, old_dsdb_dn,
8009 &la->meta_data.originating_invocation_id,
8010 la->meta_data.originating_usn, seq_num,
8011 la->meta_data.originating_change_time,
8012 la->meta_data.version,
8014 if (ret != LDB_SUCCESS) {
8015 talloc_free(tmp_ctx);
8019 if (add_as_inactive) {
8021 /* Set the new link as inactive/deleted to avoid conflicts */
8022 ret = replmd_delete_link_value(module, replmd_private, old_el,
8023 msg->dn, schema, attr, seq_num,
8024 false, &guid, dsdb_dn,
8027 if (ret != LDB_SUCCESS) {
8028 talloc_free(tmp_ctx);
8032 } else if (active) {
8034 /* if the new link is active, then add the new backlink */
8035 ret = replmd_add_backlink(module, replmd_private,
8040 if (ret != LDB_SUCCESS) {
8041 talloc_free(tmp_ctx);
8046 /* we only change whenChanged and uSNChanged if the seq_num
8048 ret = add_time_element(msg, "whenChanged", t);
8049 if (ret != LDB_SUCCESS) {
8050 talloc_free(tmp_ctx);
8055 ret = add_uint64_element(ldb, msg, "uSNChanged", seq_num);
8056 if (ret != LDB_SUCCESS) {
8057 talloc_free(tmp_ctx);
8062 old_el = ldb_msg_find_element(msg, attr->lDAPDisplayName);
8063 if (old_el == NULL) {
8064 talloc_free(tmp_ctx);
8065 return ldb_operr(ldb);
8068 ret = dsdb_check_single_valued_link(attr, old_el);
8069 if (ret != LDB_SUCCESS) {
8070 talloc_free(tmp_ctx);
8074 old_el->flags |= LDB_FLAG_INTERNAL_DISABLE_SINGLE_VALUE_CHECK;
8076 ret = linked_attr_modify(module, msg, parent);
8077 if (ret != LDB_SUCCESS) {
8078 ldb_debug(ldb, LDB_DEBUG_WARNING, "Failed to apply linked attribute change '%s'\n%s\n",
8080 ldb_ldif_message_redacted_string(ldb,
8082 LDB_CHANGETYPE_MODIFY,
8084 talloc_free(tmp_ctx);
8088 talloc_free(tmp_ctx);
8093 static int replmd_extended(struct ldb_module *module, struct ldb_request *req)
8095 if (strcmp(req->op.extended.oid, DSDB_EXTENDED_REPLICATED_OBJECTS_OID) == 0) {
8096 return replmd_extended_replicated_objects(module, req);
8099 return ldb_next_request(module, req);
8104 we hook into the transaction operations to allow us to
8105 perform the linked attribute updates at the end of the whole
8106 transaction. This allows a forward linked attribute to be created
8107 before the object is created. During a vampire, w2k8 sends us linked
8108 attributes before the objects they are part of.
8110 static int replmd_start_transaction(struct ldb_module *module)
8112 /* create our private structure for this transaction */
8113 struct replmd_private *replmd_private = talloc_get_type(ldb_module_get_private(module),
8114 struct replmd_private);
8115 replmd_txn_cleanup(replmd_private);
8117 /* free any leftover mod_usn records from cancelled
8119 while (replmd_private->ncs) {
8120 struct nc_entry *e = replmd_private->ncs;
8121 DLIST_REMOVE(replmd_private->ncs, e);
8125 replmd_private->originating_updates = false;
8127 return ldb_next_start_trans(module);
8131 on prepare commit we loop over our queued la_context structures and
8134 static int replmd_prepare_commit(struct ldb_module *module)
8136 struct replmd_private *replmd_private =
8137 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
8138 struct la_entry *la, *prev;
8142 * Walk the list of linked attributes from DRS replication.
8144 * We walk backwards, to do the first entry first, as we
8145 * added the entries with DLIST_ADD() which puts them at the
8148 for (la = DLIST_TAIL(replmd_private->la_list); la; la=prev) {
8149 prev = DLIST_PREV(la);
8150 DLIST_REMOVE(replmd_private->la_list, la);
8151 ret = replmd_process_linked_attribute(module, replmd_private,
8153 if (ret != LDB_SUCCESS) {
8154 replmd_txn_cleanup(replmd_private);
8159 replmd_txn_cleanup(replmd_private);
8161 /* possibly change @REPLCHANGED */
8162 ret = replmd_notify_store(module, NULL);
8163 if (ret != LDB_SUCCESS) {
8167 return ldb_next_prepare_commit(module);
8170 static int replmd_del_transaction(struct ldb_module *module)
8172 struct replmd_private *replmd_private =
8173 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
8174 replmd_txn_cleanup(replmd_private);
8176 return ldb_next_del_trans(module);
8180 static const struct ldb_module_ops ldb_repl_meta_data_module_ops = {
8181 .name = "repl_meta_data",
8182 .init_context = replmd_init,
8184 .modify = replmd_modify,
8185 .rename = replmd_rename,
8186 .del = replmd_delete,
8187 .extended = replmd_extended,
8188 .start_transaction = replmd_start_transaction,
8189 .prepare_commit = replmd_prepare_commit,
8190 .del_transaction = replmd_del_transaction,
8193 int ldb_repl_meta_data_module_init(const char *version)
8195 LDB_MODULE_CHECK_VERSION(version);
8196 return ldb_register_module(&ldb_repl_meta_data_module_ops);