4 Copyright (C) Simo Sorce 2004-2008
5 Copyright (C) Andrew Bartlett <abartlet@samba.org> 2005-2013
6 Copyright (C) Andrew Tridgell 2005-2009
7 Copyright (C) Stefan Metzmacher <metze@samba.org> 2007
8 Copyright (C) Matthieu Patou <mat@samba.org> 2010-2011
10 This program is free software; you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation; either version 3 of the License, or
13 (at your option) any later version.
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
20 You should have received a copy of the GNU General Public License
21 along with this program. If not, see <http://www.gnu.org/licenses/>.
27 * Component: ldb repl_meta_data module
29 * Description: - add a unique objectGUID onto every new record,
30 * - handle whenCreated, whenChanged timestamps
31 * - handle uSNCreated, uSNChanged numbers
32 * - handle replPropertyMetaData attribute
35 * Author: Stefan Metzmacher
39 #include "ldb_module.h"
40 #include "dsdb/samdb/samdb.h"
41 #include "dsdb/common/proto.h"
42 #include "dsdb/common/util.h"
43 #include "../libds/common/flags.h"
44 #include "librpc/gen_ndr/irpc.h"
45 #include "librpc/gen_ndr/ndr_misc.h"
46 #include "librpc/gen_ndr/ndr_drsuapi.h"
47 #include "librpc/gen_ndr/ndr_drsblobs.h"
48 #include "param/param.h"
49 #include "libcli/security/security.h"
50 #include "lib/util/dlinklist.h"
51 #include "dsdb/samdb/ldb_modules/util.h"
52 #include "lib/util/tsort.h"
55 #define DBGC_CLASS DBGC_DRS_REPL
57 /* the RMD_VERSION for linked attributes starts from 1 */
58 #define RMD_VERSION_INITIAL 1
61 * It's 29/12/9999 at 23:59:59 UTC as specified in MS-ADTS 7.1.1.4.2
62 * Deleted Objects Container
64 static const NTTIME DELETED_OBJECT_CONTAINER_CHANGE_TIME = 2650466015990000000ULL;
66 struct replmd_private {
68 struct la_entry *la_list;
70 struct nc_entry *prev, *next;
73 uint64_t mod_usn_urgent;
75 struct ldb_dn *schema_dn;
76 bool originating_updates;
81 struct la_entry *next, *prev;
82 struct drsuapi_DsReplicaLinkedAttribute *la;
83 uint32_t dsdb_repl_flags;
86 struct replmd_replicated_request {
87 struct ldb_module *module;
88 struct ldb_request *req;
90 const struct dsdb_schema *schema;
91 struct GUID our_invocation_id;
93 /* the controls we pass down */
94 struct ldb_control **controls;
97 * Backlinks for the replmd_add() case (we want to create
98 * backlinks after creating the user, but before the end of
101 struct la_backlink *la_backlinks;
103 /* details for the mode where we apply a bunch of inbound replication meessages */
105 uint32_t index_current;
106 struct dsdb_extended_replicated_objects *objs;
108 struct ldb_message *search_msg;
109 struct GUID local_parent_guid;
117 static int replmd_replicated_apply_merge(struct replmd_replicated_request *ar);
118 static int replmd_delete_internals(struct ldb_module *module, struct ldb_request *req, bool re_delete);
119 static int replmd_check_upgrade_links(struct ldb_context *ldb,
120 struct parsed_dn *dns, uint32_t count,
121 struct ldb_message_element *el,
122 const char *ldap_oid);
123 static int replmd_verify_linked_attribute(struct replmd_replicated_request *ar,
124 struct la_entry *la);
125 static int replmd_set_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct dsdb_dn *dsdb_dn,
126 struct dsdb_dn *old_dsdb_dn, const struct GUID *invocation_id,
127 uint64_t usn, uint64_t local_usn, NTTIME nttime,
128 uint32_t version, bool deleted);
130 static int replmd_make_deleted_child_dn(TALLOC_CTX *tmp_ctx,
131 struct ldb_context *ldb,
133 const char *rdn_name,
134 const struct ldb_val *rdn_value,
137 enum urgent_situation {
138 REPL_URGENT_ON_CREATE = 1,
139 REPL_URGENT_ON_UPDATE = 2,
140 REPL_URGENT_ON_DELETE = 4
143 enum deletion_state {
144 OBJECT_NOT_DELETED=1,
151 static void replmd_deletion_state(struct ldb_module *module,
152 const struct ldb_message *msg,
153 enum deletion_state *current_state,
154 enum deletion_state *next_state)
157 bool enabled = false;
160 *current_state = OBJECT_REMOVED;
161 if (next_state != NULL) {
162 *next_state = OBJECT_REMOVED;
167 ret = dsdb_recyclebin_enabled(module, &enabled);
168 if (ret != LDB_SUCCESS) {
172 if (ldb_msg_check_string_attribute(msg, "isDeleted", "TRUE")) {
174 *current_state = OBJECT_TOMBSTONE;
175 if (next_state != NULL) {
176 *next_state = OBJECT_REMOVED;
181 if (ldb_msg_check_string_attribute(msg, "isRecycled", "TRUE")) {
182 *current_state = OBJECT_RECYCLED;
183 if (next_state != NULL) {
184 *next_state = OBJECT_REMOVED;
189 *current_state = OBJECT_DELETED;
190 if (next_state != NULL) {
191 *next_state = OBJECT_RECYCLED;
196 *current_state = OBJECT_NOT_DELETED;
197 if (next_state == NULL) {
202 *next_state = OBJECT_DELETED;
204 *next_state = OBJECT_TOMBSTONE;
208 static const struct {
209 const char *update_name;
210 enum urgent_situation repl_situation;
211 } urgent_objects[] = {
212 {"nTDSDSA", (REPL_URGENT_ON_CREATE | REPL_URGENT_ON_DELETE)},
213 {"crossRef", (REPL_URGENT_ON_CREATE | REPL_URGENT_ON_DELETE)},
214 {"attributeSchema", (REPL_URGENT_ON_CREATE | REPL_URGENT_ON_UPDATE)},
215 {"classSchema", (REPL_URGENT_ON_CREATE | REPL_URGENT_ON_UPDATE)},
216 {"secret", (REPL_URGENT_ON_CREATE | REPL_URGENT_ON_UPDATE)},
217 {"rIDManager", (REPL_URGENT_ON_CREATE | REPL_URGENT_ON_UPDATE)},
221 /* Attributes looked for when updating or deleting, to check for a urgent replication needed */
222 static const char *urgent_attrs[] = {
225 "userAccountControl",
230 static bool replmd_check_urgent_objectclass(const struct ldb_message_element *objectclass_el,
231 enum urgent_situation situation)
234 for (i=0; urgent_objects[i].update_name; i++) {
236 if ((situation & urgent_objects[i].repl_situation) == 0) {
240 for (j=0; j<objectclass_el->num_values; j++) {
241 const struct ldb_val *v = &objectclass_el->values[j];
242 if (ldb_attr_cmp((const char *)v->data, urgent_objects[i].update_name) == 0) {
250 static bool replmd_check_urgent_attribute(const struct ldb_message_element *el)
252 if (ldb_attr_in_list(urgent_attrs, el->name)) {
258 static int replmd_replicated_apply_isDeleted(struct replmd_replicated_request *ar);
261 initialise the module
262 allocate the private structure and build the list
263 of partition DNs for use by replmd_notify()
265 static int replmd_init(struct ldb_module *module)
267 struct replmd_private *replmd_private;
268 struct ldb_context *ldb = ldb_module_get_ctx(module);
269 static const char *samba_dsdb_attrs[] = { SAMBA_COMPATIBLE_FEATURES_ATTR, NULL };
270 struct ldb_dn *samba_dsdb_dn;
271 struct ldb_result *res;
273 TALLOC_CTX *frame = talloc_stackframe();
274 replmd_private = talloc_zero(module, struct replmd_private);
275 if (replmd_private == NULL) {
278 return LDB_ERR_OPERATIONS_ERROR;
280 ldb_module_set_private(module, replmd_private);
282 replmd_private->schema_dn = ldb_get_schema_basedn(ldb);
284 samba_dsdb_dn = ldb_dn_new(frame, ldb, "@SAMBA_DSDB");
285 if (!samba_dsdb_dn) {
290 ret = dsdb_module_search_dn(module, frame, &res, samba_dsdb_dn,
291 samba_dsdb_attrs, DSDB_FLAG_NEXT_MODULE, NULL);
292 if (ret == LDB_SUCCESS) {
293 replmd_private->sorted_links
294 = ldb_msg_check_string_attribute(res->msgs[0],
295 SAMBA_COMPATIBLE_FEATURES_ATTR,
296 SAMBA_SORTED_LINKS_FEATURE);
300 return ldb_next_init(module);
304 cleanup our per-transaction contexts
306 static void replmd_txn_cleanup(struct replmd_private *replmd_private)
308 talloc_free(replmd_private->la_ctx);
309 replmd_private->la_list = NULL;
310 replmd_private->la_ctx = NULL;
316 struct la_backlink *next, *prev;
317 const char *attr_name;
318 struct ldb_dn *forward_dn;
319 struct GUID target_guid;
324 a ldb_modify request operating on modules below the
327 static int linked_attr_modify(struct ldb_module *module,
328 const struct ldb_message *message,
329 struct ldb_request *parent)
331 struct ldb_request *mod_req;
333 struct ldb_context *ldb = ldb_module_get_ctx(module);
334 TALLOC_CTX *tmp_ctx = talloc_new(module);
335 struct ldb_result *res;
337 res = talloc_zero(tmp_ctx, struct ldb_result);
339 talloc_free(tmp_ctx);
340 return ldb_oom(ldb_module_get_ctx(module));
343 ret = ldb_build_mod_req(&mod_req, ldb, tmp_ctx,
347 ldb_modify_default_callback,
349 LDB_REQ_SET_LOCATION(mod_req);
350 if (ret != LDB_SUCCESS) {
351 talloc_free(tmp_ctx);
355 ret = ldb_request_add_control(mod_req, DSDB_CONTROL_REPLICATED_UPDATE_OID,
357 if (ret != LDB_SUCCESS) {
361 /* Run the new request */
362 ret = ldb_next_request(module, mod_req);
364 if (ret == LDB_SUCCESS) {
365 ret = ldb_wait(mod_req->handle, LDB_WAIT_ALL);
368 talloc_free(tmp_ctx);
373 process a backlinks we accumulated during a transaction, adding and
374 deleting the backlinks from the target objects
376 static int replmd_process_backlink(struct ldb_module *module, struct la_backlink *bl, struct ldb_request *parent)
378 struct ldb_dn *target_dn, *source_dn;
380 struct ldb_context *ldb = ldb_module_get_ctx(module);
381 struct ldb_message *msg;
382 TALLOC_CTX *frame = talloc_stackframe();
388 - construct ldb_message
389 - either an add or a delete
391 ret = dsdb_module_dn_by_guid(module, frame, &bl->target_guid, &target_dn, parent);
392 if (ret != LDB_SUCCESS) {
393 struct GUID_txt_buf guid_str;
394 DBG_WARNING("Failed to find target DN for linked attribute with GUID %s\n",
395 GUID_buf_string(&bl->target_guid, &guid_str));
396 DBG_WARNING("Please run 'samba-tool dbcheck' to resolve any missing backlinks.\n");
401 msg = ldb_msg_new(frame);
403 ldb_module_oom(module);
405 return LDB_ERR_OPERATIONS_ERROR;
408 source_dn = ldb_dn_copy(frame, bl->forward_dn);
410 ldb_module_oom(module);
412 return LDB_ERR_OPERATIONS_ERROR;
414 /* Filter down to the attributes we want in the backlink */
415 const char *accept[] = { "GUID", "SID", NULL };
416 ldb_dn_extended_filter(source_dn, accept);
419 /* construct a ldb_message for adding/deleting the backlink */
421 dn_string = ldb_dn_get_extended_linearized(frame, bl->forward_dn, 1);
423 ldb_module_oom(module);
425 return LDB_ERR_OPERATIONS_ERROR;
427 ret = ldb_msg_add_steal_string(msg, bl->attr_name, dn_string);
428 if (ret != LDB_SUCCESS) {
432 msg->elements[0].flags = bl->active?LDB_FLAG_MOD_ADD:LDB_FLAG_MOD_DELETE;
434 /* a backlink should never be single valued. Unfortunately the
435 exchange schema has a attribute
436 msExchBridgeheadedLocalConnectorsDNBL which is single
437 valued and a backlink. We need to cope with that by
438 ignoring the single value flag */
439 msg->elements[0].flags |= LDB_FLAG_INTERNAL_DISABLE_SINGLE_VALUE_CHECK;
441 ret = dsdb_module_modify(module, msg, DSDB_FLAG_NEXT_MODULE, parent);
442 if (ret == LDB_ERR_NO_SUCH_ATTRIBUTE && !bl->active) {
443 /* we allow LDB_ERR_NO_SUCH_ATTRIBUTE as success to
444 cope with possible corruption where the backlink has
445 already been removed */
446 DEBUG(3,("WARNING: backlink from %s already removed from %s - %s\n",
447 ldb_dn_get_linearized(target_dn),
448 ldb_dn_get_linearized(source_dn),
449 ldb_errstring(ldb)));
451 } else if (ret != LDB_SUCCESS) {
452 ldb_asprintf_errstring(ldb, "Failed to %s backlink from %s to %s - %s",
453 bl->active?"add":"remove",
454 ldb_dn_get_linearized(source_dn),
455 ldb_dn_get_linearized(target_dn),
465 add a backlink to the list of backlinks to add/delete in the prepare
468 forward_dn is stolen onto the defereed context
470 static int replmd_defer_add_backlink(struct ldb_module *module,
471 struct replmd_private *replmd_private,
472 const struct dsdb_schema *schema,
473 struct replmd_replicated_request *ac,
474 struct ldb_dn *forward_dn,
475 struct GUID *target_guid, bool active,
476 const struct dsdb_attribute *schema_attr,
477 struct ldb_request *parent)
479 const struct dsdb_attribute *target_attr;
480 struct la_backlink *bl;
482 bl = talloc(ac, struct la_backlink);
484 ldb_module_oom(module);
485 return LDB_ERR_OPERATIONS_ERROR;
488 target_attr = dsdb_attribute_by_linkID(schema, schema_attr->linkID ^ 1);
491 * windows 2003 has a broken schema where the
492 * definition of msDS-IsDomainFor is missing (which is
493 * supposed to be the backlink of the
494 * msDS-HasDomainNCs attribute
499 bl->attr_name = target_attr->lDAPDisplayName;
500 bl->forward_dn = talloc_steal(bl, forward_dn);
501 bl->target_guid = *target_guid;
504 DLIST_ADD(ac->la_backlinks, bl);
510 add a backlink to the list of backlinks to add/delete in the prepare
513 static int replmd_add_backlink(struct ldb_module *module,
514 struct replmd_private *replmd_private,
515 const struct dsdb_schema *schema,
516 struct ldb_dn *forward_dn,
517 struct GUID *target_guid, bool active,
518 const struct dsdb_attribute *schema_attr,
519 struct ldb_request *parent)
521 const struct dsdb_attribute *target_attr;
522 struct la_backlink bl;
525 target_attr = dsdb_attribute_by_linkID(schema, schema_attr->linkID ^ 1);
528 * windows 2003 has a broken schema where the
529 * definition of msDS-IsDomainFor is missing (which is
530 * supposed to be the backlink of the
531 * msDS-HasDomainNCs attribute
536 bl.attr_name = target_attr->lDAPDisplayName;
537 bl.forward_dn = forward_dn;
538 bl.target_guid = *target_guid;
541 ret = replmd_process_backlink(module, &bl, parent);
547 * Callback for most write operations in this module:
549 * notify the repl task that a object has changed. The notifies are
550 * gathered up in the replmd_private structure then written to the
551 * @REPLCHANGED object in each partition during the prepare_commit
553 static int replmd_op_callback(struct ldb_request *req, struct ldb_reply *ares)
556 struct replmd_replicated_request *ac =
557 talloc_get_type_abort(req->context, struct replmd_replicated_request);
558 struct replmd_private *replmd_private =
559 talloc_get_type_abort(ldb_module_get_private(ac->module), struct replmd_private);
560 struct nc_entry *modified_partition;
561 struct ldb_control *partition_ctrl;
562 const struct dsdb_control_current_partition *partition;
564 struct ldb_control **controls;
566 partition_ctrl = ldb_reply_get_control(ares, DSDB_CONTROL_CURRENT_PARTITION_OID);
568 controls = ares->controls;
569 if (ldb_request_get_control(ac->req,
570 DSDB_CONTROL_CURRENT_PARTITION_OID) == NULL) {
572 * Remove the current partition control from what we pass up
573 * the chain if it hasn't been requested manually.
575 controls = ldb_controls_except_specified(ares->controls, ares,
579 if (ares->error != LDB_SUCCESS) {
580 struct GUID_txt_buf guid_txt;
581 struct ldb_message *msg = NULL;
584 if (ac->apply_mode == false) {
585 DBG_NOTICE("Originating update failure. Error is: %s\n",
586 ldb_strerror(ares->error));
587 return ldb_module_done(ac->req, controls,
588 ares->response, ares->error);
591 msg = ac->objs->objects[ac->index_current].msg;
593 * Set at DBG_NOTICE as once these start to happe, they
594 * will happen a lot until resolved, due to repeated
595 * replication. The caller will probably print the
596 * ldb error string anyway.
598 DBG_NOTICE("DRS replication apply failure for %s. Error is: %s\n",
599 ldb_dn_get_linearized(msg->dn),
600 ldb_strerror(ares->error));
602 s = ldb_ldif_message_redacted_string(ldb_module_get_ctx(ac->module),
607 DBG_INFO("Failing DRS %s replication message was %s:\n%s\n",
608 ac->search_msg == NULL ? "ADD" : "MODIFY",
609 GUID_buf_string(&ac->objs->objects[ac->index_current].object_guid,
613 return ldb_module_done(ac->req, controls,
614 ares->response, ares->error);
617 if (ares->type != LDB_REPLY_DONE) {
618 ldb_set_errstring(ldb_module_get_ctx(ac->module), "Invalid reply type for notify\n!");
619 return ldb_module_done(ac->req, NULL,
620 NULL, LDB_ERR_OPERATIONS_ERROR);
623 if (ac->apply_mode == false) {
624 struct la_backlink *bl;
626 * process our backlink list after an replmd_add(),
627 * creating and deleting backlinks as necessary (this
628 * code is sync). The other cases are handled inline
631 for (bl=ac->la_backlinks; bl; bl=bl->next) {
632 ret = replmd_process_backlink(ac->module, bl, ac->req);
633 if (ret != LDB_SUCCESS) {
634 return ldb_module_done(ac->req, NULL,
640 if (!partition_ctrl) {
641 ldb_set_errstring(ldb_module_get_ctx(ac->module),"No partition control on reply");
642 return ldb_module_done(ac->req, NULL,
643 NULL, LDB_ERR_OPERATIONS_ERROR);
646 partition = talloc_get_type_abort(partition_ctrl->data,
647 struct dsdb_control_current_partition);
649 if (ac->seq_num > 0) {
650 for (modified_partition = replmd_private->ncs; modified_partition;
651 modified_partition = modified_partition->next) {
652 if (ldb_dn_compare(modified_partition->dn, partition->dn) == 0) {
657 if (modified_partition == NULL) {
658 modified_partition = talloc_zero(replmd_private, struct nc_entry);
659 if (!modified_partition) {
660 ldb_oom(ldb_module_get_ctx(ac->module));
661 return ldb_module_done(ac->req, NULL,
662 NULL, LDB_ERR_OPERATIONS_ERROR);
664 modified_partition->dn = ldb_dn_copy(modified_partition, partition->dn);
665 if (!modified_partition->dn) {
666 ldb_oom(ldb_module_get_ctx(ac->module));
667 return ldb_module_done(ac->req, NULL,
668 NULL, LDB_ERR_OPERATIONS_ERROR);
670 DLIST_ADD(replmd_private->ncs, modified_partition);
673 if (ac->seq_num > modified_partition->mod_usn) {
674 modified_partition->mod_usn = ac->seq_num;
676 modified_partition->mod_usn_urgent = ac->seq_num;
679 if (!ac->apply_mode) {
680 replmd_private->originating_updates = true;
684 if (ac->apply_mode) {
685 ret = replmd_replicated_apply_isDeleted(ac);
686 if (ret != LDB_SUCCESS) {
687 return ldb_module_done(ac->req, NULL, NULL, ret);
691 /* free the partition control container here, for the
692 * common path. Other cases will have it cleaned up
693 * eventually with the ares */
694 talloc_free(partition_ctrl);
695 return ldb_module_done(ac->req, controls,
696 ares->response, LDB_SUCCESS);
702 * update a @REPLCHANGED record in each partition if there have been
703 * any writes of replicated data in the partition
705 static int replmd_notify_store(struct ldb_module *module, struct ldb_request *parent)
707 struct replmd_private *replmd_private =
708 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
710 while (replmd_private->ncs) {
712 struct nc_entry *modified_partition = replmd_private->ncs;
714 ret = dsdb_module_save_partition_usn(module, modified_partition->dn,
715 modified_partition->mod_usn,
716 modified_partition->mod_usn_urgent, parent);
717 if (ret != LDB_SUCCESS) {
718 DEBUG(0,(__location__ ": Failed to save partition uSN for %s\n",
719 ldb_dn_get_linearized(modified_partition->dn)));
723 if (ldb_dn_compare(modified_partition->dn,
724 replmd_private->schema_dn) == 0) {
725 struct ldb_result *ext_res;
726 ret = dsdb_module_extended(module,
727 replmd_private->schema_dn,
729 DSDB_EXTENDED_SCHEMA_UPDATE_NOW_OID,
731 DSDB_FLAG_NEXT_MODULE,
733 if (ret != LDB_SUCCESS) {
736 talloc_free(ext_res);
739 DLIST_REMOVE(replmd_private->ncs, modified_partition);
740 talloc_free(modified_partition);
748 created a replmd_replicated_request context
750 static struct replmd_replicated_request *replmd_ctx_init(struct ldb_module *module,
751 struct ldb_request *req)
753 struct ldb_context *ldb;
754 struct replmd_replicated_request *ac;
755 const struct GUID *our_invocation_id;
757 ldb = ldb_module_get_ctx(module);
759 ac = talloc_zero(req, struct replmd_replicated_request);
768 ac->schema = dsdb_get_schema(ldb, ac);
770 ldb_debug_set(ldb, LDB_DEBUG_FATAL,
771 "replmd_modify: no dsdb_schema loaded");
772 DEBUG(0,(__location__ ": %s\n", ldb_errstring(ldb)));
777 /* get our invocationId */
778 our_invocation_id = samdb_ntds_invocation_id(ldb);
779 if (!our_invocation_id) {
780 ldb_debug_set(ldb, LDB_DEBUG_FATAL,
781 "replmd_add: unable to find invocationId\n");
785 ac->our_invocation_id = *our_invocation_id;
791 add a time element to a record
793 static int add_time_element(struct ldb_message *msg, const char *attr, time_t t)
795 struct ldb_message_element *el;
799 if (ldb_msg_find_element(msg, attr) != NULL) {
803 s = ldb_timestring(msg, t);
805 return LDB_ERR_OPERATIONS_ERROR;
808 ret = ldb_msg_add_string(msg, attr, s);
809 if (ret != LDB_SUCCESS) {
813 el = ldb_msg_find_element(msg, attr);
814 /* always set as replace. This works because on add ops, the flag
816 el->flags = LDB_FLAG_MOD_REPLACE;
822 add a uint64_t element to a record
824 static int add_uint64_element(struct ldb_context *ldb, struct ldb_message *msg,
825 const char *attr, uint64_t v)
827 struct ldb_message_element *el;
830 if (ldb_msg_find_element(msg, attr) != NULL) {
834 ret = samdb_msg_add_uint64(ldb, msg, msg, attr, v);
835 if (ret != LDB_SUCCESS) {
839 el = ldb_msg_find_element(msg, attr);
840 /* always set as replace. This works because on add ops, the flag
842 el->flags = LDB_FLAG_MOD_REPLACE;
847 static int replmd_replPropertyMetaData1_attid_sort(const struct replPropertyMetaData1 *m1,
848 const struct replPropertyMetaData1 *m2,
849 const uint32_t *rdn_attid)
852 * This assignment seems inoccous, but it is critical for the
853 * system, as we need to do the comparisons as a unsigned
854 * quantity, not signed (enums are signed integers)
856 uint32_t attid_1 = m1->attid;
857 uint32_t attid_2 = m2->attid;
859 if (attid_1 == attid_2) {
864 * See above regarding this being an unsigned comparison.
865 * Otherwise when the high bit is set on non-standard
866 * attributes, they would end up first, before objectClass
869 return attid_1 > attid_2 ? 1 : -1;
872 static int replmd_replPropertyMetaDataCtr1_verify(struct ldb_context *ldb,
873 struct replPropertyMetaDataCtr1 *ctr1,
876 if (ctr1->count == 0) {
877 ldb_debug_set(ldb, LDB_DEBUG_FATAL,
878 "No elements found in replPropertyMetaData for %s!\n",
879 ldb_dn_get_linearized(dn));
880 return LDB_ERR_CONSTRAINT_VIOLATION;
883 /* the objectClass attribute is value 0x00000000, so must be first */
884 if (ctr1->array[0].attid != DRSUAPI_ATTID_objectClass) {
885 ldb_debug_set(ldb, LDB_DEBUG_FATAL,
886 "No objectClass found in replPropertyMetaData for %s!\n",
887 ldb_dn_get_linearized(dn));
888 return LDB_ERR_OBJECT_CLASS_VIOLATION;
894 static int replmd_replPropertyMetaDataCtr1_sort_and_verify(struct ldb_context *ldb,
895 struct replPropertyMetaDataCtr1 *ctr1,
898 /* Note this is O(n^2) for the almost-sorted case, which this is */
899 LDB_TYPESAFE_QSORT(ctr1->array, ctr1->count, NULL,
900 replmd_replPropertyMetaData1_attid_sort);
901 return replmd_replPropertyMetaDataCtr1_verify(ldb, ctr1, dn);
904 static int replmd_ldb_message_element_attid_sort(const struct ldb_message_element *e1,
905 const struct ldb_message_element *e2,
906 const struct dsdb_schema *schema)
908 const struct dsdb_attribute *a1;
909 const struct dsdb_attribute *a2;
912 * TODO: make this faster by caching the dsdb_attribute pointer
913 * on the ldb_messag_element
916 a1 = dsdb_attribute_by_lDAPDisplayName(schema, e1->name);
917 a2 = dsdb_attribute_by_lDAPDisplayName(schema, e2->name);
920 * TODO: remove this check, we should rely on e1 and e2 having valid attribute names
924 return strcasecmp(e1->name, e2->name);
926 if (a1->attributeID_id == a2->attributeID_id) {
929 return a1->attributeID_id > a2->attributeID_id ? 1 : -1;
932 static void replmd_ldb_message_sort(struct ldb_message *msg,
933 const struct dsdb_schema *schema)
935 LDB_TYPESAFE_QSORT(msg->elements, msg->num_elements, schema, replmd_ldb_message_element_attid_sort);
938 static int replmd_build_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct dsdb_dn *dsdb_dn,
939 const struct GUID *invocation_id,
940 uint64_t local_usn, NTTIME nttime);
942 static int parsed_dn_compare(struct parsed_dn *pdn1, struct parsed_dn *pdn2);
944 static int get_parsed_dns(struct ldb_module *module, TALLOC_CTX *mem_ctx,
945 struct ldb_message_element *el, struct parsed_dn **pdn,
946 const char *ldap_oid, struct ldb_request *parent);
948 static int check_parsed_dn_duplicates(struct ldb_module *module,
949 struct ldb_message_element *el,
950 struct parsed_dn *pdn);
953 fix up linked attributes in replmd_add.
954 This involves setting up the right meta-data in extended DN
955 components, and creating backlinks to the object
957 static int replmd_add_fix_la(struct ldb_module *module, TALLOC_CTX *mem_ctx,
958 struct replmd_private *replmd_private,
959 struct ldb_message_element *el,
960 struct replmd_replicated_request *ac,
962 struct ldb_dn *forward_dn,
963 const struct dsdb_attribute *sa,
964 struct ldb_request *parent)
967 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
968 struct ldb_context *ldb = ldb_module_get_ctx(module);
969 struct parsed_dn *pdn;
970 /* We will take a reference to the schema in replmd_add_backlink */
971 const struct dsdb_schema *schema = dsdb_get_schema(ldb, NULL);
972 struct ldb_val *new_values = NULL;
975 if (dsdb_check_single_valued_link(sa, el) == LDB_SUCCESS) {
976 el->flags |= LDB_FLAG_INTERNAL_DISABLE_SINGLE_VALUE_CHECK;
978 ldb_asprintf_errstring(ldb,
979 "Attribute %s is single valued but "
980 "more than one value has been supplied",
982 talloc_free(tmp_ctx);
983 return LDB_ERR_CONSTRAINT_VIOLATION;
986 ret = get_parsed_dns(module, tmp_ctx, el, &pdn,
987 sa->syntax->ldap_oid, parent);
988 if (ret != LDB_SUCCESS) {
989 talloc_free(tmp_ctx);
993 ret = check_parsed_dn_duplicates(module, el, pdn);
994 if (ret != LDB_SUCCESS) {
995 talloc_free(tmp_ctx);
999 new_values = talloc_array(tmp_ctx, struct ldb_val, el->num_values);
1000 if (new_values == NULL) {
1001 ldb_module_oom(module);
1002 talloc_free(tmp_ctx);
1003 return LDB_ERR_OPERATIONS_ERROR;
1006 for (i = 0; i < el->num_values; i++) {
1007 struct parsed_dn *p = &pdn[i];
1008 ret = replmd_build_la_val(el->values, p->v, p->dsdb_dn,
1009 &ac->our_invocation_id,
1011 if (ret != LDB_SUCCESS) {
1012 talloc_free(tmp_ctx);
1016 ret = replmd_defer_add_backlink(module, replmd_private,
1018 forward_dn, &p->guid, true, sa,
1020 if (ret != LDB_SUCCESS) {
1021 talloc_free(tmp_ctx);
1025 new_values[i] = *p->v;
1027 el->values = talloc_steal(mem_ctx, new_values);
1029 talloc_free(tmp_ctx);
1033 static int replmd_add_make_extended_dn(struct ldb_request *req,
1034 const DATA_BLOB *guid_blob,
1035 struct ldb_dn **_extended_dn)
1038 const DATA_BLOB *sid_blob;
1039 /* Calculate an extended DN for any linked attributes */
1040 struct ldb_dn *extended_dn = ldb_dn_copy(req, req->op.add.message->dn);
1042 return LDB_ERR_OPERATIONS_ERROR;
1044 ret = ldb_dn_set_extended_component(extended_dn, "GUID", guid_blob);
1045 if (ret != LDB_SUCCESS) {
1049 sid_blob = ldb_msg_find_ldb_val(req->op.add.message, "objectSID");
1050 if (sid_blob != NULL) {
1051 ret = ldb_dn_set_extended_component(extended_dn, "SID", sid_blob);
1052 if (ret != LDB_SUCCESS) {
1056 *_extended_dn = extended_dn;
1061 intercept add requests
1063 static int replmd_add(struct ldb_module *module, struct ldb_request *req)
1065 struct ldb_context *ldb;
1066 struct ldb_control *control;
1067 struct replmd_replicated_request *ac;
1068 enum ndr_err_code ndr_err;
1069 struct ldb_request *down_req;
1070 struct ldb_message *msg;
1071 const DATA_BLOB *guid_blob;
1072 DATA_BLOB guid_blob_stack;
1074 uint8_t guid_data[16];
1075 struct replPropertyMetaDataBlob nmd;
1076 struct ldb_val nmd_value;
1077 struct ldb_dn *extended_dn = NULL;
1080 * The use of a time_t here seems odd, but as the NTTIME
1081 * elements are actually declared as NTTIME_1sec in the IDL,
1082 * getting a higher resolution timestamp is not required.
1084 time_t t = time(NULL);
1089 unsigned int functional_level;
1091 bool allow_add_guid = false;
1092 bool remove_current_guid = false;
1093 bool is_urgent = false;
1094 bool is_schema_nc = false;
1095 struct ldb_message_element *objectclass_el;
1096 struct replmd_private *replmd_private =
1097 talloc_get_type_abort(ldb_module_get_private(module), struct replmd_private);
1099 /* check if there's a show relax control (used by provision to say 'I know what I'm doing') */
1100 control = ldb_request_get_control(req, LDB_CONTROL_RELAX_OID);
1102 allow_add_guid = true;
1105 /* do not manipulate our control entries */
1106 if (ldb_dn_is_special(req->op.add.message->dn)) {
1107 return ldb_next_request(module, req);
1110 ldb = ldb_module_get_ctx(module);
1112 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_add\n");
1114 guid_blob = ldb_msg_find_ldb_val(req->op.add.message, "objectGUID");
1115 if (guid_blob != NULL) {
1116 if (!allow_add_guid) {
1117 ldb_set_errstring(ldb,
1118 "replmd_add: it's not allowed to add an object with objectGUID!");
1119 return LDB_ERR_UNWILLING_TO_PERFORM;
1121 NTSTATUS status = GUID_from_data_blob(guid_blob,&guid);
1122 if (!NT_STATUS_IS_OK(status)) {
1123 ldb_set_errstring(ldb,
1124 "replmd_add: Unable to parse the 'objectGUID' as a GUID!");
1125 return LDB_ERR_UNWILLING_TO_PERFORM;
1127 /* we remove this attribute as it can be a string and
1128 * will not be treated correctly and then we will re-add
1129 * it later on in the good format */
1130 remove_current_guid = true;
1134 guid = GUID_random();
1136 guid_blob_stack = data_blob_const(guid_data, sizeof(guid_data));
1138 /* This can't fail */
1139 ndr_push_struct_into_fixed_blob(&guid_blob_stack, &guid,
1140 (ndr_push_flags_fn_t)ndr_push_GUID);
1141 guid_blob = &guid_blob_stack;
1144 ac = replmd_ctx_init(module, req);
1146 return ldb_module_oom(module);
1149 functional_level = dsdb_functional_level(ldb);
1151 /* Get a sequence number from the backend */
1152 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &ac->seq_num);
1153 if (ret != LDB_SUCCESS) {
1158 /* we have to copy the message as the caller might have it as a const */
1159 msg = ldb_msg_copy_shallow(ac, req->op.add.message);
1163 return LDB_ERR_OPERATIONS_ERROR;
1166 /* generated times */
1167 unix_to_nt_time(&now, t);
1168 time_str = ldb_timestring(msg, t);
1172 return LDB_ERR_OPERATIONS_ERROR;
1174 if (remove_current_guid) {
1175 ldb_msg_remove_attr(msg,"objectGUID");
1179 * remove autogenerated attributes
1181 ldb_msg_remove_attr(msg, "whenCreated");
1182 ldb_msg_remove_attr(msg, "whenChanged");
1183 ldb_msg_remove_attr(msg, "uSNCreated");
1184 ldb_msg_remove_attr(msg, "uSNChanged");
1185 ldb_msg_remove_attr(msg, "replPropertyMetaData");
1188 * readd replicated attributes
1190 ret = ldb_msg_add_string(msg, "whenCreated", time_str);
1191 if (ret != LDB_SUCCESS) {
1197 /* build the replication meta_data */
1200 nmd.ctr.ctr1.count = msg->num_elements;
1201 nmd.ctr.ctr1.array = talloc_array(msg,
1202 struct replPropertyMetaData1,
1203 nmd.ctr.ctr1.count);
1204 if (!nmd.ctr.ctr1.array) {
1207 return LDB_ERR_OPERATIONS_ERROR;
1210 is_schema_nc = ldb_dn_compare_base(replmd_private->schema_dn, msg->dn) == 0;
1212 for (i=0; i < msg->num_elements;) {
1213 struct ldb_message_element *e = &msg->elements[i];
1214 struct replPropertyMetaData1 *m = &nmd.ctr.ctr1.array[ni];
1215 const struct dsdb_attribute *sa;
1217 if (e->name[0] == '@') {
1222 sa = dsdb_attribute_by_lDAPDisplayName(ac->schema, e->name);
1224 ldb_debug_set(ldb, LDB_DEBUG_ERROR,
1225 "replmd_add: attribute '%s' not defined in schema\n",
1228 return LDB_ERR_NO_SUCH_ATTRIBUTE;
1231 if ((sa->systemFlags & DS_FLAG_ATTR_NOT_REPLICATED) || (sa->systemFlags & DS_FLAG_ATTR_IS_CONSTRUCTED)) {
1232 /* if the attribute is not replicated (0x00000001)
1233 * or constructed (0x00000004) it has no metadata
1239 if (sa->linkID != 0 && functional_level > DS_DOMAIN_FUNCTION_2000) {
1240 if (extended_dn == NULL) {
1241 ret = replmd_add_make_extended_dn(req,
1244 if (ret != LDB_SUCCESS) {
1251 * Prepare the context for the backlinks and
1252 * create metadata for the forward links. The
1253 * backlinks are created in
1254 * replmd_op_callback() after the successful
1255 * ADD of the object.
1257 ret = replmd_add_fix_la(module, msg->elements,
1262 if (ret != LDB_SUCCESS) {
1266 /* linked attributes are not stored in
1267 replPropertyMetaData in FL above w2k */
1272 m->attid = dsdb_attribute_get_attid(sa, is_schema_nc);
1274 if (m->attid == DRSUAPI_ATTID_isDeleted) {
1275 const struct ldb_val *rdn_val = ldb_dn_get_rdn_val(msg->dn);
1278 if (rdn_val == NULL) {
1281 return LDB_ERR_OPERATIONS_ERROR;
1284 rdn = (const char*)rdn_val->data;
1285 if (strcmp(rdn, "Deleted Objects") == 0) {
1287 * Set the originating_change_time to 29/12/9999 at 23:59:59
1288 * as specified in MS-ADTS 7.1.1.4.2 Deleted Objects Container
1290 m->originating_change_time = DELETED_OBJECT_CONTAINER_CHANGE_TIME;
1292 m->originating_change_time = now;
1295 m->originating_change_time = now;
1297 m->originating_invocation_id = ac->our_invocation_id;
1298 m->originating_usn = ac->seq_num;
1299 m->local_usn = ac->seq_num;
1302 if (!(e->flags & DSDB_FLAG_INTERNAL_FORCE_META_DATA)) {
1307 e->flags &= ~DSDB_FLAG_INTERNAL_FORCE_META_DATA;
1309 if (e->num_values != 0) {
1314 ldb_msg_remove_element(msg, e);
1317 /* fix meta data count */
1318 nmd.ctr.ctr1.count = ni;
1321 * sort meta data array
1323 ret = replmd_replPropertyMetaDataCtr1_sort_and_verify(ldb, &nmd.ctr.ctr1, msg->dn);
1324 if (ret != LDB_SUCCESS) {
1325 ldb_asprintf_errstring(ldb, "%s: error during direct ADD: %s", __func__, ldb_errstring(ldb));
1330 /* generated NDR encoded values */
1331 ndr_err = ndr_push_struct_blob(&nmd_value, msg,
1333 (ndr_push_flags_fn_t)ndr_push_replPropertyMetaDataBlob);
1334 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1337 return LDB_ERR_OPERATIONS_ERROR;
1341 * add the autogenerated values
1343 ret = dsdb_msg_add_guid(msg, &guid, "objectGUID");
1344 if (ret != LDB_SUCCESS) {
1349 ret = ldb_msg_add_string(msg, "whenChanged", time_str);
1350 if (ret != LDB_SUCCESS) {
1355 ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNCreated", ac->seq_num);
1356 if (ret != LDB_SUCCESS) {
1361 ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNChanged", ac->seq_num);
1362 if (ret != LDB_SUCCESS) {
1367 ret = ldb_msg_add_value(msg, "replPropertyMetaData", &nmd_value, NULL);
1368 if (ret != LDB_SUCCESS) {
1375 * sort the attributes by attid before storing the object
1377 replmd_ldb_message_sort(msg, ac->schema);
1380 * Assert that we do have an objectClass
1382 objectclass_el = ldb_msg_find_element(msg, "objectClass");
1383 if (objectclass_el == NULL) {
1384 ldb_asprintf_errstring(ldb, __location__
1385 ": objectClass missing on %s\n",
1386 ldb_dn_get_linearized(msg->dn));
1388 return LDB_ERR_OBJECT_CLASS_VIOLATION;
1390 is_urgent = replmd_check_urgent_objectclass(objectclass_el,
1391 REPL_URGENT_ON_CREATE);
1393 ac->is_urgent = is_urgent;
1394 ret = ldb_build_add_req(&down_req, ldb, ac,
1397 ac, replmd_op_callback,
1400 LDB_REQ_SET_LOCATION(down_req);
1401 if (ret != LDB_SUCCESS) {
1406 /* current partition control is needed by "replmd_op_callback" */
1407 if (ldb_request_get_control(req, DSDB_CONTROL_CURRENT_PARTITION_OID) == NULL) {
1408 ret = ldb_request_add_control(down_req,
1409 DSDB_CONTROL_CURRENT_PARTITION_OID,
1411 if (ret != LDB_SUCCESS) {
1417 if (functional_level == DS_DOMAIN_FUNCTION_2000) {
1418 ret = ldb_request_add_control(down_req, DSDB_CONTROL_APPLY_LINKS, false, NULL);
1419 if (ret != LDB_SUCCESS) {
1425 /* mark the control done */
1427 control->critical = 0;
1429 /* go on with the call chain */
1430 return ldb_next_request(module, down_req);
1435 * update the replPropertyMetaData for one element
1437 static int replmd_update_rpmd_element(struct ldb_context *ldb,
1438 struct ldb_message *msg,
1439 struct ldb_message_element *el,
1440 struct ldb_message_element *old_el,
1441 struct replPropertyMetaDataBlob *omd,
1442 const struct dsdb_schema *schema,
1444 const struct GUID *our_invocation_id,
1447 bool is_forced_rodc,
1448 struct ldb_request *req)
1451 const struct dsdb_attribute *a;
1452 struct replPropertyMetaData1 *md1;
1453 bool may_skip = false;
1456 a = dsdb_attribute_by_lDAPDisplayName(schema, el->name);
1458 if (ldb_request_get_control(req, LDB_CONTROL_RELAX_OID)) {
1459 /* allow this to make it possible for dbcheck
1460 to remove bad attributes */
1464 DEBUG(0,(__location__ ": Unable to find attribute %s in schema\n",
1466 return LDB_ERR_OPERATIONS_ERROR;
1469 attid = dsdb_attribute_get_attid(a, is_schema_nc);
1471 if ((a->systemFlags & DS_FLAG_ATTR_NOT_REPLICATED) || (a->systemFlags & DS_FLAG_ATTR_IS_CONSTRUCTED)) {
1476 * if the attribute's value haven't changed, and this isn't
1477 * just a delete of everything then return LDB_SUCCESS Unless
1478 * we have the provision control or if the attribute is
1479 * interSiteTopologyGenerator as this page explain:
1480 * http://support.microsoft.com/kb/224815 this attribute is
1481 * periodicaly written by the DC responsible for the intersite
1482 * generation in a given site
1484 * Unchanged could be deleting or replacing an already-gone
1485 * thing with an unconstrained delete/empty replace or a
1486 * replace with the same value, but not an add with the same
1487 * value because that could be about adding a duplicate (which
1488 * is for someone else to error out on).
1490 if (old_el != NULL && ldb_msg_element_equal_ordered(el, old_el)) {
1491 if (LDB_FLAG_MOD_TYPE(el->flags) == LDB_FLAG_MOD_REPLACE) {
1494 } else if (old_el == NULL && el->num_values == 0) {
1495 if (LDB_FLAG_MOD_TYPE(el->flags) == LDB_FLAG_MOD_REPLACE) {
1497 } else if (LDB_FLAG_MOD_TYPE(el->flags) == LDB_FLAG_MOD_DELETE) {
1500 } else if (a->linkID != 0 && LDB_FLAG_MOD_TYPE(el->flags) == LDB_FLAG_MOD_DELETE &&
1501 ldb_request_get_control(req, DSDB_CONTROL_REPLMD_VANISH_LINKS) != NULL) {
1503 * We intentionally skip the version bump when attempting to
1506 * The control is set by dbcheck and expunge-tombstones which
1507 * both attempt to be non-replicating. Otherwise, making an
1508 * alteration to the replication state would trigger a
1509 * broadcast of all expunged objects.
1514 if (el->flags & DSDB_FLAG_INTERNAL_FORCE_META_DATA) {
1516 el->flags &= ~DSDB_FLAG_INTERNAL_FORCE_META_DATA;
1520 if (strcmp(el->name, "interSiteTopologyGenerator") != 0 &&
1521 !ldb_request_get_control(req, LDB_CONTROL_PROVISION_OID)) {
1523 * allow this to make it possible for dbcheck
1524 * to rebuild broken metadata
1530 for (i=0; i<omd->ctr.ctr1.count; i++) {
1532 * First check if we find it under the msDS-IntID,
1533 * then check if we find it under the OID and
1536 * This allows the administrator to simply re-write
1537 * the attributes and so restore replication, which is
1538 * likely what they will try to do.
1540 if (attid == omd->ctr.ctr1.array[i].attid) {
1544 if (a->attributeID_id == omd->ctr.ctr1.array[i].attid) {
1549 if (a->linkID != 0 && dsdb_functional_level(ldb) > DS_DOMAIN_FUNCTION_2000) {
1550 /* linked attributes are not stored in
1551 replPropertyMetaData in FL above w2k, but we do
1552 raise the seqnum for the object */
1553 if (*seq_num == 0 &&
1554 ldb_sequence_number(ldb, LDB_SEQ_NEXT, seq_num) != LDB_SUCCESS) {
1555 return LDB_ERR_OPERATIONS_ERROR;
1560 if (i == omd->ctr.ctr1.count) {
1561 /* we need to add a new one */
1562 omd->ctr.ctr1.array = talloc_realloc(msg, omd->ctr.ctr1.array,
1563 struct replPropertyMetaData1, omd->ctr.ctr1.count+1);
1564 if (omd->ctr.ctr1.array == NULL) {
1566 return LDB_ERR_OPERATIONS_ERROR;
1568 omd->ctr.ctr1.count++;
1569 ZERO_STRUCT(omd->ctr.ctr1.array[i]);
1572 /* Get a new sequence number from the backend. We only do this
1573 * if we have a change that requires a new
1574 * replPropertyMetaData element
1576 if (*seq_num == 0) {
1577 int ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, seq_num);
1578 if (ret != LDB_SUCCESS) {
1579 return LDB_ERR_OPERATIONS_ERROR;
1583 md1 = &omd->ctr.ctr1.array[i];
1587 if (md1->attid == DRSUAPI_ATTID_isDeleted) {
1588 const struct ldb_val *rdn_val = ldb_dn_get_rdn_val(msg->dn);
1591 if (rdn_val == NULL) {
1593 return LDB_ERR_OPERATIONS_ERROR;
1596 rdn = (const char*)rdn_val->data;
1597 if (strcmp(rdn, "Deleted Objects") == 0) {
1599 * Set the originating_change_time to 29/12/9999 at 23:59:59
1600 * as specified in MS-ADTS 7.1.1.4.2 Deleted Objects Container
1602 md1->originating_change_time = DELETED_OBJECT_CONTAINER_CHANGE_TIME;
1604 md1->originating_change_time = now;
1607 md1->originating_change_time = now;
1609 md1->originating_invocation_id = *our_invocation_id;
1610 md1->originating_usn = *seq_num;
1611 md1->local_usn = *seq_num;
1613 if (is_forced_rodc) {
1614 /* Force version to 0 to be overriden later via replication */
1622 * Bump the replPropertyMetaData version on an attribute, and if it
1623 * has changed (or forced by leaving rdn_old NULL), update the value
1626 * This is important, as calling a modify operation may not change the
1627 * version number if the values appear unchanged, but a rename between
1628 * parents bumps this value.
1631 static int replmd_update_rpmd_rdn_attr(struct ldb_context *ldb,
1632 struct ldb_message *msg,
1633 const struct ldb_val *rdn_new,
1634 const struct ldb_val *rdn_old,
1635 struct replPropertyMetaDataBlob *omd,
1636 struct replmd_replicated_request *ar,
1639 bool is_forced_rodc)
1641 const char *rdn_name = ldb_dn_get_rdn_name(msg->dn);
1642 const struct dsdb_attribute *rdn_attr =
1643 dsdb_attribute_by_lDAPDisplayName(ar->schema, rdn_name);
1644 const char *attr_name = rdn_attr != NULL ?
1645 rdn_attr->lDAPDisplayName :
1647 struct ldb_message_element new_el = {
1648 .flags = LDB_FLAG_MOD_REPLACE,
1651 .values = discard_const_p(struct ldb_val, rdn_new)
1653 struct ldb_message_element old_el = {
1654 .flags = LDB_FLAG_MOD_REPLACE,
1656 .num_values = rdn_old ? 1 : 0,
1657 .values = discard_const_p(struct ldb_val, rdn_old)
1660 if (ldb_msg_element_equal_ordered(&new_el, &old_el) == false) {
1661 int ret = ldb_msg_add(msg, &new_el, LDB_FLAG_MOD_REPLACE);
1662 if (ret != LDB_SUCCESS) {
1663 return ldb_oom(ldb);
1667 return replmd_update_rpmd_element(ldb, msg, &new_el, NULL,
1668 omd, ar->schema, &ar->seq_num,
1669 &ar->our_invocation_id,
1670 now, is_schema_nc, is_forced_rodc,
1675 static uint64_t find_max_local_usn(struct replPropertyMetaDataBlob omd)
1677 uint32_t count = omd.ctr.ctr1.count;
1680 for (i=0; i < count; i++) {
1681 struct replPropertyMetaData1 m = omd.ctr.ctr1.array[i];
1682 if (max < m.local_usn) {
1690 * update the replPropertyMetaData object each time we modify an
1691 * object. This is needed for DRS replication, as the merge on the
1692 * client is based on this object
1694 static int replmd_update_rpmd(struct ldb_module *module,
1695 const struct dsdb_schema *schema,
1696 struct ldb_request *req,
1697 const char * const *rename_attrs,
1698 struct ldb_message *msg, uint64_t *seq_num,
1699 time_t t, bool is_schema_nc,
1700 bool *is_urgent, bool *rodc)
1702 const struct ldb_val *omd_value;
1703 enum ndr_err_code ndr_err;
1704 struct replPropertyMetaDataBlob omd;
1707 const struct GUID *our_invocation_id;
1709 const char * const *attrs = NULL;
1710 const char * const attrs2[] = { "uSNChanged", "objectClass", "instanceType", NULL };
1711 struct ldb_result *res;
1712 struct ldb_context *ldb;
1713 struct ldb_message_element *objectclass_el;
1714 enum urgent_situation situation;
1715 bool rmd_is_provided;
1716 bool rmd_is_just_resorted = false;
1717 const char *not_rename_attrs[4 + msg->num_elements];
1718 bool is_forced_rodc = false;
1721 attrs = rename_attrs;
1723 for (i = 0; i < msg->num_elements; i++) {
1724 not_rename_attrs[i] = msg->elements[i].name;
1726 not_rename_attrs[i] = "replPropertyMetaData";
1727 not_rename_attrs[i+1] = "objectClass";
1728 not_rename_attrs[i+2] = "instanceType";
1729 not_rename_attrs[i+3] = NULL;
1730 attrs = not_rename_attrs;
1733 ldb = ldb_module_get_ctx(module);
1735 ret = samdb_rodc(ldb, rodc);
1736 if (ret != LDB_SUCCESS) {
1737 DEBUG(4, (__location__ ": unable to tell if we are an RODC\n"));
1742 ldb_request_get_control(req, DSDB_CONTROL_FORCE_RODC_LOCAL_CHANGE)) {
1743 is_forced_rodc = true;
1746 our_invocation_id = samdb_ntds_invocation_id(ldb);
1747 if (!our_invocation_id) {
1748 /* this happens during an initial vampire while
1749 updating the schema */
1750 DEBUG(5,("No invocationID - skipping replPropertyMetaData update\n"));
1754 unix_to_nt_time(&now, t);
1756 if (ldb_request_get_control(req, DSDB_CONTROL_CHANGEREPLMETADATA_OID)) {
1757 rmd_is_provided = true;
1758 if (ldb_request_get_control(req, DSDB_CONTROL_CHANGEREPLMETADATA_RESORT_OID)) {
1759 rmd_is_just_resorted = true;
1762 rmd_is_provided = false;
1765 /* if isDeleted is present and is TRUE, then we consider we are deleting,
1766 * otherwise we consider we are updating */
1767 if (ldb_msg_check_string_attribute(msg, "isDeleted", "TRUE")) {
1768 situation = REPL_URGENT_ON_DELETE;
1769 } else if (rename_attrs) {
1770 situation = REPL_URGENT_ON_CREATE | REPL_URGENT_ON_DELETE;
1772 situation = REPL_URGENT_ON_UPDATE;
1775 if (rmd_is_provided) {
1776 /* In this case the change_replmetadata control was supplied */
1777 /* We check that it's the only attribute that is provided
1778 * (it's a rare case so it's better to keep the code simplier)
1779 * We also check that the highest local_usn is bigger or the same as
1782 if( msg->num_elements != 1 ||
1783 strncmp(msg->elements[0].name,
1784 "replPropertyMetaData", 20) ) {
1785 DEBUG(0,(__location__ ": changereplmetada control called without "\
1786 "a specified replPropertyMetaData attribute or with others\n"));
1787 return LDB_ERR_OPERATIONS_ERROR;
1789 if (situation != REPL_URGENT_ON_UPDATE) {
1790 DEBUG(0,(__location__ ": changereplmetada control can't be called when deleting an object\n"));
1791 return LDB_ERR_OPERATIONS_ERROR;
1793 omd_value = ldb_msg_find_ldb_val(msg, "replPropertyMetaData");
1795 DEBUG(0,(__location__ ": replPropertyMetaData was not specified for Object %s\n",
1796 ldb_dn_get_linearized(msg->dn)));
1797 return LDB_ERR_OPERATIONS_ERROR;
1799 ndr_err = ndr_pull_struct_blob(omd_value, msg, &omd,
1800 (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
1801 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1802 DEBUG(0,(__location__ ": Failed to parse replPropertyMetaData for %s\n",
1803 ldb_dn_get_linearized(msg->dn)));
1804 return LDB_ERR_OPERATIONS_ERROR;
1807 ret = dsdb_module_search_dn(module, msg, &res, msg->dn, attrs2,
1808 DSDB_FLAG_NEXT_MODULE |
1809 DSDB_SEARCH_SHOW_RECYCLED |
1810 DSDB_SEARCH_SHOW_EXTENDED_DN |
1811 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT |
1812 DSDB_SEARCH_REVEAL_INTERNALS, req);
1814 if (ret != LDB_SUCCESS) {
1818 if (rmd_is_just_resorted == false) {
1819 *seq_num = find_max_local_usn(omd);
1821 db_seq = ldb_msg_find_attr_as_uint64(res->msgs[0], "uSNChanged", 0);
1824 * The test here now allows for a new
1825 * replPropertyMetaData with no change, if was
1826 * just dbcheck re-sorting the values.
1828 if (*seq_num <= db_seq) {
1829 DEBUG(0,(__location__ ": changereplmetada control provided but max(local_usn)" \
1830 " is less than uSNChanged (max = %lld uSNChanged = %lld)\n",
1831 (long long)*seq_num, (long long)db_seq));
1832 return LDB_ERR_OPERATIONS_ERROR;
1837 /* search for the existing replPropertyMetaDataBlob. We need
1838 * to use REVEAL and ask for DNs in storage format to support
1839 * the check for values being the same in
1840 * replmd_update_rpmd_element()
1842 ret = dsdb_module_search_dn(module, msg, &res, msg->dn, attrs,
1843 DSDB_FLAG_NEXT_MODULE |
1844 DSDB_SEARCH_SHOW_RECYCLED |
1845 DSDB_SEARCH_SHOW_EXTENDED_DN |
1846 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT |
1847 DSDB_SEARCH_REVEAL_INTERNALS, req);
1848 if (ret != LDB_SUCCESS) {
1852 omd_value = ldb_msg_find_ldb_val(res->msgs[0], "replPropertyMetaData");
1854 DEBUG(0,(__location__ ": Object %s does not have a replPropertyMetaData attribute\n",
1855 ldb_dn_get_linearized(msg->dn)));
1856 return LDB_ERR_OPERATIONS_ERROR;
1859 ndr_err = ndr_pull_struct_blob(omd_value, msg, &omd,
1860 (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
1861 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1862 DEBUG(0,(__location__ ": Failed to parse replPropertyMetaData for %s\n",
1863 ldb_dn_get_linearized(msg->dn)));
1864 return LDB_ERR_OPERATIONS_ERROR;
1867 if (omd.version != 1) {
1868 DEBUG(0,(__location__ ": bad version %u in replPropertyMetaData for %s\n",
1869 omd.version, ldb_dn_get_linearized(msg->dn)));
1870 return LDB_ERR_OPERATIONS_ERROR;
1873 for (i=0; i<msg->num_elements;) {
1874 struct ldb_message_element *el = &msg->elements[i];
1875 struct ldb_message_element *old_el;
1877 old_el = ldb_msg_find_element(res->msgs[0], el->name);
1878 ret = replmd_update_rpmd_element(ldb, msg, el, old_el,
1879 &omd, schema, seq_num,
1884 if (ret != LDB_SUCCESS) {
1888 if (!*is_urgent && (situation == REPL_URGENT_ON_UPDATE)) {
1889 *is_urgent = replmd_check_urgent_attribute(el);
1892 if (!(el->flags & DSDB_FLAG_INTERNAL_FORCE_META_DATA)) {
1897 el->flags &= ~DSDB_FLAG_INTERNAL_FORCE_META_DATA;
1899 if (el->num_values != 0) {
1904 ldb_msg_remove_element(msg, el);
1909 * Assert that we have an objectClass attribute - this is major
1910 * corruption if we don't have this!
1912 objectclass_el = ldb_msg_find_element(res->msgs[0], "objectClass");
1913 if (objectclass_el != NULL) {
1915 * Now check if this objectClass means we need to do urgent replication
1917 if (!*is_urgent && replmd_check_urgent_objectclass(objectclass_el,
1921 } else if (!ldb_request_get_control(req, DSDB_CONTROL_DBCHECK)) {
1922 ldb_asprintf_errstring(ldb, __location__
1923 ": objectClass missing on %s\n",
1924 ldb_dn_get_linearized(msg->dn));
1925 return LDB_ERR_OBJECT_CLASS_VIOLATION;
1929 * replmd_update_rpmd_element has done an update if the
1932 if (*seq_num != 0 || rmd_is_just_resorted == true) {
1933 struct ldb_val *md_value;
1934 struct ldb_message_element *el;
1936 /*if we are RODC and this is a DRSR update then its ok*/
1937 if (!ldb_request_get_control(req, DSDB_CONTROL_REPLICATED_UPDATE_OID)
1938 && !ldb_request_get_control(req, DSDB_CONTROL_DBCHECK_MODIFY_RO_REPLICA)
1939 && !is_forced_rodc) {
1940 unsigned instanceType;
1943 ldb_set_errstring(ldb, "RODC modify is forbidden!");
1944 return LDB_ERR_REFERRAL;
1947 instanceType = ldb_msg_find_attr_as_uint(res->msgs[0], "instanceType", INSTANCE_TYPE_WRITE);
1948 if (!(instanceType & INSTANCE_TYPE_WRITE)) {
1949 return ldb_error(ldb, LDB_ERR_UNWILLING_TO_PERFORM,
1950 "cannot change replicated attribute on partial replica");
1954 md_value = talloc(msg, struct ldb_val);
1955 if (md_value == NULL) {
1957 return LDB_ERR_OPERATIONS_ERROR;
1960 ret = replmd_replPropertyMetaDataCtr1_sort_and_verify(ldb, &omd.ctr.ctr1, msg->dn);
1961 if (ret != LDB_SUCCESS) {
1962 ldb_asprintf_errstring(ldb, "%s: %s", __func__, ldb_errstring(ldb));
1966 ndr_err = ndr_push_struct_blob(md_value, msg, &omd,
1967 (ndr_push_flags_fn_t)ndr_push_replPropertyMetaDataBlob);
1968 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1969 DEBUG(0,(__location__ ": Failed to marshall replPropertyMetaData for %s\n",
1970 ldb_dn_get_linearized(msg->dn)));
1971 return LDB_ERR_OPERATIONS_ERROR;
1974 ret = ldb_msg_add_empty(msg, "replPropertyMetaData", LDB_FLAG_MOD_REPLACE, &el);
1975 if (ret != LDB_SUCCESS) {
1976 DEBUG(0,(__location__ ": Failed to add updated replPropertyMetaData %s\n",
1977 ldb_dn_get_linearized(msg->dn)));
1982 el->values = md_value;
1988 static int parsed_dn_compare(struct parsed_dn *pdn1, struct parsed_dn *pdn2)
1990 int ret = ndr_guid_compare(&pdn1->guid, &pdn2->guid);
1992 return data_blob_cmp(&pdn1->dsdb_dn->extra_part,
1993 &pdn2->dsdb_dn->extra_part);
1999 get a series of message element values as an array of DNs and GUIDs
2000 the result is sorted by GUID
2002 static int get_parsed_dns(struct ldb_module *module, TALLOC_CTX *mem_ctx,
2003 struct ldb_message_element *el, struct parsed_dn **pdn,
2004 const char *ldap_oid, struct ldb_request *parent)
2007 bool values_are_sorted = true;
2008 struct ldb_context *ldb = ldb_module_get_ctx(module);
2015 (*pdn) = talloc_array(mem_ctx, struct parsed_dn, el->num_values);
2017 ldb_module_oom(module);
2018 return LDB_ERR_OPERATIONS_ERROR;
2021 for (i=0; i<el->num_values; i++) {
2022 struct ldb_val *v = &el->values[i];
2025 struct parsed_dn *p;
2029 p->dsdb_dn = dsdb_dn_parse(*pdn, ldb, v, ldap_oid);
2030 if (p->dsdb_dn == NULL) {
2031 return LDB_ERR_INVALID_DN_SYNTAX;
2034 dn = p->dsdb_dn->dn;
2036 status = dsdb_get_extended_dn_guid(dn, &p->guid, "GUID");
2037 if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND) ||
2038 unlikely(GUID_all_zero(&p->guid))) {
2039 /* we got a DN without a GUID - go find the GUID */
2040 int ret = dsdb_module_guid_by_dn(module, dn, &p->guid, parent);
2041 if (ret != LDB_SUCCESS) {
2042 char *dn_str = NULL;
2043 dn_str = ldb_dn_get_extended_linearized(mem_ctx,
2045 ldb_asprintf_errstring(ldb,
2046 "Unable to find GUID for DN %s\n",
2048 if (ret == LDB_ERR_NO_SUCH_OBJECT &&
2049 LDB_FLAG_MOD_TYPE(el->flags) == LDB_FLAG_MOD_DELETE &&
2050 ldb_attr_cmp(el->name, "member") == 0) {
2051 return LDB_ERR_UNWILLING_TO_PERFORM;
2055 ret = dsdb_set_extended_dn_guid(dn, &p->guid, "GUID");
2056 if (ret != LDB_SUCCESS) {
2059 } else if (!NT_STATUS_IS_OK(status)) {
2060 return LDB_ERR_OPERATIONS_ERROR;
2062 if (i > 0 && values_are_sorted) {
2063 int cmp = parsed_dn_compare(p, &(*pdn)[i - 1]);
2065 values_are_sorted = false;
2068 /* keep a pointer to the original ldb_val */
2071 if (! values_are_sorted) {
2072 TYPESAFE_QSORT(*pdn, el->num_values, parsed_dn_compare);
2078 * Get a series of trusted message element values. The result is sorted by
2079 * GUID, even though the GUIDs might not be known. That works because we trust
2080 * the database to give us the elements like that if the
2081 * replmd_private->sorted_links flag is set.
2083 * We also ensure that the links are in the Functional Level 2003
2084 * linked attributes format.
2086 static int get_parsed_dns_trusted(struct ldb_module *module,
2087 struct replmd_private *replmd_private,
2088 TALLOC_CTX *mem_ctx,
2089 struct ldb_message_element *el,
2090 struct parsed_dn **pdn,
2091 const char *ldap_oid,
2092 struct ldb_request *parent)
2101 if (!replmd_private->sorted_links) {
2102 /* We need to sort the list. This is the slow old path we want
2105 ret = get_parsed_dns(module, mem_ctx, el, pdn, ldap_oid,
2107 if (ret != LDB_SUCCESS) {
2111 /* Here we get a list of 'struct parsed_dns' without the parsing */
2112 *pdn = talloc_zero_array(mem_ctx, struct parsed_dn,
2115 ldb_module_oom(module);
2116 return LDB_ERR_OPERATIONS_ERROR;
2119 for (i = 0; i < el->num_values; i++) {
2120 (*pdn)[i].v = &el->values[i];
2125 * This upgrades links to FL2003 style, and sorts the result
2126 * if that was needed.
2128 * TODO: Add a database feature that asserts we have no FL2000
2129 * style links to avoid this check or add a feature that
2130 * uses a similar check to find sorted/unsorted links
2131 * for an on-the-fly upgrade.
2134 ret = replmd_check_upgrade_links(ldb_module_get_ctx(module),
2135 *pdn, el->num_values,
2138 if (ret != LDB_SUCCESS) {
2146 Return LDB_SUCCESS if a parsed_dn list contains no duplicate values,
2147 otherwise an error code. For compatibility the error code differs depending
2148 on whether or not the attribute is "member".
2150 As always, the parsed_dn list is assumed to be sorted.
2152 static int check_parsed_dn_duplicates(struct ldb_module *module,
2153 struct ldb_message_element *el,
2154 struct parsed_dn *pdn)
2157 struct ldb_context *ldb = ldb_module_get_ctx(module);
2159 for (i = 1; i < el->num_values; i++) {
2160 struct parsed_dn *p = &pdn[i];
2161 if (parsed_dn_compare(p, &pdn[i - 1]) == 0) {
2162 ldb_asprintf_errstring(ldb,
2163 "Linked attribute %s has "
2164 "multiple identical values",
2166 if (ldb_attr_cmp(el->name, "member") == 0) {
2167 return LDB_ERR_ENTRY_ALREADY_EXISTS;
2169 return LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS;
2177 build a new extended DN, including all meta data fields
2179 RMD_FLAGS = DSDB_RMD_FLAG_* bits
2180 RMD_ADDTIME = originating_add_time
2181 RMD_INVOCID = originating_invocation_id
2182 RMD_CHANGETIME = originating_change_time
2183 RMD_ORIGINATING_USN = originating_usn
2184 RMD_LOCAL_USN = local_usn
2185 RMD_VERSION = version
2187 static int replmd_build_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v,
2188 struct dsdb_dn *dsdb_dn,
2189 const struct GUID *invocation_id,
2190 uint64_t local_usn, NTTIME nttime)
2192 return replmd_set_la_val(mem_ctx, v, dsdb_dn, NULL, invocation_id,
2193 local_usn, local_usn, nttime,
2194 RMD_VERSION_INITIAL, false);
2197 static int replmd_update_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct dsdb_dn *dsdb_dn,
2198 struct dsdb_dn *old_dsdb_dn, const struct GUID *invocation_id,
2199 uint64_t seq_num, uint64_t local_usn, NTTIME nttime,
2203 check if any links need upgrading from w2k format
2205 static int replmd_check_upgrade_links(struct ldb_context *ldb,
2206 struct parsed_dn *dns, uint32_t count,
2207 struct ldb_message_element *el,
2208 const char *ldap_oid)
2211 const struct GUID *invocation_id = NULL;
2212 for (i=0; i<count; i++) {
2216 if (dns[i].dsdb_dn == NULL) {
2217 ret = really_parse_trusted_dn(dns, ldb, &dns[i],
2219 if (ret != LDB_SUCCESS) {
2220 return LDB_ERR_INVALID_DN_SYNTAX;
2224 status = dsdb_get_extended_dn_uint32(dns[i].dsdb_dn->dn,
2225 &version, "RMD_VERSION");
2226 if (!NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
2228 * We optimistically assume they are all the same; if
2229 * the first one is fixed, they are all fixed.
2231 * If the first one was *not* fixed and we find a
2232 * later one that is, that is an occasion to shout
2238 DEBUG(0, ("Mixed w2k and fixed format "
2239 "linked attributes\n"));
2243 if (invocation_id == NULL) {
2244 invocation_id = samdb_ntds_invocation_id(ldb);
2245 if (invocation_id == NULL) {
2246 return LDB_ERR_OPERATIONS_ERROR;
2251 /* it's an old one that needs upgrading */
2252 ret = replmd_update_la_val(el->values, dns[i].v,
2253 dns[i].dsdb_dn, dns[i].dsdb_dn,
2254 invocation_id, 1, 1, 0, false);
2255 if (ret != LDB_SUCCESS) {
2261 * This sort() is critical for the operation of
2262 * get_parsed_dns_trusted() because callers of this function
2263 * expect a sorted list, and FL2000 style links are not
2264 * sorted. In particular, as well as the upgrade case,
2265 * get_parsed_dns_trusted() is called from
2266 * replmd_delete_remove_link() even in FL2000 mode
2268 * We do not normally pay the cost of the qsort() due to the
2269 * early return in the RMD_VERSION found case.
2271 TYPESAFE_QSORT(dns, count, parsed_dn_compare);
2276 Sets the value for a linked attribute, including all meta data fields
2278 see replmd_build_la_val for value names
2280 static int replmd_set_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct dsdb_dn *dsdb_dn,
2281 struct dsdb_dn *old_dsdb_dn, const struct GUID *invocation_id,
2282 uint64_t usn, uint64_t local_usn, NTTIME nttime,
2283 uint32_t version, bool deleted)
2285 struct ldb_dn *dn = dsdb_dn->dn;
2286 const char *tstring, *usn_string, *flags_string;
2287 struct ldb_val tval;
2289 struct ldb_val usnv, local_usnv;
2290 struct ldb_val vers, flagsv;
2291 const struct ldb_val *old_addtime = NULL;
2294 const char *dnstring;
2296 uint32_t rmd_flags = deleted?DSDB_RMD_FLAG_DELETED:0;
2298 tstring = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)nttime);
2300 return LDB_ERR_OPERATIONS_ERROR;
2302 tval = data_blob_string_const(tstring);
2304 usn_string = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)usn);
2306 return LDB_ERR_OPERATIONS_ERROR;
2308 usnv = data_blob_string_const(usn_string);
2310 usn_string = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)local_usn);
2312 return LDB_ERR_OPERATIONS_ERROR;
2314 local_usnv = data_blob_string_const(usn_string);
2316 status = GUID_to_ndr_blob(invocation_id, dn, &iid);
2317 if (!NT_STATUS_IS_OK(status)) {
2318 return LDB_ERR_OPERATIONS_ERROR;
2321 flags_string = talloc_asprintf(mem_ctx, "%u", rmd_flags);
2322 if (!flags_string) {
2323 return LDB_ERR_OPERATIONS_ERROR;
2325 flagsv = data_blob_string_const(flags_string);
2327 ret = ldb_dn_set_extended_component(dn, "RMD_FLAGS", &flagsv);
2328 if (ret != LDB_SUCCESS) return ret;
2330 /* get the ADDTIME from the original */
2331 if (old_dsdb_dn != NULL) {
2332 old_addtime = ldb_dn_get_extended_component(old_dsdb_dn->dn,
2335 if (old_addtime == NULL) {
2336 old_addtime = &tval;
2338 if (dsdb_dn != old_dsdb_dn ||
2339 ldb_dn_get_extended_component(dn, "RMD_ADDTIME") == NULL) {
2340 ret = ldb_dn_set_extended_component(dn, "RMD_ADDTIME", old_addtime);
2341 if (ret != LDB_SUCCESS) return ret;
2344 /* use our invocation id */
2345 ret = ldb_dn_set_extended_component(dn, "RMD_INVOCID", &iid);
2346 if (ret != LDB_SUCCESS) return ret;
2348 /* changetime is the current time */
2349 ret = ldb_dn_set_extended_component(dn, "RMD_CHANGETIME", &tval);
2350 if (ret != LDB_SUCCESS) return ret;
2352 /* update the USN */
2353 ret = ldb_dn_set_extended_component(dn, "RMD_ORIGINATING_USN", &usnv);
2354 if (ret != LDB_SUCCESS) return ret;
2356 ret = ldb_dn_set_extended_component(dn, "RMD_LOCAL_USN", &local_usnv);
2357 if (ret != LDB_SUCCESS) return ret;
2359 vstring = talloc_asprintf(mem_ctx, "%lu", (unsigned long)version);
2360 vers = data_blob_string_const(vstring);
2361 ret = ldb_dn_set_extended_component(dn, "RMD_VERSION", &vers);
2362 if (ret != LDB_SUCCESS) return ret;
2364 dnstring = dsdb_dn_get_extended_linearized(mem_ctx, dsdb_dn, 1);
2365 if (dnstring == NULL) {
2366 return LDB_ERR_OPERATIONS_ERROR;
2368 *v = data_blob_string_const(dnstring);
2374 * Updates the value for a linked attribute, including all meta data fields
2376 static int replmd_update_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct dsdb_dn *dsdb_dn,
2377 struct dsdb_dn *old_dsdb_dn, const struct GUID *invocation_id,
2378 uint64_t usn, uint64_t local_usn, NTTIME nttime,
2381 uint32_t old_version;
2382 uint32_t version = RMD_VERSION_INITIAL;
2386 * We're updating the linked attribute locally, so increase the version
2387 * by 1 so that other DCs will see the change when it gets replicated out
2389 status = dsdb_get_extended_dn_uint32(old_dsdb_dn->dn, &old_version,
2392 if (NT_STATUS_IS_OK(status)) {
2393 version = old_version + 1;
2396 return replmd_set_la_val(mem_ctx, v, dsdb_dn, old_dsdb_dn, invocation_id,
2397 usn, local_usn, nttime, version, deleted);
2401 handle adding a linked attribute
2403 static int replmd_modify_la_add(struct ldb_module *module,
2404 struct replmd_private *replmd_private,
2405 struct replmd_replicated_request *ac,
2406 struct ldb_message *msg,
2407 struct ldb_message_element *el,
2408 struct ldb_message_element *old_el,
2409 const struct dsdb_attribute *schema_attr,
2411 struct ldb_dn *msg_dn,
2412 struct ldb_request *parent)
2415 struct parsed_dn *dns, *old_dns;
2416 TALLOC_CTX *tmp_ctx = talloc_new(msg);
2418 struct ldb_val *new_values = NULL;
2419 unsigned old_num_values = old_el ? old_el->num_values : 0;
2420 unsigned num_values = 0;
2421 unsigned max_num_values;
2422 struct ldb_context *ldb = ldb_module_get_ctx(module);
2424 unix_to_nt_time(&now, t);
2426 /* get the DNs to be added, fully parsed.
2428 * We need full parsing because they came off the wire and we don't
2429 * trust them, besides which we need their details to know where to put
2432 ret = get_parsed_dns(module, tmp_ctx, el, &dns,
2433 schema_attr->syntax->ldap_oid, parent);
2434 if (ret != LDB_SUCCESS) {
2435 talloc_free(tmp_ctx);
2439 /* get the existing DNs, lazily parsed */
2440 ret = get_parsed_dns_trusted(module, replmd_private,
2441 tmp_ctx, old_el, &old_dns,
2442 schema_attr->syntax->ldap_oid, parent);
2444 if (ret != LDB_SUCCESS) {
2445 talloc_free(tmp_ctx);
2449 max_num_values = old_num_values + el->num_values;
2450 if (max_num_values < old_num_values) {
2451 DEBUG(0, ("we seem to have overflow in replmd_modify_la_add. "
2452 "old values: %u, new values: %u, sum: %u\n",
2453 old_num_values, el->num_values, max_num_values));
2454 talloc_free(tmp_ctx);
2455 return LDB_ERR_OPERATIONS_ERROR;
2458 new_values = talloc_zero_array(tmp_ctx, struct ldb_val, max_num_values);
2460 if (new_values == NULL) {
2461 ldb_module_oom(module);
2462 talloc_free(tmp_ctx);
2463 return LDB_ERR_OPERATIONS_ERROR;
2467 * For each new value, find where it would go in the list. If there is
2468 * a matching GUID there, we update the existing value; otherwise we
2472 for (i = 0; i < el->num_values; i++) {
2473 struct parsed_dn *exact;
2474 struct parsed_dn *next;
2476 int err = parsed_dn_find(ldb, old_dns, old_num_values,
2479 dns[i].dsdb_dn->extra_part, 0,
2481 schema_attr->syntax->ldap_oid,
2483 if (err != LDB_SUCCESS) {
2484 talloc_free(tmp_ctx);
2488 if (exact != NULL) {
2490 * We are trying to add one that exists, which is only
2491 * allowed if it was previously deleted.
2493 * When we do undelete a link we change it in place.
2494 * It will be copied across into the right spot in due
2498 rmd_flags = dsdb_dn_rmd_flags(exact->dsdb_dn->dn);
2500 if (!(rmd_flags & DSDB_RMD_FLAG_DELETED)) {
2501 struct GUID_txt_buf guid_str;
2502 ldb_asprintf_errstring(ldb,
2503 "Attribute %s already "
2504 "exists for target GUID %s",
2506 GUID_buf_string(&exact->guid,
2508 talloc_free(tmp_ctx);
2509 /* error codes for 'member' need to be
2511 if (ldb_attr_cmp(el->name, "member") == 0) {
2512 return LDB_ERR_ENTRY_ALREADY_EXISTS;
2514 return LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS;
2518 ret = replmd_update_la_val(new_values, exact->v,
2521 &ac->our_invocation_id,
2522 ac->seq_num, ac->seq_num,
2524 if (ret != LDB_SUCCESS) {
2525 talloc_free(tmp_ctx);
2529 ret = replmd_add_backlink(module, replmd_private,
2536 if (ret != LDB_SUCCESS) {
2537 talloc_free(tmp_ctx);
2543 * Here we don't have an exact match.
2545 * If next is NULL, this one goes beyond the end of the
2546 * existing list, so we need to add all of those ones first.
2548 * If next is not NULL, we need to add all the ones before
2552 offset = old_num_values;
2554 /* next should have been parsed, but let's make sure */
2555 if (next->dsdb_dn == NULL) {
2556 ret = really_parse_trusted_dn(tmp_ctx, ldb, next,
2557 schema_attr->syntax->ldap_oid);
2558 if (ret != LDB_SUCCESS) {
2562 offset = MIN(next - old_dns, old_num_values);
2565 /* put all the old ones before next on the list */
2566 for (; j < offset; j++) {
2567 new_values[num_values] = *old_dns[j].v;
2571 ret = replmd_add_backlink(module, replmd_private,
2576 /* Make the new linked attribute ldb_val. */
2577 ret = replmd_build_la_val(new_values, &new_values[num_values],
2578 dns[i].dsdb_dn, &ac->our_invocation_id,
2580 if (ret != LDB_SUCCESS) {
2581 talloc_free(tmp_ctx);
2585 if (ret != LDB_SUCCESS) {
2586 talloc_free(tmp_ctx);
2590 /* copy the rest of the old ones (if any) */
2591 for (; j < old_num_values; j++) {
2592 new_values[num_values] = *old_dns[j].v;
2596 talloc_steal(msg->elements, new_values);
2597 if (old_el != NULL) {
2598 talloc_steal(msg->elements, old_el->values);
2600 el->values = new_values;
2601 el->num_values = num_values;
2603 talloc_free(tmp_ctx);
2605 /* we now tell the backend to replace all existing values
2606 with the one we have constructed */
2607 el->flags = LDB_FLAG_MOD_REPLACE;
2614 handle deleting all active linked attributes
2616 static int replmd_modify_la_delete(struct ldb_module *module,
2617 struct replmd_private *replmd_private,
2618 const struct dsdb_schema *schema,
2619 struct ldb_message *msg,
2620 struct ldb_message_element *el,
2621 struct ldb_message_element *old_el,
2622 const struct dsdb_attribute *schema_attr,
2625 struct ldb_dn *msg_dn,
2626 struct ldb_request *parent)
2629 struct parsed_dn *dns, *old_dns;
2630 TALLOC_CTX *tmp_ctx = NULL;
2632 struct ldb_context *ldb = ldb_module_get_ctx(module);
2633 struct ldb_control *vanish_links_ctrl = NULL;
2634 bool vanish_links = false;
2635 unsigned int num_to_delete = el->num_values;
2637 const struct GUID *invocation_id;
2640 unix_to_nt_time(&now, t);
2642 invocation_id = samdb_ntds_invocation_id(ldb);
2643 if (!invocation_id) {
2644 return LDB_ERR_OPERATIONS_ERROR;
2647 if (old_el == NULL || old_el->num_values == 0) {
2648 /* there is nothing to delete... */
2649 if (num_to_delete == 0) {
2650 /* and we're deleting nothing, so that's OK */
2653 return LDB_ERR_NO_SUCH_ATTRIBUTE;
2656 tmp_ctx = talloc_new(msg);
2657 if (tmp_ctx == NULL) {
2658 return LDB_ERR_OPERATIONS_ERROR;
2661 ret = get_parsed_dns(module, tmp_ctx, el, &dns,
2662 schema_attr->syntax->ldap_oid, parent);
2663 if (ret != LDB_SUCCESS) {
2664 talloc_free(tmp_ctx);
2668 ret = get_parsed_dns_trusted(module, replmd_private,
2669 tmp_ctx, old_el, &old_dns,
2670 schema_attr->syntax->ldap_oid, parent);
2672 if (ret != LDB_SUCCESS) {
2673 talloc_free(tmp_ctx);
2678 vanish_links_ctrl = ldb_request_get_control(parent, DSDB_CONTROL_REPLMD_VANISH_LINKS);
2679 if (vanish_links_ctrl) {
2680 vanish_links = true;
2681 vanish_links_ctrl->critical = false;
2685 /* we empty out el->values here to avoid damage if we return early. */
2690 * If vanish links is set, we are actually removing members of
2691 * old_el->values; otherwise we are just marking them deleted.
2693 * There is a special case when no values are given: we remove them
2694 * all. When we have the vanish_links control we just have to remove
2695 * the backlinks and change our element to replace the existing values
2696 * with the empty list.
2699 if (num_to_delete == 0) {
2700 for (i = 0; i < old_el->num_values; i++) {
2701 struct parsed_dn *p = &old_dns[i];
2702 if (p->dsdb_dn == NULL) {
2703 ret = really_parse_trusted_dn(tmp_ctx, ldb, p,
2704 schema_attr->syntax->ldap_oid);
2705 if (ret != LDB_SUCCESS) {
2709 ret = replmd_add_backlink(module, replmd_private,
2710 schema, msg_dn, &p->guid,
2713 if (ret != LDB_SUCCESS) {
2714 talloc_free(tmp_ctx);
2721 rmd_flags = dsdb_dn_rmd_flags(p->dsdb_dn->dn);
2722 if (rmd_flags & DSDB_RMD_FLAG_DELETED) {
2726 ret = replmd_update_la_val(old_el->values, p->v,
2727 p->dsdb_dn, p->dsdb_dn,
2728 invocation_id, seq_num,
2729 seq_num, now, true);
2730 if (ret != LDB_SUCCESS) {
2731 talloc_free(tmp_ctx);
2737 el->flags = LDB_FLAG_MOD_REPLACE;
2738 talloc_free(tmp_ctx);
2744 for (i = 0; i < num_to_delete; i++) {
2745 struct parsed_dn *p = &dns[i];
2746 struct parsed_dn *exact = NULL;
2747 struct parsed_dn *next = NULL;
2748 ret = parsed_dn_find(ldb, old_dns, old_el->num_values,
2751 p->dsdb_dn->extra_part, 0,
2753 schema_attr->syntax->ldap_oid,
2755 if (ret != LDB_SUCCESS) {
2756 talloc_free(tmp_ctx);
2759 if (exact == NULL) {
2760 struct GUID_txt_buf buf;
2761 ldb_asprintf_errstring(ldb, "Attribute %s doesn't "
2762 "exist for target GUID %s",
2764 GUID_buf_string(&p->guid, &buf));
2765 if (ldb_attr_cmp(el->name, "member") == 0) {
2766 talloc_free(tmp_ctx);
2767 return LDB_ERR_UNWILLING_TO_PERFORM;
2769 talloc_free(tmp_ctx);
2770 return LDB_ERR_NO_SUCH_ATTRIBUTE;
2775 if (CHECK_DEBUGLVL(5)) {
2776 rmd_flags = dsdb_dn_rmd_flags(exact->dsdb_dn->dn);
2777 if ((rmd_flags & DSDB_RMD_FLAG_DELETED)) {
2778 struct GUID_txt_buf buf;
2779 const char *guid_str = \
2780 GUID_buf_string(&p->guid, &buf);
2781 DEBUG(5, ("Deleting deleted linked "
2782 "attribute %s to %s, because "
2783 "vanish_links control is set\n",
2784 el->name, guid_str));
2788 /* remove the backlink */
2789 ret = replmd_add_backlink(module,
2796 if (ret != LDB_SUCCESS) {
2797 talloc_free(tmp_ctx);
2801 /* We flag the deletion and tidy it up later. */
2806 rmd_flags = dsdb_dn_rmd_flags(exact->dsdb_dn->dn);
2808 if (rmd_flags & DSDB_RMD_FLAG_DELETED) {
2809 struct GUID_txt_buf buf;
2810 const char *guid_str = GUID_buf_string(&p->guid, &buf);
2811 ldb_asprintf_errstring(ldb, "Attribute %s already "
2812 "deleted for target GUID %s",
2813 el->name, guid_str);
2814 if (ldb_attr_cmp(el->name, "member") == 0) {
2815 talloc_free(tmp_ctx);
2816 return LDB_ERR_UNWILLING_TO_PERFORM;
2818 talloc_free(tmp_ctx);
2819 return LDB_ERR_NO_SUCH_ATTRIBUTE;
2823 ret = replmd_update_la_val(old_el->values, exact->v,
2824 exact->dsdb_dn, exact->dsdb_dn,
2825 invocation_id, seq_num, seq_num,
2827 if (ret != LDB_SUCCESS) {
2828 talloc_free(tmp_ctx);
2831 ret = replmd_add_backlink(module, replmd_private,
2836 if (ret != LDB_SUCCESS) {
2837 talloc_free(tmp_ctx);
2844 struct ldb_val *tmp_vals = NULL;
2846 tmp_vals = talloc_array(tmp_ctx, struct ldb_val,
2847 old_el->num_values);
2848 if (tmp_vals == NULL) {
2849 talloc_free(tmp_ctx);
2850 return ldb_module_oom(module);
2852 for (i = 0; i < old_el->num_values; i++) {
2853 if (old_dns[i].v == NULL) {
2856 tmp_vals[j] = *old_dns[i].v;
2859 for (i = 0; i < j; i++) {
2860 old_el->values[i] = tmp_vals[i];
2862 old_el->num_values = j;
2865 el->values = talloc_steal(msg->elements, old_el->values);
2866 el->num_values = old_el->num_values;
2868 talloc_free(tmp_ctx);
2870 /* we now tell the backend to replace all existing values
2871 with the one we have constructed */
2872 el->flags = LDB_FLAG_MOD_REPLACE;
2878 handle replacing a linked attribute
2880 static int replmd_modify_la_replace(struct ldb_module *module,
2881 struct replmd_private *replmd_private,
2882 const struct dsdb_schema *schema,
2883 struct ldb_message *msg,
2884 struct ldb_message_element *el,
2885 struct ldb_message_element *old_el,
2886 const struct dsdb_attribute *schema_attr,
2889 struct ldb_dn *msg_dn,
2890 struct ldb_request *parent)
2892 unsigned int i, old_i, new_i;
2893 struct parsed_dn *dns, *old_dns;
2894 TALLOC_CTX *tmp_ctx = talloc_new(msg);
2896 const struct GUID *invocation_id;
2897 struct ldb_context *ldb = ldb_module_get_ctx(module);
2898 struct ldb_val *new_values = NULL;
2899 const char *ldap_oid = schema_attr->syntax->ldap_oid;
2900 unsigned int old_num_values;
2901 unsigned int repl_num_values;
2902 unsigned int max_num_values;
2905 unix_to_nt_time(&now, t);
2907 invocation_id = samdb_ntds_invocation_id(ldb);
2908 if (!invocation_id) {
2909 return LDB_ERR_OPERATIONS_ERROR;
2913 * The replace operation is unlike the replace and delete cases in that
2914 * we need to look at every existing link to see whether it is being
2915 * retained or deleted. In other words, we can't avoid parsing the GUIDs.
2917 * As we are trying to combine two sorted lists, the algorithm we use
2918 * is akin to the merge phase of a merge sort. We interleave the two
2919 * lists, doing different things depending on which side the current
2922 * There are three main cases, with some sub-cases.
2924 * - a DN is in the old list but not the new one. It needs to be
2925 * marked as deleted (but left in the list).
2926 * - maybe it is already deleted, and we have less to do.
2928 * - a DN is in both lists. The old data gets replaced by the new,
2929 * and the list doesn't grow. The old link may have been marked as
2930 * deleted, in which case we undelete it.
2932 * - a DN is in the new list only. We add it in the right place.
2935 old_num_values = old_el ? old_el->num_values : 0;
2936 repl_num_values = el->num_values;
2937 max_num_values = old_num_values + repl_num_values;
2939 if (max_num_values == 0) {
2940 /* There is nothing to do! */
2944 ret = get_parsed_dns(module, tmp_ctx, el, &dns, ldap_oid, parent);
2945 if (ret != LDB_SUCCESS) {
2946 talloc_free(tmp_ctx);
2950 ret = check_parsed_dn_duplicates(module, el, dns);
2951 if (ret != LDB_SUCCESS) {
2952 talloc_free(tmp_ctx);
2956 ret = get_parsed_dns(module, tmp_ctx, old_el, &old_dns,
2958 if (ret != LDB_SUCCESS) {
2959 talloc_free(tmp_ctx);
2963 ret = replmd_check_upgrade_links(ldb, old_dns, old_num_values,
2965 if (ret != LDB_SUCCESS) {
2966 talloc_free(tmp_ctx);
2970 new_values = talloc_array(tmp_ctx, struct ldb_val, max_num_values);
2971 if (new_values == NULL) {
2972 ldb_module_oom(module);
2973 talloc_free(tmp_ctx);
2974 return LDB_ERR_OPERATIONS_ERROR;
2979 for (i = 0; i < max_num_values; i++) {
2981 struct parsed_dn *old_p, *new_p;
2982 if (old_i < old_num_values && new_i < repl_num_values) {
2983 old_p = &old_dns[old_i];
2984 new_p = &dns[new_i];
2985 cmp = parsed_dn_compare(old_p, new_p);
2986 } else if (old_i < old_num_values) {
2987 /* the new list is empty, read the old list */
2988 old_p = &old_dns[old_i];
2991 } else if (new_i < repl_num_values) {
2992 /* the old list is empty, read new list */
2994 new_p = &dns[new_i];
3002 * An old ones that come before the next replacement
3003 * (if any). We mark it as deleted and add it to the
3006 uint32_t rmd_flags = dsdb_dn_rmd_flags(old_p->dsdb_dn->dn);
3007 if ((rmd_flags & DSDB_RMD_FLAG_DELETED) == 0) {
3008 ret = replmd_update_la_val(new_values, old_p->v,
3014 if (ret != LDB_SUCCESS) {
3015 talloc_free(tmp_ctx);
3019 ret = replmd_add_backlink(module, replmd_private,
3022 &old_p->guid, false,
3025 if (ret != LDB_SUCCESS) {
3026 talloc_free(tmp_ctx);
3030 new_values[i] = *old_p->v;
3032 } else if (cmp == 0) {
3034 * We are overwriting one. If it was previously
3035 * deleted, we need to add a backlink.
3037 * Note that if any RMD_FLAGs in an extended new DN
3042 ret = replmd_update_la_val(new_values, old_p->v,
3048 if (ret != LDB_SUCCESS) {
3049 talloc_free(tmp_ctx);
3053 rmd_flags = dsdb_dn_rmd_flags(old_p->dsdb_dn->dn);
3054 if ((rmd_flags & DSDB_RMD_FLAG_DELETED) != 0) {
3055 ret = replmd_add_backlink(module, replmd_private,
3061 if (ret != LDB_SUCCESS) {
3062 talloc_free(tmp_ctx);
3067 new_values[i] = *old_p->v;
3072 * Replacements that don't match an existing one. We
3073 * just add them to the final list.
3075 ret = replmd_build_la_val(new_values,
3080 if (ret != LDB_SUCCESS) {
3081 talloc_free(tmp_ctx);
3084 ret = replmd_add_backlink(module, replmd_private,
3090 if (ret != LDB_SUCCESS) {
3091 talloc_free(tmp_ctx);
3094 new_values[i] = *new_p->v;
3098 if (old_el != NULL) {
3099 talloc_steal(msg->elements, old_el->values);
3101 el->values = talloc_steal(msg->elements, new_values);
3103 talloc_free(tmp_ctx);
3105 el->flags = LDB_FLAG_MOD_REPLACE;
3112 handle linked attributes in modify requests
3114 static int replmd_modify_handle_linked_attribs(struct ldb_module *module,
3115 struct replmd_private *replmd_private,
3116 struct replmd_replicated_request *ac,
3117 struct ldb_message *msg,
3119 struct ldb_request *parent)
3121 struct ldb_result *res;
3124 struct ldb_context *ldb = ldb_module_get_ctx(module);
3125 struct ldb_message *old_msg;
3127 if (dsdb_functional_level(ldb) == DS_DOMAIN_FUNCTION_2000) {
3129 * Nothing special is required for modifying or vanishing links
3130 * in fl2000 since they are just strings in a multi-valued
3133 struct ldb_control *ctrl = ldb_request_get_control(parent,
3134 DSDB_CONTROL_REPLMD_VANISH_LINKS);
3136 ctrl->critical = false;
3144 * We should restrict this to the intersection of the list of
3145 * linked attributes in the schema and the list of attributes
3148 * This will help performance a little, as otherwise we have
3149 * to allocate the entire object value-by-value.
3151 ret = dsdb_module_search_dn(module, msg, &res, msg->dn, NULL,
3152 DSDB_FLAG_NEXT_MODULE |
3153 DSDB_SEARCH_SHOW_RECYCLED |
3154 DSDB_SEARCH_REVEAL_INTERNALS |
3155 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT,
3157 if (ret != LDB_SUCCESS) {
3161 old_msg = res->msgs[0];
3163 for (i=0; i<msg->num_elements; i++) {
3164 struct ldb_message_element *el = &msg->elements[i];
3165 struct ldb_message_element *old_el, *new_el;
3166 unsigned int mod_type = LDB_FLAG_MOD_TYPE(el->flags);
3167 const struct dsdb_attribute *schema_attr
3168 = dsdb_attribute_by_lDAPDisplayName(ac->schema, el->name);
3170 ldb_asprintf_errstring(ldb,
3171 "%s: attribute %s is not a valid attribute in schema",
3172 __FUNCTION__, el->name);
3173 return LDB_ERR_OBJECT_CLASS_VIOLATION;
3175 if (schema_attr->linkID == 0) {
3178 if ((schema_attr->linkID & 1) == 1) {
3180 struct ldb_control *ctrl;
3182 ctrl = ldb_request_get_control(parent,
3183 DSDB_CONTROL_REPLMD_VANISH_LINKS);
3185 ctrl->critical = false;
3188 ctrl = ldb_request_get_control(parent,
3189 DSDB_CONTROL_DBCHECK);
3195 /* Odd is for the target. Illegal to modify */
3196 ldb_asprintf_errstring(ldb,
3197 "attribute %s must not be modified directly, it is a linked attribute", el->name);
3198 return LDB_ERR_UNWILLING_TO_PERFORM;
3200 old_el = ldb_msg_find_element(old_msg, el->name);
3202 case LDB_FLAG_MOD_REPLACE:
3203 ret = replmd_modify_la_replace(module, replmd_private,
3204 ac->schema, msg, el, old_el,
3205 schema_attr, ac->seq_num, t,
3209 case LDB_FLAG_MOD_DELETE:
3210 ret = replmd_modify_la_delete(module, replmd_private,
3211 ac->schema, msg, el, old_el,
3212 schema_attr, ac->seq_num, t,
3216 case LDB_FLAG_MOD_ADD:
3217 ret = replmd_modify_la_add(module, replmd_private,
3218 ac, msg, el, old_el,
3224 ldb_asprintf_errstring(ldb,
3225 "invalid flags 0x%x for %s linked attribute",
3226 el->flags, el->name);
3227 return LDB_ERR_UNWILLING_TO_PERFORM;
3229 if (dsdb_check_single_valued_link(schema_attr, el) != LDB_SUCCESS) {
3230 ldb_asprintf_errstring(ldb,
3231 "Attribute %s is single valued but more than one value has been supplied",
3233 /* Return codes as found on Windows 2012r2 */
3234 if (mod_type == LDB_FLAG_MOD_REPLACE) {
3235 return LDB_ERR_CONSTRAINT_VIOLATION;
3237 return LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS;
3240 el->flags |= LDB_FLAG_INTERNAL_DISABLE_SINGLE_VALUE_CHECK;
3243 if (ret != LDB_SUCCESS) {
3247 ldb_msg_remove_attr(old_msg, el->name);
3249 ldb_msg_add_empty(old_msg, el->name, 0, &new_el);
3250 new_el->num_values = el->num_values;
3251 new_el->values = talloc_steal(msg->elements, el->values);
3253 /* TODO: this relises a bit too heavily on the exact
3254 behaviour of ldb_msg_find_element and
3255 ldb_msg_remove_element */
3256 old_el = ldb_msg_find_element(msg, el->name);
3258 ldb_msg_remove_element(msg, old_el);
3268 static int send_rodc_referral(struct ldb_request *req,
3269 struct ldb_context *ldb,
3272 char *referral = NULL;
3273 struct loadparm_context *lp_ctx = NULL;
3274 struct ldb_dn *fsmo_role_dn = NULL;
3275 struct ldb_dn *role_owner_dn = NULL;
3276 const char *domain = NULL;
3279 lp_ctx = talloc_get_type(ldb_get_opaque(ldb, "loadparm"),
3280 struct loadparm_context);
3282 werr = dsdb_get_fsmo_role_info(req, ldb, DREPL_PDC_MASTER,
3283 &fsmo_role_dn, &role_owner_dn);
3285 if (W_ERROR_IS_OK(werr)) {
3286 struct ldb_dn *server_dn = ldb_dn_copy(req, role_owner_dn);
3287 if (server_dn != NULL) {
3288 ldb_dn_remove_child_components(server_dn, 1);
3289 domain = samdb_dn_to_dnshostname(ldb, req,
3294 if (domain == NULL) {
3295 domain = lpcfg_dnsdomain(lp_ctx);
3298 referral = talloc_asprintf(req, "ldap://%s/%s",
3300 ldb_dn_get_linearized(dn));
3301 if (referral == NULL) {
3303 return LDB_ERR_OPERATIONS_ERROR;
3306 return ldb_module_send_referral(req, referral);
3310 static int replmd_modify(struct ldb_module *module, struct ldb_request *req)
3312 struct ldb_context *ldb;
3313 struct replmd_replicated_request *ac;
3314 struct ldb_request *down_req;
3315 struct ldb_message *msg;
3316 time_t t = time(NULL);
3318 bool is_urgent = false, rodc = false;
3319 bool is_schema_nc = false;
3320 unsigned int functional_level;
3321 const struct ldb_message_element *guid_el = NULL;
3322 struct ldb_control *sd_propagation_control;
3323 struct ldb_control *fix_links_control = NULL;
3324 struct ldb_control *fix_dn_name_control = NULL;
3325 struct replmd_private *replmd_private =
3326 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
3328 /* do not manipulate our control entries */
3329 if (ldb_dn_is_special(req->op.mod.message->dn)) {
3330 return ldb_next_request(module, req);
3333 sd_propagation_control = ldb_request_get_control(req,
3334 DSDB_CONTROL_SEC_DESC_PROPAGATION_OID);
3335 if (sd_propagation_control != NULL) {
3336 if (req->op.mod.message->num_elements != 1) {
3337 return ldb_module_operr(module);
3339 ret = strcmp(req->op.mod.message->elements[0].name,
3340 "nTSecurityDescriptor");
3342 return ldb_module_operr(module);
3345 return ldb_next_request(module, req);
3348 ldb = ldb_module_get_ctx(module);
3350 fix_links_control = ldb_request_get_control(req,
3351 DSDB_CONTROL_DBCHECK_FIX_DUPLICATE_LINKS);
3352 if (fix_links_control != NULL) {
3353 struct dsdb_schema *schema = NULL;
3354 const struct dsdb_attribute *sa = NULL;
3356 if (req->op.mod.message->num_elements != 1) {
3357 return ldb_module_operr(module);
3360 if (req->op.mod.message->elements[0].flags != LDB_FLAG_MOD_REPLACE) {
3361 return ldb_module_operr(module);
3364 schema = dsdb_get_schema(ldb, req);
3365 if (schema == NULL) {
3366 return ldb_module_operr(module);
3369 sa = dsdb_attribute_by_lDAPDisplayName(schema,
3370 req->op.mod.message->elements[0].name);
3372 return ldb_module_operr(module);
3375 if (sa->linkID == 0) {
3376 return ldb_module_operr(module);
3379 fix_links_control->critical = false;
3380 return ldb_next_request(module, req);
3383 fix_dn_name_control = ldb_request_get_control(req,
3384 DSDB_CONTROL_DBCHECK_FIX_LINK_DN_NAME);
3385 if (fix_dn_name_control != NULL) {
3386 struct dsdb_schema *schema = NULL;
3387 const struct dsdb_attribute *sa = NULL;
3389 if (req->op.mod.message->num_elements != 2) {
3390 return ldb_module_operr(module);
3393 if (req->op.mod.message->elements[0].flags != LDB_FLAG_MOD_DELETE) {
3394 return ldb_module_operr(module);
3397 if (req->op.mod.message->elements[1].flags != LDB_FLAG_MOD_ADD) {
3398 return ldb_module_operr(module);
3401 if (req->op.mod.message->elements[0].num_values != 1) {
3402 return ldb_module_operr(module);
3405 if (req->op.mod.message->elements[1].num_values != 1) {
3406 return ldb_module_operr(module);
3409 schema = dsdb_get_schema(ldb, req);
3410 if (schema == NULL) {
3411 return ldb_module_operr(module);
3414 if (ldb_attr_cmp(req->op.mod.message->elements[0].name,
3415 req->op.mod.message->elements[1].name) != 0) {
3416 return ldb_module_operr(module);
3419 sa = dsdb_attribute_by_lDAPDisplayName(schema,
3420 req->op.mod.message->elements[0].name);
3422 return ldb_module_operr(module);
3425 if (sa->dn_format == DSDB_INVALID_DN) {
3426 return ldb_module_operr(module);
3429 if (sa->linkID != 0) {
3430 return ldb_module_operr(module);
3434 * If we are run from dbcheck and we are not updating
3435 * a link (as these would need to be sorted and so
3436 * can't go via such a simple update, then do not
3437 * trigger replicated updates and a new USN from this
3438 * change, it wasn't a real change, just a new
3439 * (correct) string DN
3442 fix_dn_name_control->critical = false;
3443 return ldb_next_request(module, req);
3446 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_modify\n");
3448 guid_el = ldb_msg_find_element(req->op.mod.message, "objectGUID");
3449 if (guid_el != NULL) {
3450 ldb_set_errstring(ldb,
3451 "replmd_modify: it's not allowed to change the objectGUID!");
3452 return LDB_ERR_CONSTRAINT_VIOLATION;
3455 ac = replmd_ctx_init(module, req);
3457 return ldb_module_oom(module);
3460 functional_level = dsdb_functional_level(ldb);
3462 /* we have to copy the message as the caller might have it as a const */
3463 msg = ldb_msg_copy_shallow(ac, req->op.mod.message);
3467 return LDB_ERR_OPERATIONS_ERROR;
3470 ldb_msg_remove_attr(msg, "whenChanged");
3471 ldb_msg_remove_attr(msg, "uSNChanged");
3473 is_schema_nc = ldb_dn_compare_base(replmd_private->schema_dn, msg->dn) == 0;
3475 ret = replmd_update_rpmd(module, ac->schema, req, NULL,
3476 msg, &ac->seq_num, t, is_schema_nc,
3478 if (rodc && (ret == LDB_ERR_REFERRAL)) {
3479 ret = send_rodc_referral(req, ldb, msg->dn);
3485 if (ret != LDB_SUCCESS) {
3490 ret = replmd_modify_handle_linked_attribs(module, replmd_private,
3492 if (ret != LDB_SUCCESS) {
3498 * - replace the old object with the newly constructed one
3501 ac->is_urgent = is_urgent;
3503 ret = ldb_build_mod_req(&down_req, ldb, ac,
3506 ac, replmd_op_callback,
3508 LDB_REQ_SET_LOCATION(down_req);
3509 if (ret != LDB_SUCCESS) {
3514 /* current partition control is needed by "replmd_op_callback" */
3515 if (ldb_request_get_control(req, DSDB_CONTROL_CURRENT_PARTITION_OID) == NULL) {
3516 ret = ldb_request_add_control(down_req,
3517 DSDB_CONTROL_CURRENT_PARTITION_OID,
3519 if (ret != LDB_SUCCESS) {
3525 /* If we are in functional level 2000, then
3526 * replmd_modify_handle_linked_attribs will have done
3528 if (functional_level == DS_DOMAIN_FUNCTION_2000) {
3529 ret = ldb_request_add_control(down_req, DSDB_CONTROL_APPLY_LINKS, false, NULL);
3530 if (ret != LDB_SUCCESS) {
3536 talloc_steal(down_req, msg);
3538 /* we only change whenChanged and uSNChanged if the seq_num
3540 if (ac->seq_num != 0) {
3541 ret = add_time_element(msg, "whenChanged", t);
3542 if (ret != LDB_SUCCESS) {
3548 ret = add_uint64_element(ldb, msg, "uSNChanged", ac->seq_num);
3549 if (ret != LDB_SUCCESS) {
3556 /* go on with the call chain */
3557 return ldb_next_request(module, down_req);
3560 static int replmd_rename_callback(struct ldb_request *req, struct ldb_reply *ares);
3563 handle a rename request
3565 On a rename we need to do an extra ldb_modify which sets the
3566 whenChanged and uSNChanged attributes. We do this in a callback after the success.
3568 static int replmd_rename(struct ldb_module *module, struct ldb_request *req)
3570 struct ldb_context *ldb;
3571 struct replmd_replicated_request *ac;
3573 struct ldb_request *down_req;
3575 /* do not manipulate our control entries */
3576 if (ldb_dn_is_special(req->op.mod.message->dn)) {
3577 return ldb_next_request(module, req);
3580 ldb = ldb_module_get_ctx(module);
3582 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_rename\n");
3584 ac = replmd_ctx_init(module, req);
3586 return ldb_module_oom(module);
3589 ret = ldb_build_rename_req(&down_req, ldb, ac,
3590 ac->req->op.rename.olddn,
3591 ac->req->op.rename.newdn,
3593 ac, replmd_rename_callback,
3595 LDB_REQ_SET_LOCATION(down_req);
3596 if (ret != LDB_SUCCESS) {
3601 /* go on with the call chain */
3602 return ldb_next_request(module, down_req);
3605 /* After the rename is compleated, update the whenchanged etc */
3606 static int replmd_rename_callback(struct ldb_request *req, struct ldb_reply *ares)
3608 struct ldb_context *ldb;
3609 struct ldb_request *down_req;
3610 struct ldb_message *msg;
3611 const struct dsdb_attribute *rdn_attr;
3612 const char *rdn_name;
3613 const struct ldb_val *rdn_val;
3614 const char *attrs[5] = { NULL, };
3615 time_t t = time(NULL);
3617 bool is_urgent = false, rodc = false;
3619 struct replmd_replicated_request *ac =
3620 talloc_get_type(req->context, struct replmd_replicated_request);
3621 struct replmd_private *replmd_private =
3622 talloc_get_type(ldb_module_get_private(ac->module),
3623 struct replmd_private);
3625 ldb = ldb_module_get_ctx(ac->module);
3627 if (ares->error != LDB_SUCCESS) {
3628 return ldb_module_done(ac->req, ares->controls,
3629 ares->response, ares->error);
3632 if (ares->type != LDB_REPLY_DONE) {
3633 ldb_set_errstring(ldb,
3634 "invalid ldb_reply_type in callback");
3636 return ldb_module_done(ac->req, NULL, NULL,
3637 LDB_ERR_OPERATIONS_ERROR);
3641 * - replace the old object with the newly constructed one
3644 msg = ldb_msg_new(ac);
3647 return LDB_ERR_OPERATIONS_ERROR;
3650 msg->dn = ac->req->op.rename.newdn;
3652 is_schema_nc = ldb_dn_compare_base(replmd_private->schema_dn, msg->dn) == 0;
3654 rdn_name = ldb_dn_get_rdn_name(msg->dn);
3655 if (rdn_name == NULL) {
3657 return ldb_module_done(ac->req, NULL, NULL,
3661 /* normalize the rdn attribute name */
3662 rdn_attr = dsdb_attribute_by_lDAPDisplayName(ac->schema, rdn_name);
3663 if (rdn_attr == NULL) {
3665 return ldb_module_done(ac->req, NULL, NULL,
3668 rdn_name = rdn_attr->lDAPDisplayName;
3670 rdn_val = ldb_dn_get_rdn_val(msg->dn);
3671 if (rdn_val == NULL) {
3673 return ldb_module_done(ac->req, NULL, NULL,
3677 if (ldb_msg_add_empty(msg, rdn_name, LDB_FLAG_MOD_REPLACE, NULL) != 0) {
3679 return ldb_module_done(ac->req, NULL, NULL,
3682 if (ldb_msg_add_value(msg, rdn_name, rdn_val, NULL) != 0) {
3684 return ldb_module_done(ac->req, NULL, NULL,
3687 if (ldb_msg_add_empty(msg, "name", LDB_FLAG_MOD_REPLACE, NULL) != 0) {
3689 return ldb_module_done(ac->req, NULL, NULL,
3692 if (ldb_msg_add_value(msg, "name", rdn_val, NULL) != 0) {
3694 return ldb_module_done(ac->req, NULL, NULL,
3699 * here we let replmd_update_rpmd() only search for
3700 * the existing "replPropertyMetaData" and rdn_name attributes.
3702 * We do not want the existing "name" attribute as
3703 * the "name" attribute needs to get the version
3704 * updated on rename even if the rdn value hasn't changed.
3706 * This is the diff of the meta data, for a moved user
3707 * on a w2k8r2 server:
3710 * -dn: CN=sdf df,CN=Users,DC=bla,DC=base
3711 * +dn: CN=sdf df,OU=TestOU,DC=bla,DC=base
3712 * replPropertyMetaData: NDR: struct replPropertyMetaDataBlob
3713 * version : 0x00000001 (1)
3714 * reserved : 0x00000000 (0)
3715 * @@ -66,11 +66,11 @@ replPropertyMetaData: NDR: struct re
3716 * local_usn : 0x00000000000037a5 (14245)
3717 * array: struct replPropertyMetaData1
3718 * attid : DRSUAPI_ATTID_name (0x90001)
3719 * - version : 0x00000001 (1)
3720 * - originating_change_time : Wed Feb 9 17:20:49 2011 CET
3721 * + version : 0x00000002 (2)
3722 * + originating_change_time : Wed Apr 6 15:21:01 2011 CEST
3723 * originating_invocation_id: 0d36ca05-5507-4e62-aca3-354bab0d39e1
3724 * - originating_usn : 0x00000000000037a5 (14245)
3725 * - local_usn : 0x00000000000037a5 (14245)
3726 * + originating_usn : 0x0000000000003834 (14388)
3727 * + local_usn : 0x0000000000003834 (14388)
3728 * array: struct replPropertyMetaData1
3729 * attid : DRSUAPI_ATTID_userAccountControl (0x90008)
3730 * version : 0x00000004 (4)
3732 attrs[0] = "replPropertyMetaData";
3733 attrs[1] = "objectClass";
3734 attrs[2] = "instanceType";
3735 attrs[3] = rdn_name;
3738 ret = replmd_update_rpmd(ac->module, ac->schema, req, attrs,
3739 msg, &ac->seq_num, t,
3740 is_schema_nc, &is_urgent, &rodc);
3741 if (rodc && (ret == LDB_ERR_REFERRAL)) {
3742 ret = send_rodc_referral(req, ldb, ac->req->op.rename.olddn);
3744 return ldb_module_done(req, NULL, NULL, ret);
3747 if (ret != LDB_SUCCESS) {
3749 return ldb_module_done(ac->req, NULL, NULL, ret);
3752 if (ac->seq_num == 0) {
3754 return ldb_module_done(ac->req, NULL, NULL,
3756 "internal error seq_num == 0"));
3758 ac->is_urgent = is_urgent;
3760 ret = ldb_build_mod_req(&down_req, ldb, ac,
3763 ac, replmd_op_callback,
3765 LDB_REQ_SET_LOCATION(down_req);
3766 if (ret != LDB_SUCCESS) {
3771 /* current partition control is needed by "replmd_op_callback" */
3772 if (ldb_request_get_control(req, DSDB_CONTROL_CURRENT_PARTITION_OID) == NULL) {
3773 ret = ldb_request_add_control(down_req,
3774 DSDB_CONTROL_CURRENT_PARTITION_OID,
3776 if (ret != LDB_SUCCESS) {
3782 talloc_steal(down_req, msg);
3784 ret = add_time_element(msg, "whenChanged", t);
3785 if (ret != LDB_SUCCESS) {
3791 ret = add_uint64_element(ldb, msg, "uSNChanged", ac->seq_num);
3792 if (ret != LDB_SUCCESS) {
3798 /* go on with the call chain - do the modify after the rename */
3799 return ldb_next_request(ac->module, down_req);
3803 * remove links from objects that point at this object when an object
3804 * is deleted. We remove it from the NEXT module per MS-DRSR 5.160
3805 * RemoveObj which states that link removal due to the object being
3806 * deleted is NOT an originating update - they just go away!
3809 static int replmd_delete_remove_link(struct ldb_module *module,
3810 const struct dsdb_schema *schema,
3811 struct replmd_private *replmd_private,
3814 struct ldb_message_element *el,
3815 const struct dsdb_attribute *sa,
3816 struct ldb_request *parent)
3819 TALLOC_CTX *tmp_ctx = talloc_new(module);
3820 struct ldb_context *ldb = ldb_module_get_ctx(module);
3822 for (i=0; i<el->num_values; i++) {
3823 struct dsdb_dn *dsdb_dn;
3825 struct ldb_message *msg;
3826 const struct dsdb_attribute *target_attr;
3827 struct ldb_message_element *el2;
3829 struct ldb_val dn_val;
3830 uint32_t dsdb_flags = 0;
3831 const char *attrs[] = { NULL, NULL };
3832 struct ldb_result *link_res;
3833 struct ldb_message *link_msg;
3834 struct ldb_message_element *link_el;
3835 struct parsed_dn *link_dns;
3836 struct parsed_dn *p = NULL, *unused = NULL;
3838 if (dsdb_dn_is_deleted_val(&el->values[i])) {
3842 dsdb_dn = dsdb_dn_parse(tmp_ctx, ldb, &el->values[i], sa->syntax->ldap_oid);
3844 talloc_free(tmp_ctx);
3845 return LDB_ERR_OPERATIONS_ERROR;
3848 /* remove the link */
3849 msg = ldb_msg_new(tmp_ctx);
3851 ldb_module_oom(module);
3852 talloc_free(tmp_ctx);
3853 return LDB_ERR_OPERATIONS_ERROR;
3857 msg->dn = dsdb_dn->dn;
3859 target_attr = dsdb_attribute_by_linkID(schema, sa->linkID ^ 1);
3860 if (target_attr == NULL) {
3863 attrs[0] = target_attr->lDAPDisplayName;
3865 ret = ldb_msg_add_empty(msg, target_attr->lDAPDisplayName,
3866 LDB_FLAG_MOD_DELETE, &el2);
3867 if (ret != LDB_SUCCESS) {
3868 ldb_module_oom(module);
3869 talloc_free(tmp_ctx);
3870 return LDB_ERR_OPERATIONS_ERROR;
3873 ret = dsdb_module_search_dn(module, tmp_ctx, &link_res,
3875 DSDB_FLAG_NEXT_MODULE |
3876 DSDB_SEARCH_SHOW_EXTENDED_DN |
3877 DSDB_SEARCH_SHOW_RECYCLED,
3880 if (ret != LDB_SUCCESS) {
3881 talloc_free(tmp_ctx);
3885 link_msg = link_res->msgs[0];
3886 link_el = ldb_msg_find_element(link_msg,
3887 target_attr->lDAPDisplayName);
3888 if (link_el == NULL) {
3889 talloc_free(tmp_ctx);
3890 return LDB_ERR_NO_SUCH_ATTRIBUTE;
3894 * This call 'upgrades' the links in link_dns, but we
3895 * do not commit the result back into the database, so
3896 * this is safe to call in FL2000 or on databases that
3897 * have been run at that level in the past.
3899 ret = get_parsed_dns_trusted(module, replmd_private, tmp_ctx,
3901 target_attr->syntax->ldap_oid, parent);
3902 if (ret != LDB_SUCCESS) {
3903 talloc_free(tmp_ctx);
3907 ret = parsed_dn_find(ldb, link_dns, link_el->num_values,
3911 target_attr->syntax->ldap_oid, false);
3912 if (ret != LDB_SUCCESS) {
3913 talloc_free(tmp_ctx);
3918 ldb_asprintf_errstring(ldb_module_get_ctx(module),
3919 "Failed to find forward link on %s "
3920 "as %s to remove backlink %s on %s",
3921 ldb_dn_get_linearized(msg->dn),
3922 target_attr->lDAPDisplayName,
3923 sa->lDAPDisplayName,
3924 ldb_dn_get_linearized(dn));
3925 talloc_free(tmp_ctx);
3926 return LDB_ERR_NO_SUCH_ATTRIBUTE;
3930 /* This needs to get the Binary DN, by first searching */
3931 dn_str = dsdb_dn_get_linearized(tmp_ctx,
3934 dn_val = data_blob_string_const(dn_str);
3935 el2->values = &dn_val;
3936 el2->num_values = 1;
3939 * Ensure that we tell the modification to vanish any linked
3940 * attributes (not simply mark them as isDeleted = TRUE)
3942 dsdb_flags |= DSDB_REPLMD_VANISH_LINKS;
3944 ret = dsdb_module_modify(module, msg, dsdb_flags|DSDB_FLAG_OWN_MODULE, parent);
3945 if (ret != LDB_SUCCESS) {
3946 talloc_free(tmp_ctx);
3950 talloc_free(tmp_ctx);
3956 handle update of replication meta data for deletion of objects
3958 This also handles the mapping of delete to a rename operation
3959 to allow deletes to be replicated.
3961 It also handles the incoming deleted objects, to ensure they are
3962 fully deleted here. In that case re_delete is true, and we do not
3963 use this as a signal to change the deleted state, just reinforce it.
3966 static int replmd_delete_internals(struct ldb_module *module, struct ldb_request *req, bool re_delete)
3968 int ret = LDB_ERR_OTHER;
3969 bool retb, disallow_move_on_delete;
3970 struct ldb_dn *old_dn = NULL, *new_dn = NULL;
3971 const char *rdn_name;
3972 const struct ldb_val *rdn_value, *new_rdn_value;
3974 struct ldb_context *ldb = ldb_module_get_ctx(module);
3975 const struct dsdb_schema *schema;
3976 struct ldb_message *msg, *old_msg;
3977 struct ldb_message_element *el;
3978 TALLOC_CTX *tmp_ctx;
3979 struct ldb_result *res, *parent_res;
3980 static const char * const preserved_attrs[] = {
3981 /* yes, this really is a hard coded list. See MS-ADTS
3982 section 3.1.1.5.5.1.1 */
3985 "dNReferenceUpdate",
3996 "msDS-LastKnownRDN",
4002 "distinguishedName",
4006 "proxiedObjectName",
4008 "nTSecurityDescriptor",
4009 "replPropertyMetaData",
4011 "securityIdentifier",
4019 "userAccountControl",
4026 static const char * const all_attrs[] = {
4027 DSDB_SECRET_ATTRIBUTES,
4031 static const struct ldb_val true_val = {
4032 .data = discard_const_p(uint8_t, "TRUE"),
4037 uint32_t dsdb_flags = 0;
4038 struct replmd_private *replmd_private;
4039 enum deletion_state deletion_state, next_deletion_state;
4041 if (ldb_dn_is_special(req->op.del.dn)) {
4042 return ldb_next_request(module, req);
4046 * We have to allow dbcheck to remove an object that
4047 * is beyond repair, and to do so totally. This could
4048 * mean we we can get a partial object from the other
4049 * DC, causing havoc, so dbcheck suggests
4050 * re-replication first. dbcheck sets both DBCHECK
4051 * and RELAX in this situation.
4053 if (ldb_request_get_control(req, LDB_CONTROL_RELAX_OID)
4054 && ldb_request_get_control(req, DSDB_CONTROL_DBCHECK)) {
4055 /* really, really remove it */
4056 return ldb_next_request(module, req);
4059 tmp_ctx = talloc_new(ldb);
4062 return LDB_ERR_OPERATIONS_ERROR;
4065 schema = dsdb_get_schema(ldb, tmp_ctx);
4067 talloc_free(tmp_ctx);
4068 return LDB_ERR_OPERATIONS_ERROR;
4071 old_dn = ldb_dn_copy(tmp_ctx, req->op.del.dn);
4073 /* we need the complete msg off disk, so we can work out which
4074 attributes need to be removed */
4075 ret = dsdb_module_search_dn(module, tmp_ctx, &res, old_dn, all_attrs,
4076 DSDB_FLAG_NEXT_MODULE |
4077 DSDB_SEARCH_SHOW_RECYCLED |
4078 DSDB_SEARCH_REVEAL_INTERNALS |
4079 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT, req);
4080 if (ret != LDB_SUCCESS) {
4081 ldb_asprintf_errstring(ldb_module_get_ctx(module),
4082 "repmd_delete: Failed to %s %s, because we failed to find it: %s",
4083 re_delete ? "re-delete" : "delete",
4084 ldb_dn_get_linearized(old_dn),
4085 ldb_errstring(ldb_module_get_ctx(module)));
4086 talloc_free(tmp_ctx);
4089 old_msg = res->msgs[0];
4091 replmd_deletion_state(module, old_msg,
4093 &next_deletion_state);
4095 /* This supports us noticing an incoming isDeleted and acting on it */
4097 SMB_ASSERT(deletion_state > OBJECT_NOT_DELETED);
4098 next_deletion_state = deletion_state;
4101 if (next_deletion_state == OBJECT_REMOVED) {
4103 * We have to prevent objects being deleted, even if
4104 * the administrator really wants them gone, as
4105 * without the tombstone, we can get a partial object
4106 * from the other DC, causing havoc.
4108 * The only other valid case is when the 180 day
4109 * timeout has expired, when relax is specified.
4111 if (ldb_request_get_control(req, LDB_CONTROL_RELAX_OID)) {
4112 /* it is already deleted - really remove it this time */
4113 talloc_free(tmp_ctx);
4114 return ldb_next_request(module, req);
4117 ldb_asprintf_errstring(ldb, "Refusing to delete tombstone object %s. "
4118 "This check is to prevent corruption of the replicated state.",
4119 ldb_dn_get_linearized(old_msg->dn));
4120 return LDB_ERR_UNWILLING_TO_PERFORM;
4123 rdn_name = ldb_dn_get_rdn_name(old_dn);
4124 rdn_value = ldb_dn_get_rdn_val(old_dn);
4125 if ((rdn_name == NULL) || (rdn_value == NULL)) {
4126 talloc_free(tmp_ctx);
4127 return ldb_operr(ldb);
4130 msg = ldb_msg_new(tmp_ctx);
4132 ldb_module_oom(module);
4133 talloc_free(tmp_ctx);
4134 return LDB_ERR_OPERATIONS_ERROR;
4139 /* consider the SYSTEM_FLAG_DISALLOW_MOVE_ON_DELETE flag */
4140 disallow_move_on_delete =
4141 (ldb_msg_find_attr_as_int(old_msg, "systemFlags", 0)
4142 & SYSTEM_FLAG_DISALLOW_MOVE_ON_DELETE);
4144 /* work out where we will be renaming this object to */
4145 if (!disallow_move_on_delete) {
4146 struct ldb_dn *deleted_objects_dn;
4147 ret = dsdb_get_deleted_objects_dn(ldb, tmp_ctx, old_dn,
4148 &deleted_objects_dn);
4151 * We should not move objects if we can't find the
4152 * deleted objects DN. Not moving (or otherwise
4153 * harming) the Deleted Objects DN itself is handled
4156 if (re_delete && (ret != LDB_SUCCESS)) {
4157 new_dn = ldb_dn_get_parent(tmp_ctx, old_dn);
4158 if (new_dn == NULL) {
4159 ldb_module_oom(module);
4160 talloc_free(tmp_ctx);
4161 return LDB_ERR_OPERATIONS_ERROR;
4163 } else if (ret != LDB_SUCCESS) {
4164 /* this is probably an attempted delete on a partition
4165 * that doesn't allow delete operations, such as the
4166 * schema partition */
4167 ldb_asprintf_errstring(ldb, "No Deleted Objects container for DN %s",
4168 ldb_dn_get_linearized(old_dn));
4169 talloc_free(tmp_ctx);
4170 return LDB_ERR_UNWILLING_TO_PERFORM;
4172 new_dn = deleted_objects_dn;
4175 new_dn = ldb_dn_get_parent(tmp_ctx, old_dn);
4176 if (new_dn == NULL) {
4177 ldb_module_oom(module);
4178 talloc_free(tmp_ctx);
4179 return LDB_ERR_OPERATIONS_ERROR;
4183 /* get the objects GUID from the search we just did */
4184 guid = samdb_result_guid(old_msg, "objectGUID");
4186 if (deletion_state == OBJECT_NOT_DELETED) {
4187 struct ldb_message_element *is_deleted_el;
4189 ret = replmd_make_deleted_child_dn(tmp_ctx,
4192 rdn_name, rdn_value,
4195 if (ret != LDB_SUCCESS) {
4196 talloc_free(tmp_ctx);
4200 ret = ldb_msg_add_value(msg, "isDeleted", &true_val,
4202 if (ret != LDB_SUCCESS) {
4203 ldb_asprintf_errstring(ldb, __location__
4204 ": Failed to add isDeleted string to the msg");
4205 talloc_free(tmp_ctx);
4208 is_deleted_el->flags = LDB_FLAG_MOD_REPLACE;
4211 * No matter what has happened with other renames etc, try again to
4212 * get this to be under the deleted DN. See MS-DRSR 5.160 RemoveObj
4215 struct ldb_dn *rdn = ldb_dn_copy(tmp_ctx, old_dn);
4216 retb = ldb_dn_remove_base_components(rdn, ldb_dn_get_comp_num(rdn) - 1);
4218 ldb_asprintf_errstring(ldb, __location__
4219 ": Unable to add a prepare rdn of %s",
4220 ldb_dn_get_linearized(rdn));
4221 talloc_free(tmp_ctx);
4222 return LDB_ERR_OPERATIONS_ERROR;
4224 SMB_ASSERT(ldb_dn_get_comp_num(rdn) == 1);
4226 retb = ldb_dn_add_child(new_dn, rdn);
4228 ldb_asprintf_errstring(ldb, __location__
4229 ": Unable to add rdn %s to base dn: %s",
4230 ldb_dn_get_linearized(rdn),
4231 ldb_dn_get_linearized(new_dn));
4232 talloc_free(tmp_ctx);
4233 return LDB_ERR_OPERATIONS_ERROR;
4238 now we need to modify the object in the following ways:
4240 - add isDeleted=TRUE
4241 - update rDN and name, with new rDN
4242 - remove linked attributes
4243 - remove objectCategory and sAMAccountType
4244 - remove attribs not on the preserved list
4245 - preserved if in above list, or is rDN
4246 - remove all linked attribs from this object
4247 - remove all links from other objects to this object
4248 - add lastKnownParent
4249 - update replPropertyMetaData?
4251 see MS-ADTS "Tombstone Requirements" section 3.1.1.5.5.1.1
4254 if (deletion_state == OBJECT_NOT_DELETED) {
4255 struct ldb_dn *parent_dn = ldb_dn_get_parent(tmp_ctx, old_dn);
4256 char *parent_dn_str = NULL;
4257 struct ldb_message_element *p_el;
4259 /* we need the storage form of the parent GUID */
4260 ret = dsdb_module_search_dn(module, tmp_ctx, &parent_res,
4262 DSDB_FLAG_NEXT_MODULE |
4263 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT |
4264 DSDB_SEARCH_REVEAL_INTERNALS|
4265 DSDB_SEARCH_SHOW_RECYCLED, req);
4266 if (ret != LDB_SUCCESS) {
4267 ldb_asprintf_errstring(ldb_module_get_ctx(module),
4268 "repmd_delete: Failed to %s %s, "
4269 "because we failed to find it's parent (%s): %s",
4270 re_delete ? "re-delete" : "delete",
4271 ldb_dn_get_linearized(old_dn),
4272 ldb_dn_get_linearized(parent_dn),
4273 ldb_errstring(ldb_module_get_ctx(module)));
4274 talloc_free(tmp_ctx);
4279 * Now we can use the DB version,
4280 * it will have the extended DN info in it
4282 parent_dn = parent_res->msgs[0]->dn;
4283 parent_dn_str = ldb_dn_get_extended_linearized(tmp_ctx,
4286 if (parent_dn_str == NULL) {
4287 talloc_free(tmp_ctx);
4288 return ldb_module_oom(module);
4291 ret = ldb_msg_add_steal_string(msg, "lastKnownParent",
4293 if (ret != LDB_SUCCESS) {
4294 ldb_asprintf_errstring(ldb, __location__
4295 ": Failed to add lastKnownParent "
4296 "string when deleting %s",
4297 ldb_dn_get_linearized(old_dn));
4298 talloc_free(tmp_ctx);
4301 p_el = ldb_msg_find_element(msg,
4304 talloc_free(tmp_ctx);
4305 return ldb_module_operr(module);
4307 p_el->flags = LDB_FLAG_MOD_REPLACE;
4309 if (next_deletion_state == OBJECT_DELETED) {
4310 ret = ldb_msg_add_value(msg, "msDS-LastKnownRDN", rdn_value, NULL);
4311 if (ret != LDB_SUCCESS) {
4312 ldb_asprintf_errstring(ldb, __location__
4313 ": Failed to add msDS-LastKnownRDN "
4314 "string when deleting %s",
4315 ldb_dn_get_linearized(old_dn));
4316 talloc_free(tmp_ctx);
4319 p_el = ldb_msg_find_element(msg,
4320 "msDS-LastKnownRDN");
4322 talloc_free(tmp_ctx);
4323 return ldb_module_operr(module);
4325 p_el->flags = LDB_FLAG_MOD_ADD;
4329 switch (next_deletion_state) {
4331 case OBJECT_RECYCLED:
4332 case OBJECT_TOMBSTONE:
4335 * MS-ADTS 3.1.1.5.5.1.1 Tombstone Requirements
4336 * describes what must be removed from a tombstone
4339 * MS-ADTS 3.1.1.5.5.1.3 Recycled-Object Requirements
4340 * describes what must be removed from a recycled
4346 * we also mark it as recycled, meaning this object can't be
4347 * recovered (we are stripping its attributes).
4348 * This is done only if we have this schema object of course ...
4349 * This behavior is identical to the one of Windows 2008R2 which
4350 * always set the isRecycled attribute, even if the recycle-bin is
4351 * not activated and what ever the forest level is.
4353 if (dsdb_attribute_by_lDAPDisplayName(schema, "isRecycled") != NULL) {
4354 struct ldb_message_element *is_recycled_el;
4356 ret = ldb_msg_add_value(msg, "isRecycled", &true_val,
4358 if (ret != LDB_SUCCESS) {
4359 DEBUG(0,(__location__ ": Failed to add isRecycled string to the msg\n"));
4360 ldb_module_oom(module);
4361 talloc_free(tmp_ctx);
4364 is_recycled_el->flags = LDB_FLAG_MOD_REPLACE;
4367 replmd_private = talloc_get_type(ldb_module_get_private(module),
4368 struct replmd_private);
4369 /* work out which of the old attributes we will be removing */
4370 for (i=0; i<old_msg->num_elements; i++) {
4371 const struct dsdb_attribute *sa;
4372 el = &old_msg->elements[i];
4373 sa = dsdb_attribute_by_lDAPDisplayName(schema, el->name);
4375 talloc_free(tmp_ctx);
4376 return LDB_ERR_OPERATIONS_ERROR;
4378 if (ldb_attr_cmp(el->name, rdn_name) == 0) {
4379 /* don't remove the rDN */
4383 if (sa->linkID & 1) {
4385 we have a backlink in this object
4386 that needs to be removed. We're not
4387 allowed to remove it directly
4388 however, so we instead setup a
4389 modify to delete the corresponding
4392 ret = replmd_delete_remove_link(module, schema,
4396 if (ret == LDB_SUCCESS) {
4398 * now we continue, which means we
4399 * won't remove this backlink
4405 if (ret != LDB_ERR_NO_SUCH_ATTRIBUTE) {
4406 const char *old_dn_str
4407 = ldb_dn_get_linearized(old_dn);
4408 ldb_asprintf_errstring(ldb,
4410 ": Failed to remove backlink of "
4411 "%s when deleting %s: %s",
4414 ldb_errstring(ldb));
4415 talloc_free(tmp_ctx);
4416 return LDB_ERR_OPERATIONS_ERROR;
4420 * Otherwise vanish the link, we are
4421 * out of sync and the controlling
4422 * object does not have the source
4426 dsdb_flags |= DSDB_REPLMD_VANISH_LINKS;
4428 } else if (sa->linkID == 0) {
4429 if (ldb_attr_in_list(preserved_attrs, el->name)) {
4432 if (sa->searchFlags & SEARCH_FLAG_PRESERVEONDELETE) {
4437 * Ensure that we tell the modification to vanish any linked
4438 * attributes (not simply mark them as isDeleted = TRUE)
4440 dsdb_flags |= DSDB_REPLMD_VANISH_LINKS;
4442 ret = ldb_msg_add_empty(msg, el->name, LDB_FLAG_MOD_DELETE, &el);
4443 if (ret != LDB_SUCCESS) {
4444 talloc_free(tmp_ctx);
4445 ldb_module_oom(module);
4452 case OBJECT_DELETED:
4454 * MS-ADTS 3.1.1.5.5.1.2 Deleted-Object Requirements
4455 * describes what must be removed from a deleted
4459 ret = ldb_msg_add_empty(msg, "objectCategory", LDB_FLAG_MOD_REPLACE, NULL);
4460 if (ret != LDB_SUCCESS) {
4461 talloc_free(tmp_ctx);
4462 ldb_module_oom(module);
4466 ret = ldb_msg_add_empty(msg, "sAMAccountType", LDB_FLAG_MOD_REPLACE, NULL);
4467 if (ret != LDB_SUCCESS) {
4468 talloc_free(tmp_ctx);
4469 ldb_module_oom(module);
4479 if (deletion_state == OBJECT_NOT_DELETED) {
4480 const struct dsdb_attribute *sa;
4482 /* work out what the new rdn value is, for updating the
4483 rDN and name fields */
4484 new_rdn_value = ldb_dn_get_rdn_val(new_dn);
4485 if (new_rdn_value == NULL) {
4486 talloc_free(tmp_ctx);
4487 return ldb_operr(ldb);
4490 sa = dsdb_attribute_by_lDAPDisplayName(schema, rdn_name);
4492 talloc_free(tmp_ctx);
4493 return LDB_ERR_OPERATIONS_ERROR;
4496 ret = ldb_msg_add_value(msg, sa->lDAPDisplayName, new_rdn_value,
4498 if (ret != LDB_SUCCESS) {
4499 talloc_free(tmp_ctx);
4502 el->flags = LDB_FLAG_MOD_REPLACE;
4504 el = ldb_msg_find_element(old_msg, "name");
4506 ret = ldb_msg_add_value(msg, "name", new_rdn_value, &el);
4507 if (ret != LDB_SUCCESS) {
4508 talloc_free(tmp_ctx);
4511 el->flags = LDB_FLAG_MOD_REPLACE;
4516 * TODO: Per MS-DRSR 5.160 RemoveObj we should remove links directly, not as an originating update!
4521 * No matter what has happned with other renames, try again to
4522 * get this to be under the deleted DN.
4524 if (strcmp(ldb_dn_get_linearized(old_dn), ldb_dn_get_linearized(new_dn)) != 0) {
4525 /* now rename onto the new DN */
4526 ret = dsdb_module_rename(module, old_dn, new_dn, DSDB_FLAG_NEXT_MODULE, req);
4527 if (ret != LDB_SUCCESS){
4528 DEBUG(0,(__location__ ": Failed to rename object from '%s' to '%s' - %s\n",
4529 ldb_dn_get_linearized(old_dn),
4530 ldb_dn_get_linearized(new_dn),
4531 ldb_errstring(ldb)));
4532 talloc_free(tmp_ctx);
4538 ret = dsdb_module_modify(module, msg, dsdb_flags|DSDB_FLAG_OWN_MODULE, req);
4539 if (ret != LDB_SUCCESS) {
4540 ldb_asprintf_errstring(ldb, "replmd_delete: Failed to modify object %s in delete - %s",
4541 ldb_dn_get_linearized(old_dn), ldb_errstring(ldb));
4542 talloc_free(tmp_ctx);
4546 talloc_free(tmp_ctx);
4548 return ldb_module_done(req, NULL, NULL, LDB_SUCCESS);
4551 static int replmd_delete(struct ldb_module *module, struct ldb_request *req)
4553 return replmd_delete_internals(module, req, false);
4557 static int replmd_replicated_request_error(struct replmd_replicated_request *ar, int ret)
4562 static int replmd_replicated_request_werror(struct replmd_replicated_request *ar, WERROR status)
4564 int ret = LDB_ERR_OTHER;
4565 /* TODO: do some error mapping */
4567 /* Let the caller know the full WERROR */
4568 ar->objs->error = status;
4574 static struct replPropertyMetaData1 *
4575 replmd_replPropertyMetaData1_find_attid(struct replPropertyMetaDataBlob *md_blob,
4576 enum drsuapi_DsAttributeId attid)
4579 struct replPropertyMetaDataCtr1 *rpmd_ctr = &md_blob->ctr.ctr1;
4581 for (i = 0; i < rpmd_ctr->count; i++) {
4582 if (rpmd_ctr->array[i].attid == attid) {
4583 return &rpmd_ctr->array[i];
4591 return true if an update is newer than an existing entry
4592 see section 5.11 of MS-ADTS
4594 static bool replmd_update_is_newer(const struct GUID *current_invocation_id,
4595 const struct GUID *update_invocation_id,
4596 uint32_t current_version,
4597 uint32_t update_version,
4598 NTTIME current_change_time,
4599 NTTIME update_change_time)
4601 if (update_version != current_version) {
4602 return update_version > current_version;
4604 if (update_change_time != current_change_time) {
4605 return update_change_time > current_change_time;
4607 return GUID_compare(update_invocation_id, current_invocation_id) > 0;
4610 static bool replmd_replPropertyMetaData1_is_newer(struct replPropertyMetaData1 *cur_m,
4611 struct replPropertyMetaData1 *new_m)
4613 return replmd_update_is_newer(&cur_m->originating_invocation_id,
4614 &new_m->originating_invocation_id,
4617 cur_m->originating_change_time,
4618 new_m->originating_change_time);
4621 static bool replmd_replPropertyMetaData1_new_should_be_taken(uint32_t dsdb_repl_flags,
4622 struct replPropertyMetaData1 *cur_m,
4623 struct replPropertyMetaData1 *new_m)
4628 * If the new replPropertyMetaData entry for this attribute is
4629 * not provided (this happens in the case where we look for
4630 * ATTID_name, but the name was not changed), then the local
4631 * state is clearly still current, as the remote
4632 * server didn't send it due to being older the high watermark
4635 if (new_m == NULL) {
4639 if (dsdb_repl_flags & DSDB_REPL_FLAG_PRIORITISE_INCOMING) {
4641 * if we compare equal then do an
4642 * update. This is used when a client
4643 * asks for a FULL_SYNC, and can be
4644 * used to recover a corrupt
4647 * This call is a bit tricky, what we
4648 * are doing it turning the 'is_newer'
4649 * call into a 'not is older' by
4650 * swapping cur_m and new_m, and negating the
4653 cmp = !replmd_replPropertyMetaData1_is_newer(new_m,
4656 cmp = replmd_replPropertyMetaData1_is_newer(cur_m,
4664 form a DN for a deleted (DEL:) or conflict (CNF:) DN
4666 static int replmd_make_prefix_child_dn(TALLOC_CTX *tmp_ctx,
4667 struct ldb_context *ldb,
4669 const char *four_char_prefix,
4670 const char *rdn_name,
4671 const struct ldb_val *rdn_value,
4674 struct ldb_val deleted_child_rdn_val;
4675 struct GUID_txt_buf guid_str;
4679 GUID_buf_string(&guid, &guid_str);
4681 retb = ldb_dn_add_child_fmt(dn, "X=Y");
4683 ldb_asprintf_errstring(ldb, __location__
4684 ": Unable to add a formatted child to dn: %s",
4685 ldb_dn_get_linearized(dn));
4686 return LDB_ERR_OPERATIONS_ERROR;
4690 * TODO: Per MS-ADTS 3.1.1.5.5 Delete Operation
4691 * we should truncate this value to ensure the RDN is not more than 255 chars.
4693 * However we MS-ADTS 3.1.1.5.1.2 Naming Constraints indicates that:
4695 * "Naming constraints are not enforced for replicated
4696 * updates." so this is safe and we don't have to work out not
4697 * splitting a UTF8 char right now.
4699 deleted_child_rdn_val = ldb_val_dup(tmp_ctx, rdn_value);
4702 * sizeof(guid_str.buf) will always be longer than
4703 * strlen(guid_str.buf) but we allocate using this and
4704 * waste the trailing bytes to avoid scaring folks
4705 * with memcpy() using strlen() below
4708 deleted_child_rdn_val.data
4709 = talloc_realloc(tmp_ctx, deleted_child_rdn_val.data,
4711 rdn_value->length + 5
4712 + sizeof(guid_str.buf));
4713 if (!deleted_child_rdn_val.data) {
4714 ldb_asprintf_errstring(ldb, __location__
4715 ": Unable to add a formatted child to dn: %s",
4716 ldb_dn_get_linearized(dn));
4717 return LDB_ERR_OPERATIONS_ERROR;
4720 deleted_child_rdn_val.length =
4721 rdn_value->length + 5
4722 + strlen(guid_str.buf);
4724 SMB_ASSERT(deleted_child_rdn_val.length <
4725 talloc_get_size(deleted_child_rdn_val.data));
4728 * talloc won't allocate more than 256MB so we can't
4729 * overflow but just to be sure
4731 if (deleted_child_rdn_val.length < rdn_value->length) {
4732 return LDB_ERR_OPERATIONS_ERROR;
4735 deleted_child_rdn_val.data[rdn_value->length] = 0x0a;
4736 memcpy(&deleted_child_rdn_val.data[rdn_value->length + 1],
4737 four_char_prefix, 4);
4738 memcpy(&deleted_child_rdn_val.data[rdn_value->length + 5],
4740 sizeof(guid_str.buf));
4742 /* Now set the value into the RDN, without parsing it */
4743 ret = ldb_dn_set_component(
4747 deleted_child_rdn_val);
4756 static struct ldb_dn *replmd_conflict_dn(TALLOC_CTX *mem_ctx,
4757 struct ldb_context *ldb,
4761 const struct ldb_val *rdn_val;
4762 const char *rdn_name;
4763 struct ldb_dn *new_dn;
4766 rdn_val = ldb_dn_get_rdn_val(dn);
4767 rdn_name = ldb_dn_get_rdn_name(dn);
4768 if (!rdn_val || !rdn_name) {
4772 new_dn = ldb_dn_get_parent(mem_ctx, dn);
4777 ret = replmd_make_prefix_child_dn(mem_ctx,
4783 if (ret != LDB_SUCCESS) {
4792 static int replmd_make_deleted_child_dn(TALLOC_CTX *tmp_ctx,
4793 struct ldb_context *ldb,
4795 const char *rdn_name,
4796 const struct ldb_val *rdn_value,
4799 return replmd_make_prefix_child_dn(tmp_ctx,
4809 perform a modify operation which sets the rDN and name attributes to
4810 their current values. This has the effect of changing these
4811 attributes to have been last updated by the current DC. This is
4812 needed to ensure that renames performed as part of conflict
4813 resolution are propagated to other DCs
4815 static int replmd_name_modify(struct replmd_replicated_request *ar,
4816 struct ldb_request *req, struct ldb_dn *dn)
4818 struct ldb_message *msg;
4819 const char *rdn_name;
4820 const struct ldb_val *rdn_val;
4821 const struct dsdb_attribute *rdn_attr;
4824 msg = ldb_msg_new(req);
4830 rdn_name = ldb_dn_get_rdn_name(dn);
4831 if (rdn_name == NULL) {
4835 /* normalize the rdn attribute name */
4836 rdn_attr = dsdb_attribute_by_lDAPDisplayName(ar->schema, rdn_name);
4837 if (rdn_attr == NULL) {
4840 rdn_name = rdn_attr->lDAPDisplayName;
4842 rdn_val = ldb_dn_get_rdn_val(dn);
4843 if (rdn_val == NULL) {
4847 if (ldb_msg_add_empty(msg, rdn_name, LDB_FLAG_MOD_REPLACE, NULL) != 0) {
4850 if (ldb_msg_add_value(msg, rdn_name, rdn_val, NULL) != 0) {
4853 if (ldb_msg_add_empty(msg, "name", LDB_FLAG_MOD_REPLACE, NULL) != 0) {
4856 if (ldb_msg_add_value(msg, "name", rdn_val, NULL) != 0) {
4861 * We have to mark this as a replicated update otherwise
4862 * schema_data may reject a rename in the schema partition
4865 ret = dsdb_module_modify(ar->module, msg,
4866 DSDB_FLAG_OWN_MODULE|DSDB_FLAG_REPLICATED_UPDATE,
4868 if (ret != LDB_SUCCESS) {
4869 DEBUG(0,(__location__ ": Failed to modify rDN/name of DN being DRS renamed '%s' - %s",
4870 ldb_dn_get_linearized(dn),
4871 ldb_errstring(ldb_module_get_ctx(ar->module))));
4881 DEBUG(0,(__location__ ": Failed to setup modify rDN/name of DN being DRS renamed '%s'",
4882 ldb_dn_get_linearized(dn)));
4883 return LDB_ERR_OPERATIONS_ERROR;
4888 callback for conflict DN handling where we have renamed the incoming
4889 record. After renaming it, we need to ensure the change of name and
4890 rDN for the incoming record is seen as an originating update by this DC.
4892 This also handles updating lastKnownParent for entries sent to lostAndFound
4894 static int replmd_op_name_modify_callback(struct ldb_request *req, struct ldb_reply *ares)
4896 struct replmd_replicated_request *ar =
4897 talloc_get_type_abort(req->context, struct replmd_replicated_request);
4898 struct ldb_dn *conflict_dn = NULL;
4901 if (ares->error != LDB_SUCCESS) {
4902 /* call the normal callback for everything except success */
4903 return replmd_op_callback(req, ares);
4906 switch (req->operation) {
4908 conflict_dn = req->op.add.message->dn;
4911 conflict_dn = req->op.mod.message->dn;
4914 smb_panic("replmd_op_name_modify_callback called in unknown circumstances");
4917 /* perform a modify of the rDN and name of the record */
4918 ret = replmd_name_modify(ar, req, conflict_dn);
4919 if (ret != LDB_SUCCESS) {
4921 return replmd_op_callback(req, ares);
4924 if (ar->objs->objects[ar->index_current].last_known_parent) {
4925 struct ldb_message *msg = ldb_msg_new(req);
4927 ldb_module_oom(ar->module);
4928 return LDB_ERR_OPERATIONS_ERROR;
4931 msg->dn = req->op.add.message->dn;
4933 ret = ldb_msg_add_steal_string(msg, "lastKnownParent",
4934 ldb_dn_get_extended_linearized(msg, ar->objs->objects[ar->index_current].last_known_parent, 1));
4935 if (ret != LDB_SUCCESS) {
4936 DEBUG(0,(__location__ ": Failed to add lastKnownParent string to the msg\n"));
4937 ldb_module_oom(ar->module);
4940 msg->elements[0].flags = LDB_FLAG_MOD_REPLACE;
4942 ret = dsdb_module_modify(ar->module, msg, DSDB_FLAG_OWN_MODULE, req);
4943 if (ret != LDB_SUCCESS) {
4944 DEBUG(0,(__location__ ": Failed to modify lastKnownParent of lostAndFound DN '%s' - %s",
4945 ldb_dn_get_linearized(msg->dn),
4946 ldb_errstring(ldb_module_get_ctx(ar->module))));
4952 return replmd_op_callback(req, ares);
4956 callback for replmd_replicated_apply_add()
4957 This copes with the creation of conflict records in the case where
4958 the DN exists, but with a different objectGUID
4960 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))
4962 struct ldb_dn *conflict_dn;
4963 struct replmd_replicated_request *ar =
4964 talloc_get_type_abort(req->context, struct replmd_replicated_request);
4965 struct ldb_result *res;
4966 const char *attrs[] = { "replPropertyMetaData", "objectGUID", NULL };
4968 const struct ldb_val *omd_value;
4969 struct replPropertyMetaDataBlob omd, *rmd;
4970 enum ndr_err_code ndr_err;
4971 bool rename_incoming_record, rodc;
4972 struct replPropertyMetaData1 *rmd_name, *omd_name;
4973 struct ldb_message *msg;
4974 struct ldb_request *down_req = NULL;
4976 /* call the normal callback for success */
4977 if (ares->error == LDB_SUCCESS) {
4978 return callback(req, ares);
4982 * we have a conflict, and need to decide if we will keep the
4983 * new record or the old record
4986 msg = ar->objs->objects[ar->index_current].msg;
4987 conflict_dn = msg->dn;
4989 /* For failures other than conflicts, fail the whole operation here */
4990 if (ares->error != LDB_ERR_ENTRY_ALREADY_EXISTS) {
4991 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module), "Failed to locally apply remote add of %s: %s",
4992 ldb_dn_get_linearized(conflict_dn),
4993 ldb_errstring(ldb_module_get_ctx(ar->module)));
4995 return ldb_module_done(ar->req, NULL, NULL,
4996 LDB_ERR_OPERATIONS_ERROR);
4999 ret = samdb_rodc(ldb_module_get_ctx(ar->module), &rodc);
5000 if (ret != LDB_SUCCESS) {
5001 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)));
5002 return ldb_module_done(ar->req, NULL, NULL,
5003 LDB_ERR_OPERATIONS_ERROR);
5009 * We are on an RODC, or were a GC for this
5010 * partition, so we have to fail this until
5011 * someone who owns the partition sorts it
5014 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
5015 "Conflict adding object '%s' from incoming replication as we are read only for the partition. \n"
5016 " - We must fail the operation until a master for this partition resolves the conflict",
5017 ldb_dn_get_linearized(conflict_dn));
5018 ret = LDB_ERR_OPERATIONS_ERROR;
5023 * first we need the replPropertyMetaData attribute from the
5024 * local, conflicting record
5026 ret = dsdb_module_search_dn(ar->module, req, &res, conflict_dn,
5028 DSDB_FLAG_NEXT_MODULE |
5029 DSDB_SEARCH_SHOW_DELETED |
5030 DSDB_SEARCH_SHOW_RECYCLED, req);
5031 if (ret != LDB_SUCCESS) {
5032 DEBUG(0,(__location__ ": Unable to find object for conflicting record '%s'\n",
5033 ldb_dn_get_linearized(conflict_dn)));
5037 omd_value = ldb_msg_find_ldb_val(res->msgs[0], "replPropertyMetaData");
5038 if (omd_value == NULL) {
5039 DEBUG(0,(__location__ ": Unable to find replPropertyMetaData for conflicting record '%s'\n",
5040 ldb_dn_get_linearized(conflict_dn)));
5044 ndr_err = ndr_pull_struct_blob(omd_value, res->msgs[0], &omd,
5045 (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
5046 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
5047 DEBUG(0,(__location__ ": Failed to parse old replPropertyMetaData for %s\n",
5048 ldb_dn_get_linearized(conflict_dn)));
5052 rmd = ar->objs->objects[ar->index_current].meta_data;
5055 * we decide which is newer based on the RPMD on the name
5056 * attribute. See [MS-DRSR] ResolveNameConflict.
5058 * We expect omd_name to be present, as this is from a local
5059 * search, but while rmd_name should have been given to us by
5060 * the remote server, if it is missing we just prefer the
5062 * replmd_replPropertyMetaData1_new_should_be_taken()
5064 rmd_name = replmd_replPropertyMetaData1_find_attid(rmd, DRSUAPI_ATTID_name);
5065 omd_name = replmd_replPropertyMetaData1_find_attid(&omd, DRSUAPI_ATTID_name);
5067 DEBUG(0,(__location__ ": Failed to find name attribute in local LDB replPropertyMetaData for %s\n",
5068 ldb_dn_get_linearized(conflict_dn)));
5073 * Should we preserve the current record, and so rename the
5074 * incoming record to be a conflict?
5076 rename_incoming_record
5077 = !replmd_replPropertyMetaData1_new_should_be_taken(ar->objs->dsdb_repl_flags & DSDB_REPL_FLAG_PRIORITISE_INCOMING,
5078 omd_name, rmd_name);
5080 if (rename_incoming_record) {
5082 struct ldb_dn *new_dn;
5084 guid = samdb_result_guid(msg, "objectGUID");
5085 if (GUID_all_zero(&guid)) {
5086 DEBUG(0,(__location__ ": Failed to find objectGUID for conflicting incoming record %s\n",
5087 ldb_dn_get_linearized(conflict_dn)));
5090 new_dn = replmd_conflict_dn(req,
5091 ldb_module_get_ctx(ar->module),
5092 conflict_dn, &guid);
5093 if (new_dn == NULL) {
5094 DEBUG(0,(__location__ ": Failed to form conflict DN for %s\n",
5095 ldb_dn_get_linearized(conflict_dn)));
5099 DEBUG(2,(__location__ ": Resolving conflict record via incoming rename '%s' -> '%s'\n",
5100 ldb_dn_get_linearized(conflict_dn), ldb_dn_get_linearized(new_dn)));
5102 /* re-submit the request, but with the new DN */
5103 callback = replmd_op_name_modify_callback;
5106 /* we are renaming the existing record */
5108 struct ldb_dn *new_dn;
5110 guid = samdb_result_guid(res->msgs[0], "objectGUID");
5111 if (GUID_all_zero(&guid)) {
5112 DEBUG(0,(__location__ ": Failed to find objectGUID for existing conflict record %s\n",
5113 ldb_dn_get_linearized(conflict_dn)));
5117 new_dn = replmd_conflict_dn(req,
5118 ldb_module_get_ctx(ar->module),
5119 conflict_dn, &guid);
5120 if (new_dn == NULL) {
5121 DEBUG(0,(__location__ ": Failed to form conflict DN for %s\n",
5122 ldb_dn_get_linearized(conflict_dn)));
5126 DEBUG(2,(__location__ ": Resolving conflict record via existing-record rename '%s' -> '%s'\n",
5127 ldb_dn_get_linearized(conflict_dn), ldb_dn_get_linearized(new_dn)));
5129 ret = dsdb_module_rename(ar->module, conflict_dn, new_dn,
5130 DSDB_FLAG_OWN_MODULE, req);
5131 if (ret != LDB_SUCCESS) {
5132 DEBUG(0,(__location__ ": Failed to rename conflict dn '%s' to '%s' - %s\n",
5133 ldb_dn_get_linearized(conflict_dn),
5134 ldb_dn_get_linearized(new_dn),
5135 ldb_errstring(ldb_module_get_ctx(ar->module))));
5140 * now we need to ensure that the rename is seen as an
5141 * originating update. We do that with a modify.
5143 ret = replmd_name_modify(ar, req, new_dn);
5144 if (ret != LDB_SUCCESS) {
5148 DEBUG(2,(__location__ ": With conflicting record renamed, re-apply replicated creation of '%s'\n",
5149 ldb_dn_get_linearized(req->op.add.message->dn)));
5152 ret = ldb_build_add_req(&down_req,
5153 ldb_module_get_ctx(ar->module),
5160 if (ret != LDB_SUCCESS) {
5163 LDB_REQ_SET_LOCATION(down_req);
5165 /* current partition control needed by "repmd_op_callback" */
5166 ret = ldb_request_add_control(down_req,
5167 DSDB_CONTROL_CURRENT_PARTITION_OID,
5169 if (ret != LDB_SUCCESS) {
5170 return replmd_replicated_request_error(ar, ret);
5173 if (ar->objs->dsdb_repl_flags & DSDB_REPL_FLAG_PARTIAL_REPLICA) {
5174 /* this tells the partition module to make it a
5175 partial replica if creating an NC */
5176 ret = ldb_request_add_control(down_req,
5177 DSDB_CONTROL_PARTIAL_REPLICA,
5179 if (ret != LDB_SUCCESS) {
5180 return replmd_replicated_request_error(ar, ret);
5185 * Finally we re-run the add, otherwise the new record won't
5186 * exist, as we are here because of that exact failure!
5188 return ldb_next_request(ar->module, down_req);
5191 /* on failure make the caller get the error. This means
5192 * replication will stop with an error, but there is not much
5195 if (ret == LDB_SUCCESS) {
5196 ret = LDB_ERR_OPERATIONS_ERROR;
5198 return ldb_module_done(ar->req, NULL, NULL,
5203 callback for replmd_replicated_apply_add()
5204 This copes with the creation of conflict records in the case where
5205 the DN exists, but with a different objectGUID
5207 static int replmd_op_add_callback(struct ldb_request *req, struct ldb_reply *ares)
5209 struct replmd_replicated_request *ar =
5210 talloc_get_type_abort(req->context, struct replmd_replicated_request);
5212 if (ar->objs->objects[ar->index_current].last_known_parent) {
5213 /* This is like a conflict DN, where we put the object in LostAndFound
5214 see MS-DRSR 4.1.10.6.10 FindBestParentObject */
5215 return replmd_op_possible_conflict_callback(req, ares, replmd_op_name_modify_callback);
5218 return replmd_op_possible_conflict_callback(req, ares, replmd_op_callback);
5222 this is called when a new object comes in over DRS
5224 static int replmd_replicated_apply_add(struct replmd_replicated_request *ar)
5226 struct ldb_context *ldb;
5227 struct ldb_request *change_req;
5228 enum ndr_err_code ndr_err;
5229 struct ldb_message *msg;
5230 struct replPropertyMetaDataBlob *md;
5231 struct ldb_val md_value;
5234 bool remote_isDeleted = false;
5237 time_t t = time(NULL);
5238 const struct ldb_val *rdn_val;
5239 struct replmd_private *replmd_private =
5240 talloc_get_type(ldb_module_get_private(ar->module),
5241 struct replmd_private);
5242 unix_to_nt_time(&now, t);
5244 ldb = ldb_module_get_ctx(ar->module);
5245 msg = ar->objs->objects[ar->index_current].msg;
5246 md = ar->objs->objects[ar->index_current].meta_data;
5247 is_schema_nc = ldb_dn_compare_base(replmd_private->schema_dn, msg->dn) == 0;
5249 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &ar->seq_num);
5250 if (ret != LDB_SUCCESS) {
5251 return replmd_replicated_request_error(ar, ret);
5254 ret = dsdb_msg_add_guid(msg,
5255 &ar->objs->objects[ar->index_current].object_guid,
5257 if (ret != LDB_SUCCESS) {
5258 return replmd_replicated_request_error(ar, ret);
5261 ret = ldb_msg_add_string(msg, "whenChanged", ar->objs->objects[ar->index_current].when_changed);
5262 if (ret != LDB_SUCCESS) {
5263 return replmd_replicated_request_error(ar, ret);
5266 ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNCreated", ar->seq_num);
5267 if (ret != LDB_SUCCESS) {
5268 return replmd_replicated_request_error(ar, ret);
5271 ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNChanged", ar->seq_num);
5272 if (ret != LDB_SUCCESS) {
5273 return replmd_replicated_request_error(ar, ret);
5276 /* remove any message elements that have zero values */
5277 for (i=0; i<msg->num_elements; i++) {
5278 struct ldb_message_element *el = &msg->elements[i];
5280 if (el->num_values == 0) {
5281 if (ldb_attr_cmp(msg->elements[i].name, "objectClass") == 0) {
5282 ldb_asprintf_errstring(ldb, __location__
5283 ": empty objectClass sent on %s, aborting replication\n",
5284 ldb_dn_get_linearized(msg->dn));
5285 return replmd_replicated_request_error(ar, LDB_ERR_OBJECT_CLASS_VIOLATION);
5288 DEBUG(4,(__location__ ": Removing attribute %s with num_values==0\n",
5290 memmove(el, el+1, sizeof(*el)*(msg->num_elements - (i+1)));
5291 msg->num_elements--;
5298 struct GUID_txt_buf guid_txt;
5300 char *s = ldb_ldif_message_redacted_string(ldb, ar,
5303 DEBUG(8, ("DRS replication add message of %s:\n%s\n",
5304 GUID_buf_string(&ar->objs->objects[ar->index_current].object_guid, &guid_txt),
5307 } else if (DEBUGLVL(4)) {
5308 struct GUID_txt_buf guid_txt;
5309 DEBUG(4, ("DRS replication add DN of %s is %s\n",
5310 GUID_buf_string(&ar->objs->objects[ar->index_current].object_guid, &guid_txt),
5311 ldb_dn_get_linearized(msg->dn)));
5313 remote_isDeleted = ldb_msg_find_attr_as_bool(msg,
5314 "isDeleted", false);
5317 * the meta data array is already sorted by the caller, except
5318 * for the RDN, which needs to be added.
5322 rdn_val = ldb_dn_get_rdn_val(msg->dn);
5323 ret = replmd_update_rpmd_rdn_attr(ldb, msg, rdn_val, NULL,
5324 md, ar, now, is_schema_nc,
5326 if (ret != LDB_SUCCESS) {
5327 ldb_asprintf_errstring(ldb, "%s: error during DRS repl ADD: %s", __func__, ldb_errstring(ldb));
5328 return replmd_replicated_request_error(ar, ret);
5331 ret = replmd_replPropertyMetaDataCtr1_sort_and_verify(ldb, &md->ctr.ctr1, msg->dn);
5332 if (ret != LDB_SUCCESS) {
5333 ldb_asprintf_errstring(ldb, "%s: error during DRS repl ADD: %s", __func__, ldb_errstring(ldb));
5334 return replmd_replicated_request_error(ar, ret);
5337 for (i=0; i < md->ctr.ctr1.count; i++) {
5338 md->ctr.ctr1.array[i].local_usn = ar->seq_num;
5340 ndr_err = ndr_push_struct_blob(&md_value, msg, md,
5341 (ndr_push_flags_fn_t)ndr_push_replPropertyMetaDataBlob);
5342 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
5343 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
5344 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
5346 ret = ldb_msg_add_value(msg, "replPropertyMetaData", &md_value, NULL);
5347 if (ret != LDB_SUCCESS) {
5348 return replmd_replicated_request_error(ar, ret);
5351 replmd_ldb_message_sort(msg, ar->schema);
5353 if (!remote_isDeleted) {
5354 ret = dsdb_module_schedule_sd_propagation(ar->module,
5355 ar->objs->partition_dn,
5357 if (ret != LDB_SUCCESS) {
5358 return replmd_replicated_request_error(ar, ret);
5362 ar->isDeleted = remote_isDeleted;
5364 ret = ldb_build_add_req(&change_req,
5370 replmd_op_add_callback,
5372 LDB_REQ_SET_LOCATION(change_req);
5373 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
5375 /* current partition control needed by "repmd_op_callback" */
5376 ret = ldb_request_add_control(change_req,
5377 DSDB_CONTROL_CURRENT_PARTITION_OID,
5379 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
5381 if (ar->objs->dsdb_repl_flags & DSDB_REPL_FLAG_PARTIAL_REPLICA) {
5382 /* this tells the partition module to make it a
5383 partial replica if creating an NC */
5384 ret = ldb_request_add_control(change_req,
5385 DSDB_CONTROL_PARTIAL_REPLICA,
5387 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
5390 return ldb_next_request(ar->module, change_req);
5393 static int replmd_replicated_apply_search_for_parent_callback(struct ldb_request *req,
5394 struct ldb_reply *ares)
5396 struct replmd_replicated_request *ar = talloc_get_type(req->context,
5397 struct replmd_replicated_request);
5401 return ldb_module_done(ar->req, NULL, NULL,
5402 LDB_ERR_OPERATIONS_ERROR);
5406 * The error NO_SUCH_OBJECT is not expected, unless the search
5407 * base is the partition DN, and that case doesn't happen here
5408 * because then we wouldn't get a parent_guid_value in any
5411 if (ares->error != LDB_SUCCESS) {
5412 return ldb_module_done(ar->req, ares->controls,
5413 ares->response, ares->error);
5416 switch (ares->type) {
5417 case LDB_REPLY_ENTRY:
5419 struct ldb_message *parent_msg = ares->message;
5420 struct ldb_message *msg = ar->objs->objects[ar->index_current].msg;
5421 struct ldb_dn *parent_dn = NULL;
5424 if (!ldb_msg_check_string_attribute(msg, "isDeleted", "TRUE")
5425 && ldb_msg_check_string_attribute(parent_msg, "isDeleted", "TRUE")) {
5426 /* Per MS-DRSR 4.1.10.6.10
5427 * FindBestParentObject we need to move this
5428 * new object under a deleted object to
5430 struct ldb_dn *nc_root;
5432 ret = dsdb_find_nc_root(ldb_module_get_ctx(ar->module), msg, msg->dn, &nc_root);
5433 if (ret == LDB_ERR_NO_SUCH_OBJECT) {
5434 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
5435 "No suitable NC root found for %s. "
5436 "We need to move this object because parent object %s "
5437 "is deleted, but this object is not.",
5438 ldb_dn_get_linearized(msg->dn),
5439 ldb_dn_get_linearized(parent_msg->dn));
5440 return ldb_module_done(ar->req, NULL, NULL, LDB_ERR_OPERATIONS_ERROR);
5441 } else if (ret != LDB_SUCCESS) {
5442 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
5443 "Unable to find NC root for %s: %s. "
5444 "We need to move this object because parent object %s "
5445 "is deleted, but this object is not.",
5446 ldb_dn_get_linearized(msg->dn),
5447 ldb_errstring(ldb_module_get_ctx(ar->module)),
5448 ldb_dn_get_linearized(parent_msg->dn));
5449 return ldb_module_done(ar->req, NULL, NULL, LDB_ERR_OPERATIONS_ERROR);
5452 ret = dsdb_wellknown_dn(ldb_module_get_ctx(ar->module), msg,
5454 DS_GUID_LOSTANDFOUND_CONTAINER,
5456 if (ret != LDB_SUCCESS) {
5457 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
5458 "Unable to find LostAndFound Container for %s "
5459 "in partition %s: %s. "
5460 "We need to move this object because parent object %s "
5461 "is deleted, but this object is not.",
5462 ldb_dn_get_linearized(msg->dn), ldb_dn_get_linearized(nc_root),
5463 ldb_errstring(ldb_module_get_ctx(ar->module)),
5464 ldb_dn_get_linearized(parent_msg->dn));
5465 return ldb_module_done(ar->req, NULL, NULL, LDB_ERR_OPERATIONS_ERROR);
5467 ar->objs->objects[ar->index_current].last_known_parent
5468 = talloc_steal(ar->objs->objects[ar->index_current].msg, parent_msg->dn);
5472 = talloc_steal(ar->objs->objects[ar->index_current].msg, parent_msg->dn);
5475 ar->objs->objects[ar->index_current].local_parent_dn = parent_dn;
5477 comp_num = ldb_dn_get_comp_num(msg->dn);
5479 if (!ldb_dn_remove_base_components(msg->dn, comp_num - 1)) {
5481 return ldb_module_done(ar->req, NULL, NULL, ldb_module_operr(ar->module));
5484 if (!ldb_dn_add_base(msg->dn, parent_dn)) {
5486 return ldb_module_done(ar->req, NULL, NULL, ldb_module_operr(ar->module));
5490 case LDB_REPLY_REFERRAL:
5491 /* we ignore referrals */
5494 case LDB_REPLY_DONE:
5496 if (ar->objs->objects[ar->index_current].local_parent_dn == NULL) {
5497 struct GUID_txt_buf str_buf;
5498 if (ar->search_msg != NULL) {
5499 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
5500 "No parent with GUID %s found for object locally known as %s",
5501 GUID_buf_string(ar->objs->objects[ar->index_current].parent_guid, &str_buf),
5502 ldb_dn_get_linearized(ar->search_msg->dn));
5504 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
5505 "No parent with GUID %s found for object remotely known as %s",
5506 GUID_buf_string(ar->objs->objects[ar->index_current].parent_guid, &str_buf),
5507 ldb_dn_get_linearized(ar->objs->objects[ar->index_current].msg->dn));
5511 * This error code is really important, as it
5512 * is the flag back to the callers to retry
5513 * this with DRSUAPI_DRS_GET_ANC, and so get
5514 * the parent objects before the child
5517 return ldb_module_done(ar->req, NULL, NULL,
5518 replmd_replicated_request_werror(ar, WERR_DS_DRA_MISSING_PARENT));
5521 if (ar->search_msg != NULL) {
5522 ret = replmd_replicated_apply_merge(ar);
5524 ret = replmd_replicated_apply_add(ar);
5526 if (ret != LDB_SUCCESS) {
5527 return ldb_module_done(ar->req, NULL, NULL, ret);
5536 * Look for the parent object, so we put the new object in the right
5537 * place This is akin to NameObject in MS-DRSR - this routine and the
5538 * callbacks find the right parent name, and correct name for this
5542 static int replmd_replicated_apply_search_for_parent(struct replmd_replicated_request *ar)
5544 struct ldb_context *ldb;
5548 struct ldb_request *search_req;
5549 static const char *attrs[] = {"isDeleted", NULL};
5550 struct GUID_txt_buf guid_str_buf;
5552 ldb = ldb_module_get_ctx(ar->module);
5554 if (ar->objs->objects[ar->index_current].parent_guid == NULL) {
5555 if (ar->search_msg != NULL) {
5556 return replmd_replicated_apply_merge(ar);
5558 return replmd_replicated_apply_add(ar);
5562 tmp_str = GUID_buf_string(ar->objs->objects[ar->index_current].parent_guid,
5565 filter = talloc_asprintf(ar, "(objectGUID=%s)", tmp_str);
5566 if (!filter) return replmd_replicated_request_werror(ar, WERR_NOT_ENOUGH_MEMORY);
5568 ret = ldb_build_search_req(&search_req,
5571 ar->objs->partition_dn,
5577 replmd_replicated_apply_search_for_parent_callback,
5579 LDB_REQ_SET_LOCATION(search_req);
5581 ret = dsdb_request_add_controls(search_req,
5582 DSDB_SEARCH_SHOW_RECYCLED|
5583 DSDB_SEARCH_SHOW_DELETED|
5584 DSDB_SEARCH_SHOW_EXTENDED_DN);
5585 if (ret != LDB_SUCCESS) {
5589 return ldb_next_request(ar->module, search_req);
5593 handle renames that come in over DRS replication
5595 static int replmd_replicated_handle_rename(struct replmd_replicated_request *ar,
5596 struct ldb_message *msg,
5597 struct ldb_request *parent,
5601 TALLOC_CTX *tmp_ctx = talloc_new(msg);
5602 struct ldb_result *res;
5603 struct ldb_dn *conflict_dn;
5604 const char *attrs[] = { "replPropertyMetaData", "objectGUID", NULL };
5605 const struct ldb_val *omd_value;
5606 struct replPropertyMetaDataBlob omd, *rmd;
5607 enum ndr_err_code ndr_err;
5608 bool rename_incoming_record, rodc;
5609 struct replPropertyMetaData1 *rmd_name, *omd_name;
5610 struct ldb_dn *new_dn;
5613 DEBUG(4,("replmd_replicated_request rename %s => %s\n",
5614 ldb_dn_get_linearized(ar->search_msg->dn),
5615 ldb_dn_get_linearized(msg->dn)));
5618 ret = dsdb_module_rename(ar->module, ar->search_msg->dn, msg->dn,
5619 DSDB_FLAG_NEXT_MODULE, ar->req);
5620 if (ret == LDB_SUCCESS) {
5621 talloc_free(tmp_ctx);
5626 if (ret != LDB_ERR_ENTRY_ALREADY_EXISTS) {
5627 talloc_free(tmp_ctx);
5628 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module), "Failed to locally apply remote rename from %s to %s: %s",
5629 ldb_dn_get_linearized(ar->search_msg->dn),
5630 ldb_dn_get_linearized(msg->dn),
5631 ldb_errstring(ldb_module_get_ctx(ar->module)));
5635 ret = samdb_rodc(ldb_module_get_ctx(ar->module), &rodc);
5636 if (ret != LDB_SUCCESS) {
5637 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
5638 "Failed to determine if we are an RODC when attempting to form conflict DN: %s",
5639 ldb_errstring(ldb_module_get_ctx(ar->module)));
5640 return LDB_ERR_OPERATIONS_ERROR;
5643 * we have a conflict, and need to decide if we will keep the
5644 * new record or the old record
5647 conflict_dn = msg->dn;
5651 * We are on an RODC, or were a GC for this
5652 * partition, so we have to fail this until
5653 * someone who owns the partition sorts it
5656 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
5657 "Conflict adding object '%s' from incoming replication but we are read only for the partition. \n"
5658 " - We must fail the operation until a master for this partition resolves the conflict",
5659 ldb_dn_get_linearized(conflict_dn));
5660 ret = LDB_ERR_OPERATIONS_ERROR;
5665 * first we need the replPropertyMetaData attribute from the
5668 ret = dsdb_module_search_dn(ar->module, tmp_ctx, &res, conflict_dn,
5670 DSDB_FLAG_NEXT_MODULE |
5671 DSDB_SEARCH_SHOW_DELETED |
5672 DSDB_SEARCH_SHOW_RECYCLED, ar->req);
5673 if (ret != LDB_SUCCESS) {
5674 DEBUG(0,(__location__ ": Unable to find object for conflicting record '%s'\n",
5675 ldb_dn_get_linearized(conflict_dn)));
5679 omd_value = ldb_msg_find_ldb_val(res->msgs[0], "replPropertyMetaData");
5680 if (omd_value == NULL) {
5681 DEBUG(0,(__location__ ": Unable to find replPropertyMetaData for conflicting record '%s'\n",
5682 ldb_dn_get_linearized(conflict_dn)));
5686 ndr_err = ndr_pull_struct_blob(omd_value, res->msgs[0], &omd,
5687 (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
5688 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
5689 DEBUG(0,(__location__ ": Failed to parse old replPropertyMetaData for %s\n",
5690 ldb_dn_get_linearized(conflict_dn)));
5694 rmd = ar->objs->objects[ar->index_current].meta_data;
5697 * we decide which is newer based on the RPMD on the name
5698 * attribute. See [MS-DRSR] ResolveNameConflict.
5700 * We expect omd_name to be present, as this is from a local
5701 * search, but while rmd_name should have been given to us by
5702 * the remote server, if it is missing we just prefer the
5704 * replmd_replPropertyMetaData1_new_should_be_taken()
5706 rmd_name = replmd_replPropertyMetaData1_find_attid(rmd, DRSUAPI_ATTID_name);
5707 omd_name = replmd_replPropertyMetaData1_find_attid(&omd, DRSUAPI_ATTID_name);
5709 DEBUG(0,(__location__ ": Failed to find name attribute in local LDB replPropertyMetaData for %s\n",
5710 ldb_dn_get_linearized(conflict_dn)));
5715 * Should we preserve the current record, and so rename the
5716 * incoming record to be a conflict?
5718 rename_incoming_record =
5719 !replmd_replPropertyMetaData1_new_should_be_taken(
5720 ar->objs->dsdb_repl_flags & DSDB_REPL_FLAG_PRIORITISE_INCOMING,
5721 omd_name, rmd_name);
5723 if (rename_incoming_record) {
5725 new_dn = replmd_conflict_dn(msg,
5726 ldb_module_get_ctx(ar->module),
5728 &ar->objs->objects[ar->index_current].object_guid);
5729 if (new_dn == NULL) {
5730 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
5731 "Failed to form conflict DN for %s\n",
5732 ldb_dn_get_linearized(msg->dn));
5734 return replmd_replicated_request_werror(ar, WERR_NOT_ENOUGH_MEMORY);
5737 ret = dsdb_module_rename(ar->module, ar->search_msg->dn, new_dn,
5738 DSDB_FLAG_NEXT_MODULE, ar->req);
5739 if (ret != LDB_SUCCESS) {
5740 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
5741 "Failed to rename incoming conflicting dn '%s' (was '%s') to '%s' - %s\n",
5742 ldb_dn_get_linearized(conflict_dn),
5743 ldb_dn_get_linearized(ar->search_msg->dn),
5744 ldb_dn_get_linearized(new_dn),
5745 ldb_errstring(ldb_module_get_ctx(ar->module)));
5746 return replmd_replicated_request_werror(ar, WERR_DS_DRA_DB_ERROR);
5754 /* we are renaming the existing record */
5756 guid = samdb_result_guid(res->msgs[0], "objectGUID");
5757 if (GUID_all_zero(&guid)) {
5758 DEBUG(0,(__location__ ": Failed to find objectGUID for existing conflict record %s\n",
5759 ldb_dn_get_linearized(conflict_dn)));
5763 new_dn = replmd_conflict_dn(tmp_ctx,
5764 ldb_module_get_ctx(ar->module),
5765 conflict_dn, &guid);
5766 if (new_dn == NULL) {
5767 DEBUG(0,(__location__ ": Failed to form conflict DN for %s\n",
5768 ldb_dn_get_linearized(conflict_dn)));
5772 DEBUG(2,(__location__ ": Resolving conflict record via existing-record rename '%s' -> '%s'\n",
5773 ldb_dn_get_linearized(conflict_dn), ldb_dn_get_linearized(new_dn)));
5775 ret = dsdb_module_rename(ar->module, conflict_dn, new_dn,
5776 DSDB_FLAG_OWN_MODULE, ar->req);
5777 if (ret != LDB_SUCCESS) {
5778 DEBUG(0,(__location__ ": Failed to rename conflict dn '%s' to '%s' - %s\n",
5779 ldb_dn_get_linearized(conflict_dn),
5780 ldb_dn_get_linearized(new_dn),
5781 ldb_errstring(ldb_module_get_ctx(ar->module))));
5786 * now we need to ensure that the rename is seen as an
5787 * originating update. We do that with a modify.
5789 ret = replmd_name_modify(ar, ar->req, new_dn);
5790 if (ret != LDB_SUCCESS) {
5794 DEBUG(2,(__location__ ": With conflicting record renamed, re-apply replicated rename '%s' -> '%s'\n",
5795 ldb_dn_get_linearized(ar->search_msg->dn),
5796 ldb_dn_get_linearized(msg->dn)));
5799 ret = dsdb_module_rename(ar->module, ar->search_msg->dn, msg->dn,
5800 DSDB_FLAG_NEXT_MODULE, ar->req);
5801 if (ret != LDB_SUCCESS) {
5802 DEBUG(0,(__location__ ": After conflict resolution, failed to rename dn '%s' to '%s' - %s\n",
5803 ldb_dn_get_linearized(ar->search_msg->dn),
5804 ldb_dn_get_linearized(msg->dn),
5805 ldb_errstring(ldb_module_get_ctx(ar->module))));
5809 talloc_free(tmp_ctx);
5813 * On failure make the caller get the error
5814 * This means replication will stop with an error,
5815 * but there is not much else we can do. In the
5816 * LDB_ERR_ENTRY_ALREADY_EXISTS case this is exactly what is
5819 if (ret == LDB_SUCCESS) {
5820 ret = LDB_ERR_OPERATIONS_ERROR;
5823 talloc_free(tmp_ctx);
5828 static int replmd_replicated_apply_merge(struct replmd_replicated_request *ar)
5830 struct ldb_context *ldb;
5831 struct ldb_request *change_req;
5832 enum ndr_err_code ndr_err;
5833 struct ldb_message *msg;
5834 struct replPropertyMetaDataBlob *rmd;
5835 struct replPropertyMetaDataBlob omd;
5836 const struct ldb_val *omd_value;
5837 struct replPropertyMetaDataBlob nmd;
5838 struct ldb_val nmd_value;
5839 struct GUID remote_parent_guid;
5842 unsigned int removed_attrs = 0;
5844 int (*callback)(struct ldb_request *req, struct ldb_reply *ares) = replmd_op_callback;
5845 bool isDeleted = false;
5846 bool local_isDeleted = false;
5847 bool remote_isDeleted = false;
5848 bool take_remote_isDeleted = false;
5849 bool sd_updated = false;
5850 bool renamed = false;
5851 bool is_schema_nc = false;
5853 const struct ldb_val *old_rdn, *new_rdn;
5854 struct replmd_private *replmd_private =
5855 talloc_get_type(ldb_module_get_private(ar->module),
5856 struct replmd_private);
5858 time_t t = time(NULL);
5859 unix_to_nt_time(&now, t);
5861 ldb = ldb_module_get_ctx(ar->module);
5862 msg = ar->objs->objects[ar->index_current].msg;
5864 is_schema_nc = ldb_dn_compare_base(replmd_private->schema_dn, msg->dn) == 0;
5866 rmd = ar->objs->objects[ar->index_current].meta_data;
5870 /* find existing meta data */
5871 omd_value = ldb_msg_find_ldb_val(ar->search_msg, "replPropertyMetaData");
5873 ndr_err = ndr_pull_struct_blob(omd_value, ar, &omd,
5874 (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
5875 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
5876 nt_status = ndr_map_error2ntstatus(ndr_err);
5877 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
5880 if (omd.version != 1) {
5881 return replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
5886 struct GUID_txt_buf guid_txt;
5888 char *s = ldb_ldif_message_redacted_string(ldb, ar,
5889 LDB_CHANGETYPE_MODIFY, msg);
5890 DEBUG(8, ("Initial DRS replication modify message of %s is:\n%s\n"
5893 GUID_buf_string(&ar->objs->objects[ar->index_current].object_guid, &guid_txt),
5895 ndr_print_struct_string(s,
5896 (ndr_print_fn_t)ndr_print_replPropertyMetaDataBlob,
5897 "existing replPropertyMetaData",
5899 ndr_print_struct_string(s,
5900 (ndr_print_fn_t)ndr_print_replPropertyMetaDataBlob,
5901 "incoming replPropertyMetaData",
5904 } else if (DEBUGLVL(4)) {
5905 struct GUID_txt_buf guid_txt;
5907 DEBUG(4, ("Initial DRS replication modify DN of %s is: %s\n",
5908 GUID_buf_string(&ar->objs->objects[ar->index_current].object_guid,
5910 ldb_dn_get_linearized(msg->dn)));
5913 local_isDeleted = ldb_msg_find_attr_as_bool(ar->search_msg,
5914 "isDeleted", false);
5915 remote_isDeleted = ldb_msg_find_attr_as_bool(msg,
5916 "isDeleted", false);
5919 * Fill in the remote_parent_guid with the GUID or an all-zero
5922 if (ar->objs->objects[ar->index_current].parent_guid != NULL) {
5923 remote_parent_guid = *ar->objs->objects[ar->index_current].parent_guid;
5925 remote_parent_guid = GUID_zero();
5929 * To ensure we follow a complex rename chain around, we have
5930 * to confirm that the DN is the same (mostly to confirm the
5931 * RDN) and the parentGUID is the same.
5933 * This ensures we keep things under the correct parent, which
5934 * replmd_replicated_handle_rename() will do.
5937 if (strcmp(ldb_dn_get_linearized(msg->dn), ldb_dn_get_linearized(ar->search_msg->dn)) == 0
5938 && GUID_equal(&remote_parent_guid, &ar->local_parent_guid)) {
5942 * handle renames, even just by case that come in over
5943 * DRS. Changes in the parent DN don't hit us here,
5944 * because the search for a parent will clean up those
5947 * We also have already filtered out the case where
5948 * the peer has an older name to what we have (see
5949 * replmd_replicated_apply_search_callback())
5951 ret = replmd_replicated_handle_rename(ar, msg, ar->req, &renamed);
5954 if (ret != LDB_SUCCESS) {
5955 ldb_debug(ldb, LDB_DEBUG_FATAL,
5956 "replmd_replicated_request rename %s => %s failed - %s\n",
5957 ldb_dn_get_linearized(ar->search_msg->dn),
5958 ldb_dn_get_linearized(msg->dn),
5959 ldb_errstring(ldb));
5960 return replmd_replicated_request_werror(ar, WERR_DS_DRA_DB_ERROR);
5963 if (renamed == true) {
5965 * Set the callback to one that will fix up the name
5966 * metadata on the new conflict DN
5968 callback = replmd_op_name_modify_callback;
5973 nmd.ctr.ctr1.count = omd.ctr.ctr1.count + rmd->ctr.ctr1.count;
5974 nmd.ctr.ctr1.array = talloc_array(ar,
5975 struct replPropertyMetaData1,
5976 nmd.ctr.ctr1.count);
5977 if (!nmd.ctr.ctr1.array) return replmd_replicated_request_werror(ar, WERR_NOT_ENOUGH_MEMORY);
5979 /* first copy the old meta data */
5980 for (i=0; i < omd.ctr.ctr1.count; i++) {
5981 nmd.ctr.ctr1.array[ni] = omd.ctr.ctr1.array[i];
5986 /* now merge in the new meta data */
5987 for (i=0; i < rmd->ctr.ctr1.count; i++) {
5990 for (j=0; j < ni; j++) {
5993 if (rmd->ctr.ctr1.array[i].attid != nmd.ctr.ctr1.array[j].attid) {
5997 cmp = replmd_replPropertyMetaData1_new_should_be_taken(
5998 ar->objs->dsdb_repl_flags,
5999 &nmd.ctr.ctr1.array[j],
6000 &rmd->ctr.ctr1.array[i]);
6002 /* replace the entry */
6003 nmd.ctr.ctr1.array[j] = rmd->ctr.ctr1.array[i];
6004 if (ar->seq_num == 0) {
6005 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &ar->seq_num);
6006 if (ret != LDB_SUCCESS) {
6007 return replmd_replicated_request_error(ar, ret);
6010 nmd.ctr.ctr1.array[j].local_usn = ar->seq_num;
6011 switch (nmd.ctr.ctr1.array[j].attid) {
6012 case DRSUAPI_ATTID_ntSecurityDescriptor:
6015 case DRSUAPI_ATTID_isDeleted:
6016 take_remote_isDeleted = true;
6025 if (rmd->ctr.ctr1.array[i].attid != DRSUAPI_ATTID_instanceType) {
6026 DEBUG(3,("Discarding older DRS attribute update to %s on %s from %s\n",
6027 msg->elements[i-removed_attrs].name,
6028 ldb_dn_get_linearized(msg->dn),
6029 GUID_string(ar, &rmd->ctr.ctr1.array[i].originating_invocation_id)));
6032 /* we don't want to apply this change so remove the attribute */
6033 ldb_msg_remove_element(msg, &msg->elements[i-removed_attrs]);
6040 if (found) continue;
6042 nmd.ctr.ctr1.array[ni] = rmd->ctr.ctr1.array[i];
6043 if (ar->seq_num == 0) {
6044 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &ar->seq_num);
6045 if (ret != LDB_SUCCESS) {
6046 return replmd_replicated_request_error(ar, ret);
6049 nmd.ctr.ctr1.array[ni].local_usn = ar->seq_num;
6050 switch (nmd.ctr.ctr1.array[ni].attid) {
6051 case DRSUAPI_ATTID_ntSecurityDescriptor:
6054 case DRSUAPI_ATTID_isDeleted:
6055 take_remote_isDeleted = true;
6064 * finally correct the size of the meta_data array
6066 nmd.ctr.ctr1.count = ni;
6068 new_rdn = ldb_dn_get_rdn_val(msg->dn);
6069 old_rdn = ldb_dn_get_rdn_val(ar->search_msg->dn);
6072 ret = replmd_update_rpmd_rdn_attr(ldb, msg, new_rdn, old_rdn,
6073 &nmd, ar, now, is_schema_nc,
6075 if (ret != LDB_SUCCESS) {
6076 ldb_asprintf_errstring(ldb, "%s: error during DRS repl merge: %s", __func__, ldb_errstring(ldb));
6077 return replmd_replicated_request_error(ar, ret);
6081 * sort the new meta data array
6083 ret = replmd_replPropertyMetaDataCtr1_sort_and_verify(ldb, &nmd.ctr.ctr1, msg->dn);
6084 if (ret != LDB_SUCCESS) {
6085 ldb_asprintf_errstring(ldb, "%s: error during DRS repl merge: %s", __func__, ldb_errstring(ldb));
6090 * Work out if this object is deleted, so we can prune any extra attributes. See MS-DRSR 4.1.10.6.9
6093 * This also controls SD propagation below
6095 if (take_remote_isDeleted) {
6096 isDeleted = remote_isDeleted;
6098 isDeleted = local_isDeleted;
6101 ar->isDeleted = isDeleted;
6104 * check if some replicated attributes left, otherwise skip the ldb_modify() call
6106 if (msg->num_elements == 0) {
6107 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_replicated_apply_merge[%u]: skip replace\n",
6110 return replmd_replicated_apply_isDeleted(ar);
6113 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_replicated_apply_merge[%u]: replace %u attributes\n",
6114 ar->index_current, msg->num_elements);
6120 if (sd_updated && !isDeleted) {
6121 ret = dsdb_module_schedule_sd_propagation(ar->module,
6122 ar->objs->partition_dn,
6124 if (ret != LDB_SUCCESS) {
6125 return ldb_operr(ldb);
6129 /* create the meta data value */
6130 ndr_err = ndr_push_struct_blob(&nmd_value, msg, &nmd,
6131 (ndr_push_flags_fn_t)ndr_push_replPropertyMetaDataBlob);
6132 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
6133 nt_status = ndr_map_error2ntstatus(ndr_err);
6134 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
6138 * when we know that we'll modify the record, add the whenChanged, uSNChanged
6139 * and replPopertyMetaData attributes
6141 ret = ldb_msg_add_string(msg, "whenChanged", ar->objs->objects[ar->index_current].when_changed);
6142 if (ret != LDB_SUCCESS) {
6143 return replmd_replicated_request_error(ar, ret);
6145 ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNChanged", ar->seq_num);
6146 if (ret != LDB_SUCCESS) {
6147 return replmd_replicated_request_error(ar, ret);
6149 ret = ldb_msg_add_value(msg, "replPropertyMetaData", &nmd_value, NULL);
6150 if (ret != LDB_SUCCESS) {
6151 return replmd_replicated_request_error(ar, ret);
6154 replmd_ldb_message_sort(msg, ar->schema);
6156 /* we want to replace the old values */
6157 for (i=0; i < msg->num_elements; i++) {
6158 msg->elements[i].flags = LDB_FLAG_MOD_REPLACE;
6159 if (ldb_attr_cmp(msg->elements[i].name, "objectClass") == 0) {
6160 if (msg->elements[i].num_values == 0) {
6161 ldb_asprintf_errstring(ldb, __location__
6162 ": objectClass removed on %s, aborting replication\n",
6163 ldb_dn_get_linearized(msg->dn));
6164 return replmd_replicated_request_error(ar, LDB_ERR_OBJECT_CLASS_VIOLATION);
6170 struct GUID_txt_buf guid_txt;
6172 char *s = ldb_ldif_message_redacted_string(ldb, ar,
6173 LDB_CHANGETYPE_MODIFY,
6175 DEBUG(8, ("Final DRS replication modify message of %s:\n%s\n",
6176 GUID_buf_string(&ar->objs->objects[ar->index_current].object_guid,
6180 } else if (DEBUGLVL(4)) {
6181 struct GUID_txt_buf guid_txt;
6183 DEBUG(4, ("Final DRS replication modify DN of %s is %s\n",
6184 GUID_buf_string(&ar->objs->objects[ar->index_current].object_guid,
6186 ldb_dn_get_linearized(msg->dn)));
6189 ret = ldb_build_mod_req(&change_req,
6197 LDB_REQ_SET_LOCATION(change_req);
6198 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
6200 /* current partition control needed by "repmd_op_callback" */
6201 ret = ldb_request_add_control(change_req,
6202 DSDB_CONTROL_CURRENT_PARTITION_OID,
6204 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
6206 return ldb_next_request(ar->module, change_req);
6209 static int replmd_replicated_apply_search_callback(struct ldb_request *req,
6210 struct ldb_reply *ares)
6212 struct replmd_replicated_request *ar = talloc_get_type(req->context,
6213 struct replmd_replicated_request);
6217 return ldb_module_done(ar->req, NULL, NULL,
6218 LDB_ERR_OPERATIONS_ERROR);
6220 if (ares->error != LDB_SUCCESS &&
6221 ares->error != LDB_ERR_NO_SUCH_OBJECT) {
6222 return ldb_module_done(ar->req, ares->controls,
6223 ares->response, ares->error);
6226 switch (ares->type) {
6227 case LDB_REPLY_ENTRY:
6228 ar->search_msg = talloc_steal(ar, ares->message);
6231 case LDB_REPLY_REFERRAL:
6232 /* we ignore referrals */
6235 case LDB_REPLY_DONE:
6237 struct replPropertyMetaData1 *md_remote;
6238 struct replPropertyMetaData1 *md_local;
6240 struct replPropertyMetaDataBlob omd;
6241 const struct ldb_val *omd_value;
6242 struct replPropertyMetaDataBlob *rmd;
6243 struct ldb_message *msg;
6245 ar->objs->objects[ar->index_current].local_parent_dn = NULL;
6246 ar->objs->objects[ar->index_current].last_known_parent = NULL;
6249 * This is the ADD case, find the appropriate parent,
6250 * as this object doesn't exist locally:
6252 if (ar->search_msg == NULL) {
6253 ret = replmd_replicated_apply_search_for_parent(ar);
6254 if (ret != LDB_SUCCESS) {
6255 return ldb_module_done(ar->req, NULL, NULL, ret);
6262 * Otherwise, in the MERGE case, work out if we are
6263 * attempting a rename, and if so find the parent the
6264 * newly renamed object wants to belong under (which
6265 * may not be the parent in it's attached string DN
6267 rmd = ar->objs->objects[ar->index_current].meta_data;
6271 /* find existing meta data */
6272 omd_value = ldb_msg_find_ldb_val(ar->search_msg, "replPropertyMetaData");
6274 enum ndr_err_code ndr_err;
6275 ndr_err = ndr_pull_struct_blob(omd_value, ar, &omd,
6276 (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
6277 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
6278 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
6279 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
6282 if (omd.version != 1) {
6283 return replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
6287 ar->local_parent_guid = samdb_result_guid(ar->search_msg, "parentGUID");
6289 instanceType = ldb_msg_find_attr_as_int(ar->search_msg, "instanceType", 0);
6290 if (((instanceType & INSTANCE_TYPE_IS_NC_HEAD) == 0)
6291 && GUID_all_zero(&ar->local_parent_guid)) {
6292 DEBUG(0, ("Refusing to replicate new version of %s "
6293 "as local object has an all-zero parentGUID attribute, "
6294 "despite not being an NC root\n",
6295 ldb_dn_get_linearized(ar->search_msg->dn)));
6296 return replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
6300 * now we need to check for double renames. We could have a
6301 * local rename pending which our replication partner hasn't
6302 * received yet. We choose which one wins by looking at the
6303 * attribute stamps on the two objects, the newer one wins.
6305 * This also simply applies the correct algorithms for
6306 * determining if a change was made to name at all, or
6307 * if the object has just been renamed under the same
6310 md_remote = replmd_replPropertyMetaData1_find_attid(rmd, DRSUAPI_ATTID_name);
6311 md_local = replmd_replPropertyMetaData1_find_attid(&omd, DRSUAPI_ATTID_name);
6313 DEBUG(0,(__location__ ": Failed to find name attribute in local LDB replPropertyMetaData for %s\n",
6314 ldb_dn_get_linearized(ar->search_msg->dn)));
6315 return replmd_replicated_request_werror(ar, WERR_DS_DRA_DB_ERROR);
6319 * if there is no name attribute given then we have to assume the
6320 * object we've received has the older name
6322 if (replmd_replPropertyMetaData1_new_should_be_taken(
6323 ar->objs->dsdb_repl_flags & DSDB_REPL_FLAG_PRIORITISE_INCOMING,
6324 md_local, md_remote)) {
6325 struct GUID_txt_buf p_guid_local;
6326 struct GUID_txt_buf p_guid_remote;
6327 msg = ar->objs->objects[ar->index_current].msg;
6329 /* Merge on the existing object, with rename */
6331 DEBUG(4,(__location__ ": Looking for new parent for object %s currently under %s "
6332 "as incoming object changing to %s under %s\n",
6333 ldb_dn_get_linearized(ar->search_msg->dn),
6334 GUID_buf_string(&ar->local_parent_guid, &p_guid_local),
6335 ldb_dn_get_linearized(msg->dn),
6336 GUID_buf_string(ar->objs->objects[ar->index_current].parent_guid,
6338 ret = replmd_replicated_apply_search_for_parent(ar);
6340 struct GUID_txt_buf p_guid_local;
6341 struct GUID_txt_buf p_guid_remote;
6342 msg = ar->objs->objects[ar->index_current].msg;
6345 * Merge on the existing object, force no
6346 * rename (code below just to explain why in
6350 if (strcmp(ldb_dn_get_linearized(ar->search_msg->dn),
6351 ldb_dn_get_linearized(msg->dn)) == 0) {
6352 if (ar->objs->objects[ar->index_current].parent_guid != NULL &&
6353 GUID_equal(&ar->local_parent_guid,
6354 ar->objs->objects[ar->index_current].parent_guid)
6356 DEBUG(4,(__location__ ": Keeping object %s at under %s "
6357 "despite incoming object changing parent to %s\n",
6358 ldb_dn_get_linearized(ar->search_msg->dn),
6359 GUID_buf_string(&ar->local_parent_guid, &p_guid_local),
6360 GUID_buf_string(ar->objs->objects[ar->index_current].parent_guid,
6364 DEBUG(4,(__location__ ": Keeping object %s at under %s "
6365 " and rejecting older rename to %s under %s\n",
6366 ldb_dn_get_linearized(ar->search_msg->dn),
6367 GUID_buf_string(&ar->local_parent_guid, &p_guid_local),
6368 ldb_dn_get_linearized(msg->dn),
6369 GUID_buf_string(ar->objs->objects[ar->index_current].parent_guid,
6373 * This assignment ensures that the strcmp()
6374 * and GUID_equal() calls in
6375 * replmd_replicated_apply_merge() avoids the
6378 ar->objs->objects[ar->index_current].parent_guid =
6379 &ar->local_parent_guid;
6381 msg->dn = ar->search_msg->dn;
6382 ret = replmd_replicated_apply_merge(ar);
6384 if (ret != LDB_SUCCESS) {
6385 return ldb_module_done(ar->req, NULL, NULL, ret);
6395 * Stores the linked attributes received in the replication chunk - these get
6396 * applied at the end of the transaction. We also check that each linked
6397 * attribute is valid, i.e. source and target objects are known.
6399 static int replmd_store_linked_attributes(struct replmd_replicated_request *ar)
6401 int ret = LDB_SUCCESS;
6403 struct ldb_module *module = ar->module;
6404 struct replmd_private *replmd_private =
6405 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
6406 struct ldb_context *ldb;
6408 ldb = ldb_module_get_ctx(module);
6410 DEBUG(4,("linked_attributes_count=%u\n", ar->objs->linked_attributes_count));
6412 /* save away the linked attributes for the end of the transaction */
6413 for (i = 0; i < ar->objs->linked_attributes_count; i++) {
6414 struct la_entry *la_entry;
6416 if (replmd_private->la_ctx == NULL) {
6417 replmd_private->la_ctx = talloc_new(replmd_private);
6419 la_entry = talloc(replmd_private->la_ctx, struct la_entry);
6420 if (la_entry == NULL) {
6422 return LDB_ERR_OPERATIONS_ERROR;
6424 la_entry->la = talloc(la_entry, struct drsuapi_DsReplicaLinkedAttribute);
6425 if (la_entry->la == NULL) {
6426 talloc_free(la_entry);
6428 return LDB_ERR_OPERATIONS_ERROR;
6430 *la_entry->la = ar->objs->linked_attributes[i];
6431 la_entry->dsdb_repl_flags = ar->objs->dsdb_repl_flags;
6433 /* we need to steal the non-scalars so they stay
6434 around until the end of the transaction */
6435 talloc_steal(la_entry->la, la_entry->la->identifier);
6436 talloc_steal(la_entry->la, la_entry->la->value.blob);
6438 ret = replmd_verify_linked_attribute(ar, la_entry);
6440 if (ret != LDB_SUCCESS) {
6444 DLIST_ADD(replmd_private->la_list, la_entry);
6450 static int replmd_replicated_uptodate_vector(struct replmd_replicated_request *ar);
6452 static int replmd_replicated_apply_next(struct replmd_replicated_request *ar)
6454 struct ldb_context *ldb;
6458 struct ldb_request *search_req;
6459 static const char *attrs[] = { "repsFrom", "replUpToDateVector",
6460 "parentGUID", "instanceType",
6461 "replPropertyMetaData", "nTSecurityDescriptor",
6462 "isDeleted", NULL };
6463 struct GUID_txt_buf guid_str_buf;
6465 if (ar->index_current >= ar->objs->num_objects) {
6468 * Now that we've applied all the objects, check the new linked
6469 * attributes and store them (we apply them in .prepare_commit)
6471 ret = replmd_store_linked_attributes(ar);
6473 if (ret != LDB_SUCCESS) {
6477 /* done applying objects, move on to the next stage */
6478 return replmd_replicated_uptodate_vector(ar);
6481 ldb = ldb_module_get_ctx(ar->module);
6482 ar->search_msg = NULL;
6483 ar->isDeleted = false;
6485 tmp_str = GUID_buf_string(&ar->objs->objects[ar->index_current].object_guid,
6488 filter = talloc_asprintf(ar, "(objectGUID=%s)", tmp_str);
6489 if (!filter) return replmd_replicated_request_werror(ar, WERR_NOT_ENOUGH_MEMORY);
6491 ret = ldb_build_search_req(&search_req,
6494 ar->objs->partition_dn,
6500 replmd_replicated_apply_search_callback,
6502 LDB_REQ_SET_LOCATION(search_req);
6504 ret = dsdb_request_add_controls(search_req, DSDB_SEARCH_SHOW_RECYCLED);
6506 if (ret != LDB_SUCCESS) {
6510 return ldb_next_request(ar->module, search_req);
6514 * This is essentially a wrapper for replmd_replicated_apply_next()
6516 * This is needed to ensure that both codepaths call this handler.
6518 static int replmd_replicated_apply_isDeleted(struct replmd_replicated_request *ar)
6520 struct ldb_dn *deleted_objects_dn;
6521 struct ldb_message *msg = ar->objs->objects[ar->index_current].msg;
6522 int ret = dsdb_get_deleted_objects_dn(ldb_module_get_ctx(ar->module), msg, msg->dn,
6523 &deleted_objects_dn);
6524 if (ar->isDeleted && (ret != LDB_SUCCESS || ldb_dn_compare(msg->dn, deleted_objects_dn) != 0)) {
6526 * Do a delete here again, so that if there is
6527 * anything local that conflicts with this
6528 * object being deleted, it is removed. This
6529 * includes links. See MS-DRSR 4.1.10.6.9
6532 * If the object is already deleted, and there
6533 * is no more work required, it doesn't do
6537 /* This has been updated to point to the DN we eventually did the modify on */
6539 struct ldb_request *del_req;
6540 struct ldb_result *res;
6542 TALLOC_CTX *tmp_ctx = talloc_new(ar);
6544 ret = ldb_oom(ldb_module_get_ctx(ar->module));
6548 res = talloc_zero(tmp_ctx, struct ldb_result);
6550 ret = ldb_oom(ldb_module_get_ctx(ar->module));
6551 talloc_free(tmp_ctx);
6555 /* Build a delete request, which hopefully will artually turn into nothing */
6556 ret = ldb_build_del_req(&del_req, ldb_module_get_ctx(ar->module), tmp_ctx,
6560 ldb_modify_default_callback,
6562 LDB_REQ_SET_LOCATION(del_req);
6563 if (ret != LDB_SUCCESS) {
6564 talloc_free(tmp_ctx);
6569 * This is the guts of the call, call back
6570 * into our delete code, but setting the
6571 * re_delete flag so we delete anything that
6572 * shouldn't be there on a deleted or recycled
6575 ret = replmd_delete_internals(ar->module, del_req, true);
6576 if (ret == LDB_SUCCESS) {
6577 ret = ldb_wait(del_req->handle, LDB_WAIT_ALL);
6580 talloc_free(tmp_ctx);
6581 if (ret != LDB_SUCCESS) {
6586 ar->index_current++;
6587 return replmd_replicated_apply_next(ar);
6590 static int replmd_replicated_uptodate_modify_callback(struct ldb_request *req,
6591 struct ldb_reply *ares)
6593 struct ldb_context *ldb;
6594 struct replmd_replicated_request *ar = talloc_get_type(req->context,
6595 struct replmd_replicated_request);
6596 ldb = ldb_module_get_ctx(ar->module);
6599 return ldb_module_done(ar->req, NULL, NULL,
6600 LDB_ERR_OPERATIONS_ERROR);
6602 if (ares->error != LDB_SUCCESS) {
6603 return ldb_module_done(ar->req, ares->controls,
6604 ares->response, ares->error);
6607 if (ares->type != LDB_REPLY_DONE) {
6608 ldb_asprintf_errstring(ldb, "Invalid LDB reply type %d", ares->type);
6609 return ldb_module_done(ar->req, NULL, NULL,
6610 LDB_ERR_OPERATIONS_ERROR);
6615 return ldb_module_done(ar->req, NULL, NULL, LDB_SUCCESS);
6618 static int replmd_replicated_uptodate_modify(struct replmd_replicated_request *ar)
6620 struct ldb_context *ldb;
6621 struct ldb_request *change_req;
6622 enum ndr_err_code ndr_err;
6623 struct ldb_message *msg;
6624 struct replUpToDateVectorBlob ouv;
6625 const struct ldb_val *ouv_value;
6626 const struct drsuapi_DsReplicaCursor2CtrEx *ruv;
6627 struct replUpToDateVectorBlob nuv;
6628 struct ldb_val nuv_value;
6629 struct ldb_message_element *nuv_el = NULL;
6630 struct ldb_message_element *orf_el = NULL;
6631 struct repsFromToBlob nrf;
6632 struct ldb_val *nrf_value = NULL;
6633 struct ldb_message_element *nrf_el = NULL;
6637 time_t t = time(NULL);
6640 uint32_t instanceType;
6642 ldb = ldb_module_get_ctx(ar->module);
6643 ruv = ar->objs->uptodateness_vector;
6649 unix_to_nt_time(&now, t);
6651 if (ar->search_msg == NULL) {
6652 /* this happens for a REPL_OBJ call where we are
6653 creating the target object by replicating it. The
6654 subdomain join code does this for the partition DN
6656 DEBUG(4,(__location__ ": Skipping UDV and repsFrom update as no target DN\n"));
6657 return ldb_module_done(ar->req, NULL, NULL, LDB_SUCCESS);
6660 instanceType = ldb_msg_find_attr_as_uint(ar->search_msg, "instanceType", 0);
6661 if (! (instanceType & INSTANCE_TYPE_IS_NC_HEAD)) {
6662 DEBUG(4,(__location__ ": Skipping UDV and repsFrom update as not NC root: %s\n",
6663 ldb_dn_get_linearized(ar->search_msg->dn)));
6664 return ldb_module_done(ar->req, NULL, NULL, LDB_SUCCESS);
6668 * first create the new replUpToDateVector
6670 ouv_value = ldb_msg_find_ldb_val(ar->search_msg, "replUpToDateVector");
6672 ndr_err = ndr_pull_struct_blob(ouv_value, ar, &ouv,
6673 (ndr_pull_flags_fn_t)ndr_pull_replUpToDateVectorBlob);
6674 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
6675 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
6676 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
6679 if (ouv.version != 2) {
6680 return replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
6685 * the new uptodateness vector will at least
6686 * contain 1 entry, one for the source_dsa
6688 * plus optional values from our old vector and the one from the source_dsa
6690 nuv.ctr.ctr2.count = ouv.ctr.ctr2.count;
6691 if (ruv) nuv.ctr.ctr2.count += ruv->count;
6692 nuv.ctr.ctr2.cursors = talloc_array(ar,
6693 struct drsuapi_DsReplicaCursor2,
6694 nuv.ctr.ctr2.count);
6695 if (!nuv.ctr.ctr2.cursors) return replmd_replicated_request_werror(ar, WERR_NOT_ENOUGH_MEMORY);
6697 /* first copy the old vector */
6698 for (i=0; i < ouv.ctr.ctr2.count; i++) {
6699 nuv.ctr.ctr2.cursors[ni] = ouv.ctr.ctr2.cursors[i];
6703 /* merge in the source_dsa vector is available */
6704 for (i=0; (ruv && i < ruv->count); i++) {
6707 if (GUID_equal(&ruv->cursors[i].source_dsa_invocation_id,
6708 &ar->our_invocation_id)) {
6712 for (j=0; j < ni; j++) {
6713 if (!GUID_equal(&ruv->cursors[i].source_dsa_invocation_id,
6714 &nuv.ctr.ctr2.cursors[j].source_dsa_invocation_id)) {
6720 if (ruv->cursors[i].highest_usn > nuv.ctr.ctr2.cursors[j].highest_usn) {
6721 nuv.ctr.ctr2.cursors[j] = ruv->cursors[i];
6726 if (found) continue;
6728 /* if it's not there yet, add it */
6729 nuv.ctr.ctr2.cursors[ni] = ruv->cursors[i];
6734 * finally correct the size of the cursors array
6736 nuv.ctr.ctr2.count = ni;
6741 TYPESAFE_QSORT(nuv.ctr.ctr2.cursors, nuv.ctr.ctr2.count, drsuapi_DsReplicaCursor2_compare);
6744 * create the change ldb_message
6746 msg = ldb_msg_new(ar);
6747 if (!msg) return replmd_replicated_request_werror(ar, WERR_NOT_ENOUGH_MEMORY);
6748 msg->dn = ar->search_msg->dn;
6750 ndr_err = ndr_push_struct_blob(&nuv_value, msg, &nuv,
6751 (ndr_push_flags_fn_t)ndr_push_replUpToDateVectorBlob);
6752 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
6753 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
6754 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
6756 ret = ldb_msg_add_value(msg, "replUpToDateVector", &nuv_value, &nuv_el);
6757 if (ret != LDB_SUCCESS) {
6758 return replmd_replicated_request_error(ar, ret);
6760 nuv_el->flags = LDB_FLAG_MOD_REPLACE;
6763 * now create the new repsFrom value from the given repsFromTo1 structure
6767 nrf.ctr.ctr1 = *ar->objs->source_dsa;
6768 nrf.ctr.ctr1.last_attempt = now;
6769 nrf.ctr.ctr1.last_success = now;
6770 nrf.ctr.ctr1.result_last_attempt = WERR_OK;
6773 * first see if we already have a repsFrom value for the current source dsa
6774 * if so we'll later replace this value
6776 orf_el = ldb_msg_find_element(ar->search_msg, "repsFrom");
6778 for (i=0; i < orf_el->num_values; i++) {
6779 struct repsFromToBlob *trf;
6781 trf = talloc(ar, struct repsFromToBlob);
6782 if (!trf) return replmd_replicated_request_werror(ar, WERR_NOT_ENOUGH_MEMORY);
6784 ndr_err = ndr_pull_struct_blob(&orf_el->values[i], trf, trf,
6785 (ndr_pull_flags_fn_t)ndr_pull_repsFromToBlob);
6786 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
6787 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
6788 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
6791 if (trf->version != 1) {
6792 return replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
6796 * we compare the source dsa objectGUID not the invocation_id
6797 * because we want only one repsFrom value per source dsa
6798 * and when the invocation_id of the source dsa has changed we don't need
6799 * the old repsFrom with the old invocation_id
6801 if (!GUID_equal(&trf->ctr.ctr1.source_dsa_obj_guid,
6802 &ar->objs->source_dsa->source_dsa_obj_guid)) {
6808 nrf_value = &orf_el->values[i];
6813 * copy over all old values to the new ldb_message
6815 ret = ldb_msg_add_empty(msg, "repsFrom", 0, &nrf_el);
6816 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
6821 * if we haven't found an old repsFrom value for the current source dsa
6822 * we'll add a new value
6825 struct ldb_val zero_value;
6826 ZERO_STRUCT(zero_value);
6827 ret = ldb_msg_add_value(msg, "repsFrom", &zero_value, &nrf_el);
6828 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
6830 nrf_value = &nrf_el->values[nrf_el->num_values - 1];
6833 /* we now fill the value which is already attached to ldb_message */
6834 ndr_err = ndr_push_struct_blob(nrf_value, msg,
6836 (ndr_push_flags_fn_t)ndr_push_repsFromToBlob);
6837 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
6838 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
6839 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
6843 * the ldb_message_element for the attribute, has all the old values and the new one
6844 * so we'll replace the whole attribute with all values
6846 nrf_el->flags = LDB_FLAG_MOD_REPLACE;
6848 if (CHECK_DEBUGLVL(4)) {
6849 char *s = ldb_ldif_message_redacted_string(ldb, ar,
6850 LDB_CHANGETYPE_MODIFY,
6852 DEBUG(4, ("DRS replication uptodate modify message:\n%s\n", s));
6856 /* prepare the ldb_modify() request */
6857 ret = ldb_build_mod_req(&change_req,
6863 replmd_replicated_uptodate_modify_callback,
6865 LDB_REQ_SET_LOCATION(change_req);
6866 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
6868 return ldb_next_request(ar->module, change_req);
6871 static int replmd_replicated_uptodate_search_callback(struct ldb_request *req,
6872 struct ldb_reply *ares)
6874 struct replmd_replicated_request *ar = talloc_get_type(req->context,
6875 struct replmd_replicated_request);
6879 return ldb_module_done(ar->req, NULL, NULL,
6880 LDB_ERR_OPERATIONS_ERROR);
6882 if (ares->error != LDB_SUCCESS &&
6883 ares->error != LDB_ERR_NO_SUCH_OBJECT) {
6884 return ldb_module_done(ar->req, ares->controls,
6885 ares->response, ares->error);
6888 switch (ares->type) {
6889 case LDB_REPLY_ENTRY:
6890 ar->search_msg = talloc_steal(ar, ares->message);
6893 case LDB_REPLY_REFERRAL:
6894 /* we ignore referrals */
6897 case LDB_REPLY_DONE:
6898 ret = replmd_replicated_uptodate_modify(ar);
6899 if (ret != LDB_SUCCESS) {
6900 return ldb_module_done(ar->req, NULL, NULL, ret);
6909 static int replmd_replicated_uptodate_vector(struct replmd_replicated_request *ar)
6911 struct ldb_context *ldb = ldb_module_get_ctx(ar->module);
6912 struct replmd_private *replmd_private =
6913 talloc_get_type_abort(ldb_module_get_private(ar->module),
6914 struct replmd_private);
6916 static const char *attrs[] = {
6917 "replUpToDateVector",
6922 struct ldb_request *search_req;
6924 ar->search_msg = NULL;
6927 * Let the caller know that we did an originating updates
6929 ar->objs->originating_updates = replmd_private->originating_updates;
6931 ret = ldb_build_search_req(&search_req,
6934 ar->objs->partition_dn,
6940 replmd_replicated_uptodate_search_callback,
6942 LDB_REQ_SET_LOCATION(search_req);
6943 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
6945 return ldb_next_request(ar->module, search_req);
6950 static int replmd_extended_replicated_objects(struct ldb_module *module, struct ldb_request *req)
6952 struct ldb_context *ldb;
6953 struct dsdb_extended_replicated_objects *objs;
6954 struct replmd_replicated_request *ar;
6955 struct ldb_control **ctrls;
6958 ldb = ldb_module_get_ctx(module);
6960 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_extended_replicated_objects\n");
6962 objs = talloc_get_type(req->op.extended.data, struct dsdb_extended_replicated_objects);
6964 ldb_debug(ldb, LDB_DEBUG_FATAL, "replmd_extended_replicated_objects: invalid extended data\n");
6965 return LDB_ERR_PROTOCOL_ERROR;
6968 if (objs->version != DSDB_EXTENDED_REPLICATED_OBJECTS_VERSION) {
6969 ldb_debug(ldb, LDB_DEBUG_FATAL, "replmd_extended_replicated_objects: extended data invalid version [%u != %u]\n",
6970 objs->version, DSDB_EXTENDED_REPLICATED_OBJECTS_VERSION);
6971 return LDB_ERR_PROTOCOL_ERROR;
6974 ar = replmd_ctx_init(module, req);
6976 return LDB_ERR_OPERATIONS_ERROR;
6978 /* Set the flags to have the replmd_op_callback run over the full set of objects */
6979 ar->apply_mode = true;
6981 ar->schema = dsdb_get_schema(ldb, ar);
6983 ldb_debug_set(ldb, LDB_DEBUG_FATAL, "replmd_ctx_init: no loaded schema found\n");
6985 DEBUG(0,(__location__ ": %s\n", ldb_errstring(ldb)));
6986 return LDB_ERR_CONSTRAINT_VIOLATION;
6989 ctrls = req->controls;
6991 if (req->controls) {
6992 req->controls = talloc_memdup(ar, req->controls,
6993 talloc_get_size(req->controls));
6994 if (!req->controls) return replmd_replicated_request_werror(ar, WERR_NOT_ENOUGH_MEMORY);
6997 ret = ldb_request_add_control(req, DSDB_CONTROL_REPLICATED_UPDATE_OID, false, NULL);
6998 if (ret != LDB_SUCCESS) {
7002 /* If this change contained linked attributes in the body
7003 * (rather than in the links section) we need to update
7004 * backlinks in linked_attributes */
7005 ret = ldb_request_add_control(req, DSDB_CONTROL_APPLY_LINKS, false, NULL);
7006 if (ret != LDB_SUCCESS) {
7010 ar->controls = req->controls;
7011 req->controls = ctrls;
7013 return replmd_replicated_apply_next(ar);
7017 * Checks how to handle an missing target - either we need to fail the
7018 * replication and retry with GET_TGT, ignore the link and continue, or try to
7019 * add a partial link to an unknown target.
7021 static int replmd_allow_missing_target(struct ldb_module *module,
7022 TALLOC_CTX *mem_ctx,
7023 struct ldb_dn *target_dn,
7024 struct ldb_dn *source_dn,
7027 uint32_t dsdb_repl_flags,
7029 const char * missing_str)
7031 struct ldb_context *ldb = ldb_module_get_ctx(module);
7035 * we may not be able to resolve link targets properly when
7036 * dealing with subsets of objects, e.g. the source is a
7037 * critical object and the target isn't
7040 * When we implement Trusted Domains we need to consider
7041 * whether they get treated as an incomplete replica here or not
7043 if (dsdb_repl_flags & DSDB_REPL_FLAG_OBJECT_SUBSET) {
7046 * Ignore the link. We don't increase the highwater-mark in
7047 * the object subset cases, so subsequent replications should
7048 * resolve any missing links
7050 DEBUG(2, ("%s target %s linked from %s\n", missing_str,
7051 ldb_dn_get_linearized(target_dn),
7052 ldb_dn_get_linearized(source_dn)));
7053 *ignore_link = true;
7057 if (dsdb_repl_flags & DSDB_REPL_FLAG_TARGETS_UPTODATE) {
7060 * target should already be up-to-date so there's no point in
7061 * retrying. This could be due to bad timing, or if a target
7062 * on a one-way link was deleted. We ignore the link rather
7063 * than failing the replication cycle completely
7065 *ignore_link = true;
7066 DBG_WARNING("%s is %s but up to date. Ignoring link from %s\n",
7067 ldb_dn_get_linearized(target_dn), missing_str,
7068 ldb_dn_get_linearized(source_dn));
7072 is_in_same_nc = dsdb_objects_have_same_nc(ldb,
7076 if (is_in_same_nc) {
7077 /* fail the replication and retry with GET_TGT */
7078 ldb_asprintf_errstring(ldb, "%s target %s GUID %s linked from %s\n",
7080 ldb_dn_get_linearized(target_dn),
7081 GUID_string(mem_ctx, guid),
7082 ldb_dn_get_linearized(source_dn));
7083 return LDB_ERR_NO_SUCH_OBJECT;
7087 * The target of the cross-partition link is missing. Continue
7088 * and try to at least add the forward-link. This isn't great,
7089 * but a partial link can be fixed by dbcheck, so it's better
7090 * than dropping the link completely.
7092 *ignore_link = false;
7094 if (is_obj_commit) {
7097 * Only log this when we're actually committing the objects.
7098 * This avoids spurious logs, i.e. if we're just verifying the
7099 * received link during a join.
7101 DBG_WARNING("%s cross-partition target %s linked from %s\n",
7102 missing_str, ldb_dn_get_linearized(target_dn),
7103 ldb_dn_get_linearized(source_dn));
7110 * Checks that the target object for a linked attribute exists.
7111 * @param guid returns the target object's GUID (is returned)if it exists)
7112 * @param ignore_link set to true if the linked attribute should be ignored
7113 * (i.e. the target doesn't exist, but that it's OK to skip the link)
7115 static int replmd_check_target_exists(struct ldb_module *module,
7116 struct dsdb_dn *dsdb_dn,
7117 struct la_entry *la_entry,
7118 struct ldb_dn *source_dn,
7123 struct drsuapi_DsReplicaLinkedAttribute *la = la_entry->la;
7124 struct ldb_context *ldb = ldb_module_get_ctx(module);
7125 struct ldb_result *target_res;
7126 TALLOC_CTX *tmp_ctx = talloc_new(la_entry);
7127 const char *attrs[] = { "isDeleted", "isRecycled", NULL };
7130 enum deletion_state target_deletion_state = OBJECT_REMOVED;
7131 bool active = (la->flags & DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE) ? true : false;
7133 *ignore_link = false;
7134 ntstatus = dsdb_get_extended_dn_guid(dsdb_dn->dn, guid, "GUID");
7136 if (!NT_STATUS_IS_OK(ntstatus) && !active) {
7139 * This strange behaviour (allowing a NULL/missing
7140 * GUID) originally comes from:
7142 * commit e3054ce0fe0f8f62d2f5b2a77893e7a1479128bd
7143 * Author: Andrew Tridgell <tridge@samba.org>
7144 * Date: Mon Dec 21 21:21:55 2009 +1100
7146 * s4-drs: cope better with NULL GUIDS from DRS
7148 * It is valid to get a NULL GUID over DRS for a deleted forward link. We
7149 * need to match by DN if possible when seeing if we should update an
7152 * Pair-Programmed-With: Andrew Bartlett <abartlet@samba.org>
7154 ret = dsdb_module_search_dn(module, tmp_ctx, &target_res,
7156 DSDB_FLAG_NEXT_MODULE |
7157 DSDB_SEARCH_SHOW_RECYCLED |
7158 DSDB_SEARCH_SEARCH_ALL_PARTITIONS |
7159 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT,
7161 } else if (!NT_STATUS_IS_OK(ntstatus)) {
7162 ldb_asprintf_errstring(ldb, "Failed to find GUID in linked attribute 0x%x blob for %s from %s",
7164 ldb_dn_get_linearized(dsdb_dn->dn),
7165 ldb_dn_get_linearized(source_dn));
7166 talloc_free(tmp_ctx);
7167 return LDB_ERR_OPERATIONS_ERROR;
7169 ret = dsdb_module_search(module, tmp_ctx, &target_res,
7170 NULL, LDB_SCOPE_SUBTREE,
7172 DSDB_FLAG_NEXT_MODULE |
7173 DSDB_SEARCH_SHOW_RECYCLED |
7174 DSDB_SEARCH_SEARCH_ALL_PARTITIONS |
7175 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT,
7178 GUID_string(tmp_ctx, guid));
7181 if (ret != LDB_SUCCESS) {
7182 ldb_asprintf_errstring(ldb, "Failed to re-resolve GUID %s: %s\n",
7183 GUID_string(tmp_ctx, guid),
7184 ldb_errstring(ldb));
7185 talloc_free(tmp_ctx);
7189 if (target_res->count == 0) {
7192 * target object is unknown. Check whether to ignore the link,
7193 * fail the replication, or add a partial link
7195 ret = replmd_allow_missing_target(module, tmp_ctx, dsdb_dn->dn,
7196 source_dn, is_obj_commit, guid,
7197 la_entry->dsdb_repl_flags,
7198 ignore_link, "Unknown");
7200 } else if (target_res->count != 1) {
7201 ldb_asprintf_errstring(ldb, "More than one object found matching objectGUID %s\n",
7202 GUID_string(tmp_ctx, guid));
7203 ret = LDB_ERR_OPERATIONS_ERROR;
7205 struct ldb_message *target_msg = target_res->msgs[0];
7207 dsdb_dn->dn = talloc_steal(dsdb_dn, target_msg->dn);
7209 /* Get the object's state (i.e. Not Deleted, Tombstone, etc) */
7210 replmd_deletion_state(module, target_msg,
7211 &target_deletion_state, NULL);
7214 * Check for deleted objects as per MS-DRSR 4.1.10.6.14
7215 * ProcessLinkValue(). Link updates should not be sent for
7216 * recycled and tombstone objects (deleting the links should
7217 * happen when we delete the object). This probably means our
7218 * copy of the target object isn't up to date.
7220 if (target_deletion_state >= OBJECT_RECYCLED) {
7223 * target object is deleted. Check whether to ignore the
7224 * link, fail the replication, or add a partial link
7226 ret = replmd_allow_missing_target(module, tmp_ctx,
7227 dsdb_dn->dn, source_dn,
7228 is_obj_commit, guid,
7229 la_entry->dsdb_repl_flags,
7230 ignore_link, "Deleted");
7234 talloc_free(tmp_ctx);
7239 * Extracts the key details about the source/target object for a
7240 * linked-attribute entry.
7241 * This returns the following details:
7242 * @param ret_attr the schema details for the linked attribute
7243 * @param source_msg the search result for the source object
7244 * @param target_dsdb_dn the unpacked DN info for the target object
7246 static int replmd_extract_la_entry_details(struct ldb_module *module,
7247 struct la_entry *la_entry,
7248 TALLOC_CTX *mem_ctx,
7249 const struct dsdb_attribute **ret_attr,
7250 struct ldb_message **source_msg,
7251 struct dsdb_dn **target_dsdb_dn)
7253 struct drsuapi_DsReplicaLinkedAttribute *la = la_entry->la;
7254 struct ldb_context *ldb = ldb_module_get_ctx(module);
7255 const struct dsdb_schema *schema = dsdb_get_schema(ldb, mem_ctx);
7257 const struct dsdb_attribute *attr;
7259 struct ldb_result *res;
7260 const char *attrs[4];
7263 linked_attributes[0]:
7264 &objs->linked_attributes[i]: struct drsuapi_DsReplicaLinkedAttribute
7266 identifier: struct drsuapi_DsReplicaObjectIdentifier
7267 __ndr_size : 0x0000003a (58)
7268 __ndr_size_sid : 0x00000000 (0)
7269 guid : 8e95b6a9-13dd-4158-89db-3220a5be5cc7
7271 __ndr_size_dn : 0x00000000 (0)
7273 attid : DRSUAPI_ATTID_member (0x1F)
7274 value: struct drsuapi_DsAttributeValue
7275 __ndr_size : 0x0000007e (126)
7277 blob : DATA_BLOB length=126
7278 flags : 0x00000001 (1)
7279 1: DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE
7280 originating_add_time : Wed Sep 2 22:20:01 2009 EST
7281 meta_data: struct drsuapi_DsReplicaMetaData
7282 version : 0x00000015 (21)
7283 originating_change_time : Wed Sep 2 23:39:07 2009 EST
7284 originating_invocation_id: 794640f3-18cf-40ee-a211-a93992b67a64
7285 originating_usn : 0x000000000001e19c (123292)
7287 (for cases where the link is to a normal DN)
7288 &target: struct drsuapi_DsReplicaObjectIdentifier3
7289 __ndr_size : 0x0000007e (126)
7290 __ndr_size_sid : 0x0000001c (28)
7291 guid : 7639e594-db75-4086-b0d4-67890ae46031
7292 sid : S-1-5-21-2848215498-2472035911-1947525656-19924
7293 __ndr_size_dn : 0x00000022 (34)
7294 dn : 'CN=UOne,OU=TestOU,DC=vsofs8,DC=com'
7297 /* find the attribute being modified */
7298 attr = dsdb_attribute_by_attributeID_id(schema, la->attid);
7300 struct GUID_txt_buf guid_str;
7301 ldb_asprintf_errstring(ldb, "Unable to find attributeID 0x%x for link on <GUID=%s>",
7303 GUID_buf_string(&la->identifier->guid,
7305 return LDB_ERR_OPERATIONS_ERROR;
7309 * All attributes listed here must be dealt with in some way
7310 * by replmd_process_linked_attribute() otherwise in the case
7311 * of isDeleted: FALSE the modify will fail with:
7313 * Failed to apply linked attribute change 'attribute 'isDeleted':
7314 * invalid modify flags on
7315 * 'CN=g1_1527570609273,CN=Users,DC=samba,DC=example,DC=com':
7318 * This is becaue isDeleted is a Boolean, so FALSE is a
7319 * legitimate value (set by Samba's deletetest.py)
7321 attrs[0] = attr->lDAPDisplayName;
7322 attrs[1] = "isDeleted";
7323 attrs[2] = "isRecycled";
7327 * get the existing message from the db for the object with
7328 * this GUID, returning attribute being modified. We will then
7329 * use this msg as the basis for a modify call
7331 ret = dsdb_module_search(module, mem_ctx, &res, NULL, LDB_SCOPE_SUBTREE, attrs,
7332 DSDB_FLAG_NEXT_MODULE |
7333 DSDB_SEARCH_SEARCH_ALL_PARTITIONS |
7334 DSDB_SEARCH_SHOW_RECYCLED |
7335 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT |
7336 DSDB_SEARCH_REVEAL_INTERNALS,
7338 "objectGUID=%s", GUID_string(mem_ctx, &la->identifier->guid));
7339 if (ret != LDB_SUCCESS) {
7342 if (res->count != 1) {
7343 ldb_asprintf_errstring(ldb, "DRS linked attribute for GUID %s - DN not found",
7344 GUID_string(mem_ctx, &la->identifier->guid));
7345 return LDB_ERR_NO_SUCH_OBJECT;
7348 *source_msg = res->msgs[0];
7350 /* the value blob for the attribute holds the target object DN */
7351 status = dsdb_dn_la_from_blob(ldb, attr, schema, mem_ctx, la->value.blob, target_dsdb_dn);
7352 if (!W_ERROR_IS_OK(status)) {
7353 ldb_asprintf_errstring(ldb, "Failed to parsed linked attribute blob for %s on %s - %s\n",
7354 attr->lDAPDisplayName,
7355 ldb_dn_get_linearized(res->msgs[0]->dn),
7356 win_errstr(status));
7357 return LDB_ERR_OPERATIONS_ERROR;
7366 * Verifies the source and target objects are known for a linked attribute
7368 static int replmd_verify_linked_attribute(struct replmd_replicated_request *ar,
7369 struct la_entry *la)
7371 int ret = LDB_SUCCESS;
7372 TALLOC_CTX *tmp_ctx = talloc_new(la);
7373 struct ldb_module *module = ar->module;
7374 struct ldb_message *src_msg;
7375 const struct dsdb_attribute *attr;
7376 struct dsdb_dn *tgt_dsdb_dn;
7377 struct GUID guid = GUID_zero();
7380 ret = replmd_extract_la_entry_details(module, la, tmp_ctx, &attr,
7381 &src_msg, &tgt_dsdb_dn);
7384 * When we fail to find the source object, the error code we pass
7385 * back here is really important. It flags back to the callers to
7386 * retry this request with DRSUAPI_DRS_GET_ANC. This case should
7387 * never happen if we're replicating from a Samba DC, but it is
7388 * needed to talk to a Windows DC
7390 if (ret == LDB_ERR_NO_SUCH_OBJECT) {
7391 ret = replmd_replicated_request_werror(ar, WERR_DS_DRA_MISSING_PARENT);
7394 if (ret != LDB_SUCCESS) {
7395 talloc_free(tmp_ctx);
7400 * We can skip the target object checks if we're only syncing critical
7401 * objects, or we know the target is up-to-date. If either case, we
7402 * still continue even if the target doesn't exist
7404 if ((la->dsdb_repl_flags & (DSDB_REPL_FLAG_OBJECT_SUBSET |
7405 DSDB_REPL_FLAG_TARGETS_UPTODATE)) == 0) {
7407 ret = replmd_check_target_exists(module, tgt_dsdb_dn, la,
7408 src_msg->dn, false, &guid,
7413 * When we fail to find the target object, the error code we pass
7414 * back here is really important. It flags back to the callers to
7415 * retry this request with DRSUAPI_DRS_GET_TGT
7417 if (ret == LDB_ERR_NO_SUCH_OBJECT) {
7418 ret = replmd_replicated_request_werror(ar, WERR_DS_DRA_RECYCLED_TARGET);
7421 talloc_free(tmp_ctx);
7426 * Finds the current active Parsed-DN value for a single-valued linked
7427 * attribute, if one exists.
7428 * @param ret_pdn assigned the active Parsed-DN, or NULL if none was found
7429 * @returns LDB_SUCCESS (regardless of whether a match was found), unless
7432 static int replmd_get_active_singleval_link(struct ldb_module *module,
7433 TALLOC_CTX *mem_ctx,
7434 struct parsed_dn pdn_list[],
7436 const struct dsdb_attribute *attr,
7437 struct parsed_dn **ret_pdn)
7443 if (!(attr->ldb_schema_attribute->flags & LDB_ATTR_FLAG_SINGLE_VALUE)) {
7445 /* nothing to do for multi-valued linked attributes */
7449 for (i = 0; i < count; i++) {
7450 int ret = LDB_SUCCESS;
7451 struct parsed_dn *pdn = &pdn_list[i];
7453 /* skip any inactive links */
7454 if (dsdb_dn_is_deleted_val(pdn->v)) {
7458 /* we've found an active value for this attribute */
7461 if (pdn->dsdb_dn == NULL) {
7462 struct ldb_context *ldb = ldb_module_get_ctx(module);
7464 ret = really_parse_trusted_dn(mem_ctx, ldb, pdn,
7465 attr->syntax->ldap_oid);
7471 /* no active link found */
7476 * @returns true if the replication linked attribute info is newer than we
7477 * already have in our DB
7478 * @param pdn the existing linked attribute info in our DB
7479 * @param la the new linked attribute info received during replication
7481 static bool replmd_link_update_is_newer(struct parsed_dn *pdn,
7482 struct drsuapi_DsReplicaLinkedAttribute *la)
7484 /* see if this update is newer than what we have already */
7485 struct GUID invocation_id = GUID_zero();
7486 uint32_t version = 0;
7487 NTTIME change_time = 0;
7491 /* no existing info so update is newer */
7495 dsdb_get_extended_dn_guid(pdn->dsdb_dn->dn, &invocation_id, "RMD_INVOCID");
7496 dsdb_get_extended_dn_uint32(pdn->dsdb_dn->dn, &version, "RMD_VERSION");
7497 dsdb_get_extended_dn_nttime(pdn->dsdb_dn->dn, &change_time, "RMD_CHANGETIME");
7499 return replmd_update_is_newer(&invocation_id,
7500 &la->meta_data.originating_invocation_id,
7502 la->meta_data.version,
7504 la->meta_data.originating_change_time);
7508 * Marks an existing linked attribute value as deleted in the DB
7509 * @param pdn the parsed-DN of the target-value to delete
7511 static int replmd_delete_link_value(struct ldb_module *module,
7512 struct replmd_private *replmd_private,
7513 TALLOC_CTX *mem_ctx,
7514 struct ldb_dn *src_obj_dn,
7515 const struct dsdb_schema *schema,
7516 const struct dsdb_attribute *attr,
7519 struct GUID *target_guid,
7520 struct dsdb_dn *target_dsdb_dn,
7521 struct ldb_val *output_val)
7523 struct ldb_context *ldb = ldb_module_get_ctx(module);
7526 const struct GUID *invocation_id = NULL;
7530 unix_to_nt_time(&now, t);
7532 invocation_id = samdb_ntds_invocation_id(ldb);
7533 if (invocation_id == NULL) {
7534 return LDB_ERR_OPERATIONS_ERROR;
7537 /* if the existing link is active, remove its backlink */
7540 ret = replmd_add_backlink(module, replmd_private, schema,
7541 src_obj_dn, target_guid, false,
7543 if (ret != LDB_SUCCESS) {
7548 /* mark the existing value as deleted */
7549 ret = replmd_update_la_val(mem_ctx, output_val, target_dsdb_dn,
7550 target_dsdb_dn, invocation_id, seq_num,
7551 seq_num, now, true);
7556 * Checks for a conflict in single-valued link attributes, and tries to
7557 * resolve the problem if possible.
7559 * Single-valued links should only ever have one active value. If we already
7560 * have an active link value, and during replication we receive an active link
7561 * value for a different target DN, then we need to resolve this inconsistency
7562 * and determine which value should be active. If the received info is better/
7563 * newer than the existing link attribute, then we need to set our existing
7564 * link as deleted. If the received info is worse/older, then we should continue
7565 * to add it, but set it as an inactive link.
7567 * Note that this is a corner-case that is unlikely to happen (but if it does
7568 * happen, we don't want it to break replication completely).
7570 * @param pdn_being_modified the parsed DN corresponding to the received link
7571 * target (note this is NULL if the link does not already exist in our DB)
7572 * @param pdn_list all the source object's Parsed-DNs for this attribute, i.e.
7573 * any existing active or inactive values for the attribute in our DB.
7574 * @param dsdb_dn the target DN for the received link attribute
7575 * @param add_as_inactive gets set to true if the received link is worse than
7576 * the existing link - it should still be added, but as an inactive link.
7578 static int replmd_check_singleval_la_conflict(struct ldb_module *module,
7579 struct replmd_private *replmd_private,
7580 TALLOC_CTX *mem_ctx,
7581 struct ldb_dn *src_obj_dn,
7582 struct drsuapi_DsReplicaLinkedAttribute *la,
7583 struct dsdb_dn *dsdb_dn,
7584 struct parsed_dn *pdn_being_modified,
7585 struct parsed_dn *pdn_list,
7586 struct ldb_message_element *old_el,
7587 const struct dsdb_schema *schema,
7588 const struct dsdb_attribute *attr,
7590 bool *add_as_inactive)
7592 struct parsed_dn *active_pdn = NULL;
7593 bool update_is_newer = false;
7597 * check if there's a conflict for single-valued links, i.e. an active
7598 * linked attribute already exists, but it has a different target value
7600 ret = replmd_get_active_singleval_link(module, mem_ctx, pdn_list,
7601 old_el->num_values, attr,
7604 if (ret != LDB_SUCCESS) {
7609 * If no active value exists (or the received info is for the currently
7610 * active value), then no conflict exists
7612 if (active_pdn == NULL || active_pdn == pdn_being_modified) {
7616 DBG_WARNING("Link conflict for %s attribute on %s\n",
7617 attr->lDAPDisplayName, ldb_dn_get_linearized(src_obj_dn));
7619 /* Work out how to resolve the conflict based on which info is better */
7620 update_is_newer = replmd_link_update_is_newer(active_pdn, la);
7622 if (update_is_newer) {
7623 DBG_WARNING("Using received value %s, over existing target %s\n",
7624 ldb_dn_get_linearized(dsdb_dn->dn),
7625 ldb_dn_get_linearized(active_pdn->dsdb_dn->dn));
7628 * Delete our existing active link. The received info will then
7629 * be added (through normal link processing) as the active value
7631 ret = replmd_delete_link_value(module, replmd_private, old_el,
7632 src_obj_dn, schema, attr,
7633 seq_num, true, &active_pdn->guid,
7634 active_pdn->dsdb_dn,
7637 if (ret != LDB_SUCCESS) {
7641 DBG_WARNING("Using existing target %s, over received value %s\n",
7642 ldb_dn_get_linearized(active_pdn->dsdb_dn->dn),
7643 ldb_dn_get_linearized(dsdb_dn->dn));
7646 * we want to keep our existing active link and add the
7647 * received link as inactive
7649 *add_as_inactive = true;
7656 process one linked attribute structure
7658 static int replmd_process_linked_attribute(struct ldb_module *module,
7659 struct replmd_private *replmd_private,
7660 struct la_entry *la_entry,
7661 struct ldb_request *parent)
7663 struct drsuapi_DsReplicaLinkedAttribute *la = la_entry->la;
7664 struct ldb_context *ldb = ldb_module_get_ctx(module);
7665 struct ldb_message *msg;
7666 TALLOC_CTX *tmp_ctx = talloc_new(la_entry);
7667 const struct dsdb_schema *schema = dsdb_get_schema(ldb, tmp_ctx);
7669 const struct dsdb_attribute *attr;
7670 struct dsdb_dn *dsdb_dn;
7671 uint64_t seq_num = 0;
7672 struct ldb_message_element *old_el;
7673 time_t t = time(NULL);
7674 struct parsed_dn *pdn_list, *pdn, *next;
7675 struct GUID guid = GUID_zero();
7676 bool active = (la->flags & DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE)?true:false;
7678 enum deletion_state deletion_state = OBJECT_NOT_DELETED;
7679 struct dsdb_dn *old_dsdb_dn = NULL;
7680 struct ldb_val *val_to_update = NULL;
7681 bool add_as_inactive = false;
7684 * get the attribute being modified, the search result for the source object,
7685 * and the target object's DN details
7687 ret = replmd_extract_la_entry_details(module, la_entry, tmp_ctx, &attr,
7690 if (ret != LDB_SUCCESS) {
7691 talloc_free(tmp_ctx);
7696 * Check for deleted objects per MS-DRSR 4.1.10.6.14
7697 * ProcessLinkValue, because link updates are not applied to
7698 * recycled and tombstone objects. We don't have to delete
7699 * any existing link, that should have happened when the
7700 * object deletion was replicated or initiated.
7702 * This needs isDeleted and isRecycled to be included as
7703 * attributes in the search and so in msg if set.
7705 replmd_deletion_state(module, msg, &deletion_state, NULL);
7707 if (deletion_state >= OBJECT_RECYCLED) {
7708 talloc_free(tmp_ctx);
7713 * Now that we know the deletion_state, remove the extra
7714 * attributes added for that purpose. We need to do this
7715 * otherwise in the case of isDeleted: FALSE the modify will
7718 * Failed to apply linked attribute change 'attribute 'isDeleted':
7719 * invalid modify flags on
7720 * 'CN=g1_1527570609273,CN=Users,DC=samba,DC=example,DC=com':
7723 * This is becaue isDeleted is a Boolean, so FALSE is a
7724 * legitimate value (set by Samba's deletetest.py)
7727 ldb_msg_remove_attr(msg, "isDeleted");
7728 ldb_msg_remove_attr(msg, "isRecycled");
7730 old_el = ldb_msg_find_element(msg, attr->lDAPDisplayName);
7731 if (old_el == NULL) {
7732 ret = ldb_msg_add_empty(msg, attr->lDAPDisplayName, LDB_FLAG_MOD_REPLACE, &old_el);
7733 if (ret != LDB_SUCCESS) {
7734 ldb_module_oom(module);
7735 talloc_free(tmp_ctx);
7736 return LDB_ERR_OPERATIONS_ERROR;
7739 old_el->flags = LDB_FLAG_MOD_REPLACE;
7742 /* parse the existing links */
7743 ret = get_parsed_dns_trusted(module, replmd_private, tmp_ctx, old_el, &pdn_list,
7744 attr->syntax->ldap_oid, parent);
7746 if (ret != LDB_SUCCESS) {
7747 talloc_free(tmp_ctx);
7751 ret = replmd_check_target_exists(module, dsdb_dn, la_entry, msg->dn,
7752 true, &guid, &ignore_link);
7754 if (ret != LDB_SUCCESS) {
7755 talloc_free(tmp_ctx);
7760 * there are some cases where the target object doesn't exist, but it's
7761 * OK to ignore the linked attribute
7764 talloc_free(tmp_ctx);
7768 /* see if this link already exists */
7769 ret = parsed_dn_find(ldb, pdn_list, old_el->num_values,
7772 dsdb_dn->extra_part, 0,
7774 attr->syntax->ldap_oid,
7776 if (ret != LDB_SUCCESS) {
7777 talloc_free(tmp_ctx);
7781 if (!replmd_link_update_is_newer(pdn, la)) {
7782 DEBUG(3,("Discarding older DRS linked attribute update to %s on %s from %s\n",
7783 old_el->name, ldb_dn_get_linearized(msg->dn),
7784 GUID_string(tmp_ctx, &la->meta_data.originating_invocation_id)));
7785 talloc_free(tmp_ctx);
7789 /* get a seq_num for this change */
7790 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &seq_num);
7791 if (ret != LDB_SUCCESS) {
7792 talloc_free(tmp_ctx);
7797 * check for single-valued link conflicts, i.e. an active linked
7798 * attribute already exists, but it has a different target value
7801 ret = replmd_check_singleval_la_conflict(module, replmd_private,
7802 tmp_ctx, msg->dn, la,
7803 dsdb_dn, pdn, pdn_list,
7804 old_el, schema, attr,
7807 if (ret != LDB_SUCCESS) {
7808 talloc_free(tmp_ctx);
7814 uint32_t rmd_flags = dsdb_dn_rmd_flags(pdn->dsdb_dn->dn);
7816 if (!(rmd_flags & DSDB_RMD_FLAG_DELETED)) {
7817 /* remove the existing backlink */
7818 ret = replmd_add_backlink(module, replmd_private,
7821 &pdn->guid, false, attr,
7823 if (ret != LDB_SUCCESS) {
7824 talloc_free(tmp_ctx);
7829 val_to_update = pdn->v;
7830 old_dsdb_dn = pdn->dsdb_dn;
7836 * We know where the new one needs to be, from the *next
7837 * pointer into pdn_list.
7840 offset = old_el->num_values;
7842 if (next->dsdb_dn == NULL) {
7843 ret = really_parse_trusted_dn(tmp_ctx, ldb, next,
7844 attr->syntax->ldap_oid);
7845 if (ret != LDB_SUCCESS) {
7849 offset = next - pdn_list;
7850 if (offset > old_el->num_values) {
7851 talloc_free(tmp_ctx);
7852 return LDB_ERR_OPERATIONS_ERROR;
7856 old_el->values = talloc_realloc(msg->elements, old_el->values,
7857 struct ldb_val, old_el->num_values+1);
7858 if (!old_el->values) {
7859 ldb_module_oom(module);
7860 return LDB_ERR_OPERATIONS_ERROR;
7863 if (offset != old_el->num_values) {
7864 memmove(&old_el->values[offset + 1], &old_el->values[offset],
7865 (old_el->num_values - offset) * sizeof(old_el->values[0]));
7868 old_el->num_values++;
7870 val_to_update = &old_el->values[offset];
7874 /* set the link attribute's value to the info that was received */
7875 ret = replmd_set_la_val(tmp_ctx, val_to_update, dsdb_dn, old_dsdb_dn,
7876 &la->meta_data.originating_invocation_id,
7877 la->meta_data.originating_usn, seq_num,
7878 la->meta_data.originating_change_time,
7879 la->meta_data.version,
7881 if (ret != LDB_SUCCESS) {
7882 talloc_free(tmp_ctx);
7886 if (add_as_inactive) {
7888 /* Set the new link as inactive/deleted to avoid conflicts */
7889 ret = replmd_delete_link_value(module, replmd_private, old_el,
7890 msg->dn, schema, attr, seq_num,
7891 false, &guid, dsdb_dn,
7894 if (ret != LDB_SUCCESS) {
7895 talloc_free(tmp_ctx);
7899 } else if (active) {
7901 /* if the new link is active, then add the new backlink */
7902 ret = replmd_add_backlink(module, replmd_private,
7907 if (ret != LDB_SUCCESS) {
7908 talloc_free(tmp_ctx);
7913 /* we only change whenChanged and uSNChanged if the seq_num
7915 ret = add_time_element(msg, "whenChanged", t);
7916 if (ret != LDB_SUCCESS) {
7917 talloc_free(tmp_ctx);
7922 ret = add_uint64_element(ldb, msg, "uSNChanged", seq_num);
7923 if (ret != LDB_SUCCESS) {
7924 talloc_free(tmp_ctx);
7929 old_el = ldb_msg_find_element(msg, attr->lDAPDisplayName);
7930 if (old_el == NULL) {
7931 talloc_free(tmp_ctx);
7932 return ldb_operr(ldb);
7935 ret = dsdb_check_single_valued_link(attr, old_el);
7936 if (ret != LDB_SUCCESS) {
7937 talloc_free(tmp_ctx);
7941 old_el->flags |= LDB_FLAG_INTERNAL_DISABLE_SINGLE_VALUE_CHECK;
7943 ret = linked_attr_modify(module, msg, parent);
7944 if (ret != LDB_SUCCESS) {
7945 ldb_debug(ldb, LDB_DEBUG_WARNING, "Failed to apply linked attribute change '%s'\n%s\n",
7947 ldb_ldif_message_redacted_string(ldb,
7949 LDB_CHANGETYPE_MODIFY,
7951 talloc_free(tmp_ctx);
7955 talloc_free(tmp_ctx);
7960 static int replmd_extended(struct ldb_module *module, struct ldb_request *req)
7962 if (strcmp(req->op.extended.oid, DSDB_EXTENDED_REPLICATED_OBJECTS_OID) == 0) {
7963 return replmd_extended_replicated_objects(module, req);
7966 return ldb_next_request(module, req);
7971 we hook into the transaction operations to allow us to
7972 perform the linked attribute updates at the end of the whole
7973 transaction. This allows a forward linked attribute to be created
7974 before the object is created. During a vampire, w2k8 sends us linked
7975 attributes before the objects they are part of.
7977 static int replmd_start_transaction(struct ldb_module *module)
7979 /* create our private structure for this transaction */
7980 struct replmd_private *replmd_private = talloc_get_type(ldb_module_get_private(module),
7981 struct replmd_private);
7982 replmd_txn_cleanup(replmd_private);
7984 /* free any leftover mod_usn records from cancelled
7986 while (replmd_private->ncs) {
7987 struct nc_entry *e = replmd_private->ncs;
7988 DLIST_REMOVE(replmd_private->ncs, e);
7992 replmd_private->originating_updates = false;
7994 return ldb_next_start_trans(module);
7998 on prepare commit we loop over our queued la_context structures and
8001 static int replmd_prepare_commit(struct ldb_module *module)
8003 struct replmd_private *replmd_private =
8004 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
8005 struct la_entry *la, *prev;
8009 * Walk the list of linked attributes from DRS replication.
8011 * We walk backwards, to do the first entry first, as we
8012 * added the entries with DLIST_ADD() which puts them at the
8015 for (la = DLIST_TAIL(replmd_private->la_list); la; la=prev) {
8016 prev = DLIST_PREV(la);
8017 DLIST_REMOVE(replmd_private->la_list, la);
8018 ret = replmd_process_linked_attribute(module, replmd_private,
8020 if (ret != LDB_SUCCESS) {
8021 replmd_txn_cleanup(replmd_private);
8026 replmd_txn_cleanup(replmd_private);
8028 /* possibly change @REPLCHANGED */
8029 ret = replmd_notify_store(module, NULL);
8030 if (ret != LDB_SUCCESS) {
8034 return ldb_next_prepare_commit(module);
8037 static int replmd_del_transaction(struct ldb_module *module)
8039 struct replmd_private *replmd_private =
8040 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
8041 replmd_txn_cleanup(replmd_private);
8043 return ldb_next_del_trans(module);
8047 static const struct ldb_module_ops ldb_repl_meta_data_module_ops = {
8048 .name = "repl_meta_data",
8049 .init_context = replmd_init,
8051 .modify = replmd_modify,
8052 .rename = replmd_rename,
8053 .del = replmd_delete,
8054 .extended = replmd_extended,
8055 .start_transaction = replmd_start_transaction,
8056 .prepare_commit = replmd_prepare_commit,
8057 .del_transaction = replmd_del_transaction,
8060 int ldb_repl_meta_data_module_init(const char *version)
8062 LDB_MODULE_CHECK_VERSION(version);
8063 return ldb_register_module(&ldb_repl_meta_data_module_ops);